summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am3
-rw-r--r--README.md2
-rw-r--r--babeld/subdir.am2
-rw-r--r--bfdd/Makefile10
-rw-r--r--bfdd/bfdd_vty.c13
-rw-r--r--bgpd/bgp_aspath.c55
-rw-r--r--bgpd/bgp_debug.c61
-rw-r--r--bgpd/bgp_debug.h1
-rw-r--r--bgpd/bgp_evpn_private.h7
-rw-r--r--bgpd/bgp_evpn_vty.c92
-rw-r--r--bgpd/bgp_route.c18
-rw-r--r--bgpd/bgp_routemap.c15
-rw-r--r--bgpd/bgp_rpki.c22
-rw-r--r--bgpd/bgp_vty.c8
-rw-r--r--bgpd/bgp_zebra.c29
-rw-r--r--bgpd/bgp_zebra.h2
-rw-r--r--bgpd/bgpd.c25
-rw-r--r--bgpd/rfapi/bgp_rfapi_cfg.c54
-rw-r--r--bgpd/subdir.am11
-rwxr-xr-xconfigure.ac23
-rw-r--r--doc/developer/conf.py2
-rw-r--r--doc/developer/index.rst1
-rw-r--r--doc/developer/subdir.am3
-rw-r--r--doc/developer/testing.rst10
-rw-r--r--doc/developer/topotests-snippets.rst272
-rw-r--r--doc/developer/topotests.rst927
-rw-r--r--doc/user/ipv6.rst55
-rw-r--r--doc/user/routemap.rst11
-rw-r--r--doc/user/sharp.rst21
-rw-r--r--docker/debian/Dockerfile10
-rw-r--r--docker/debian/README.md17
-rw-r--r--docker/debian/daemons65
-rwxr-xr-xdocker/debian/docker-start10
-rw-r--r--eigrpd/eigrp_dump.c6
-rw-r--r--eigrpd/eigrp_dump.h5
-rw-r--r--eigrpd/eigrp_hello.c2
-rw-r--r--eigrpd/eigrp_interface.c30
-rw-r--r--eigrpd/eigrp_network.c4
-rw-r--r--eigrpd/eigrp_packet.c14
-rw-r--r--eigrpd/eigrp_structs.h2
-rw-r--r--eigrpd/eigrp_topology.c7
-rw-r--r--eigrpd/eigrp_vty.c111
-rw-r--r--eigrpd/eigrp_zebra.c8
-rw-r--r--eigrpd/eigrp_zebra.h3
-rw-r--r--eigrpd/subdir.am2
-rw-r--r--isisd/isis_cli.c32
-rw-r--r--isisd/isis_northbound.c108
-rw-r--r--isisd/isis_redist.c2
-rw-r--r--isisd/subdir.am2
-rw-r--r--ldpd/subdir.am2
-rw-r--r--lib/agg_table.h9
-rw-r--r--lib/bfd.h8
-rw-r--r--lib/bitfield.h8
-rw-r--r--lib/buffer.h8
-rw-r--r--lib/checksum.h8
-rw-r--r--lib/clippy.h8
-rw-r--r--lib/command.c2
-rw-r--r--lib/command.h9
-rw-r--r--lib/command_graph.h10
-rw-r--r--lib/command_match.h10
-rw-r--r--lib/compiler.h8
-rw-r--r--lib/csv.h8
-rw-r--r--lib/db.h8
-rw-r--r--lib/debug.h10
-rw-r--r--lib/distribute.h8
-rw-r--r--lib/event_counter.h8
-rw-r--r--lib/ferr.h8
-rw-r--r--lib/fifo.h8
-rw-r--r--lib/filter.h8
-rw-r--r--lib/freebsd-queue.h8
-rw-r--r--lib/frr_pthread.c4
-rw-r--r--lib/frr_pthread.h10
-rw-r--r--lib/frr_zmq.h8
-rw-r--r--lib/frratomic.h31
-rw-r--r--lib/frrstr.h8
-rw-r--r--lib/graph.h9
-rw-r--r--lib/hash.h12
-rw-r--r--lib/hook.h8
-rw-r--r--lib/id_alloc.h8
-rw-r--r--lib/if.c8
-rw-r--r--lib/if.h12
-rw-r--r--lib/if_rmap.h8
-rw-r--r--lib/imsg.h8
-rw-r--r--lib/ipaddr.h8
-rw-r--r--lib/jhash.h8
-rw-r--r--lib/json.h8
-rw-r--r--lib/keychain.h8
-rw-r--r--lib/lib_errors.h8
-rw-r--r--lib/libfrr.h8
-rw-r--r--lib/libospf.h8
-rw-r--r--lib/linklist.h13
-rw-r--r--lib/log.c9
-rw-r--r--lib/log.h18
-rw-r--r--lib/log_int.h8
-rw-r--r--lib/logicalrouter.h8
-rw-r--r--lib/lua.h9
-rw-r--r--lib/md5.h8
-rw-r--r--lib/memory.c1
-rw-r--r--lib/memory.h19
-rw-r--r--lib/memory_vty.h9
-rw-r--r--lib/mlag.h9
-rw-r--r--lib/module.h15
-rw-r--r--lib/monotime.h8
-rw-r--r--lib/mpls.h8
-rw-r--r--lib/network.h8
-rw-r--r--lib/nexthop.h9
-rw-r--r--lib/nexthop_group.h13
-rw-r--r--lib/northbound.c20
-rw-r--r--lib/northbound.h12
-rw-r--r--lib/northbound_cli.h8
-rw-r--r--lib/northbound_confd.c2
-rw-r--r--lib/northbound_db.h8
-rw-r--r--lib/northbound_sysrepo.c4
-rw-r--r--lib/ns.h8
-rw-r--r--lib/openbsd-queue.h8
-rw-r--r--lib/openbsd-tree.h39
-rw-r--r--lib/pbr.h8
-rw-r--r--lib/plist.h8
-rw-r--r--lib/plist_int.h8
-rw-r--r--lib/pqueue.h8
-rw-r--r--lib/prefix.c1
-rw-r--r--lib/prefix.h38
-rw-r--r--lib/privs.c4
-rw-r--r--lib/privs.h8
-rw-r--r--lib/ptm_lib.h8
-rw-r--r--lib/pw.h11
-rw-r--r--lib/qobj.h14
-rw-r--r--lib/queue.h8
-rw-r--r--lib/ringbuf.h8
-rwxr-xr-xlib/route_types.pl2
-rw-r--r--lib/routemap.c55
-rw-r--r--lib/routemap.h17
-rw-r--r--lib/sbuf.h8
-rw-r--r--lib/sha256.h8
-rw-r--r--lib/sigevent.h8
-rw-r--r--lib/skiplist.h8
-rw-r--r--lib/smux.h8
-rw-r--r--lib/sockopt.h9
-rw-r--r--lib/sockunion.h8
-rw-r--r--lib/spf_backoff.h8
-rw-r--r--lib/srcdest_table.h11
-rw-r--r--lib/stream.h12
-rw-r--r--lib/subdir.am16
-rw-r--r--lib/systemd.h8
-rw-r--r--lib/table.h9
-rw-r--r--lib/termtable.h8
-rw-r--r--lib/thread.c3
-rw-r--r--lib/thread.h16
-rw-r--r--lib/vector.h9
-rw-r--r--lib/vlan.h8
-rw-r--r--lib/vrf.c4
-rw-r--r--lib/vrf.h10
-rw-r--r--lib/vrf_int.h8
-rw-r--r--lib/vty.h8
-rw-r--r--lib/vxlan.h9
-rw-r--r--lib/wheel.h8
-rw-r--r--lib/workqueue.c11
-rw-r--r--lib/workqueue.h22
-rw-r--r--lib/yang.h8
-rw-r--r--lib/yang_translator.h8
-rw-r--r--lib/zclient.c8
-rw-r--r--lib/zclient.h1
-rw-r--r--lib/zebra.h9
-rw-r--r--nhrpd/subdir.am4
-rw-r--r--ospf6d/ospf6_asbr.c12
-rw-r--r--ospf6d/subdir.am2
-rw-r--r--ospfclient/subdir.am2
-rw-r--r--ospfd/ospf_packet.c22
-rw-r--r--ospfd/ospf_routemap.c18
-rw-r--r--ospfd/ospf_zebra.c9
-rw-r--r--ospfd/subdir.am2
-rw-r--r--pbrd/pbr_map.c8
-rw-r--r--pbrd/pbr_zebra.c60
-rw-r--r--pbrd/subdir.am2
-rw-r--r--pimd/pim_cmd.c36
-rw-r--r--pimd/pim_iface.c2
-rw-r--r--pimd/pim_iface.h3
-rw-r--r--pimd/pim_oil.c6
-rw-r--r--pimd/pim_rp.c12
-rw-r--r--pimd/pim_vty.c3
-rw-r--r--pimd/pim_zebra.c22
-rw-r--r--pimd/pimd.h21
-rw-r--r--pimd/subdir.am5
-rw-r--r--redhat/frr.service7
-rw-r--r--redhat/frr.spec.in2
-rw-r--r--ripd/rip_cli.c28
-rw-r--r--ripd/rip_northbound.c32
-rw-r--r--ripd/ripd.c5
-rw-r--r--ripd/subdir.am2
-rw-r--r--ripngd/ripng_cli.c20
-rw-r--r--ripngd/ripng_northbound.c20
-rw-r--r--ripngd/ripngd.c5
-rw-r--r--ripngd/subdir.am2
-rw-r--r--sharpd/Makefile10
-rw-r--r--sharpd/sharp_globals.h55
-rw-r--r--sharpd/sharp_main.c15
-rw-r--r--sharpd/sharp_nht.c67
-rw-r--r--sharpd/sharp_nht.h38
-rw-r--r--sharpd/sharp_vty.c126
-rw-r--r--sharpd/sharp_zebra.c77
-rw-r--r--sharpd/sharp_zebra.h3
-rw-r--r--sharpd/subdir.am5
-rw-r--r--staticd/subdir.am2
-rw-r--r--tests/.gitignore1
-rw-r--r--tests/Makefile.in1338
-rw-r--r--tests/lib/cxxcompat.c113
-rw-r--r--tests/subdir.am12
-rw-r--r--tests/topotests/GUIDELINES.md571
-rw-r--r--tests/topotests/README.md200
-rw-r--r--tests/topotests/SNIPPETS.md275
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py7
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py11
-rw-r--r--tests/topotests/eigrp-topo1/r1/show_ip_route.json_ref8
-rw-r--r--tests/topotests/eigrp-topo1/r1/zebra.conf1
-rw-r--r--tests/topotests/eigrp-topo1/r2/show_ip_route.json_ref8
-rw-r--r--tests/topotests/eigrp-topo1/r3/show_ip_route.json_ref8
-rwxr-xr-xtests/topotests/eigrp-topo1/test_eigrp_topo1.py11
-rw-r--r--tests/topotests/ospf-topo1-vrf/r1/zebra.conf4
-rw-r--r--tools/frr.service6
-rw-r--r--tools/gen_northbound_callbacks.c2
-rw-r--r--tools/subdir.am4
-rw-r--r--vtysh/subdir.am2
-rw-r--r--vtysh/vtysh.c4
-rw-r--r--watchfrr/subdir.am2
-rw-r--r--yang/libyang_plugins/subdir.am2
-rw-r--r--zebra/debug.c24
-rw-r--r--zebra/debug.h5
-rw-r--r--zebra/interface.c8
-rw-r--r--zebra/interface.h51
-rw-r--r--zebra/irdp_interface.c4
-rw-r--r--zebra/irdp_main.c8
-rw-r--r--zebra/irdp_packet.c4
-rw-r--r--zebra/kernel_netlink.c7
-rw-r--r--zebra/kernel_socket.c6
-rw-r--r--zebra/label_manager.c7
-rw-r--r--zebra/main.c23
-rw-r--r--zebra/redistribute.c63
-rw-r--r--zebra/router-id.c11
-rw-r--r--zebra/rt.h6
-rw-r--r--zebra/rt_netlink.c41
-rw-r--r--zebra/rtadv.c416
-rw-r--r--zebra/rtadv.h31
-rw-r--r--zebra/subdir.am3
-rw-r--r--zebra/zapi_msg.c37
-rw-r--r--zebra/zapi_msg.h2
-rw-r--r--zebra/zebra_dplane.c234
-rw-r--r--zebra/zebra_dplane.h25
-rw-r--r--zebra/zebra_mlag.c26
-rw-r--r--zebra/zebra_mpls.c36
-rw-r--r--zebra/zebra_mpls_netlink.c10
-rw-r--r--zebra/zebra_mpls_null.c9
-rw-r--r--zebra/zebra_mpls_openbsd.c67
-rw-r--r--zebra/zebra_netns_notify.c10
-rw-r--r--zebra/zebra_ptm.c30
-rw-r--r--zebra/zebra_ptm_redistribute.c10
-rw-r--r--zebra/zebra_pw.c15
-rw-r--r--zebra/zebra_pw.h4
-rw-r--r--zebra/zebra_rib.c157
-rw-r--r--zebra/zebra_routemap.c41
-rw-r--r--zebra/zebra_router.c6
-rw-r--r--zebra/zebra_router.h39
-rw-r--r--zebra/zebra_vrf.c26
-rw-r--r--zebra/zebra_vrf.h2
-rw-r--r--zebra/zebra_vty.c31
-rw-r--r--zebra/zebra_vxlan.c225
-rw-r--r--zebra/zebra_vxlan.h1
-rw-r--r--zebra/zebra_vxlan_private.h3
-rw-r--r--zebra/zserv.c71
-rw-r--r--zebra/zserv.h28
269 files changed, 6522 insertions, 2018 deletions
diff --git a/Makefile.am b/Makefile.am
index 7f7d7d6236..9e6c53d87c 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -4,6 +4,8 @@ AUTOMAKE_OPTIONS = subdir-objects 1.12
ACLOCAL_AMFLAGS = -I m4
AM_CFLAGS = \
+ $(LIBYANG_CFLAGS) \
+ $(SQLITE3_CFLAGS) \
$(UNWIND_CFLAGS) \
$(SAN_FLAGS) \
$(WERROR) \
@@ -17,7 +19,6 @@ AM_LDFLAGS = \
$(SAN_FLAGS) \
# end
DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" -DCONFDATE=$(CONFDATE)
-LIBCAP = @LIBCAP@
AR_FLAGS = @AR_FLAGS@
ARFLAGS = @ARFLAGS@
diff --git a/README.md b/README.md
index 48142f21b7..995c1b50ba 100644
--- a/README.md
+++ b/README.md
@@ -18,6 +18,8 @@ FRR currently supports the following protocols:
* LDP
* BFD
* Babel
+* PBR
+* OpenFabric
* EIGRP (alpha)
* NHRP (alpha)
diff --git a/babeld/subdir.am b/babeld/subdir.am
index e1f2cb0a00..7081c730aa 100644
--- a/babeld/subdir.am
+++ b/babeld/subdir.am
@@ -51,4 +51,4 @@ noinst_HEADERS += \
# end
babeld_babeld_SOURCES = babeld/babel_main.c
-babeld_babeld_LDADD = babeld/libbabel.a lib/libfrr.la @LIBCAP@
+babeld_babeld_LDADD = babeld/libbabel.a lib/libfrr.la $(LIBCAP)
diff --git a/bfdd/Makefile b/bfdd/Makefile
new file mode 100644
index 0000000000..dfe78232c4
--- /dev/null
+++ b/bfdd/Makefile
@@ -0,0 +1,10 @@
+all: ALWAYS
+ @$(MAKE) -s -C .. bfdd/bfdd
+%: ALWAYS
+ @$(MAKE) -s -C .. bfdd/$@
+
+Makefile:
+ #nothing
+ALWAYS:
+.PHONY: ALWAYS makefiles
+.SUFFIXES:
diff --git a/bfdd/bfdd_vty.c b/bfdd/bfdd_vty.c
index 8f8fff6b18..3476e16210 100644
--- a/bfdd/bfdd_vty.c
+++ b/bfdd/bfdd_vty.c
@@ -968,6 +968,18 @@ static void _bfdd_peer_write_config(struct hash_backet *hb, void *arg)
vty_out(vty, " !\n");
}
+DEFUN_NOSH(show_debugging_bfd,
+ show_debugging_bfd_cmd,
+ "show debugging [bfd]",
+ SHOW_STR
+ DEBUG_STR
+ "BFD daemon\n")
+{
+ vty_out(vty, "BFD debugging status:\n");
+
+ return CMD_SUCCESS;
+}
+
static int bfdd_peer_write_config(struct vty *vty)
{
bfd_id_iterate(_bfdd_peer_write_config, vty);
@@ -993,6 +1005,7 @@ void bfdd_vty_init(void)
install_element(ENABLE_NODE, &bfd_show_peers_cmd);
install_element(ENABLE_NODE, &bfd_show_peer_cmd);
install_element(CONFIG_NODE, &bfd_enter_cmd);
+ install_element(ENABLE_NODE, &show_debugging_bfd_cmd);
/* Install BFD node and commands. */
install_node(&bfd_node, bfdd_write_config);
diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c
index 4f756519ca..9521a9e912 100644
--- a/bgpd/bgp_aspath.c
+++ b/bgpd/bgp_aspath.c
@@ -1381,39 +1381,45 @@ static struct aspath *aspath_merge(struct aspath *as1, struct aspath *as2)
/* Prepend as1 to as2. as2 should be uninterned aspath. */
struct aspath *aspath_prepend(struct aspath *as1, struct aspath *as2)
{
- struct assegment *seg1;
- struct assegment *seg2;
+ struct assegment *as1segtail;
+ struct assegment *as2segtail;
+ struct assegment *as2seghead;
if (!as1 || !as2)
return NULL;
- seg1 = as1->segments;
- seg2 = as2->segments;
-
/* If as2 is empty, only need to dupe as1's chain onto as2 */
- if (seg2 == NULL) {
+ if (as2->segments == NULL) {
as2->segments = assegment_dup_all(as1->segments);
aspath_str_update(as2, false);
return as2;
}
/* If as1 is empty AS, no prepending to do. */
- if (seg1 == NULL)
+ if (as1->segments == NULL)
return as2;
/* find the tail as1's segment chain. */
- while (seg1 && seg1->next)
- seg1 = seg1->next;
+ as1segtail = as1->segments;
+ while (as1segtail && as1segtail->next)
+ as1segtail = as1segtail->next;
/* Delete any AS_CONFED_SEQUENCE segment from as2. */
- if (seg1->type == AS_SEQUENCE && seg2->type == AS_CONFED_SEQUENCE)
+ if (as1segtail->type == AS_SEQUENCE
+ && as2->segments->type == AS_CONFED_SEQUENCE)
as2 = aspath_delete_confed_seq(as2);
+ if (!as2->segments) {
+ as2->segments = assegment_dup_all(as1->segments);
+ aspath_str_update(as2, false);
+ return as2;
+ }
+
/* Compare last segment type of as1 and first segment type of as2. */
- if (seg1->type != seg2->type)
+ if (as1segtail->type != as2->segments->type)
return aspath_merge(as1, as2);
- if (seg1->type == AS_SEQUENCE) {
+ if (as1segtail->type == AS_SEQUENCE) {
/* We have two chains of segments, as1->segments and seg2,
* and we have to attach them together, merging the attaching
* segments together into one.
@@ -1423,23 +1429,28 @@ struct aspath *aspath_prepend(struct aspath *as1, struct aspath *as2)
* 3. attach chain after seg2
*/
+ /* save as2 head */
+ as2seghead = as2->segments;
+
/* dupe as1 onto as2's head */
- seg1 = as2->segments = assegment_dup_all(as1->segments);
+ as2segtail = as2->segments = assegment_dup_all(as1->segments);
- /* refind the tail of as2, reusing seg1 */
- while (seg1 && seg1->next)
- seg1 = seg1->next;
+ /* refind the tail of as2 */
+ while (as2segtail && as2segtail->next)
+ as2segtail = as2segtail->next;
/* merge the old head, seg2, into tail, seg1 */
- seg1 = assegment_append_asns(seg1, seg2->as, seg2->length);
+ assegment_append_asns(as2segtail, as2seghead->as,
+ as2seghead->length);
- /* bypass the merged seg2, and attach any chain after it to
- * chain descending from as2's head
+ /*
+ * bypass the merged seg2, and attach any chain after it
+ * to chain descending from as2's head
*/
- seg1->next = seg2->next;
+ as2segtail->next = as2seghead->next;
- /* seg2 is now referenceless and useless*/
- assegment_free(seg2);
+ /* as2->segments is now referenceless and useless */
+ assegment_free(as2seghead);
/* we've now prepended as1's segment chain to as2, merging
* the inbetween AS_SEQUENCE of seg2 in the process
diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c
index 39ba404f38..f476b16188 100644
--- a/bgpd/bgp_debug.c
+++ b/bgpd/bgp_debug.c
@@ -2123,67 +2123,6 @@ DEFUN_NOSH (show_debugging_bgp,
return CMD_SUCCESS;
}
-/* return count of number of debug flags set */
-int bgp_debug_count(void)
-{
- int ret = 0;
- if (BGP_DEBUG(as4, AS4))
- ret++;
-
- if (BGP_DEBUG(as4, AS4_SEGMENT))
- ret++;
-
- if (BGP_DEBUG(bestpath, BESTPATH))
- ret++;
-
- if (BGP_DEBUG(keepalive, KEEPALIVE))
- ret++;
-
- if (BGP_DEBUG(neighbor_events, NEIGHBOR_EVENTS))
- ret++;
-
- if (BGP_DEBUG(nht, NHT))
- ret++;
-
- if (BGP_DEBUG(update_groups, UPDATE_GROUPS))
- ret++;
-
- if (BGP_DEBUG(update, UPDATE_PREFIX))
- ret++;
-
- if (BGP_DEBUG(update, UPDATE_IN))
- ret++;
-
- if (BGP_DEBUG(update, UPDATE_OUT))
- ret++;
-
- if (BGP_DEBUG(zebra, ZEBRA))
- ret++;
-
- if (BGP_DEBUG(allow_martians, ALLOW_MARTIANS))
- ret++;
-
- if (BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF))
- ret++;
- if (BGP_DEBUG(vpn, VPN_LEAK_TO_VRF))
- ret++;
- if (BGP_DEBUG(vpn, VPN_LEAK_RMAP_EVENT))
- ret++;
- if (BGP_DEBUG(vpn, VPN_LEAK_LABEL))
- ret++;
- if (BGP_DEBUG(flowspec, FLOWSPEC))
- ret++;
- if (BGP_DEBUG(labelpool, LABELPOOL))
- ret++;
-
- if (BGP_DEBUG(pbr, PBR))
- ret++;
- if (BGP_DEBUG(pbr, PBR_ERROR))
- ret++;
-
- return ret;
-}
-
static int bgp_config_write_debug(struct vty *vty)
{
int write = 0;
diff --git a/bgpd/bgp_debug.h b/bgpd/bgp_debug.h
index d5d8fbb505..e05da37647 100644
--- a/bgpd/bgp_debug.h
+++ b/bgpd/bgp_debug.h
@@ -168,7 +168,6 @@ extern int bgp_debug_update(struct peer *peer, struct prefix *p,
extern int bgp_debug_bestpath(struct prefix *p);
extern int bgp_debug_zebra(struct prefix *p);
-extern int bgp_debug_count(void);
extern const char *bgp_debug_rdpfxpath2str(afi_t, safi_t, struct prefix_rd *,
union prefixconstptr, mpls_label_t *,
uint32_t, int, uint32_t, char *,
diff --git a/bgpd/bgp_evpn_private.h b/bgpd/bgp_evpn_private.h
index 43b1f05b3d..c7f2671b78 100644
--- a/bgpd/bgp_evpn_private.h
+++ b/bgpd/bgp_evpn_private.h
@@ -73,6 +73,9 @@ struct bgpevpn {
* advertising subnet for this VNI */
uint8_t advertise_subnet;
+ /* Flag to indicate if we are advertising the svi mac ip for this VNI*/
+ uint8_t advertise_svi_macip;
+
/* Id for deriving the RD
* automatically for this VNI */
uint16_t rd_id;
@@ -177,6 +180,10 @@ struct bgp_evpn_info {
bool dad_freeze;
/* Recovery time */
uint32_t dad_freeze_time;
+
+ /* EVPN enable - advertise svi macip routes */
+ int advertise_svi_macip;
+
};
static inline int is_vrf_rd_configured(struct bgp *bgp_vrf)
diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c
index 776f8f8ef7..a3d8b8a647 100644
--- a/bgpd/bgp_evpn_vty.c
+++ b/bgpd/bgp_evpn_vty.c
@@ -489,6 +489,8 @@ static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json)
inet_ntoa(vpn->originator_ip));
vty_out(vty, " Advertise-gw-macip : %s\n",
vpn->advertise_gw_macip ? "Yes" : "No");
+ vty_out(vty, " Advertise-svi-macip : %s\n",
+ vpn->advertise_svi_macip ? "Yes" : "No");
}
if (!json)
@@ -2619,6 +2621,33 @@ static void evpn_show_all_vnis(struct vty *vty, struct bgp *bgp,
}
/*
+ * evpn - enable advertisement of svi MAC-IP
+ */
+static void evpn_set_advertise_svi_macip(struct bgp *bgp, struct bgpevpn *vpn,
+ uint32_t set)
+{
+ if (!vpn) {
+ if (set && bgp->evpn_info->advertise_svi_macip)
+ return;
+ else if (!set && !bgp->evpn_info->advertise_svi_macip)
+ return;
+
+ bgp->evpn_info->advertise_svi_macip = set;
+ bgp_zebra_advertise_svi_macip(bgp,
+ bgp->evpn_info->advertise_svi_macip, 0);
+ } else {
+ if (set && vpn->advertise_svi_macip)
+ return;
+ else if (!set && !vpn->advertise_svi_macip)
+ return;
+
+ vpn->advertise_svi_macip = set;
+ bgp_zebra_advertise_svi_macip(bgp, vpn->advertise_svi_macip,
+ vpn->vni);
+ }
+}
+
+/*
* evpn - enable advertisement of default g/w
*/
static void evpn_set_advertise_default_gw(struct bgp *bgp, struct bgpevpn *vpn)
@@ -2798,6 +2827,9 @@ static void write_vni_config(struct vty *vty, struct bgpevpn *vpn)
if (vpn->advertise_gw_macip)
vty_out(vty, " advertise-default-gw\n");
+ if (vpn->advertise_svi_macip)
+ vty_out(vty, " advertise-svi-ip\n");
+
if (vpn->advertise_subnet)
vty_out(vty, " advertise-subnet\n");
@@ -3151,6 +3183,54 @@ DEFPY (no_dup_addr_detection,
return CMD_SUCCESS;
}
+DEFPY(bgp_evpn_advertise_svi_ip,
+ bgp_evpn_advertise_svi_ip_cmd,
+ "[no$no] advertise-svi-ip",
+ NO_STR
+ "Advertise svi mac-ip routes in EVPN\n")
+{
+ struct bgp *bgp = VTY_GET_CONTEXT(bgp);
+
+ if (!bgp)
+ return CMD_WARNING;
+
+ if (bgp->vrf_id != VRF_DEFAULT) {
+ vty_out(vty,
+ "This command is only supported under Default VRF\n");
+ return CMD_WARNING;
+ }
+
+ if (no)
+ evpn_set_advertise_svi_macip(bgp, NULL, 0);
+ else
+ evpn_set_advertise_svi_macip(bgp, NULL, 1);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY(bgp_evpn_advertise_svi_ip_vni,
+ bgp_evpn_advertise_svi_ip_vni_cmd,
+ "[no$no] advertise-svi-ip",
+ NO_STR
+ "Advertise svi mac-ip routes in EVPN for a VNI\n")
+{
+ struct bgp *bgp = VTY_GET_CONTEXT(bgp);
+ VTY_DECLVAR_CONTEXT_SUB(bgpevpn, vpn);
+
+ if (!bgp)
+ return CMD_WARNING;
+
+ if (!vpn)
+ return CMD_WARNING;
+
+ if (no)
+ evpn_set_advertise_svi_macip(bgp, vpn, 0);
+ else
+ evpn_set_advertise_svi_macip(bgp, vpn, 1);
+
+ return CMD_SUCCESS;
+}
+
DEFUN_HIDDEN (bgp_evpn_advertise_vni_subnet,
bgp_evpn_advertise_vni_subnet_cmd,
"advertise-subnet",
@@ -3260,6 +3340,8 @@ DEFUN (bgp_evpn_advertise_type5,
if (bgp_vrf->adv_cmd_rmap[afi][safi].name) {
XFREE(MTYPE_ROUTE_MAP_NAME,
bgp_vrf->adv_cmd_rmap[afi][safi].name);
+ route_map_counter_decrement(
+ bgp_vrf->adv_cmd_rmap[afi][safi].map);
bgp_vrf->adv_cmd_rmap[afi][safi].name = NULL;
bgp_vrf->adv_cmd_rmap[afi][safi].map = NULL;
}
@@ -3271,6 +3353,8 @@ DEFUN (bgp_evpn_advertise_type5,
XSTRDUP(MTYPE_ROUTE_MAP_NAME, argv[idx_rmap + 1]->arg);
bgp_vrf->adv_cmd_rmap[afi][safi].map =
route_map_lookup_by_name(argv[idx_rmap + 1]->arg);
+ route_map_counter_increment(
+ bgp_vrf->adv_cmd_rmap[afi][safi].map);
}
/* advertise type-5 routes */
@@ -3409,6 +3493,9 @@ DEFUN(show_bgp_l2vpn_evpn_vni,
vty_out(vty, "Advertise Gateway Macip: %s\n",
bgp_def->advertise_gw_macip ? "Enabled"
: "Disabled");
+ vty_out(vty, "Advertise SVI Macip: %s\n",
+ bgp_def->evpn_info->advertise_svi_macip ? "Enabled"
+ : "Disabled");
vty_out(vty, "Advertise All VNI flag: %s\n",
is_evpn_enabled() ? "Enabled" : "Disabled");
vty_out(vty, "BUM flooding: %s\n",
@@ -5071,6 +5158,9 @@ void bgp_config_write_evpn_info(struct vty *vty, struct bgp *bgp, afi_t afi,
if (bgp->advertise_gw_macip)
vty_out(vty, " advertise-default-gw\n");
+ if (bgp->evpn_info->advertise_svi_macip)
+ vty_out(vty, " advertise-svi-ip\n");
+
if (!bgp->evpn_info->dup_addr_detect)
vty_out(vty, " no dup-addr-detection\n");
@@ -5181,6 +5271,7 @@ void bgp_ethernetvpn_init(void)
install_element(BGP_EVPN_NODE, &no_bgp_evpn_advertise_autort_rfc8365_cmd);
install_element(BGP_EVPN_NODE, &bgp_evpn_advertise_default_gw_cmd);
install_element(BGP_EVPN_NODE, &no_bgp_evpn_advertise_default_gw_cmd);
+ install_element(BGP_EVPN_NODE, &bgp_evpn_advertise_svi_ip_cmd);
install_element(BGP_EVPN_NODE, &bgp_evpn_advertise_type5_cmd);
install_element(BGP_EVPN_NODE, &no_bgp_evpn_advertise_type5_cmd);
install_element(BGP_EVPN_NODE, &bgp_evpn_default_originate_cmd);
@@ -5237,6 +5328,7 @@ void bgp_ethernetvpn_init(void)
install_element(BGP_NODE, &no_bgp_evpn_vrf_rd_without_val_cmd);
install_element(BGP_EVPN_NODE, &bgp_evpn_vrf_rt_cmd);
install_element(BGP_EVPN_NODE, &no_bgp_evpn_vrf_rt_cmd);
+ install_element(BGP_EVPN_VNI_NODE, &bgp_evpn_advertise_svi_ip_vni_cmd);
install_element(BGP_EVPN_VNI_NODE,
&bgp_evpn_advertise_default_gw_vni_cmd);
install_element(BGP_EVPN_VNI_NODE,
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 99dc9d8124..59ca223a2d 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -4417,6 +4417,8 @@ static void bgp_static_free(struct bgp_static *bgp_static)
{
if (bgp_static->rmap.name)
XFREE(MTYPE_ROUTE_MAP_NAME, bgp_static->rmap.name);
+ route_map_counter_decrement(bgp_static->rmap.map);
+
if (bgp_static->eth_s_id)
XFREE(MTYPE_ATTR, bgp_static->eth_s_id);
XFREE(MTYPE_BGP_STATIC, bgp_static);
@@ -4981,14 +4983,20 @@ static int bgp_static_set(struct vty *vty, const char *negate,
if (bgp_static->rmap.name)
XFREE(MTYPE_ROUTE_MAP_NAME,
bgp_static->rmap.name);
+ route_map_counter_decrement(
+ bgp_static->rmap.map);
bgp_static->rmap.name =
XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap);
bgp_static->rmap.map =
route_map_lookup_by_name(rmap);
+ route_map_counter_increment(
+ bgp_static->rmap.map);
} else {
if (bgp_static->rmap.name)
XFREE(MTYPE_ROUTE_MAP_NAME,
bgp_static->rmap.name);
+ route_map_counter_decrement(
+ bgp_static->rmap.map);
bgp_static->rmap.name = NULL;
bgp_static->rmap.map = NULL;
bgp_static->valid = 0;
@@ -5007,10 +5015,14 @@ static int bgp_static_set(struct vty *vty, const char *negate,
if (bgp_static->rmap.name)
XFREE(MTYPE_ROUTE_MAP_NAME,
bgp_static->rmap.name);
+ route_map_counter_decrement(
+ bgp_static->rmap.map);
bgp_static->rmap.name =
XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap);
bgp_static->rmap.map =
route_map_lookup_by_name(rmap);
+ route_map_counter_increment(
+ bgp_static->rmap.map);
}
bgp_node_set_bgp_static_info(rn, bgp_static);
}
@@ -5289,10 +5301,12 @@ int bgp_static_set_safi(afi_t afi, safi_t safi, struct vty *vty,
if (bgp_static->rmap.name)
XFREE(MTYPE_ROUTE_MAP_NAME,
bgp_static->rmap.name);
+ route_map_counter_decrement(bgp_static->rmap.map);
bgp_static->rmap.name =
XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap_str);
bgp_static->rmap.map =
route_map_lookup_by_name(rmap_str);
+ route_map_counter_increment(bgp_static->rmap.map);
}
if (safi == SAFI_EVPN) {
@@ -5395,11 +5409,14 @@ static int bgp_table_map_set(struct vty *vty, afi_t afi, safi_t safi,
if (rmap_name) {
if (rmap->name)
XFREE(MTYPE_ROUTE_MAP_NAME, rmap->name);
+ route_map_counter_decrement(rmap->map);
rmap->name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap_name);
rmap->map = route_map_lookup_by_name(rmap_name);
+ route_map_counter_increment(rmap->map);
} else {
if (rmap->name)
XFREE(MTYPE_ROUTE_MAP_NAME, rmap->name);
+ route_map_counter_decrement(rmap->map);
rmap->name = NULL;
rmap->map = NULL;
}
@@ -5419,6 +5436,7 @@ static int bgp_table_map_unset(struct vty *vty, afi_t afi, safi_t safi,
rmap = &bgp->table_map[afi][safi];
if (rmap->name)
XFREE(MTYPE_ROUTE_MAP_NAME, rmap->name);
+ route_map_counter_decrement(rmap->map);
rmap->name = NULL;
rmap->map = NULL;
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index 4953032f97..e28acdfbae 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -3250,6 +3250,15 @@ static void bgp_route_map_process_update(struct bgp *bgp, const char *rmap_name,
if (bgp->table_map[afi][safi].name
&& (strcmp(rmap_name, bgp->table_map[afi][safi].name)
== 0)) {
+
+ /* bgp->table_map[afi][safi].map is NULL.
+ * i.e Route map creation event.
+ * So update applied_counter.
+ * If it is not NULL, i.e It may be routemap updation or
+ * deletion. so no need to update the counter.
+ */
+ if (!bgp->table_map[afi][safi].map)
+ route_map_counter_increment(map);
bgp->table_map[afi][safi].map = map;
if (BGP_DEBUG(zebra, ZEBRA))
@@ -3272,6 +3281,9 @@ static void bgp_route_map_process_update(struct bgp *bgp, const char *rmap_name,
|| (strcmp(rmap_name, bgp_static->rmap.name) != 0))
continue;
+ if (!bgp_static->rmap.map)
+ route_map_counter_increment(map);
+
bgp_static->rmap.map = map;
if (route_update && !bgp_static->backdoor) {
@@ -3303,6 +3315,9 @@ static void bgp_route_map_process_update(struct bgp *bgp, const char *rmap_name,
|| (strcmp(rmap_name, red->rmap.name) != 0))
continue;
+ if (!red->rmap.map)
+ route_map_counter_increment(map);
+
red->rmap.map = map;
if (!route_update)
diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c
index b614e87d23..a38d78916c 100644
--- a/bgpd/bgp_rpki.c
+++ b/bgpd/bgp_rpki.c
@@ -1134,7 +1134,7 @@ DEFPY (no_rpki_cache,
{
struct cache *cache_p = find_cache(preference);
- if (!cache) {
+ if (!cache_p) {
vty_out(vty, "Could not find cache %ld\n", preference);
return CMD_WARNING;
}
@@ -1190,9 +1190,23 @@ DEFUN (show_rpki_cache_server,
struct cache *cache;
for (ALL_LIST_ELEMENTS_RO(cache_list, cache_node, cache)) {
- vty_out(vty, "host: %s port: %s\n",
- cache->tr_config.tcp_config->host,
- cache->tr_config.tcp_config->port);
+ if (cache->type == TCP) {
+ vty_out(vty, "host: %s port: %s\n",
+ cache->tr_config.tcp_config->host,
+ cache->tr_config.tcp_config->port);
+
+ } else if (cache->type == SSH) {
+ vty_out(vty,
+ "host: %s port: %d username: %s "
+ "server_hostkey_path: %s client_privkey_path: %s\n",
+ cache->tr_config.ssh_config->host,
+ cache->tr_config.ssh_config->port,
+ cache->tr_config.ssh_config->username,
+ cache->tr_config.ssh_config
+ ->server_hostkey_path,
+ cache->tr_config.ssh_config
+ ->client_privkey_path);
+ }
}
return CMD_SUCCESS;
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index be6c06d236..93d89668e7 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -11650,11 +11650,11 @@ static int bgp_show_one_peer_group(struct vty *vty, struct peer_group *group)
conf = group->conf;
if (conf->as_type == AS_SPECIFIED || conf->as_type == AS_EXTERNAL) {
- vty_out(vty, "\nBGP peer-group %s, remote AS %d\n", group->name,
- conf->as);
+ vty_out(vty, "\nBGP peer-group %s, remote AS %" PRIu32 "\n",
+ group->name, conf->as);
} else if (conf->as_type == AS_INTERNAL) {
- vty_out(vty, "\nBGP peer-group %s, remote AS %d\n", group->name,
- group->bgp->as);
+ vty_out(vty, "\nBGP peer-group %s, remote AS %" PRIu32 "\n",
+ group->name, group->bgp->as);
} else {
vty_out(vty, "\nBGP peer-group %s\n", group->name);
}
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index 75da038829..3f18d69a2d 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -1683,8 +1683,13 @@ int bgp_redistribute_rmap_set(struct bgp_redist *red, const char *name,
if (red->rmap.name)
XFREE(MTYPE_ROUTE_MAP_NAME, red->rmap.name);
+ /* Decrement the count for existing routemap and
+ * increment the count for new route map.
+ */
+ route_map_counter_decrement(red->rmap.map);
red->rmap.name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, name);
red->rmap.map = route_map;
+ route_map_counter_increment(red->rmap.map);
return 1;
}
@@ -1792,6 +1797,7 @@ int bgp_redistribute_unset(struct bgp *bgp, afi_t afi, int type,
/* Unset route-map. */
if (red->rmap.name)
XFREE(MTYPE_ROUTE_MAP_NAME, red->rmap.name);
+ route_map_counter_decrement(red->rmap.map);
red->rmap.name = NULL;
red->rmap.map = NULL;
@@ -1930,6 +1936,29 @@ int bgp_zebra_advertise_subnet(struct bgp *bgp, int advertise, vni_t vni)
return zclient_send_message(zclient);
}
+int bgp_zebra_advertise_svi_macip(struct bgp *bgp, int advertise, vni_t vni)
+{
+ struct stream *s = NULL;
+
+ /* Check socket. */
+ if (!zclient || zclient->sock < 0)
+ return 0;
+
+ /* Don't try to register if Zebra doesn't know of this instance. */
+ if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp))
+ return 0;
+
+ s = zclient->obuf;
+ stream_reset(s);
+
+ zclient_create_header(s, ZEBRA_ADVERTISE_SVI_MACIP, bgp->vrf_id);
+ stream_putc(s, advertise);
+ stream_putl(s, vni);
+ stream_putw_at(s, 0, stream_get_endp(s));
+
+ return zclient_send_message(zclient);
+}
+
int bgp_zebra_advertise_gw_macip(struct bgp *bgp, int advertise, vni_t vni)
{
struct stream *s = NULL;
diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h
index c6520c43e4..fc19c5e17f 100644
--- a/bgpd/bgp_zebra.h
+++ b/bgpd/bgp_zebra.h
@@ -72,6 +72,8 @@ extern struct interface *if_lookup_by_ipv6_exact(struct in6_addr *, ifindex_t,
extern int bgp_zebra_advertise_subnet(struct bgp *bgp, int advertise,
vni_t vni);
extern int bgp_zebra_advertise_gw_macip(struct bgp *, int, vni_t);
+extern int bgp_zebra_advertise_svi_macip(struct bgp *bgp, int advertise,
+ vni_t vni);
extern int bgp_zebra_advertise_all_vni(struct bgp *, int);
extern int bgp_zebra_dup_addr_detection(struct bgp *bgp);
extern int bgp_zebra_vxlan_flood_control(struct bgp *bgp,
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 0ab9a0b921..0ff9d75781 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -4594,15 +4594,18 @@ int peer_default_originate_set(struct peer *peer, afi_t afi, safi_t safi,
XFREE(MTYPE_ROUTE_MAP_NAME,
peer->default_rmap[afi][safi].name);
+ route_map_counter_decrement(peer->default_rmap[afi][safi].map);
peer->default_rmap[afi][safi].name =
XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap);
peer->default_rmap[afi][safi].map = route_map;
+ route_map_counter_increment(route_map);
}
} else if (!rmap) {
if (peer->default_rmap[afi][safi].name)
XFREE(MTYPE_ROUTE_MAP_NAME,
peer->default_rmap[afi][safi].name);
+ route_map_counter_decrement(peer->default_rmap[afi][safi].map);
peer->default_rmap[afi][safi].name = NULL;
peer->default_rmap[afi][safi].map = NULL;
}
@@ -4637,10 +4640,12 @@ int peer_default_originate_set(struct peer *peer, afi_t afi, safi_t safi,
if (member->default_rmap[afi][safi].name)
XFREE(MTYPE_ROUTE_MAP_NAME,
member->default_rmap[afi][safi].name);
-
+ route_map_counter_decrement(
+ member->default_rmap[afi][safi].map);
member->default_rmap[afi][safi].name =
XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap);
member->default_rmap[afi][safi].map = route_map;
+ route_map_counter_increment(route_map);
}
/* Update peer route announcements. */
@@ -4677,6 +4682,7 @@ int peer_default_originate_unset(struct peer *peer, afi_t afi, safi_t safi)
if (peer->default_rmap[afi][safi].name)
XFREE(MTYPE_ROUTE_MAP_NAME,
peer->default_rmap[afi][safi].name);
+ route_map_counter_decrement(peer->default_rmap[afi][safi].map);
peer->default_rmap[afi][safi].name = NULL;
peer->default_rmap[afi][safi].map = NULL;
}
@@ -4710,6 +4716,7 @@ int peer_default_originate_unset(struct peer *peer, afi_t afi, safi_t safi)
if (peer->default_rmap[afi][safi].name)
XFREE(MTYPE_ROUTE_MAP_NAME,
peer->default_rmap[afi][safi].name);
+ route_map_counter_decrement(peer->default_rmap[afi][safi].map);
peer->default_rmap[afi][safi].name = NULL;
peer->default_rmap[afi][safi].map = NULL;
@@ -6118,8 +6125,10 @@ int peer_route_map_set(struct peer *peer, afi_t afi, safi_t safi, int direct,
filter = &peer->filter[afi][safi];
if (filter->map[direct].name)
XFREE(MTYPE_BGP_FILTER_NAME, filter->map[direct].name);
+ route_map_counter_decrement(filter->map[direct].map);
filter->map[direct].name = XSTRDUP(MTYPE_BGP_FILTER_NAME, name);
filter->map[direct].map = route_map;
+ route_map_counter_increment(route_map);
/* Check if handling a regular peer. */
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
@@ -6147,8 +6156,10 @@ int peer_route_map_set(struct peer *peer, afi_t afi, safi_t safi, int direct,
filter = &member->filter[afi][safi];
if (filter->map[direct].name)
XFREE(MTYPE_BGP_FILTER_NAME, filter->map[direct].name);
+ route_map_counter_decrement(filter->map[direct].map);
filter->map[direct].name = XSTRDUP(MTYPE_BGP_FILTER_NAME, name);
filter->map[direct].map = route_map;
+ route_map_counter_increment(route_map);
/* Process peer route updates. */
peer_on_policy_change(member, afi, safi,
@@ -6182,6 +6193,7 @@ int peer_route_map_unset(struct peer *peer, afi_t afi, safi_t safi, int direct)
filter = &peer->filter[afi][safi];
if (filter->map[direct].name)
XFREE(MTYPE_BGP_FILTER_NAME, filter->map[direct].name);
+ route_map_counter_decrement(filter->map[direct].map);
filter->map[direct].name = NULL;
filter->map[direct].map = NULL;
}
@@ -6210,6 +6222,7 @@ int peer_route_map_unset(struct peer *peer, afi_t afi, safi_t safi, int direct)
filter = &member->filter[afi][safi];
if (filter->map[direct].name)
XFREE(MTYPE_BGP_FILTER_NAME, filter->map[direct].name);
+ route_map_counter_decrement(filter->map[direct].map);
filter->map[direct].name = NULL;
filter->map[direct].map = NULL;
@@ -6233,8 +6246,10 @@ int peer_unsuppress_map_set(struct peer *peer, afi_t afi, safi_t safi,
filter = &peer->filter[afi][safi];
if (filter->usmap.name)
XFREE(MTYPE_BGP_FILTER_NAME, filter->usmap.name);
+ route_map_counter_decrement(filter->usmap.map);
filter->usmap.name = XSTRDUP(MTYPE_BGP_FILTER_NAME, name);
filter->usmap.map = route_map;
+ route_map_counter_increment(route_map);
/* Check if handling a regular peer. */
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
@@ -6261,8 +6276,10 @@ int peer_unsuppress_map_set(struct peer *peer, afi_t afi, safi_t safi,
filter = &member->filter[afi][safi];
if (filter->usmap.name)
XFREE(MTYPE_BGP_FILTER_NAME, filter->usmap.name);
+ route_map_counter_decrement(filter->usmap.map);
filter->usmap.name = XSTRDUP(MTYPE_BGP_FILTER_NAME, name);
filter->usmap.map = route_map;
+ route_map_counter_increment(route_map);
/* Process peer route updates. */
peer_on_policy_change(member, afi, safi, 1);
@@ -6293,6 +6310,7 @@ int peer_unsuppress_map_unset(struct peer *peer, afi_t afi, safi_t safi)
filter = &peer->filter[afi][safi];
if (filter->usmap.name)
XFREE(MTYPE_BGP_FILTER_NAME, filter->usmap.name);
+ route_map_counter_decrement(filter->usmap.map);
filter->usmap.name = NULL;
filter->usmap.map = NULL;
}
@@ -6320,6 +6338,7 @@ int peer_unsuppress_map_unset(struct peer *peer, afi_t afi, safi_t safi)
filter = &member->filter[afi][safi];
if (filter->usmap.name)
XFREE(MTYPE_BGP_FILTER_NAME, filter->usmap.name);
+ route_map_counter_decrement(filter->usmap.map);
filter->usmap.name = NULL;
filter->usmap.map = NULL;
@@ -7838,9 +7857,11 @@ void bgp_master_init(struct thread_master *master)
*/
static void bgp_if_finish(struct bgp *bgp)
{
- struct vrf *vrf = vrf_lookup_by_id(bgp->vrf_id);
+ struct vrf *vrf;
struct interface *ifp;
+ vrf = bgp_vrf_lookup_by_instance_type(bgp);
+
if (bgp->inst_type == BGP_INSTANCE_TYPE_VIEW || !vrf)
return;
diff --git a/bgpd/rfapi/bgp_rfapi_cfg.c b/bgpd/rfapi/bgp_rfapi_cfg.c
index 05e057f07f..d621d58e48 100644
--- a/bgpd/rfapi/bgp_rfapi_cfg.c
+++ b/bgpd/rfapi/bgp_rfapi_cfg.c
@@ -1164,9 +1164,16 @@ DEFUN (vnc_redist_bgpdirect_routemap,
if (hc->routemap_redist_name[route_type])
free(hc->routemap_redist_name[route_type]);
+
+ /* If the old route map config overwrite with new
+ * route map config , old routemap counter have to be
+ * reduced.
+ */
+ route_map_counter_decrement(hc->routemap_redist[route_type]);
hc->routemap_redist_name[route_type] = strdup(argv[4]->arg);
hc->routemap_redist[route_type] =
route_map_lookup_by_name(argv[4]->arg);
+ route_map_counter_increment(hc->routemap_redist[route_type]);
vnc_redistribute_postchange(bgp);
@@ -1285,6 +1292,8 @@ DEFUN (vnc_nve_group_redist_bgpdirect_no_routemap,
if (rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT])
free(rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT]);
+ route_map_counter_decrement(
+ rfg->routemap_redist[ZEBRA_ROUTE_BGP_DIRECT]);
rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT] = NULL;
rfg->routemap_redist[ZEBRA_ROUTE_BGP_DIRECT] = NULL;
@@ -1316,10 +1325,14 @@ DEFUN (vnc_nve_group_redist_bgpdirect_routemap,
if (rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT])
free(rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT]);
+ route_map_counter_decrement(
+ rfg->routemap_redist[ZEBRA_ROUTE_BGP_DIRECT]);
rfg->routemap_redist_name[ZEBRA_ROUTE_BGP_DIRECT] =
strdup(argv[3]->arg);
rfg->routemap_redist[ZEBRA_ROUTE_BGP_DIRECT] =
route_map_lookup_by_name(argv[3]->arg);
+ route_map_counter_increment(
+ rfg->routemap_redist[ZEBRA_ROUTE_BGP_DIRECT]);
vnc_redistribute_postchange(bgp);
@@ -1741,6 +1754,7 @@ DEFUN (vnc_nve_group_export_no_routemap,
rfg->routemap_export_bgp_name))) {
if (rfg->routemap_export_bgp_name)
free(rfg->routemap_export_bgp_name);
+ route_map_counter_decrement(rfg->routemap_export_bgp);
rfg->routemap_export_bgp_name = NULL;
rfg->routemap_export_bgp = NULL;
@@ -1754,6 +1768,7 @@ DEFUN (vnc_nve_group_export_no_routemap,
rfg->routemap_export_zebra_name))) {
if (rfg->routemap_export_zebra_name)
free(rfg->routemap_export_zebra_name);
+ route_map_counter_decrement(rfg->routemap_export_zebra);
rfg->routemap_export_zebra_name = NULL;
rfg->routemap_export_zebra = NULL;
@@ -1800,17 +1815,21 @@ DEFUN (vnc_nve_group_export_routemap,
if (is_bgp) {
if (rfg->routemap_export_bgp_name)
free(rfg->routemap_export_bgp_name);
+ route_map_counter_decrement(rfg->routemap_export_bgp);
rfg->routemap_export_bgp_name = strdup(argv[idx]->arg);
rfg->routemap_export_bgp =
route_map_lookup_by_name(argv[idx]->arg);
+ route_map_counter_increment(rfg->routemap_export_bgp);
vnc_direct_bgp_reexport_group_afi(bgp, rfg, AFI_IP);
vnc_direct_bgp_reexport_group_afi(bgp, rfg, AFI_IP6);
} else {
if (rfg->routemap_export_zebra_name)
free(rfg->routemap_export_zebra_name);
+ route_map_counter_decrement(rfg->routemap_export_zebra);
rfg->routemap_export_zebra_name = strdup(argv[idx]->arg);
rfg->routemap_export_zebra =
route_map_lookup_by_name(argv[idx]->arg);
+ route_map_counter_increment(rfg->routemap_export_zebra);
vnc_zebra_reexport_group_afi(bgp, rfg, AFI_IP);
vnc_zebra_reexport_group_afi(bgp, rfg, AFI_IP6);
}
@@ -1937,6 +1956,7 @@ DEFUN (vnc_nve_export_no_routemap,
|| (argc <= 5)) {
free(hc->routemap_export_bgp_name);
+ route_map_counter_decrement(hc->routemap_export_bgp);
hc->routemap_export_bgp_name = NULL;
hc->routemap_export_bgp = NULL;
vnc_direct_bgp_reexport(bgp, AFI_IP);
@@ -1948,6 +1968,7 @@ DEFUN (vnc_nve_export_no_routemap,
|| (argc <= 5)) {
free(hc->routemap_export_zebra_name);
+ route_map_counter_decrement(hc->routemap_export_zebra);
hc->routemap_export_zebra_name = NULL;
hc->routemap_export_zebra = NULL;
/* TBD vnc_zebra_rh_reexport(bgp, AFI_IP); */
@@ -1975,17 +1996,21 @@ DEFUN (vnc_nve_export_routemap,
if (argv[2]->arg[0] == 'b') {
if (hc->routemap_export_bgp_name)
free(hc->routemap_export_bgp_name);
+ route_map_counter_decrement(hc->routemap_export_bgp);
hc->routemap_export_bgp_name = strdup(argv[4]->arg);
hc->routemap_export_bgp =
route_map_lookup_by_name(argv[4]->arg);
+ route_map_counter_increment(hc->routemap_export_bgp);
vnc_direct_bgp_reexport(bgp, AFI_IP);
vnc_direct_bgp_reexport(bgp, AFI_IP6);
} else {
if (hc->routemap_export_zebra_name)
free(hc->routemap_export_zebra_name);
+ route_map_counter_decrement(hc->routemap_export_zebra);
hc->routemap_export_zebra_name = strdup(argv[4]->arg);
hc->routemap_export_zebra =
route_map_lookup_by_name(argv[4]->arg);
+ route_map_counter_increment(hc->routemap_export_zebra);
/* TBD vnc_zebra_rh_reexport(bgp, AFI_IP); */
/* TBD vnc_zebra_rh_reexport(bgp, AFI_IP6); */
}
@@ -2083,6 +2108,7 @@ void vnc_routemap_update(struct bgp *bgp, const char *unused)
struct rfapi_nve_group_cfg *rfg;
struct rfapi_cfg *hc;
int i;
+ struct route_map *old = NULL;
vnc_zlog_debug_verbose("%s(arg=%s)", __func__, unused);
@@ -2104,18 +2130,36 @@ void vnc_routemap_update(struct bgp *bgp, const char *unused)
rfg)) {
if (rfg->routemap_export_bgp_name) {
+ old = rfg->routemap_export_bgp;
rfg->routemap_export_bgp = route_map_lookup_by_name(
rfg->routemap_export_bgp_name);
+ /* old is NULL. i.e Route map creation event.
+ * So update applied_counter.
+ * If Old is not NULL, i.e It may be routemap
+ * updation or deletion.
+ * So no need to update the counter.
+ */
+ if (!old)
+ route_map_counter_increment(
+ rfg->routemap_export_bgp);
}
if (rfg->routemap_export_zebra_name) {
+ old = rfg->routemap_export_bgp;
rfg->routemap_export_bgp = route_map_lookup_by_name(
rfg->routemap_export_zebra_name);
+ if (!old)
+ route_map_counter_increment(
+ rfg->routemap_export_bgp);
}
for (i = 0; i < ZEBRA_ROUTE_MAX; ++i) {
if (rfg->routemap_redist_name[i]) {
+ old = rfg->routemap_redist[i];
rfg->routemap_redist[i] =
route_map_lookup_by_name(
rfg->routemap_redist_name[i]);
+ if (!old)
+ route_map_counter_increment(
+ rfg->routemap_redist[i]);
}
}
@@ -2128,17 +2172,27 @@ void vnc_routemap_update(struct bgp *bgp, const char *unused)
* RH config, too
*/
if (hc->routemap_export_bgp_name) {
+ old = hc->routemap_export_bgp;
hc->routemap_export_bgp =
route_map_lookup_by_name(hc->routemap_export_bgp_name);
+ if (!old)
+ route_map_counter_increment(hc->routemap_export_bgp);
}
if (hc->routemap_export_zebra_name) {
+ old = hc->routemap_export_bgp;
hc->routemap_export_bgp = route_map_lookup_by_name(
hc->routemap_export_zebra_name);
+ if (!old)
+ route_map_counter_increment(hc->routemap_export_bgp);
}
for (i = 0; i < ZEBRA_ROUTE_MAX; ++i) {
if (hc->routemap_redist_name[i]) {
+ old = hc->routemap_redist[i];
hc->routemap_redist[i] = route_map_lookup_by_name(
hc->routemap_redist_name[i]);
+ if (!old)
+ route_map_counter_increment(
+ hc->routemap_redist[i]);
}
}
diff --git a/bgpd/subdir.am b/bgpd/subdir.am
index 7dd1d73f69..aed2939d3e 100644
--- a/bgpd/subdir.am
+++ b/bgpd/subdir.am
@@ -191,17 +191,20 @@ noinst_HEADERS += \
bgpd_bgpd_SOURCES = bgpd/bgp_main.c
bgpd_bgp_btoa_SOURCES = bgpd/bgp_btoa.c
+bgpd_bgpd_CFLAGS = $(AM_CFLAGS)
+bgpd_bgp_btoa_CFLAGS = $(AM_CFLAGS)
+
if ENABLE_BGP_VNC
bgpd_bgpd_SOURCES += bgpd/rfapi/rfapi_descriptor_rfp_utils.c
-bgpd_bgpd_CFLAGS = -Irfapi -I@top_srcdir@/$(RFPINC)
+bgpd_bgpd_CFLAGS += -Irfapi -I@top_srcdir@/$(RFPINC)
bgpd_bgp_btoa_SOURCES += bgpd/rfapi/rfapi_descriptor_rfp_utils.c
-bgpd_bgp_btoa_CFLAGS = -Irfapi -I@top_srcdir@/$(RFPINC)
+bgpd_bgp_btoa_CFLAGS += -Irfapi -I@top_srcdir@/$(RFPINC)
endif
# RFPLDADD is set in bgpd/rfp-example/librfp/subdir.am
-bgpd_bgpd_LDADD = bgpd/libbgp.a $(RFPLDADD) lib/libfrr.la @LIBCAP@ @LIBM@
-bgpd_bgp_btoa_LDADD = bgpd/libbgp.a $(RFPLDADD) lib/libfrr.la @LIBCAP@ @LIBM@
+bgpd_bgpd_LDADD = bgpd/libbgp.a $(RFPLDADD) lib/libfrr.la $(LIBCAP) $(LIBM)
+bgpd_bgp_btoa_LDADD = bgpd/libbgp.a $(RFPLDADD) lib/libfrr.la $(LIBCAP) $(LIBM)
bgpd_bgpd_snmp_la_SOURCES = bgpd/bgp_snmp.c
bgpd_bgpd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu99
diff --git a/configure.ac b/configure.ac
index afdc6336b0..936e1ccda6 100755
--- a/configure.ac
+++ b/configure.ac
@@ -147,7 +147,7 @@ dnl - specifically, options to control warnings
AC_USE_SYSTEM_EXTENSIONS
AC_DEFUN([AC_C_FLAG], [{
- m4_pushdef([cachename],[m4_translit([frr_cv_$1],[ =-],[___])])
+ m4_pushdef([cachename],[m4_translit([frr_cv_$1],[ =-+],[____])])
AC_CACHE_CHECK([[whether $CC supports $1]], cachename, [
AC_LANG_PUSH([C])
ac_c_flag_save="$CFLAGS"
@@ -261,6 +261,9 @@ fi
AC_C_FLAG([-Wno-unused-parameter])
AC_C_FLAG([-Wno-missing-field-initializers])
+AC_C_FLAG([-Wc++-compat], [], [CXX_COMPAT_CFLAGS="-Wc++-compat"])
+AC_SUBST([CXX_COMPAT_CFLAGS])
+
dnl ICC emits a broken warning for const char *x = a ? "b" : "c";
dnl for some reason the string consts get 'promoted' to char *,
dnl triggering a const to non-const conversion warning.
@@ -1600,18 +1603,21 @@ AC_SUBST([SNMP_CFLAGS])
dnl ---------------
dnl libyang
dnl ---------------
-PKG_CHECK_MODULES([libyang], [libyang >= 0.16.7], , [
+PKG_CHECK_MODULES([LIBYANG], [libyang >= 0.16.7], , [
AC_MSG_ERROR([libyang (>= 0.16.7) was not found on your system.])
])
+ac_cflags_save="$CFLAGS"
+CFLAGS="$CFLAGS $LIBYANG_CFLAGS"
AC_CHECK_MEMBER([struct lyd_node.priv], [], [
AC_MSG_ERROR([m4_normalize([
libyang needs to be compiled with ENABLE_LYD_PRIV=ON.
See http://docs.frrouting.org/projects/dev-guide/en/latest/building-libyang.html for details.])
])
], [[#include <libyang/libyang.h>]])
+CFLAGS="$ac_cflags_save"
-ac_ld_flag_save="$LDFLAGS"
-LDFLAGS="$LDFLAGS $libyang_LIBS"
+ac_libs_save="$LIBS"
+LIBS="$LIBS $LIBYANG_LIBS"
AC_CHECK_FUNC([ly_register_types], [
libyang_ext_builtin=true
AC_DEFINE([LIBYANG_EXT_BUILTIN], [1], [have ly_register_types()])
@@ -1626,14 +1632,14 @@ AC_CHECK_FUNC([ly_register_types], [
AC_MSG_WARN([===== old libyang (before 0.16.74) detected =====])
])
AM_CONDITIONAL([LIBYANG_EXT_BUILTIN], [$libyang_ext_builtin])
-LDFLAGS="$ac_ld_flag_save"
+LIBS="$ac_libs_save"
dnl ---------------
dnl configuration rollbacks
dnl ---------------
SQLITE3=false
if test "$enable_config_rollbacks" = "yes"; then
- PKG_CHECK_MODULES([sqlite3], [sqlite3], [
+ PKG_CHECK_MODULES([SQLITE3], [sqlite3], [
AC_DEFINE([HAVE_CONFIG_ROLLBACKS], [1], [Enable configuration rollbacks])
AC_DEFINE([HAVE_SQLITE3], [1], [Enable sqlite3 database])
SQLITE3=true
@@ -1661,7 +1667,7 @@ dnl ---------------
dnl sysrepo
dnl ---------------
if test "$enable_sysrepo" = "yes"; then
- PKG_CHECK_MODULES([sysrepo], [libsysrepo],
+ PKG_CHECK_MODULES([SYSREPO], [libsysrepo],
[AC_DEFINE([HAVE_SYSREPO], [1], [Enable sysrepo integration])
SYSREPO=true],
[SYSREPO=false
@@ -1735,7 +1741,8 @@ AC_CHECK_TYPES([
vifi_t, struct sioc_vif_req, struct igmpmsg,
struct ifaliasreq, struct if6_aliasreq, struct in6_aliasreq,
struct nd_opt_adv_interval, struct rt_addrinfo,
- struct nd_opt_homeagent_info, struct nd_opt_adv_interval],
+ struct nd_opt_homeagent_info, struct nd_opt_adv_interval,
+ struct nd_opt_rdnss, struct nd_opt_dnssl],
[], [], FRR_INCLUDES)
AC_CHECK_MEMBERS([struct sockaddr.sa_len,
diff --git a/doc/developer/conf.py b/doc/developer/conf.py
index 254c9f6bfc..ad501ae39d 100644
--- a/doc/developer/conf.py
+++ b/doc/developer/conf.py
@@ -131,7 +131,7 @@ language = None
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
-exclude_patterns = ['_build', 'building-libyang.rst']
+exclude_patterns = ['_build', 'building-libyang.rst', 'topotests-snippets.rst']
# The reST default role (used for this markup: `text`) to use for all
# documents.
diff --git a/doc/developer/index.rst b/doc/developer/index.rst
index 9838e1098c..3a33d9a5ec 100644
--- a/doc/developer/index.rst
+++ b/doc/developer/index.rst
@@ -9,6 +9,7 @@ FRRouting Developer's Guide
packaging
process-architecture
library
+ testing
bgpd
ospf
zebra
diff --git a/doc/developer/subdir.am b/doc/developer/subdir.am
index 575722a805..19910e7627 100644
--- a/doc/developer/subdir.am
+++ b/doc/developer/subdir.am
@@ -38,6 +38,9 @@ dev_RSTFILES = \
doc/developer/ospf-api.rst \
doc/developer/ospf-sr.rst \
doc/developer/ospf.rst \
+ doc/developer/testing.rst \
+ doc/developer/topotests-snippets.rst \
+ doc/developer/topotests.rst \
doc/developer/workflow.rst \
doc/developer/zebra.rst \
# end
diff --git a/doc/developer/testing.rst b/doc/developer/testing.rst
new file mode 100644
index 0000000000..6396faf9a6
--- /dev/null
+++ b/doc/developer/testing.rst
@@ -0,0 +1,10 @@
+.. _testing:
+
+*******
+Testing
+*******
+
+.. toctree::
+ :maxdepth: 2
+
+ topotests
diff --git a/doc/developer/topotests-snippets.rst b/doc/developer/topotests-snippets.rst
new file mode 100644
index 0000000000..649229b433
--- /dev/null
+++ b/doc/developer/topotests-snippets.rst
@@ -0,0 +1,272 @@
+.. _topotests-snippets:
+
+Snippets
+--------
+
+This document will describe common snippets of code that are frequently needed
+to perform some test checks.
+
+Checking for router / test failures
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The following check uses the topogen API to check for software failure (e.g.
+zebra died) and/or for errors manually set by ``Topogen.set_error()``.
+
+.. code:: py
+
+ # Get the topology reference
+ tgen = get_topogen()
+
+ # Check for errors in the topology
+ if tgen.routers_have_failure():
+ # Skip the test with the topology errors as reason
+ pytest.skip(tgen.errors)
+
+Checking FRR routers version
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This code snippet is usually run after the topology setup to make sure all
+routers instantiated in the topology have the correct software version.
+
+.. code:: py
+
+ # Get the topology reference
+ tgen = get_topogen()
+
+ # Get the router list
+ router_list = tgen.routers()
+
+ # Run the check for all routers
+ for router in router_list.values():
+ if router.has_version('<', '3'):
+ # Set topology error, so the next tests are skipped
+ tgen.set_error('unsupported version')
+
+A sample of this snippet in a test can be found `here
+<ldp-vpls-topo1/test_ldp_vpls_topo1.py>`__.
+
+Interacting with equipment
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+You might want to interact with the topology equipments during the tests and
+there are different ways to do so.
+
+Notes:
+
+1. When using the Topogen API, all the equipments code derive from ``Topogear``
+ (`lib/topogen.py <lib/topogen.py>`__). If you feel brave you can look by
+ yourself how the abstractions that will be mentioned here works.
+
+2. When not using the ``Topogen`` API there is only one way to interact with
+ the equipments, which is by calling the ``mininet`` API functions directly
+ to spawn commands.
+
+Interacting with the Linux sandbox
+""""""""""""""""""""""""""""""""""
+
+Without ``Topogen``:
+
+.. code:: py
+
+ global net
+ output = net['r1'].cmd('echo "foobar"')
+ print 'output is: {}'.format(output)
+
+With ``Topogen``:
+
+.. code:: py
+
+ tgen = get_topogen()
+ output = tgen.gears['r1'].run('echo "foobar"')
+ print 'output is: {}'.format(output)
+
+Interacting with VTYSH
+""""""""""""""""""""""
+
+Without ``Topogen``:
+
+.. code:: py
+
+ global net
+ output = net['r1'].cmd('vtysh "show ip route" 2>/dev/null')
+ print 'output is: {}'.format(output)
+
+With ``Topogen``:
+
+.. code:: py
+
+ tgen = get_topogen()
+ output = tgen.gears['r1'].vtysh_cmd("show ip route")
+ print 'output is: {}'.format(output)
+
+``Topogen`` also supports sending multiple lines of command:
+
+.. code:: py
+
+ tgen = get_topogen()
+ output = tgen.gears['r1'].vtysh_cmd("""
+ configure terminal
+ router bgp 10
+ bgp router-id 10.0.255.1
+ neighbor 1.2.3.4 remote-as 10
+ !
+ router bgp 11
+ bgp router-id 10.0.255.2
+ !
+ """)
+ print 'output is: {}'.format(output)
+
+You might also want to run multiple commands and get only the commands that
+failed:
+
+.. code:: py
+
+ tgen = get_topogen()
+ output = tgen.gears['r1'].vtysh_multicmd("""
+ configure terminal
+ router bgp 10
+ bgp router-id 10.0.255.1
+ neighbor 1.2.3.4 remote-as 10
+ !
+ router bgp 11
+ bgp router-id 10.0.255.2
+ !
+ """, pretty_output=false)
+ print 'output is: {}'.format(output)
+
+Translating vtysh JSON output into Python structures:
+
+.. code:: py
+
+ tgen = get_topogen()
+ json_output = tgen.gears['r1'].vtysh_cmd("show ip route json", isjson=True)
+ output = json.dumps(json_output, indent=4)
+ print 'output is: {}'.format(output)
+
+ # You can also access the data structure as normal. For example:
+ # protocol = json_output['1.1.1.1/32']['protocol']
+ # assert protocol == "ospf", "wrong protocol"
+
+.. note::
+
+ ``vtysh_(multi)cmd`` is only available for router type of equipments.
+
+Invoking mininet CLI
+^^^^^^^^^^^^^^^^^^^^
+
+Without ``Topogen``:
+
+.. code:: py
+
+ CLI(net)
+
+With ``Topogen``:
+
+.. code:: py
+
+ tgen = get_topogen()
+ tgen.mininet_cli()
+
+Reading files
+^^^^^^^^^^^^^
+
+Loading a normal text file content in the current directory:
+
+.. code:: py
+
+ # If you are using Topogen
+ # CURDIR = CWD
+ #
+ # Otherwise find the directory manually:
+ CURDIR = os.path.dirname(os.path.realpath(__file__))
+
+ file_name = '{}/r1/show_ip_route.txt'.format(CURDIR)
+ file_content = open(file_name).read()
+
+Loading JSON from a file:
+
+.. code:: py
+
+ import json
+
+ file_name = '{}/r1/show_ip_route.json'.format(CURDIR)
+ file_content = json.loads(open(file_name).read())
+
+Comparing JSON output
+^^^^^^^^^^^^^^^^^^^^^
+
+After obtaining JSON output formated with Python data structures, you may use
+it to assert a minimalist schema:
+
+.. code:: py
+
+ tgen = get_topogen()
+ json_output = tgen.gears['r1'].vtysh_cmd("show ip route json", isjson=True)
+
+ expect = {
+ '1.1.1.1/32': {
+ 'protocol': 'ospf'
+ }
+ }
+
+ assertmsg = "route 1.1.1.1/32 was not learned through OSPF"
+ assert json_cmp(json_output, expect) is None, assertmsg
+
+``json_cmp`` function description (it might be outdated, you can find the
+latest description in the source code at
+:file:`tests/topotests/lib/topotest.py`
+
+.. code:: text
+
+ JSON compare function. Receives two parameters:
+ * `d1`: json value
+ * `d2`: json subset which we expect
+
+ Returns `None` when all keys that `d1` has matches `d2`,
+ otherwise a string containing what failed.
+
+ Note: key absence can be tested by adding a key with value `None`.
+
+Pausing execution
+^^^^^^^^^^^^^^^^^
+
+Preferably, choose the ``sleep`` function that ``topotest`` provides, as it
+prints a notice during the test execution to help debug topology test execution
+time.
+
+.. code:: py
+
+ # Using the topotest sleep
+ from lib import topotest
+
+ topotest.sleep(10, 'waiting 10 seconds for bla')
+ # or just tell it the time:
+ # topotest.sleep(10)
+ # It will print 'Sleeping for 10 seconds'.
+
+ # Or you can also use the Python sleep, but it won't show anything
+ from time import sleep
+ sleep(5)
+
+iproute2 Linux commands as JSON
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+``topotest`` has two helpers implemented that parses the output of ``ip route``
+commands to JSON. It might simplify your comparison needs by only needing to
+provide a Python dictionary.
+
+.. code:: py
+
+ from lib import topotest
+
+ tgen = get_topogen()
+ routes = topotest.ip4_route(tgen.gears['r1'])
+ expected = {
+ '10.0.1.0/24': {},
+ '10.0.2.0/24': {
+ 'dev': 'r1-eth0'
+ }
+ }
+
+ assertmsg = "failed to find 10.0.1.0/24 and/or 10.0.2.0/24"
+ assert json_cmp(routes, expected) is None, assertmsg
diff --git a/doc/developer/topotests.rst b/doc/developer/topotests.rst
new file mode 100644
index 0000000000..aa06c8dffd
--- /dev/null
+++ b/doc/developer/topotests.rst
@@ -0,0 +1,927 @@
+.. _topotests:
+
+Topotests
+=========
+
+Topotests is a suite of topology tests for FRR built on top of Mininet.
+
+Installation and Setup
+----------------------
+
+Only tested with Ubuntu 16.04 and Ubuntu 18.04 (which uses Mininet 2.2.x).
+
+Instructions are the same for all setups (i.e. ExaBGP is only used for BGP
+tests).
+
+Installing Mininet Infrastructure
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code:: shell
+
+ apt-get install mininet
+ apt-get install python-pip
+ apt-get install iproute
+ pip install ipaddr
+ pip install pytest
+ pip install exabgp==3.4.17 (Newer 4.0 version of exabgp is not yet
+ supported)
+ useradd -d /var/run/exabgp/ -s /bin/false exabgp
+
+Enable Coredumps
+""""""""""""""""
+
+Optional, will give better output.
+
+.. code:: shell
+
+ apt-get install gdb
+ disable apport (which move core files)
+
+Set ``enabled=0`` in ``/etc/default/apport``.
+
+Next, update security limits by changing :file:`/etc/security/limits.conf` to::
+
+ #<domain> <type> <item> <value>
+ * soft core unlimited
+ root soft core unlimited
+ * hard core unlimited
+ root hard core unlimited
+
+Reboot for options to take effect.
+
+FRR Installation
+^^^^^^^^^^^^^^^^
+
+FRR needs to be installed separately. It is assume to be configured like the
+standard Ubuntu Packages:
+
+- Binaries in :file:`/usr/lib/frr`
+- State Directory :file:`/var/run/frr`
+- Running under user ``frr``, group ``frr``
+- vtygroup: ``frrvty``
+- config directory: :file:`/etc/frr`
+- For FRR Packages, install the dbg package as well for coredump decoding
+
+No FRR config needs to be done and no FRR daemons should be run ahead of the
+test. They are all started as part of the test.
+
+Manual FRR build
+""""""""""""""""
+
+If you prefer to manually build FRR, then use the following suggested config:
+
+.. code:: shell
+
+ ./configure \
+ --prefix=/usr \
+ --localstatedir=/var/run/frr \
+ --sbindir=/usr/lib/frr \
+ --sysconfdir=/etc/frr \
+ --enable-vtysh \
+ --enable-pimd \
+ --enable-multipath=64 \
+ --enable-user=frr \
+ --enable-group=frr \
+ --enable-vty-group=frrvty \
+ --with-pkg-extra-version=-my-manual-build
+
+And create ``frr`` user and ``frrvty`` group as follows:
+
+.. code:: shell
+
+ addgroup --system --gid 92 frr
+ addgroup --system --gid 85 frrvty
+ adduser --system --ingroup frr --home /var/run/frr/ \
+ --gecos "FRRouting suite" --shell /bin/false frr
+ usermod -G frrvty frr
+
+Executing Tests
+---------------
+
+Execute all tests with output to console
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code:: shell
+
+ py.test -s -v --tb=no
+
+All test\_\* scripts in subdirectories are detected and executed (unless
+disabled in ``pytest.ini`` file).
+
+``--tb=no`` disables the python traceback which might be irrelevant unless the
+test script itself is debugged.
+
+Execute single test
+^^^^^^^^^^^^^^^^^^^
+
+.. code:: shell
+
+ cd test_to_be_run
+ ./test_to_be_run.py
+
+For further options, refer to pytest documentation.
+
+Test will set exit code which can be used with ``git bisect``.
+
+For the simulated topology, see the description in the python file.
+
+If you need to clear the mininet setup between tests (if it isn't cleanly
+shutdown), then use the ``mn -c`` command to clean up the environment.
+
+StdErr log from daemos after exit
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+To enable the reporting of any messages seen on StdErr after the daemons exit,
+the following env variable can be set::
+
+ export TOPOTESTS_CHECK_STDERR=Yes
+
+(The value doesn't matter at this time. The check is if the env variable exists
+or not) There is no pass/fail on this reporting. The Output will be reported to
+the console::
+
+ export TOPOTESTS_CHECK_MEMLEAK="/home/mydir/memleak_"
+
+This will enable the check and output to console and the writing of the
+information to files with the given prefix (followed by testname), ie
+:file:`/home/mydir/memcheck_test_bgp_multiview_topo1.txt` in case of a memory
+leak.
+
+Collect Memory Leak Information
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+FRR processes have the capabilities to report remaining memory allocations upon
+exit. To enable the reporting of the memory, define an enviroment variable
+``TOPOTESTS_CHECK_MEMLEAK`` with the file prefix, i.e.::
+
+ export TOPOTESTS_CHECK_MEMLEAK="/home/mydir/memleak_"
+
+This will enable the check and output to console and the writing of the
+information to files with the given prefix (followed by testname), ie
+:file:`/home/mydir/memcheck_test_bgp_multiview_topo1.txt` in case of a memory
+leak.
+
+Running Topotests with AddressSanitizer
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Topotests can be run with AddressSanitizer. It requires GCC 4.8 or newer.
+(Ubuntu 16.04 as suggested here is fine with GCC 5 as default). For more
+information on AddressSanitizer, see
+https://github.com/google/sanitizers/wiki/AddressSanitizer.
+
+The checks are done automatically in the library call of ``checkRouterRunning``
+(ie at beginning of tests when there is a check for all daemons running). No
+changes or extra configuration for topotests is required beside compiling the
+suite with AddressSanitizer enabled.
+
+If a daemon crashed, then the errorlog is checked for AddressSanitizer output.
+If found, then this is added with context (calling test) to
+:file:`/tmp/AddressSanitizer.txt` in Markdown compatible format.
+
+Compiling for GCC AddressSanitizer requires to use ``gcc`` as a linker as well
+(instead of ``ld``). Here is a suggest way to compile frr with AddressSanitizer
+for ``stable/3.0`` branch:
+
+.. code:: shell
+
+ git clone https://github.com/FRRouting/frr.git
+ cd frr
+ git checkout stable/3.0
+ ./bootstrap.sh
+ export CC=gcc
+ export CFLAGS="-O1 -g -fsanitize=address -fno-omit-frame-pointer"
+ export LD=gcc
+ export LDFLAGS="-g -fsanitize=address -ldl"
+ ./configure --enable-shared=no \
+ --prefix=/usr/lib/frr --sysconfdir=/etc/frr \
+ --localstatedir=/var/run/frr \
+ --sbindir=/usr/lib/frr --bindir=/usr/lib/frr \
+ --enable-exampledir=/usr/lib/frr/examples \
+ --with-moduledir=/usr/lib/frr/modules \
+ --enable-multipath=0 --enable-rtadv \
+ --enable-tcp-zebra --enable-fpm --enable-pimd
+ make
+ sudo make install
+ # Create symlink for vtysh, so topotest finds it in /usr/lib/frr
+ sudo ln -s /usr/lib/frr/vtysh /usr/bin/
+
+and create ``frr`` user and ``frrvty`` group as shown above.
+
+.. _topotests_docker:
+
+Running Tests with Docker
+-------------------------
+
+There is a Docker image which allows to run topotests.
+
+Quickstart
+^^^^^^^^^^
+
+If you have Docker installed, you can run the topotests in Docker. The easiest
+way to do this, is to use the make targets from this repository.
+
+Your current user needs to have access to the Docker daemon. Alternatively you
+can run these commands as root.
+
+.. code:: console
+
+ make topotests
+
+This command will pull the most recent topotests image from Dockerhub, compile
+FRR inside of it, and run the topotests.
+
+Advanced Usage
+^^^^^^^^^^^^^^
+
+Internally, the topotests make target uses a shell script to pull the image and
+spawn the Docker container.
+
+There are several environment variables which can be used to modify the
+behavior of the script, these can be listed by calling it with ``-h``:
+
+.. code:: console
+
+ ./tests/topotests/docker/frr-topotests.sh -h
+
+For example, a volume is used to cache build artifacts between multiple runs of
+the image. If you need to force a complete recompile, you can set
+``TOPOTEST_CLEAN``:
+
+.. code:: console
+
+ TOPOTEST_CLEAN=1 ./tests/topotests/docker/frr-topotests.sh
+
+By default, ``frr-topotests.sh`` will build frr and run pytest. If you append
+arguments and the first one starts with ``/`` or ``./``, they will replace the
+call to pytest. If the appended arguments do not match this patttern, they will
+be provided to pytest as arguments. So, to run a specific test with more
+verbose logging:
+
+.. code:: console
+
+ ./tests/topotests/docker/frr-topotests.sh -vv -s all-protocol-startup/test_all_protocol_startup.py
+
+And to compile FRR but drop into a shell instead of running pytest:
+
+.. code:: console
+
+ ./tests/topotests/docker/frr-topotests.sh /bin/bash
+
+Development
+^^^^^^^^^^^
+
+The Docker image just includes all the components to run the topotests, but not
+the topotests themselves. So if you just want to write tests and don't want to
+make changes to the environment provided by the Docker image. You don't need to
+build your own Docker image if you do not want to.
+
+When developing new tests, there is one caveat though: The startup script of
+the container will run a ``git-clean`` on its copy of the FRR tree to avoid any
+pollution of the container with build artefacts from the host. This will also
+result in your newly written tests being unavailable in the container unless at
+least added to the index with ``git-add``.
+
+If you do want to test changes to the Docker image, you can locally build the
+image and run the tests without pulling from the registry using the following
+commands:
+
+.. code:: console
+
+ make topotests-build
+ TOPOTEST_PULL=0 make topotests
+
+
+.. _topotests-guidelines:
+
+Guidelines
+----------
+
+Executing Tests
+^^^^^^^^^^^^^^^
+
+To run the whole suite of tests the following commands must be executed at the
+top level directory of topotest:
+
+.. code:: shell
+
+ $ # Change to the top level directory of topotests.
+ $ cd path/to/topotests
+ $ # Tests must be run as root, since Mininet requires it.
+ $ sudo pytest
+
+In order to run a specific test, you can use the following command:
+
+.. code:: shell
+
+ $ # running a specific topology
+ $ sudo pytest ospf-topo1/
+ $ # or inside the test folder
+ $ cd ospf-topo1
+ $ sudo pytest # to run all tests inside the directory
+ $ sudo pytest test_ospf_topo1.py # to run a specific test
+ $ # or outside the test folder
+ $ cd ..
+ $ sudo pytest ospf-topo1/test_ospf_topo1.py # to run a specific one
+
+The output of the tested daemons will be available at the temporary folder of
+your machine:
+
+.. code:: shell
+
+ $ ls /tmp/topotest/ospf-topo1.test_ospf-topo1/r1
+ ...
+ zebra.err # zebra stderr output
+ zebra.log # zebra log file
+ zebra.out # zebra stdout output
+ ...
+
+You can also run memory leak tests to get reports:
+
+.. code:: shell
+
+ $ # Set the environment variable to apply to a specific test...
+ $ sudo env TOPOTESTS_CHECK_MEMLEAK="/tmp/memleak_report_" pytest ospf-topo1/test_ospf_topo1.py
+ $ # ...or apply to all tests adding this line to the configuration file
+ $ echo 'memleak_path = /tmp/memleak_report_' >> pytest.ini
+ $ # You can also use your editor
+ $ $EDITOR pytest.ini
+ $ # After running tests you should see your files:
+ $ ls /tmp/memleak_report_*
+ memleak_report_test_ospf_topo1.txt
+
+Writing a New Test
+^^^^^^^^^^^^^^^^^^
+
+This section will guide you in all recommended steps to produce a standard
+topology test.
+
+This is the recommended test writing routine:
+
+- Write a topology (Graphviz recommended)
+- Obtain configuration files
+- Write the test itself
+- Create a Pull Request
+
+Topotest File Hierarchy
+"""""""""""""""""""""""
+
+Before starting to write any tests one must know the file hierarchy. The
+repository hierarchy looks like this:
+
+.. code:: shell
+
+ $ cd path/to/topotest
+ $ find ./*
+ ...
+ ./README.md # repository read me
+ ./GUIDELINES.md # this file
+ ./conftest.py # test hooks - pytest related functions
+ ./example-test # example test folder
+ ./example-test/__init__.py # python package marker - must always exist.
+ ./example-test/test_template.jpg # generated topology picture - see next section
+ ./example-test/test_template.dot # Graphviz dot file
+ ./example-test/test_template.py # the topology plus the test
+ ...
+ ./ospf-topo1 # the ospf topology test
+ ./ospf-topo1/r1 # router 1 configuration files
+ ./ospf-topo1/r1/zebra.conf # zebra configuration file
+ ./ospf-topo1/r1/ospfd.conf # ospf configuration file
+ ./ospf-topo1/r1/ospfroute.txt # 'show ip ospf' output reference file
+ # removed other for shortness sake
+ ...
+ ./lib # shared test/topology functions
+ ./lib/topogen.py # topogen implementation
+ ./lib/topotest.py # topotest implementation
+
+Guidelines for creating/editing topotest:
+
+- New topologies that don't fit the existing directories should create its own
+- Always remember to add the ``__init__.py`` to new folders, this makes auto
+ complete engines and pylint happy
+- Router (Quagga/FRR) specific code should go on topotest.py
+- Generic/repeated router actions should have an abstraction in
+ topogen.TopoRouter.
+- Generic/repeated non-router code should go to topotest.py
+- pytest related code should go to conftest.py (e.g. specialized asserts)
+
+Defining the Topology
+"""""""""""""""""""""
+
+The first step to write a new test is to define the topology. This step can be
+done in many ways, but the recommended is to use Graphviz to generate a drawing
+of the topology. It allows us to see the topology graphically and to see the
+names of equipments, links and addresses.
+
+Here is an example of Graphviz dot file that generates the template topology
+:file:`tests/topotests/example-test/test_template.dot` (the inlined code might
+get outdated, please see the linked file)::
+
+ graph template {
+ label="template";
+
+ # Routers
+ r1 [
+ shape=doubleoctagon,
+ label="r1",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r2 [
+ shape=doubleoctagon,
+ label="r2",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+
+ # Switches
+ s1 [
+ shape=oval,
+ label="s1\n192.168.0.0/24",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+ s2 [
+ shape=oval,
+ label="s2\n192.168.1.0/24",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+
+ # Connections
+ r1 -- s1 [label="eth0\n.1"];
+
+ r1 -- s2 [label="eth1\n.100"];
+ r2 -- s2 [label="eth0\n.1"];
+ }
+
+Here is the produced graph:
+
+.. graphviz::
+
+ graph template {
+ label="template";
+
+ # Routers
+ r1 [
+ shape=doubleoctagon,
+ label="r1",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r2 [
+ shape=doubleoctagon,
+ label="r2",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+
+ # Switches
+ s1 [
+ shape=oval,
+ label="s1\n192.168.0.0/24",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+ s2 [
+ shape=oval,
+ label="s2\n192.168.1.0/24",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+
+ # Connections
+ r1 -- s1 [label="eth0\n.1"];
+
+ r1 -- s2 [label="eth1\n.100"];
+ r2 -- s2 [label="eth0\n.1"];
+ }
+
+Generating / Obtaining Configuration Files
+""""""""""""""""""""""""""""""""""""""""""
+
+In order to get the configuration files or command output for each router, we
+need to run the topology and execute commands in ``vtysh``. The quickest way to
+achieve that is writing the topology building code and running the topology.
+
+To bootstrap your test topology, do the following steps:
+
+- Copy the template test
+
+.. code:: shell
+
+ $ mkdir new-topo/
+ $ touch new-topo/__init__.py
+ $ cp example-test/test_template.py new-topo/test_new_topo.py
+
+- Modify the template according to your dot file
+
+Here is the template topology described in the previous section in python code:
+
+.. code:: py
+
+ class TemplateTopo(Topo):
+ "Test topology builder"
+ def build(self, *_args, **_opts):
+ "Build function"
+ tgen = get_topogen(self)
+
+ # Create 2 routers
+ for routern in range(1, 3):
+ tgen.add_router('r{}'.format(routern))
+
+ # Create a switch with just one router connected to it to simulate a
+ # empty network.
+ switch = tgen.add_switch('s1')
+ switch.add_link(tgen.gears['r1'])
+
+ # Create a connection between r1 and r2
+ switch = tgen.add_switch('s2')
+ switch.add_link(tgen.gears['r1'])
+ switch.add_link(tgen.gears['r2'])
+
+- Run the topology
+
+Topogen allows us to run the topology without running any tests, you can do
+that using the following example commands:
+
+.. code:: shell
+
+ $ # Running your bootstraped topology
+ $ sudo pytest -s --topology-only new-topo/test_new_topo.py
+ $ # Running the test_template.py topology
+ $ sudo pytest -s --topology-only example-test/test_template.py
+ $ # Running the ospf_topo1.py topology
+ $ sudo pytest -s --topology-only ospf-topo1/test_ospf_topo1.py
+
+Parameters explanation:
+
+.. program:: pytest
+
+.. option:: -s
+
+ Actives input/output capture. This is required by mininet in order to show
+ the interactive shell.
+
+.. option:: --topology-only
+
+ Don't run any tests, just build the topology.
+
+After executing the commands above, you should get the following terminal
+output:
+
+.. code:: shell
+
+ === test session starts ===
+ platform linux2 -- Python 2.7.12, pytest-3.1.2, py-1.4.34, pluggy-0.4.0
+ rootdir: /media/sf_src/topotests, inifile: pytest.ini
+ collected 3 items
+
+ ospf-topo1/test_ospf_topo1.py *** Starting controller
+
+ *** Starting 6 switches
+ switch1 switch2 switch3 switch4 switch5 switch6 ...
+ r2: frr zebra started
+ r2: frr ospfd started
+ r3: frr zebra started
+ r3: frr ospfd started
+ r1: frr zebra started
+ r1: frr ospfd started
+ r4: frr zebra started
+ r4: frr ospfd started
+ *** Starting CLI:
+ mininet>
+
+The last line shows us that we are now using the Mininet CLI (Command Line
+Interface), from here you can call your router ``vtysh`` or even bash.
+
+Here are some commands example:
+
+.. code:: shell
+
+ mininet> r1 ping 10.0.3.1
+ PING 10.0.3.1 (10.0.3.1) 56(84) bytes of data.
+ 64 bytes from 10.0.3.1: icmp_seq=1 ttl=64 time=0.576 ms
+ 64 bytes from 10.0.3.1: icmp_seq=2 ttl=64 time=0.083 ms
+ 64 bytes from 10.0.3.1: icmp_seq=3 ttl=64 time=0.088 ms
+ ^C
+ --- 10.0.3.1 ping statistics ---
+ 3 packets transmitted, 3 received, 0% packet loss, time 1998ms
+ rtt min/avg/max/mdev = 0.083/0.249/0.576/0.231 ms
+
+
+
+ mininet> r1 ping 10.0.3.3
+ PING 10.0.3.3 (10.0.3.3) 56(84) bytes of data.
+ 64 bytes from 10.0.3.3: icmp_seq=1 ttl=64 time=2.87 ms
+ 64 bytes from 10.0.3.3: icmp_seq=2 ttl=64 time=0.080 ms
+ 64 bytes from 10.0.3.3: icmp_seq=3 ttl=64 time=0.091 ms
+ ^C
+ --- 10.0.3.3 ping statistics ---
+ 3 packets transmitted, 3 received, 0% packet loss, time 2003ms
+ rtt min/avg/max/mdev = 0.080/1.014/2.872/1.313 ms
+
+
+
+ mininet> r3 vtysh
+
+ Hello, this is FRRouting (version 3.1-devrzalamena-build).
+ Copyright 1996-2005 Kunihiro Ishiguro, et al.
+
+ frr-1# show running-config
+ Building configuration...
+
+ Current configuration:
+ !
+ frr version 3.1-devrzalamena-build
+ frr defaults traditional
+ hostname r3
+ no service integrated-vtysh-config
+ !
+ log file zebra.log
+ !
+ log file ospfd.log
+ !
+ interface r3-eth0
+ ip address 10.0.3.1/24
+ !
+ interface r3-eth1
+ ip address 10.0.10.1/24
+ !
+ interface r3-eth2
+ ip address 172.16.0.2/24
+ !
+ router ospf
+ ospf router-id 10.0.255.3
+ redistribute kernel
+ redistribute connected
+ redistribute static
+ network 10.0.3.0/24 area 0
+ network 10.0.10.0/24 area 0
+ network 172.16.0.0/24 area 1
+ !
+ line vty
+ !
+ end
+ frr-1#
+
+After you successfully configured your topology, you can obtain the
+configuration files (per-daemon) using the following commands:
+
+.. code:: shell
+
+ mininet> r3 vtysh -d ospfd
+
+ Hello, this is FRRouting (version 3.1-devrzalamena-build).
+ Copyright 1996-2005 Kunihiro Ishiguro, et al.
+
+ frr-1# show running-config
+ Building configuration...
+
+ Current configuration:
+ !
+ frr version 3.1-devrzalamena-build
+ frr defaults traditional
+ no service integrated-vtysh-config
+ !
+ log file ospfd.log
+ !
+ router ospf
+ ospf router-id 10.0.255.3
+ redistribute kernel
+ redistribute connected
+ redistribute static
+ network 10.0.3.0/24 area 0
+ network 10.0.10.0/24 area 0
+ network 172.16.0.0/24 area 1
+ !
+ line vty
+ !
+ end
+ frr-1#
+
+Writing Tests
+"""""""""""""
+
+Test topologies should always be bootstrapped from
+:file:`tests/topotests/example-test/test_template.py` because it contains
+important boilerplate code that can't be avoided, like:
+
+- imports: os, sys, pytest, topotest/topogen and mininet topology class
+- The global variable CWD (Current Working directory): which is most likely
+ going to be used to reference the routers configuration file location
+
+Example:
+
+.. code:: py
+
+ # For all registered routers, load the zebra configuration file
+ for rname, router in router_list.iteritems():
+ router.load_config(
+ TopoRouter.RD_ZEBRA,
+ os.path.join(CWD, '{}/zebra.conf'.format(rname))
+ )
+ # os.path.join() joins the CWD string with arguments adding the necessary
+ # slashes ('/'). Arguments must not begin with '/'.
+
+- The topology class that inherits from Mininet Topo class:
+
+.. code:: py
+
+ class TemplateTopo(Topo):
+ def build(self, *_args, **_opts):
+ tgen = get_topogen(self)
+ # topology build code
+
+- pytest ``setup_module()`` and ``teardown_module()`` to start the topology
+
+.. code:: py
+
+ def setup_module(_m):
+ tgen = Topogen(TemplateTopo)
+ tgen.start_topology('debug')
+
+ def teardown_module(_m):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+- ``__main__`` initialization code (to support running the script directly)
+
+.. code:: py
+
+ if __name__ == '__main__':
+ sys.exit(pytest.main(["-s"]))
+
+Requirements:
+
+- Test code should always be declared inside functions that begin with the
+ ``test_`` prefix. Functions beginning with different prefixes will not be run
+ by pytest.
+- Configuration files and long output commands should go into separated files
+ inside folders named after the equipment.
+- Tests must be able to run without any interaction. To make sure your test
+ conforms with this, run it without the :option:`-s` parameter.
+
+Tips:
+
+- Keep results in stack variables, so people inspecting code with ``pdb`` can
+ easily print their values.
+
+Don't do this:
+
+.. code:: py
+
+ assert foobar(router1, router2)
+
+Do this instead:
+
+.. code:: py
+
+ result = foobar(router1, router2)
+ assert result
+
+- Use ``assert`` messages to indicate where the test failed.
+
+Example:
+
+.. code:: py
+
+ for router in router_list:
+ # ...
+ assert condition, 'Router "{}" condition failed'.format(router.name)
+
+Debugging Execution
+^^^^^^^^^^^^^^^^^^^
+
+The most effective ways to inspect topology tests are:
+
+- Run pytest with ``--pdb`` option. This option will cause a pdb shell to
+ appear when an assertion fails
+
+Example: ``pytest -s --pdb ospf-topo1/test_ospf_topo1.py``
+
+- Set a breakpoint in the test code with ``pdb``
+
+Example:
+
+.. code:: py
+
+ # Add the pdb import at the beginning of the file
+ import pdb
+ # ...
+
+ # Add a breakpoint where you think the problem is
+ def test_bla():
+ # ...
+ pdb.set_trace()
+ # ...
+
+The `Python Debugger <https://docs.python.org/2.7/library/pdb.html>`__ (pdb)
+shell allows us to run many useful operations like:
+
+- Setting breaking point on file/function/conditions (e.g. ``break``,
+ ``condition``)
+- Inspecting variables (e.g. ``p`` (print), ``pp`` (pretty print))
+- Running python code
+
+.. tip::
+
+ The TopoGear (equipment abstraction class) implements the ``__str__`` method
+ that allows the user to inspect equipment information.
+
+Example of pdb usage:
+
+.. code:: shell
+
+ > /media/sf_src/topotests/ospf-topo1/test_ospf_topo1.py(121)test_ospf_convergence()
+ -> for rnum in range(1, 5):
+ (Pdb) help
+ Documented commands (type help <topic>):
+ ========================================
+ EOF bt cont enable jump pp run unt
+ a c continue exit l q s until
+ alias cl d h list quit step up
+ args clear debug help n r tbreak w
+ b commands disable ignore next restart u whatis
+ break condition down j p return unalias where
+
+ Miscellaneous help topics:
+ ==========================
+ exec pdb
+
+ Undocumented commands:
+ ======================
+ retval rv
+
+ (Pdb) list
+ 116 title2="Expected output")
+ 117
+ 118 def test_ospf_convergence():
+ 119 "Test OSPF daemon convergence"
+ 120 pdb.set_trace()
+ 121 -> for rnum in range(1, 5):
+ 122 router = 'r{}'.format(rnum)
+ 123
+ 124 # Load expected results from the command
+ 125 reffile = os.path.join(CWD, '{}/ospfroute.txt'.format(router))
+ 126 expected = open(reffile).read()
+ (Pdb) step
+ > /media/sf_src/topotests/ospf-topo1/test_ospf_topo1.py(122)test_ospf_convergence()
+ -> router = 'r{}'.format(rnum)
+ (Pdb) step
+ > /media/sf_src/topotests/ospf-topo1/test_ospf_topo1.py(125)test_ospf_convergence()
+ -> reffile = os.path.join(CWD, '{}/ospfroute.txt'.format(router))
+ (Pdb) print rnum
+ 1
+ (Pdb) print router
+ r1
+ (Pdb) tgen = get_topogen()
+ (Pdb) pp tgen.gears[router]
+ <lib.topogen.TopoRouter object at 0x7f74e06c9850>
+ (Pdb) pp str(tgen.gears[router])
+ 'TopoGear<name="r1",links=["r1-eth0"<->"s1-eth0","r1-eth1"<->"s3-eth0"]> TopoRouter<>'
+ (Pdb) l 125
+ 120 pdb.set_trace()
+ 121 for rnum in range(1, 5):
+ 122 router = 'r{}'.format(rnum)
+ 123
+ 124 # Load expected results from the command
+ 125 -> reffile = os.path.join(CWD, '{}/ospfroute.txt'.format(router))
+ 126 expected = open(reffile).read()
+ 127
+ 128 # Run test function until we get an result. Wait at most 60 seconds.
+ 129 test_func = partial(compare_show_ip_ospf, router, expected)
+ 130 result, diff = topotest.run_and_expect(test_func, '',
+ (Pdb) router1 = tgen.gears[router]
+ (Pdb) router1.vtysh_cmd('show ip ospf route')
+ '============ OSPF network routing table ============\r\nN 10.0.1.0/24 [10] area: 0.0.0.0\r\n directly attached to r1-eth0\r\nN 10.0.2.0/24 [20] area: 0.0.0.0\r\n via 10.0.3.3, r1-eth1\r\nN 10.0.3.0/24 [10] area: 0.0.0.0\r\n directly attached to r1-eth1\r\nN 10.0.10.0/24 [20] area: 0.0.0.0\r\n via 10.0.3.1, r1-eth1\r\nN IA 172.16.0.0/24 [20] area: 0.0.0.0\r\n via 10.0.3.1, r1-eth1\r\nN IA 172.16.1.0/24 [30] area: 0.0.0.0\r\n via 10.0.3.1, r1-eth1\r\n\r\n============ OSPF router routing table =============\r\nR 10.0.255.2 [10] area: 0.0.0.0, ASBR\r\n via 10.0.3.3, r1-eth1\r\nR 10.0.255.3 [10] area: 0.0.0.0, ABR, ASBR\r\n via 10.0.3.1, r1-eth1\r\nR 10.0.255.4 IA [20] area: 0.0.0.0, ASBR\r\n via 10.0.3.1, r1-eth1\r\n\r\n============ OSPF external routing table ===========\r\n\r\n\r\n'
+ (Pdb) tgen.mininet_cli()
+ *** Starting CLI:
+ mininet>
+
+To enable more debug messages in other Topogen subsystems (like Mininet), more
+logging messages can be displayed by modifying the test configuration file
+``pytest.ini``:
+
+.. code:: ini
+
+ [topogen]
+ # Change the default verbosity line from 'info'...
+ #verbosity = info
+ # ...to 'debug'
+ verbosity = debug
+
+Instructions for use, write or debug topologies can be found in :ref:`topotests-guidelines`.
+To learn/remember common code snippets see :ref:`topotests-snippets`.
+
+Before creating a new topology, make sure that there isn't one already that
+does what you need. If nothing is similar, then you may create a new topology,
+preferably, using the newest template
+(:file:`tests/topotests/example-test/test_template.py`).
+
+.. include:: topotests-snippets.rst
+
+License
+-------
+
+All the configs and scripts are licensed under a ISC-style license. See Python
+scripts for details.
diff --git a/doc/user/ipv6.rst b/doc/user/ipv6.rst
index 585c3a505a..cc8fd18fee 100644
--- a/doc/user/ipv6.rst
+++ b/doc/user/ipv6.rst
@@ -179,10 +179,56 @@ Router Advertisement
hosts in proper interface configuration. The announced value is not verified
to be consistent with router interface MTU.
- Default: don't advertise any MTU option.::
- interface eth0
- no ipv6 nd suppress-ra
- ipv6 nd prefix 2001:0DB8:5009::/64
+ Default: don't advertise any MTU option.
+
+.. index::
+ single: ipv6 nd rdnss ipv6address [lifetime]
+ single: no ipv6 nd rdnss ipv6address [lifetime]
+.. clicmd:: [no] ipv6 nd rdnss ipv6address [lifetime]
+
+ Recursive DNS server address to advertise using the RDNSS (type 25) option
+ described in RFC8106. Can be specified more than once to advertise multiple
+ addresses. Note that hosts may choose to limit the number of RDNSS addresses
+ to track.
+
+ Optional parameter:
+
+ - ``lifetime``: the maximum time in seconds over which the specified address
+ may be used for domain name resolution. Value ``infinite`` represents
+ infinity (i.e. a value of all one bits (``0xffffffff``)). A value of 0
+ indicates that the address must no longer be used.
+ Range: ``(0-4294967295)`` Default: ``3 * ra-interval``
+
+ Default: do not emit RDNSS option
+
+.. index::
+ single: ipv6 nd dnssl domain-name-suffix [lifetime]
+ single: no ipv6 nd dnssl domain-name-suffix [lifetime]
+.. clicmd:: [no] ipv6 nd dnssl domain-name-suffix [lifetime]
+
+ Advertise DNS search list using the DNSSL (type 31) option described in
+ RFC8106. Specify more than once to advertise multiple domain name suffixes.
+ Host implementations may limit the number of honored search list entries.
+
+ Optional parameter:
+
+ - ``lifetime``: the maximum time in seconds over which the specified domain
+ suffix may be used in the course of name resolution. Value ``infinite``
+ represents infinity (i.e. a value of all one bits (``0xffffffff``)). A
+ value of 0 indicates that the name suffix must no longer be used.
+ Range: ``(0-4294967295)`` Default: ``3 * ra-interval``
+
+ Default: do not emit DNSSL option
+
+Router Advertisement Configuration Example
+==========================================
+A small example:
+
+.. code-block:: frr
+
+ interface eth0
+ no ipv6 nd suppress-ra
+ ipv6 nd prefix 2001:0DB8:5009::/64
.. seealso::
@@ -191,3 +237,4 @@ Router Advertisement
- :rfc:`4861` (Neighbor Discovery for IP Version 6 (IPv6))
- :rfc:`6275` (Mobility Support in IPv6)
- :rfc:`4191` (Default Router Preferences and More-Specific Routes)
+ - :rfc:`8106` (IPv6 Router Advertisement Options for DNS Configuration)
diff --git a/doc/user/routemap.rst b/doc/user/routemap.rst
index 42a8250ae0..ef9ebe8ddc 100644
--- a/doc/user/routemap.rst
+++ b/doc/user/routemap.rst
@@ -38,11 +38,12 @@ to four distinct sets of clauses:
the ordered entry in the route-map. See below.
Call Action
- Call to another route-map, after any :term:`Set Actions` have been carried out.
- If the route-map called returns `deny` then processing of the route-map
- finishes and the route is denied, regardless of the :term:Matching Policy` or
- the :term:`Exit Policy`. If the called route-map returns `permit`, then
- :term:`Matching Policy` and :term:`Exit Policy` govern further behaviour, as normal.
+ Call to another route-map, after any :term:`Set Actions` have been
+ carried out. If the route-map called returns `deny` then processing of
+ the route-map finishes and the route is denied, regardless of the
+ :term:`Matching Policy` or the :term:`Exit Policy`. If the called
+ route-map returns `permit`, then :term:`Matching Policy` and :term:`Exit
+ Policy` govern further behaviour, as normal.
Exit Policy
An entry may, optionally, specify an alternative :dfn:`Exit Policy` to
diff --git a/doc/user/sharp.rst b/doc/user/sharp.rst
index c2d32a718e..ca8f1f512f 100644
--- a/doc/user/sharp.rst
+++ b/doc/user/sharp.rst
@@ -56,6 +56,14 @@ keyword. At present, no sharp commands will be preserved in the config.
log and when all routes have been successfully deleted the debug log will be
updated with this information as well.
+.. index:: sharp data route
+.. clicmd:: sharp data route
+
+ Allow end user doing route install and deletion to get timing information
+ from the vty or vtysh instead of having to read the log file. This command
+ is informational only and you should look at sharp_vty.c for explanation
+ of the output as that it may change.
+
.. index:: sharp label
.. clicmd:: sharp label <ipv4|ipv6> vrf NAME label (0-1000000)
@@ -63,7 +71,18 @@ keyword. At present, no sharp commands will be preserved in the config.
be used for pop and forward operations when the specified label is seen.
.. index:: sharp watch
-.. clicmd:: sharp watch nexthop <A.B.C.D|X:X::X:X>
+.. clicmd:: [no] sharp watch <nexthop|import> <A.B.C.D|X:X::X:X> [connected]
Instruct zebra to monitor and notify sharp when the specified nexthop is
changed. The notification from zebra is written into the debug log.
+ The nexthop or import choice chooses the type of nexthop we are asking
+ zebra to watch for us. This choice affects zebra's decision on what
+ matches. Connected tells zebra whether or not that we want the route
+ matched against to be a static or connected route. The no form of
+ the command obviously turns this watching off.
+
+.. index:: sharp data nexthop
+.. clicmd:: sharp data nexthop
+
+ Allow end user to dump associated data with the nexthop tracking that
+ may have been turned on.
diff --git a/docker/debian/Dockerfile b/docker/debian/Dockerfile
new file mode 100644
index 0000000000..4f192ec33e
--- /dev/null
+++ b/docker/debian/Dockerfile
@@ -0,0 +1,10 @@
+FROM debian:stretch
+MAINTAINER Rob Gil (rob@rem5.com)
+RUN apt-get update
+RUN apt-get install -y libpcre3-dev apt-transport-https ca-certificates curl wget logrotate \
+ libc-ares2 libjson-c3 vim systemd procps
+RUN curl -sLO https://ci1.netdef.org/artifact/LIBYANG-YANGRELEASE/shared/build-1/Debian-9-x86_64-Packages/libyang_0.16.46_amd64.deb && dpkg -i libyang_0.16.46_amd64.deb
+RUN curl -sLO https://github.com/FRRouting/frr/releases/download/frr-6.0.2/frr_6.0.2-0.deb9u1_amd64.deb && dpkg -i frr_6.0.2-0.deb9u1_amd64.deb
+ADD daemons /etc/frr/daemons
+ADD docker-start /usr/sbin/docker-start
+ENTRYPOINT ["/usr/sbin/docker-start"]
diff --git a/docker/debian/README.md b/docker/debian/README.md
new file mode 100644
index 0000000000..b10d696a78
--- /dev/null
+++ b/docker/debian/README.md
@@ -0,0 +1,17 @@
+# Debian9 Docker
+This is a binary docker container build of debian9.
+
+# Build
+```
+docker build --rm -t frr:6.0.2 .
+```
+
+# Running
+```
+docker run -itd --privileged --name frr frr:latest
+```
+
+vtysh
+```
+docker exec -it frr vtysh
+```
diff --git a/docker/debian/daemons b/docker/debian/daemons
new file mode 100644
index 0000000000..ed4d98e1f8
--- /dev/null
+++ b/docker/debian/daemons
@@ -0,0 +1,65 @@
+# This file tells the frr package which daemons to start.
+#
+# Sample configurations for these daemons can be found in
+# /usr/share/doc/frr/examples/.
+#
+# ATTENTION:
+#
+# When activation a daemon at the first time, a config file, even if it is
+# empty, has to be present *and* be owned by the user and group "frr", else
+# the daemon will not be started by /etc/init.d/frr. The permissions should
+# be u=rw,g=r,o=.
+# When using "vtysh" such a config file is also needed. It should be owned by
+# group "frrvty" and set to ug=rw,o= though. Check /etc/pam.d/frr, too.
+#
+# The watchfrr and zebra daemons are always started.
+#
+bgpd=yes
+ospfd=no
+ospf6d=no
+ripd=no
+ripngd=no
+isisd=no
+pimd=no
+ldpd=no
+nhrpd=no
+eigrpd=no
+babeld=no
+sharpd=no
+pbrd=no
+bfdd=no
+fabricd=no
+
+#
+# If this option is set the /etc/init.d/frr script automatically loads
+# the config via "vtysh -b" when the servers are started.
+# Check /etc/pam.d/frr if you intend to use "vtysh"!
+#
+vtysh_enable=yes
+zebra_options=" -A 127.0.0.1 -s 90000000"
+bgpd_options=" -A 127.0.0.1"
+ospfd_options=" -A 127.0.0.1"
+ospf6d_options=" -A ::1"
+ripd_options=" -A 127.0.0.1"
+ripngd_options=" -A ::1"
+isisd_options=" -A 127.0.0.1"
+pimd_options=" -A 127.0.0.1"
+ldpd_options=" -A 127.0.0.1"
+nhrpd_options=" -A 127.0.0.1"
+eigrpd_options=" -A 127.0.0.1"
+babeld_options=" -A 127.0.0.1"
+sharpd_options=" -A 127.0.0.1"
+pbrd_options=" -A 127.0.0.1"
+staticd_options="-A 127.0.0.1"
+bfdd_options=" -A 127.0.0.1"
+fabricd_options="-A 127.0.0.1"
+
+# The list of daemons to watch is automatically generated by the init script.
+watchfrr_options="-r '/usr/lib/frr/watchfrr.sh restart %s' -s '/usr/lib/frr/watchfrr.sh start %s' -k '/usr/lib/frr/watchfrr.sh stop %s'"
+
+# for debugging purposes, you can specify a "wrap" command to start instead
+# of starting the daemon directly, e.g. to use valgrind on ospfd:
+# ospfd_wrap="/usr/bin/valgrind"
+# or you can use "all_wrap" for all daemons, e.g. to use perf record:
+# all_wrap="/usr/bin/perf record --call-graph -"
+# the normal daemon command is added to this at the end.
diff --git a/docker/debian/docker-start b/docker/debian/docker-start
new file mode 100755
index 0000000000..43854ab142
--- /dev/null
+++ b/docker/debian/docker-start
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+set -e
+
+##
+# For volume mounts...
+##
+chown -R frr:frr /etc/frr
+/etc/init.d/frr start
+exec sleep 10000d
diff --git a/eigrpd/eigrp_dump.c b/eigrpd/eigrp_dump.c
index 876e1cac07..583db6622d 100644
--- a/eigrpd/eigrp_dump.c
+++ b/eigrpd/eigrp_dump.c
@@ -174,7 +174,7 @@ const char *eigrp_if_ip_string(struct eigrp_interface *ei)
if (!ei)
return "inactive";
- ifaddr = ntohl(ei->address->u.prefix4.s_addr);
+ ifaddr = ntohl(ei->address.u.prefix4.s_addr);
snprintf(buf, EIGRP_IF_STRING_MAXLEN, "%u.%u.%u.%u",
(ifaddr >> 24) & 0xff, (ifaddr >> 16) & 0xff,
(ifaddr >> 8) & 0xff, ifaddr & 0xff);
@@ -301,14 +301,14 @@ void show_ip_eigrp_prefix_entry(struct vty *vty, struct eigrp_prefix_entry *tn)
}
void show_ip_eigrp_nexthop_entry(struct vty *vty, struct eigrp *eigrp,
- struct eigrp_nexthop_entry *te, int *first)
+ struct eigrp_nexthop_entry *te, bool *first)
{
if (te->reported_distance == EIGRP_MAX_METRIC)
return;
if (*first) {
show_ip_eigrp_prefix_entry(vty, te->prefix);
- *first = 0;
+ *first = false;
}
if (te->adv_router == eigrp->neighbor_self)
diff --git a/eigrpd/eigrp_dump.h b/eigrpd/eigrp_dump.h
index 389ac1b5fd..34b55ab419 100644
--- a/eigrpd/eigrp_dump.h
+++ b/eigrpd/eigrp_dump.h
@@ -156,8 +156,9 @@ extern void show_ip_eigrp_neighbor_sub(struct vty *, struct eigrp_neighbor *,
int);
extern void show_ip_eigrp_prefix_entry(struct vty *,
struct eigrp_prefix_entry *);
-extern void show_ip_eigrp_nexthop_entry(struct vty *, struct eigrp *,
- struct eigrp_nexthop_entry *, int *);
+extern void show_ip_eigrp_nexthop_entry(struct vty *vty, struct eigrp *eigrp,
+ struct eigrp_nexthop_entry *ne,
+ bool *first);
extern void eigrp_debug_init(void);
diff --git a/eigrpd/eigrp_hello.c b/eigrpd/eigrp_hello.c
index 413a35f2fa..b4d850be08 100644
--- a/eigrpd/eigrp_hello.c
+++ b/eigrpd/eigrp_hello.c
@@ -248,7 +248,7 @@ static void eigrp_peer_termination_decode(struct eigrp_neighbor *nbr,
struct TLV_Peer_Termination_type *param =
(struct TLV_Peer_Termination_type *)tlv;
- uint32_t my_ip = nbr->ei->address->u.prefix4.s_addr;
+ uint32_t my_ip = nbr->ei->address.u.prefix4.s_addr;
uint32_t received_ip = param->neighbor_ip;
if (my_ip == received_ip) {
diff --git a/eigrpd/eigrp_interface.c b/eigrpd/eigrp_interface.c
index e6cfe1deea..c52a98ee25 100644
--- a/eigrpd/eigrp_interface.c
+++ b/eigrpd/eigrp_interface.c
@@ -68,7 +68,7 @@ struct eigrp_interface *eigrp_if_new(struct eigrp *eigrp, struct interface *ifp,
/* Set zebra interface pointer. */
ei->ifp = ifp;
- ei->address = p;
+ prefix_copy(&ei->address, p);
ifp->info = ei;
listnode_add(eigrp->eiflist, ei);
@@ -114,6 +114,8 @@ int eigrp_if_delete_hook(struct interface *ifp)
eigrp = ei->eigrp;
listnode_delete(eigrp->eiflist, ei);
+ eigrp_fifo_free(ei->obuf);
+
XFREE(MTYPE_EIGRP_IF_INFO, ifp->info);
ifp->info = NULL;
@@ -183,7 +185,7 @@ int eigrp_if_up(struct eigrp_interface *ei)
struct prefix dest_addr;
- dest_addr = *ei->address;
+ dest_addr = ei->address;
apply_mask(&dest_addr);
pe = eigrp_topology_table_lookup_ipv4(eigrp->topology_table,
&dest_addr);
@@ -265,16 +267,11 @@ void eigrp_if_stream_unset(struct eigrp_interface *ei)
{
struct eigrp *eigrp = ei->eigrp;
- if (ei->obuf) {
- eigrp_fifo_free(ei->obuf);
- ei->obuf = NULL;
-
- if (ei->on_write_q) {
- listnode_delete(eigrp->oi_write_q, ei);
- if (list_isempty(eigrp->oi_write_q))
- thread_cancel(eigrp->t_write);
- ei->on_write_q = 0;
- }
+ if (ei->on_write_q) {
+ listnode_delete(eigrp->oi_write_q, ei);
+ if (list_isempty(eigrp->oi_write_q))
+ thread_cancel(eigrp->t_write);
+ ei->on_write_q = 0;
}
}
@@ -295,7 +292,7 @@ void eigrp_if_set_multicast(struct eigrp_interface *ei)
/* The interface should belong to the EIGRP-all-routers group.
*/
if (!ei->member_allrouters
- && (eigrp_if_add_allspfrouters(ei->eigrp, ei->address,
+ && (eigrp_if_add_allspfrouters(ei->eigrp, &ei->address,
ei->ifp->ifindex)
>= 0))
/* Set the flag only if the system call to join
@@ -306,7 +303,7 @@ void eigrp_if_set_multicast(struct eigrp_interface *ei)
* group. */
if (ei->member_allrouters) {
/* Only actually drop if this is the last reference */
- eigrp_if_drop_allspfrouters(ei->eigrp, ei->address,
+ eigrp_if_drop_allspfrouters(ei->eigrp, &ei->address,
ei->ifp->ifindex);
/* Unset the flag regardless of whether the system call
to leave
@@ -342,7 +339,7 @@ void eigrp_if_free(struct eigrp_interface *ei, int source)
eigrp_hello_send(ei, EIGRP_HELLO_GRACEFUL_SHUTDOWN, NULL);
}
- dest_addr = *ei->address;
+ dest_addr = ei->address;
apply_mask(&dest_addr);
pe = eigrp_topology_table_lookup_ipv4(eigrp->topology_table,
&dest_addr);
@@ -351,7 +348,6 @@ void eigrp_if_free(struct eigrp_interface *ei, int source)
eigrp_if_down(ei);
- list_delete(&ei->nbrs);
listnode_delete(ei->eigrp->eiflist, ei);
}
@@ -379,7 +375,7 @@ struct eigrp_interface *eigrp_if_lookup_by_local_addr(struct eigrp *eigrp,
if (ifp && ei->ifp != ifp)
continue;
- if (IPV4_ADDR_SAME(&address, &ei->address->u.prefix4))
+ if (IPV4_ADDR_SAME(&address, &ei->address.u.prefix4))
return ei;
}
diff --git a/eigrpd/eigrp_network.c b/eigrpd/eigrp_network.c
index 6bb619f0e1..76f8cfc93b 100644
--- a/eigrpd/eigrp_network.c
+++ b/eigrpd/eigrp_network.c
@@ -293,7 +293,7 @@ void eigrp_if_update(struct interface *ifp)
*/
for (ALL_LIST_ELEMENTS(eigrp_om->eigrp, node, nnode, eigrp)) {
/* EIGRP must be on and Router-ID must be configured. */
- if (!eigrp || eigrp->router_id.s_addr == 0)
+ if (eigrp->router_id.s_addr == 0)
continue;
/* Run each network for this interface. */
@@ -333,7 +333,7 @@ int eigrp_network_unset(struct eigrp *eigrp, struct prefix *p)
if (rn->info == NULL)
continue;
- if (eigrp_network_match_iface(ei->address, &rn->p)) {
+ if (eigrp_network_match_iface(&ei->address, &rn->p)) {
found = true;
route_unlock_node(rn);
break;
diff --git a/eigrpd/eigrp_packet.c b/eigrpd/eigrp_packet.c
index ee0476b28d..bedaf15c47 100644
--- a/eigrpd/eigrp_packet.c
+++ b/eigrpd/eigrp_packet.c
@@ -281,7 +281,7 @@ int eigrp_make_sha256_digest(struct eigrp_interface *ei, struct stream *s,
return 0;
}
- inet_ntop(AF_INET, &ei->address->u.prefix4, source_ip, PREFIX_STRLEN);
+ inet_ntop(AF_INET, &ei->address.u.prefix4, source_ip, PREFIX_STRLEN);
memset(&ctx, 0, sizeof(ctx));
buffer[0] = '\n';
@@ -362,7 +362,7 @@ int eigrp_write(struct thread *thread)
}
if (ep->dst.s_addr == htonl(EIGRP_MULTICAST_ADDRESS))
- eigrp_if_ipmulticast(eigrp, ei->address, ei->ifp->ifindex);
+ eigrp_if_ipmulticast(eigrp, &ei->address, ei->ifp->ifindex);
memset(&iph, 0, sizeof(struct ip));
memset(&sa_dst, 0, sizeof(sa_dst));
@@ -418,7 +418,7 @@ int eigrp_write(struct thread *thread)
iph.ip_ttl = EIGRP_IP_TTL;
iph.ip_p = IPPROTO_EIGRPIGP;
iph.ip_sum = 0;
- iph.ip_src.s_addr = ei->address->u.prefix4.s_addr;
+ iph.ip_src.s_addr = ei->address.u.prefix4.s_addr;
iph.ip_dst.s_addr = ep->dst.s_addr;
memset(&msg, 0, sizeof(msg));
@@ -547,7 +547,7 @@ int eigrp_read(struct thread *thread)
/* Self-originated packet should be discarded silently. */
if (eigrp_if_lookup_by_local_addr(eigrp, NULL, iph->ip_src)
- || (IPV4_ADDR_SAME(&iph->ip_src, &ei->address->u.prefix4))) {
+ || (IPV4_ADDR_SAME(&iph->ip_src, &ei->address.u.prefix4))) {
if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV))
zlog_debug(
"eigrp_read[%s]: Dropping self-originated packet",
@@ -581,7 +581,7 @@ int eigrp_read(struct thread *thread)
sizeof(buf[0])),
inet_ntop(AF_INET, &iph->ip_dst, buf[1],
sizeof(buf[1])),
- inet_ntop(AF_INET, &ei->address->u.prefix4,
+ inet_ntop(AF_INET, &ei->address.u.prefix4,
buf[2], sizeof(buf[2])));
if (iph->ip_dst.s_addr == htonl(EIGRP_MULTICAST_ADDRESS)) {
@@ -981,9 +981,9 @@ static int eigrp_check_network_mask(struct eigrp_interface *ei,
if (ei->type == EIGRP_IFTYPE_POINTOPOINT)
return 1;
- masklen2ip(ei->address->prefixlen, &mask);
+ masklen2ip(ei->address.prefixlen, &mask);
- me.s_addr = ei->address->u.prefix4.s_addr & mask.s_addr;
+ me.s_addr = ei->address.u.prefix4.s_addr & mask.s_addr;
him.s_addr = ip_src.s_addr & mask.s_addr;
if (IPV4_ADDR_SAME(&me, &him))
diff --git a/eigrpd/eigrp_structs.h b/eigrpd/eigrp_structs.h
index 644ab0829f..a78e5a53cf 100644
--- a/eigrpd/eigrp_structs.h
+++ b/eigrpd/eigrp_structs.h
@@ -180,7 +180,7 @@ struct eigrp_interface {
/* EIGRP Network Type. */
uint8_t type;
- struct prefix *address; /* Interface prefix */
+ struct prefix address; /* Interface prefix */
/* Neighbor information. */
struct list *nbrs; /* EIGRP Neighbor List */
diff --git a/eigrpd/eigrp_topology.c b/eigrpd/eigrp_topology.c
index 2d0ebf1bc5..e861cdb333 100644
--- a/eigrpd/eigrp_topology.c
+++ b/eigrpd/eigrp_topology.c
@@ -141,10 +141,10 @@ void eigrp_prefix_entry_add(struct route_table *topology,
__PRETTY_FUNCTION__,
prefix2str(pe->destination, buf, sizeof(buf)));
}
+ route_unlock_node(rn);
}
rn->info = pe;
- route_lock_node(rn);
}
/*
@@ -161,7 +161,7 @@ void eigrp_nexthop_entry_add(struct eigrp_prefix_entry *node,
listnode_add_sort(node->entries, entry);
entry->prefix = node;
- eigrp_zebra_route_add(node->destination, l);
+ eigrp_zebra_route_add(node->destination, l, node->fdistance);
}
list_delete(&l);
@@ -477,7 +477,8 @@ void eigrp_update_routing_table(struct eigrp_prefix_entry *prefix)
successors = eigrp_topology_get_successor_max(prefix, eigrp->max_paths);
if (successors) {
- eigrp_zebra_route_add(prefix->destination, successors);
+ eigrp_zebra_route_add(prefix->destination, successors,
+ prefix->fdistance);
for (ALL_LIST_ELEMENTS_RO(successors, node, entry))
entry->flags |= EIGRP_NEXTHOP_ENTRY_INTABLE_FLAG;
diff --git a/eigrpd/eigrp_vty.c b/eigrpd/eigrp_vty.c
index 474f683989..a9b103de47 100644
--- a/eigrpd/eigrp_vty.c
+++ b/eigrpd/eigrp_vty.c
@@ -455,9 +455,33 @@ DEFUN (no_eigrp_neighbor,
return CMD_SUCCESS;
}
-DEFUN (show_ip_eigrp_topology,
- show_ip_eigrp_topology_cmd,
- "show ip eigrp topology [all-links]",
+static void eigrp_vty_display_prefix_entry(struct vty *vty,
+ struct eigrp *eigrp,
+ struct eigrp_prefix_entry *pe,
+ bool all)
+{
+ bool first = true;
+ struct eigrp_nexthop_entry *te;
+ struct listnode *node;
+
+ for (ALL_LIST_ELEMENTS_RO(pe->entries, node, te)) {
+ if (all
+ || (((te->flags
+ & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG)
+ == EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG)
+ || ((te->flags
+ & EIGRP_NEXTHOP_ENTRY_FSUCCESSOR_FLAG)
+ == EIGRP_NEXTHOP_ENTRY_FSUCCESSOR_FLAG))) {
+ show_ip_eigrp_nexthop_entry(vty, eigrp, te,
+ &first);
+ first = false;
+ }
+ }
+}
+
+DEFPY (show_ip_eigrp_topology_all,
+ show_ip_eigrp_topology_all_cmd,
+ "show ip eigrp topology [all-links$all]",
SHOW_STR
IP_STR
"IP-EIGRP show commands\n"
@@ -465,11 +489,8 @@ DEFUN (show_ip_eigrp_topology,
"Show all links in topology table\n")
{
struct eigrp *eigrp;
- struct listnode *node;
struct eigrp_prefix_entry *tn;
- struct eigrp_nexthop_entry *te;
struct route_node *rn;
- int first;
eigrp = eigrp_lookup();
if (eigrp == NULL) {
@@ -484,34 +505,63 @@ DEFUN (show_ip_eigrp_topology,
continue;
tn = rn->info;
- first = 1;
- for (ALL_LIST_ELEMENTS_RO(tn->entries, node, te)) {
- if (argc == 5
- || (((te->flags
- & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG)
- == EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG)
- || ((te->flags
- & EIGRP_NEXTHOP_ENTRY_FSUCCESSOR_FLAG)
- == EIGRP_NEXTHOP_ENTRY_FSUCCESSOR_FLAG))) {
- show_ip_eigrp_nexthop_entry(vty, eigrp, te,
- &first);
- first = 0;
- }
- }
+ eigrp_vty_display_prefix_entry(vty, eigrp, tn,
+ all ? true : false);
}
return CMD_SUCCESS;
+
}
-ALIAS(show_ip_eigrp_topology, show_ip_eigrp_topology_detail_cmd,
- "show ip eigrp topology <A.B.C.D|A.B.C.D/M|detail|summary>",
- SHOW_STR IP_STR
- "IP-EIGRP show commands\n"
- "IP-EIGRP topology\n"
- "Netwok to display information about\n"
- "IP prefix <network>/<length>, e.g., 192.168.0.0/16\n"
- "Show all links in topology table\n"
- "Show a summary of the topology table\n")
+DEFPY (show_ip_eigrp_topology,
+ show_ip_eigrp_topology_cmd,
+ "show ip eigrp topology <A.B.C.D$address|A.B.C.D/M$prefix>",
+ SHOW_STR
+ IP_STR
+ "IP-EIGRP show commands\n"
+ "IP-EIGRP topology\n"
+ "For a specific address\n"
+ "For a specific prefix\n")
+{
+ struct eigrp *eigrp;
+ struct eigrp_prefix_entry *tn;
+ struct route_node *rn;
+ struct prefix cmp;
+
+ eigrp = eigrp_lookup();
+ if (eigrp == NULL) {
+ vty_out(vty, " EIGRP Routing Process not enabled\n");
+ return CMD_SUCCESS;
+ }
+
+ show_ip_eigrp_topology_header(vty, eigrp);
+
+ if (address_str)
+ prefix_str = address_str;
+
+ if (str2prefix(prefix_str, &cmp) < 0) {
+ vty_out(vty, "%% Malformed address\n");
+ return CMD_WARNING;
+ }
+
+ rn = route_node_match(eigrp->topology_table, &cmp);
+ if (!rn) {
+ vty_out(vty, "%% Network not in table\n");
+ return CMD_WARNING;
+ }
+
+ if (!rn->info) {
+ vty_out(vty, "%% Network not in table\n");
+ route_unlock_node(rn);
+ return CMD_WARNING;
+ }
+
+ tn = rn->info;
+ eigrp_vty_display_prefix_entry(vty, eigrp, tn, argc == 5);
+
+ route_unlock_node(rn);
+ return CMD_SUCCESS;
+}
DEFUN (show_ip_eigrp_interfaces,
show_ip_eigrp_interfaces_cmd,
@@ -1485,8 +1535,7 @@ void eigrp_vty_show_init(void)
install_element(VIEW_NODE, &show_ip_eigrp_neighbors_cmd);
install_element(VIEW_NODE, &show_ip_eigrp_topology_cmd);
-
- install_element(VIEW_NODE, &show_ip_eigrp_topology_detail_cmd);
+ install_element(VIEW_NODE, &show_ip_eigrp_topology_all_cmd);
}
/* eigrpd's interface node. */
diff --git a/eigrpd/eigrp_zebra.c b/eigrpd/eigrp_zebra.c
index a810e01468..dc1ae675b0 100644
--- a/eigrpd/eigrp_zebra.c
+++ b/eigrpd/eigrp_zebra.c
@@ -258,7 +258,8 @@ static int eigrp_interface_address_delete(int command, struct zclient *zclient,
return 0;
/* Call interface hook functions to clean up */
- eigrp_if_free(ei, INTERFACE_DOWN_BY_ZEBRA);
+ if (prefix_cmp(&ei->address, c->address) == 0)
+ eigrp_if_free(ei, INTERFACE_DOWN_BY_ZEBRA);
connected_free(c);
@@ -353,7 +354,8 @@ static struct interface *zebra_interface_if_lookup(struct stream *s)
return if_lookup_by_name(ifname_tmp, VRF_DEFAULT);
}
-void eigrp_zebra_route_add(struct prefix *p, struct list *successors)
+void eigrp_zebra_route_add(struct prefix *p, struct list *successors,
+ uint32_t distance)
{
struct zapi_route api;
struct zapi_nexthop *api_nh;
@@ -368,9 +370,11 @@ void eigrp_zebra_route_add(struct prefix *p, struct list *successors)
api.vrf_id = VRF_DEFAULT;
api.type = ZEBRA_ROUTE_EIGRP;
api.safi = SAFI_UNICAST;
+ api.metric = distance;
memcpy(&api.prefix, p, sizeof(*p));
SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
+ SET_FLAG(api.message, ZAPI_MESSAGE_METRIC);
/* Nexthop, ifindex, distance and metric information. */
for (ALL_LIST_ELEMENTS_RO(successors, node, te)) {
diff --git a/eigrpd/eigrp_zebra.h b/eigrpd/eigrp_zebra.h
index 1c418dddef..86b337cfe6 100644
--- a/eigrpd/eigrp_zebra.h
+++ b/eigrpd/eigrp_zebra.h
@@ -33,7 +33,8 @@
extern void eigrp_zebra_init(void);
-extern void eigrp_zebra_route_add(struct prefix *, struct list *);
+extern void eigrp_zebra_route_add(struct prefix *, struct list *,
+ uint32_t distance);
extern void eigrp_zebra_route_delete(struct prefix *);
extern int eigrp_redistribute_set(struct eigrp *, int, struct eigrp_metrics);
extern int eigrp_redistribute_unset(struct eigrp *, int);
diff --git a/eigrpd/subdir.am b/eigrpd/subdir.am
index d532afbbe6..4503030fdf 100644
--- a/eigrpd/subdir.am
+++ b/eigrpd/subdir.am
@@ -65,4 +65,4 @@ noinst_HEADERS += \
# end
eigrpd_eigrpd_SOURCES = eigrpd/eigrp_main.c
-eigrpd_eigrpd_LDADD = eigrpd/libeigrp.a lib/libfrr.la @LIBCAP@
+eigrpd_eigrpd_LDADD = eigrpd/libeigrp.a lib/libfrr.la $(LIBCAP)
diff --git a/isisd/isis_cli.c b/isisd/isis_cli.c
index c68f49f92d..bd8b58e8f0 100644
--- a/isisd/isis_cli.c
+++ b/isisd/isis_cli.c
@@ -89,7 +89,7 @@ DEFPY(no_router_isis, no_router_isis_cmd, "no router isis WORD$tag",
return CMD_ERR_NOTHING_TODO;
}
- nb_cli_enqueue_change(vty, ".", NB_OP_DELETE, NULL);
+ nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
area = isis_area_lookup(tag);
if (area && area->circuit_list && listcount(area->circuit_list)) {
for (ALL_LIST_ELEMENTS(area->circuit_list, node, nnode,
@@ -103,7 +103,7 @@ DEFPY(no_router_isis, no_router_isis_cmd, "no router isis WORD$tag",
temp_xpath, XPATH_MAXLEN,
"/frr-interface:lib/interface[name='%s'][vrf='%s']/frr-isisd:isis",
circuit->interface->name, vrf_name);
- nb_cli_enqueue_change(vty, temp_xpath, NB_OP_DELETE,
+ nb_cli_enqueue_change(vty, temp_xpath, NB_OP_DESTROY,
NULL);
}
}
@@ -289,7 +289,7 @@ DEFPY(no_ip_router_isis, no_ip_router_isis_cmd,
&& !yang_dnode_get_bool(dnode,
"./frr-isisd:isis/ipv4-routing"))
nb_cli_enqueue_change(vty, "./frr-isisd:isis",
- NB_OP_DELETE, NULL);
+ NB_OP_DESTROY, NULL);
else
nb_cli_enqueue_change(vty,
"./frr-isisd:isis/ipv6-routing",
@@ -299,7 +299,7 @@ DEFPY(no_ip_router_isis, no_ip_router_isis_cmd,
&& !yang_dnode_get_bool(dnode,
"./frr-isisd:isis/ipv6-routing"))
nb_cli_enqueue_change(vty, "./frr-isisd:isis",
- NB_OP_DELETE, NULL);
+ NB_OP_DESTROY, NULL);
else
nb_cli_enqueue_change(vty,
"./frr-isisd:isis/ipv4-routing",
@@ -336,7 +336,7 @@ DEFPY(net, net_cmd, "[no] net WORD",
"XX.XXXX. ... .XXX.XX Network entity title (NET)\n")
{
nb_cli_enqueue_change(vty, "./area-address",
- no ? NB_OP_DELETE : NB_OP_CREATE, net);
+ no ? NB_OP_DESTROY : NB_OP_CREATE, net);
return nb_cli_apply_changes(vty, NULL);
}
@@ -589,7 +589,7 @@ DEFPY(no_area_passwd, no_area_passwd_cmd,
"Configure the authentication password for an area\n"
"Set the authentication password for a routing domain\n")
{
- nb_cli_enqueue_change(vty, ".", NB_OP_DELETE, NULL);
+ nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
return nb_cli_apply_changes(vty, "./%s", cmd);
}
@@ -892,7 +892,7 @@ DEFPY(no_spf_delay_ietf, no_spf_delay_ietf_cmd,
"Maximum duration needed to learn all the events related to a single failure\n"
"Maximum duration needed to learn all the events related to a single failure (in milliseconds)\n")
{
- nb_cli_enqueue_change(vty, "./spf/ietf-backoff-delay", NB_OP_DELETE,
+ nb_cli_enqueue_change(vty, "./spf/ietf-backoff-delay", NB_OP_DESTROY,
NULL);
return nb_cli_apply_changes(vty, NULL);
@@ -947,7 +947,7 @@ DEFPY(no_isis_mpls_te_on, no_isis_mpls_te_on_cmd, "no mpls-te [on]",
"Disable the MPLS-TE functionality\n"
"Enable the MPLS-TE functionality\n")
{
- nb_cli_enqueue_change(vty, "/frr-isisd:isis/mpls-te", NB_OP_DELETE,
+ nb_cli_enqueue_change(vty, "/frr-isisd:isis/mpls-te", NB_OP_DESTROY,
NULL);
return nb_cli_apply_changes(vty, NULL);
@@ -1014,16 +1014,16 @@ DEFPY(isis_default_originate, isis_default_originate_cmd,
"Pointer to route-map entries\n")
{
if (no)
- nb_cli_enqueue_change(vty, ".", NB_OP_DELETE, NULL);
+ nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
else {
nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL);
nb_cli_enqueue_change(vty, "./always", NB_OP_MODIFY,
always ? "true" : "false");
nb_cli_enqueue_change(vty, "./route-map",
- rmap ? NB_OP_MODIFY : NB_OP_DELETE,
+ rmap ? NB_OP_MODIFY : NB_OP_DESTROY,
rmap ? rmap : NULL);
nb_cli_enqueue_change(vty, "./metric",
- metric ? NB_OP_MODIFY : NB_OP_DELETE,
+ metric ? NB_OP_MODIFY : NB_OP_DESTROY,
metric ? metric_str : NULL);
if (strmatch(ip, "ipv6") && !always) {
vty_out(vty,
@@ -1094,14 +1094,14 @@ DEFPY(isis_redistribute, isis_redistribute_cmd,
"Pointer to route-map entries\n")
{
if (no)
- nb_cli_enqueue_change(vty, ".", NB_OP_DELETE, NULL);
+ nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
else {
nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL);
nb_cli_enqueue_change(vty, "./route-map",
- route_map ? NB_OP_MODIFY : NB_OP_DELETE,
+ route_map ? NB_OP_MODIFY : NB_OP_DESTROY,
route_map ? route_map : NULL);
nb_cli_enqueue_change(vty, "./metric",
- metric ? NB_OP_MODIFY : NB_OP_DELETE,
+ metric ? NB_OP_MODIFY : NB_OP_DESTROY,
metric ? metric_str : NULL);
}
@@ -1182,7 +1182,7 @@ DEFPY(isis_topology, isis_topology_cmd,
topology);
if (no)
- nb_cli_enqueue_change(vty, ".", NB_OP_DELETE, NULL);
+ nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
else {
nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL);
nb_cli_enqueue_change(vty, "./overload", NB_OP_MODIFY,
@@ -1297,7 +1297,7 @@ DEFPY(no_isis_passwd, no_isis_passwd_cmd, "no isis password [<md5|clear> WORD]",
"Cleartext password\n"
"Circuit password\n")
{
- nb_cli_enqueue_change(vty, "./frr-isisd:isis/password", NB_OP_DELETE,
+ nb_cli_enqueue_change(vty, "./frr-isisd:isis/password", NB_OP_DESTROY,
NULL);
return nb_cli_apply_changes(vty, NULL);
diff --git a/isisd/isis_northbound.c b/isisd/isis_northbound.c
index 9c2bb1728e..3364a9f0be 100644
--- a/isisd/isis_northbound.c
+++ b/isisd/isis_northbound.c
@@ -72,7 +72,7 @@ static int isis_instance_create(enum nb_event event,
return NB_OK;
}
-static int isis_instance_delete(enum nb_event event,
+static int isis_instance_destroy(enum nb_event event,
const struct lyd_node *dnode)
{
const char *area_tag;
@@ -193,7 +193,7 @@ static int isis_instance_area_address_create(enum nb_event event,
return NB_OK;
}
-static int isis_instance_area_address_delete(enum nb_event event,
+static int isis_instance_area_address_destroy(enum nb_event event,
const struct lyd_node *dnode)
{
struct area_addr addr, *addrp = NULL;
@@ -536,7 +536,7 @@ isis_instance_spf_ietf_backoff_delay_create(enum nb_event event,
}
static int
-isis_instance_spf_ietf_backoff_delay_delete(enum nb_event event,
+isis_instance_spf_ietf_backoff_delay_destroy(enum nb_event event,
const struct lyd_node *dnode)
{
struct isis_area *area;
@@ -676,7 +676,7 @@ static int isis_instance_area_password_create(enum nb_event event,
return NB_OK;
}
-static int isis_instance_area_password_delete(enum nb_event event,
+static int isis_instance_area_password_destroy(enum nb_event event,
const struct lyd_node *dnode)
{
struct isis_area *area;
@@ -755,7 +755,7 @@ static int isis_instance_domain_password_create(enum nb_event event,
return NB_OK;
}
-static int isis_instance_domain_password_delete(enum nb_event event,
+static int isis_instance_domain_password_destroy(enum nb_event event,
const struct lyd_node *dnode)
{
struct isis_area *area;
@@ -851,7 +851,7 @@ static int isis_instance_default_information_originate_ipv4_create(
return NB_OK;
}
-static int isis_instance_default_information_originate_ipv4_delete(
+static int isis_instance_default_information_originate_ipv4_destroy(
enum nb_event event, const struct lyd_node *dnode)
{
struct isis_area *area;
@@ -889,7 +889,7 @@ static int isis_instance_default_information_originate_ipv4_route_map_modify(
return NB_OK;
}
-static int isis_instance_default_information_originate_ipv4_route_map_delete(
+static int isis_instance_default_information_originate_ipv4_route_map_destroy(
enum nb_event event, const struct lyd_node *dnode)
{
/* It's all done by default_info_origin_apply_finish */
@@ -907,7 +907,7 @@ static int isis_instance_default_information_originate_ipv4_metric_modify(
return NB_OK;
}
-static int isis_instance_default_information_originate_ipv4_metric_delete(
+static int isis_instance_default_information_originate_ipv4_metric_destroy(
enum nb_event event, const struct lyd_node *dnode)
{
/* It's all done by default_info_origin_apply_finish */
@@ -925,7 +925,7 @@ static int isis_instance_default_information_originate_ipv6_create(
return NB_OK;
}
-static int isis_instance_default_information_originate_ipv6_delete(
+static int isis_instance_default_information_originate_ipv6_destroy(
enum nb_event event, const struct lyd_node *dnode)
{
struct isis_area *area;
@@ -963,7 +963,7 @@ static int isis_instance_default_information_originate_ipv6_route_map_modify(
return NB_OK;
}
-static int isis_instance_default_information_originate_ipv6_route_map_delete(
+static int isis_instance_default_information_originate_ipv6_route_map_destroy(
enum nb_event event, const struct lyd_node *dnode)
{
/* It's all done by default_info_origin_apply_finish */
@@ -981,7 +981,7 @@ static int isis_instance_default_information_originate_ipv6_metric_modify(
return NB_OK;
}
-static int isis_instance_default_information_originate_ipv6_metric_delete(
+static int isis_instance_default_information_originate_ipv6_metric_destroy(
enum nb_event event, const struct lyd_node *dnode)
{
/* It's all done by default_info_origin_apply_finish */
@@ -1029,7 +1029,7 @@ static int isis_instance_redistribute_ipv4_create(enum nb_event event,
return NB_OK;
}
-static int isis_instance_redistribute_ipv4_delete(enum nb_event event,
+static int isis_instance_redistribute_ipv4_destroy(enum nb_event event,
const struct lyd_node *dnode)
{
struct isis_area *area;
@@ -1059,7 +1059,7 @@ isis_instance_redistribute_ipv4_route_map_modify(enum nb_event event,
}
static int
-isis_instance_redistribute_ipv4_route_map_delete(enum nb_event event,
+isis_instance_redistribute_ipv4_route_map_destroy(enum nb_event event,
const struct lyd_node *dnode)
{
/* It's all done by redistribute_apply_finish */
@@ -1079,7 +1079,7 @@ isis_instance_redistribute_ipv4_metric_modify(enum nb_event event,
}
static int
-isis_instance_redistribute_ipv4_metric_delete(enum nb_event event,
+isis_instance_redistribute_ipv4_metric_destroy(enum nb_event event,
const struct lyd_node *dnode)
{
/* It's all done by redistribute_apply_finish */
@@ -1097,7 +1097,7 @@ static int isis_instance_redistribute_ipv6_create(enum nb_event event,
return NB_OK;
}
-static int isis_instance_redistribute_ipv6_delete(enum nb_event event,
+static int isis_instance_redistribute_ipv6_destroy(enum nb_event event,
const struct lyd_node *dnode)
{
struct isis_area *area;
@@ -1127,7 +1127,7 @@ isis_instance_redistribute_ipv6_route_map_modify(enum nb_event event,
}
static int
-isis_instance_redistribute_ipv6_route_map_delete(enum nb_event event,
+isis_instance_redistribute_ipv6_route_map_destroy(enum nb_event event,
const struct lyd_node *dnode)
{
/* It's all done by redistribute_apply_finish */
@@ -1147,7 +1147,7 @@ isis_instance_redistribute_ipv6_metric_modify(enum nb_event event,
}
static int
-isis_instance_redistribute_ipv6_metric_delete(enum nb_event event,
+isis_instance_redistribute_ipv6_metric_destroy(enum nb_event event,
const struct lyd_node *dnode)
{
/* It's all done by redistribute_apply_finish */
@@ -1217,7 +1217,7 @@ isis_instance_multi_topology_ipv4_multicast_create(enum nb_event event,
}
static int
-isis_instance_multi_topology_ipv4_multicast_delete(enum nb_event event,
+isis_instance_multi_topology_ipv4_multicast_destroy(enum nb_event event,
const struct lyd_node *dnode)
{
return isis_multi_topology_common(event, dnode, "ipv4-multicast",
@@ -1245,7 +1245,7 @@ static int isis_instance_multi_topology_ipv4_management_create(
return isis_multi_topology_common(event, dnode, "ipv4-mgmt", true);
}
-static int isis_instance_multi_topology_ipv4_management_delete(
+static int isis_instance_multi_topology_ipv4_management_destroy(
enum nb_event event, const struct lyd_node *dnode)
{
return isis_multi_topology_common(event, dnode, "ipv4-mgmt", false);
@@ -1273,7 +1273,7 @@ isis_instance_multi_topology_ipv6_unicast_create(enum nb_event event,
}
static int
-isis_instance_multi_topology_ipv6_unicast_delete(enum nb_event event,
+isis_instance_multi_topology_ipv6_unicast_destroy(enum nb_event event,
const struct lyd_node *dnode)
{
return isis_multi_topology_common(event, dnode, "ipv6-unicast", false);
@@ -1302,7 +1302,7 @@ isis_instance_multi_topology_ipv6_multicast_create(enum nb_event event,
}
static int
-isis_instance_multi_topology_ipv6_multicast_delete(enum nb_event event,
+isis_instance_multi_topology_ipv6_multicast_destroy(enum nb_event event,
const struct lyd_node *dnode)
{
return isis_multi_topology_common(event, dnode, "ipv6-multicast",
@@ -1330,7 +1330,7 @@ static int isis_instance_multi_topology_ipv6_management_create(
return isis_multi_topology_common(event, dnode, "ipv6-mgmt", true);
}
-static int isis_instance_multi_topology_ipv6_management_delete(
+static int isis_instance_multi_topology_ipv6_management_destroy(
enum nb_event event, const struct lyd_node *dnode)
{
return isis_multi_topology_common(event, dnode, "ipv6-mgmt", false);
@@ -1358,7 +1358,7 @@ isis_instance_multi_topology_ipv6_dstsrc_create(enum nb_event event,
}
static int
-isis_instance_multi_topology_ipv6_dstsrc_delete(enum nb_event event,
+isis_instance_multi_topology_ipv6_dstsrc_destroy(enum nb_event event,
const struct lyd_node *dnode)
{
return isis_multi_topology_common(event, dnode, "ipv6-dstsrc", false);
@@ -1436,7 +1436,7 @@ static int isis_mpls_te_create(enum nb_event event,
return NB_OK;
}
-static int isis_mpls_te_delete(enum nb_event event,
+static int isis_mpls_te_destroy(enum nb_event event,
const struct lyd_node *dnode)
{
struct listnode *node;
@@ -1494,7 +1494,7 @@ static int isis_mpls_te_router_address_modify(enum nb_event event,
return NB_OK;
}
-static int isis_mpls_te_router_address_delete(enum nb_event event,
+static int isis_mpls_te_router_address_destroy(enum nb_event event,
const struct lyd_node *dnode)
{
struct listnode *node;
@@ -1555,7 +1555,7 @@ static int lib_interface_isis_create(enum nb_event event,
return NB_OK;
}
-static int lib_interface_isis_delete(enum nb_event event,
+static int lib_interface_isis_destroy(enum nb_event event,
const struct lyd_node *dnode)
{
struct isis_circuit *circuit;
@@ -2062,7 +2062,7 @@ static int lib_interface_isis_password_create(enum nb_event event,
return NB_OK;
}
-static int lib_interface_isis_password_delete(enum nb_event event,
+static int lib_interface_isis_password_destroy(enum nb_event event,
const struct lyd_node *dnode)
{
struct isis_circuit *circuit;
@@ -2749,7 +2749,7 @@ const struct frr_yang_module_info frr_isisd_info = {
{
.xpath = "/frr-isisd:isis/instance",
.cbs.create = isis_instance_create,
- .cbs.delete = isis_instance_delete,
+ .cbs.destroy = isis_instance_destroy,
.cbs.cli_show = cli_show_router_isis,
.priority = NB_DFLT_PRIORITY - 1,
},
@@ -2761,7 +2761,7 @@ const struct frr_yang_module_info frr_isisd_info = {
{
.xpath = "/frr-isisd:isis/instance/area-address",
.cbs.create = isis_instance_area_address_create,
- .cbs.delete = isis_instance_area_address_delete,
+ .cbs.destroy = isis_instance_area_address_destroy,
.cbs.cli_show = cli_show_isis_area_address,
},
{
@@ -2833,7 +2833,7 @@ const struct frr_yang_module_info frr_isisd_info = {
{
.xpath = "/frr-isisd:isis/instance/spf/ietf-backoff-delay",
.cbs.create = isis_instance_spf_ietf_backoff_delay_create,
- .cbs.delete = isis_instance_spf_ietf_backoff_delay_delete,
+ .cbs.destroy = isis_instance_spf_ietf_backoff_delay_destroy,
.cbs.apply_finish = ietf_backoff_delay_apply_finish,
.cbs.cli_show = cli_show_isis_spf_ietf_backoff,
},
@@ -2872,7 +2872,7 @@ const struct frr_yang_module_info frr_isisd_info = {
{
.xpath = "/frr-isisd:isis/instance/area-password",
.cbs.create = isis_instance_area_password_create,
- .cbs.delete = isis_instance_area_password_delete,
+ .cbs.destroy = isis_instance_area_password_destroy,
.cbs.apply_finish = area_password_apply_finish,
.cbs.cli_show = cli_show_isis_area_pwd,
},
@@ -2891,7 +2891,7 @@ const struct frr_yang_module_info frr_isisd_info = {
{
.xpath = "/frr-isisd:isis/instance/domain-password",
.cbs.create = isis_instance_domain_password_create,
- .cbs.delete = isis_instance_domain_password_delete,
+ .cbs.destroy = isis_instance_domain_password_destroy,
.cbs.apply_finish = domain_password_apply_finish,
.cbs.cli_show = cli_show_isis_domain_pwd,
},
@@ -2910,7 +2910,7 @@ const struct frr_yang_module_info frr_isisd_info = {
{
.xpath = "/frr-isisd:isis/instance/default-information-originate/ipv4",
.cbs.create = isis_instance_default_information_originate_ipv4_create,
- .cbs.delete = isis_instance_default_information_originate_ipv4_delete,
+ .cbs.destroy = isis_instance_default_information_originate_ipv4_destroy,
.cbs.apply_finish = default_info_origin_ipv4_apply_finish,
.cbs.cli_show = cli_show_isis_def_origin_ipv4,
},
@@ -2921,17 +2921,17 @@ const struct frr_yang_module_info frr_isisd_info = {
{
.xpath = "/frr-isisd:isis/instance/default-information-originate/ipv4/route-map",
.cbs.modify = isis_instance_default_information_originate_ipv4_route_map_modify,
- .cbs.delete = isis_instance_default_information_originate_ipv4_route_map_delete,
+ .cbs.destroy = isis_instance_default_information_originate_ipv4_route_map_destroy,
},
{
.xpath = "/frr-isisd:isis/instance/default-information-originate/ipv4/metric",
.cbs.modify = isis_instance_default_information_originate_ipv4_metric_modify,
- .cbs.delete = isis_instance_default_information_originate_ipv4_metric_delete,
+ .cbs.destroy = isis_instance_default_information_originate_ipv4_metric_destroy,
},
{
.xpath = "/frr-isisd:isis/instance/default-information-originate/ipv6",
.cbs.create = isis_instance_default_information_originate_ipv6_create,
- .cbs.delete = isis_instance_default_information_originate_ipv6_delete,
+ .cbs.destroy = isis_instance_default_information_originate_ipv6_destroy,
.cbs.apply_finish = default_info_origin_ipv6_apply_finish,
.cbs.cli_show = cli_show_isis_def_origin_ipv6,
},
@@ -2942,51 +2942,51 @@ const struct frr_yang_module_info frr_isisd_info = {
{
.xpath = "/frr-isisd:isis/instance/default-information-originate/ipv6/route-map",
.cbs.modify = isis_instance_default_information_originate_ipv6_route_map_modify,
- .cbs.delete = isis_instance_default_information_originate_ipv6_route_map_delete,
+ .cbs.destroy = isis_instance_default_information_originate_ipv6_route_map_destroy,
},
{
.xpath = "/frr-isisd:isis/instance/default-information-originate/ipv6/metric",
.cbs.modify = isis_instance_default_information_originate_ipv6_metric_modify,
- .cbs.delete = isis_instance_default_information_originate_ipv6_metric_delete,
+ .cbs.destroy = isis_instance_default_information_originate_ipv6_metric_destroy,
},
{
.xpath = "/frr-isisd:isis/instance/redistribute/ipv4",
.cbs.create = isis_instance_redistribute_ipv4_create,
- .cbs.delete = isis_instance_redistribute_ipv4_delete,
+ .cbs.destroy = isis_instance_redistribute_ipv4_destroy,
.cbs.apply_finish = redistribute_ipv4_apply_finish,
.cbs.cli_show = cli_show_isis_redistribute_ipv4,
},
{
.xpath = "/frr-isisd:isis/instance/redistribute/ipv4/route-map",
.cbs.modify = isis_instance_redistribute_ipv4_route_map_modify,
- .cbs.delete = isis_instance_redistribute_ipv4_route_map_delete,
+ .cbs.destroy = isis_instance_redistribute_ipv4_route_map_destroy,
},
{
.xpath = "/frr-isisd:isis/instance/redistribute/ipv4/metric",
.cbs.modify = isis_instance_redistribute_ipv4_metric_modify,
- .cbs.delete = isis_instance_redistribute_ipv4_metric_delete,
+ .cbs.destroy = isis_instance_redistribute_ipv4_metric_destroy,
},
{
.xpath = "/frr-isisd:isis/instance/redistribute/ipv6",
.cbs.create = isis_instance_redistribute_ipv6_create,
- .cbs.delete = isis_instance_redistribute_ipv6_delete,
+ .cbs.destroy = isis_instance_redistribute_ipv6_destroy,
.cbs.apply_finish = redistribute_ipv6_apply_finish,
.cbs.cli_show = cli_show_isis_redistribute_ipv6,
},
{
.xpath = "/frr-isisd:isis/instance/redistribute/ipv6/route-map",
.cbs.modify = isis_instance_redistribute_ipv6_route_map_modify,
- .cbs.delete = isis_instance_redistribute_ipv6_route_map_delete,
+ .cbs.destroy = isis_instance_redistribute_ipv6_route_map_destroy,
},
{
.xpath = "/frr-isisd:isis/instance/redistribute/ipv6/metric",
.cbs.modify = isis_instance_redistribute_ipv6_metric_modify,
- .cbs.delete = isis_instance_redistribute_ipv6_metric_delete,
+ .cbs.destroy = isis_instance_redistribute_ipv6_metric_destroy,
},
{
.xpath = "/frr-isisd:isis/instance/multi-topology/ipv4-multicast",
.cbs.create = isis_instance_multi_topology_ipv4_multicast_create,
- .cbs.delete = isis_instance_multi_topology_ipv4_multicast_delete,
+ .cbs.destroy = isis_instance_multi_topology_ipv4_multicast_destroy,
.cbs.cli_show = cli_show_isis_mt_ipv4_multicast,
},
{
@@ -2996,7 +2996,7 @@ const struct frr_yang_module_info frr_isisd_info = {
{
.xpath = "/frr-isisd:isis/instance/multi-topology/ipv4-management",
.cbs.create = isis_instance_multi_topology_ipv4_management_create,
- .cbs.delete = isis_instance_multi_topology_ipv4_management_delete,
+ .cbs.destroy = isis_instance_multi_topology_ipv4_management_destroy,
.cbs.cli_show = cli_show_isis_mt_ipv4_mgmt,
},
{
@@ -3006,7 +3006,7 @@ const struct frr_yang_module_info frr_isisd_info = {
{
.xpath = "/frr-isisd:isis/instance/multi-topology/ipv6-unicast",
.cbs.create = isis_instance_multi_topology_ipv6_unicast_create,
- .cbs.delete = isis_instance_multi_topology_ipv6_unicast_delete,
+ .cbs.destroy = isis_instance_multi_topology_ipv6_unicast_destroy,
.cbs.cli_show = cli_show_isis_mt_ipv6_unicast,
},
{
@@ -3016,7 +3016,7 @@ const struct frr_yang_module_info frr_isisd_info = {
{
.xpath = "/frr-isisd:isis/instance/multi-topology/ipv6-multicast",
.cbs.create = isis_instance_multi_topology_ipv6_multicast_create,
- .cbs.delete = isis_instance_multi_topology_ipv6_multicast_delete,
+ .cbs.destroy = isis_instance_multi_topology_ipv6_multicast_destroy,
.cbs.cli_show = cli_show_isis_mt_ipv6_multicast,
},
{
@@ -3026,7 +3026,7 @@ const struct frr_yang_module_info frr_isisd_info = {
{
.xpath = "/frr-isisd:isis/instance/multi-topology/ipv6-management",
.cbs.create = isis_instance_multi_topology_ipv6_management_create,
- .cbs.delete = isis_instance_multi_topology_ipv6_management_delete,
+ .cbs.destroy = isis_instance_multi_topology_ipv6_management_destroy,
.cbs.cli_show = cli_show_isis_mt_ipv6_mgmt,
},
{
@@ -3036,7 +3036,7 @@ const struct frr_yang_module_info frr_isisd_info = {
{
.xpath = "/frr-isisd:isis/instance/multi-topology/ipv6-dstsrc",
.cbs.create = isis_instance_multi_topology_ipv6_dstsrc_create,
- .cbs.delete = isis_instance_multi_topology_ipv6_dstsrc_delete,
+ .cbs.destroy = isis_instance_multi_topology_ipv6_dstsrc_destroy,
.cbs.cli_show = cli_show_isis_mt_ipv6_dstsrc,
},
{
@@ -3051,19 +3051,19 @@ const struct frr_yang_module_info frr_isisd_info = {
{
.xpath = "/frr-isisd:isis/mpls-te",
.cbs.create = isis_mpls_te_create,
- .cbs.delete = isis_mpls_te_delete,
+ .cbs.destroy = isis_mpls_te_destroy,
.cbs.cli_show = cli_show_isis_mpls_te,
},
{
.xpath = "/frr-isisd:isis/mpls-te/router-address",
.cbs.modify = isis_mpls_te_router_address_modify,
- .cbs.delete = isis_mpls_te_router_address_delete,
+ .cbs.destroy = isis_mpls_te_router_address_destroy,
.cbs.cli_show = cli_show_isis_mpls_te_router_addr,
},
{
.xpath = "/frr-interface:lib/interface/frr-isisd:isis",
.cbs.create = lib_interface_isis_create,
- .cbs.delete = lib_interface_isis_delete,
+ .cbs.destroy = lib_interface_isis_destroy,
},
{
.xpath = "/frr-interface:lib/interface/frr-isisd:isis/area-tag",
@@ -3174,7 +3174,7 @@ const struct frr_yang_module_info frr_isisd_info = {
{
.xpath = "/frr-interface:lib/interface/frr-isisd:isis/password",
.cbs.create = lib_interface_isis_password_create,
- .cbs.delete = lib_interface_isis_password_delete,
+ .cbs.destroy = lib_interface_isis_password_destroy,
.cbs.cli_show = cli_show_ip_isis_password,
},
{
diff --git a/isisd/isis_redist.c b/isisd/isis_redist.c
index 815de513fc..20f3e62a74 100644
--- a/isisd/isis_redist.c
+++ b/isisd/isis_redist.c
@@ -338,12 +338,14 @@ static void isis_redist_routemap_set(struct isis_redist *redist,
{
if (redist->map_name) {
XFREE(MTYPE_ISIS, redist->map_name);
+ route_map_counter_decrement(redist->map);
redist->map = NULL;
}
if (routemap && strlen(routemap)) {
redist->map_name = XSTRDUP(MTYPE_ISIS, routemap);
redist->map = route_map_lookup_by_name(routemap);
+ route_map_counter_increment(redist->map);
}
}
diff --git a/isisd/subdir.am b/isisd/subdir.am
index c5b9b31a48..4371d5993a 100644
--- a/isisd/subdir.am
+++ b/isisd/subdir.am
@@ -98,7 +98,7 @@ ISIS_SOURCES = \
isisd/isis_pfpacket.c \
# end
-ISIS_LDADD_COMMON = lib/libfrr.la @LIBCAP@
+ISIS_LDADD_COMMON = lib/libfrr.la $(LIBCAP)
# Building isisd
diff --git a/ldpd/subdir.am b/ldpd/subdir.am
index 24e738d622..42c5ad024b 100644
--- a/ldpd/subdir.am
+++ b/ldpd/subdir.am
@@ -55,4 +55,4 @@ noinst_HEADERS += \
# end
ldpd_ldpd_SOURCES = ldpd/ldpd.c
-ldpd_ldpd_LDADD = ldpd/libldp.a lib/libfrr.la @LIBCAP@
+ldpd_ldpd_LDADD = ldpd/libldp.a lib/libfrr.la $(LIBCAP)
diff --git a/lib/agg_table.h b/lib/agg_table.h
index dc2ff03b67..40ffe8c755 100644
--- a/lib/agg_table.h
+++ b/lib/agg_table.h
@@ -23,6 +23,10 @@
#include "prefix.h"
#include "table.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct agg_table {
struct route_table *route_table;
@@ -150,4 +154,9 @@ static inline struct agg_table *agg_get_table(struct agg_node *node)
{
return (struct agg_table *)route_table_get_info(node->table);
}
+
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/lib/bfd.h b/lib/bfd.h
index b1e490a622..a93875c4cf 100644
--- a/lib/bfd.h
+++ b/lib/bfd.h
@@ -26,6 +26,10 @@
#include "lib/json.h"
#include "lib/zclient.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#define BFD_DEF_MIN_RX 300
#define BFD_MIN_MIN_RX 50
#define BFD_MAX_MIN_RX 60000
@@ -104,4 +108,8 @@ extern void bfd_gbl_init(void);
extern void bfd_gbl_exit(void);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _ZEBRA_BFD_H */
diff --git a/lib/bitfield.h b/lib/bitfield.h
index 0e031ccc49..eebfc049d9 100644
--- a/lib/bitfield.h
+++ b/lib/bitfield.h
@@ -44,6 +44,10 @@
#include <string.h>
#include <stdlib.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
typedef unsigned int word_t;
#define WORD_MAX 0xFFFFFFFF
#define WORD_SIZE (sizeof(word_t) * 8)
@@ -153,4 +157,8 @@ typedef unsigned int word_t;
} \
} while (0)
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/lib/buffer.h b/lib/buffer.h
index 0c945a2acf..8b5a89825f 100644
--- a/lib/buffer.h
+++ b/lib/buffer.h
@@ -22,6 +22,10 @@
#ifndef _ZEBRA_BUFFER_H
#define _ZEBRA_BUFFER_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* Create a new buffer. Memory will be allocated in chunks of the given
size. If the argument is 0, the library will supply a reasonable
default size suitable for buffering socket I/O. */
@@ -99,4 +103,8 @@ extern buffer_status_t buffer_flush_all(struct buffer *, int fd);
extern buffer_status_t buffer_flush_window(struct buffer *, int fd, int width,
int height, int erase, int no_more);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _ZEBRA_BUFFER_H */
diff --git a/lib/checksum.h b/lib/checksum.h
index c2764e35fb..7d50371439 100644
--- a/lib/checksum.h
+++ b/lib/checksum.h
@@ -1,4 +1,12 @@
+#ifdef __cplusplus
+extern "C" {
+#endif
+
extern int in_cksum(void *, int);
#define FLETCHER_CHECKSUM_VALIDATE 0xffff
extern uint16_t fletcher_checksum(uint8_t *, const size_t len,
const uint16_t offset);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/lib/clippy.h b/lib/clippy.h
index 8df98cbb8e..be4db6e638 100644
--- a/lib/clippy.h
+++ b/lib/clippy.h
@@ -22,7 +22,15 @@
#include <Python.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
extern PyObject *clippy_parse(PyObject *self, PyObject *args);
extern PyMODINIT_FUNC command_py_init(void);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _FRR_CLIPPY_H */
diff --git a/lib/command.c b/lib/command.c
index 06879f6854..b46241ac87 100644
--- a/lib/command.c
+++ b/lib/command.c
@@ -1009,7 +1009,7 @@ enum node_type node_parent(enum node_type node)
}
/* Execute command by argument vline vector. */
-static int cmd_execute_command_real(vector vline, enum filter_type filter,
+static int cmd_execute_command_real(vector vline, enum cmd_filter_type filter,
struct vty *vty,
const struct cmd_element **cmd)
{
diff --git a/lib/command.h b/lib/command.h
index 11514fd5e8..0faaa426ac 100644
--- a/lib/command.h
+++ b/lib/command.h
@@ -30,6 +30,10 @@
#include "hash.h"
#include "command_graph.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
DECLARE_MTYPE(HOST)
DECLARE_MTYPE(COMPLETION)
@@ -488,4 +492,9 @@ cmd_variable_handler_register(const struct cmd_variable_handler *cvh);
extern char *cmd_variable_comp2str(vector comps, unsigned short cols);
extern void command_setup_early_logging(const char *dest, const char *level);
+
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _ZEBRA_COMMAND_H */
diff --git a/lib/command_graph.h b/lib/command_graph.h
index 82d562694c..903d515834 100644
--- a/lib/command_graph.h
+++ b/lib/command_graph.h
@@ -32,6 +32,10 @@
#include "vector.h"
#include "graph.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
DECLARE_MTYPE(CMD_ARG)
struct vty;
@@ -114,7 +118,7 @@ extern void cmd_token_varname_set(struct cmd_token *token, const char *varname);
extern void cmd_graph_parse(struct graph *graph, struct cmd_element *cmd);
extern void cmd_graph_names(struct graph *graph);
-extern void cmd_graph_merge(struct graph *old, struct graph *new,
+extern void cmd_graph_merge(struct graph *old, struct graph *n,
int direction);
/*
* Print callback for DOT dumping.
@@ -133,4 +137,8 @@ extern void cmd_graph_node_print_cb(struct graph_node *gn, struct buffer *buf);
*/
char *cmd_graph_dump_dot(struct graph *cmdgraph);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _FRR_COMMAND_GRAPH_H */
diff --git a/lib/command_match.h b/lib/command_match.h
index c636d2dd95..fcb333120f 100644
--- a/lib/command_match.h
+++ b/lib/command_match.h
@@ -28,10 +28,14 @@
#include "linklist.h"
#include "command.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* These definitions exist in command.c in the current engine but should be
* relocated here in the new engine
*/
-enum filter_type { FILTER_RELAXED, FILTER_STRICT };
+enum cmd_filter_type { FILTER_RELAXED, FILTER_STRICT };
/* matcher result value */
enum matcher_rv {
@@ -98,4 +102,8 @@ enum matcher_rv command_match(struct graph *cmdgraph, vector vline,
enum matcher_rv command_complete(struct graph *cmdgraph, vector vline,
struct list **completions);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _ZEBRA_COMMAND_MATCH_H */
diff --git a/lib/compiler.h b/lib/compiler.h
index 24b8fafd10..cb4f7531ec 100644
--- a/lib/compiler.h
+++ b/lib/compiler.h
@@ -17,6 +17,10 @@
#ifndef _FRR_COMPILER_H
#define _FRR_COMPILER_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* function attributes, use like
* void prototype(void) __attribute__((_CONSTRUCTOR(100)));
*/
@@ -88,4 +92,8 @@
#define CPP_NOTICE(text)
#endif
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _FRR_COMPILER_H */
diff --git a/lib/csv.h b/lib/csv.h
index 3a0e5558cb..fe3599d5db 100644
--- a/lib/csv.h
+++ b/lib/csv.h
@@ -70,6 +70,10 @@
#include <stdarg.h>
#include <sys/queue.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
typedef struct _csv_field_t_ csv_field_t;
typedef struct _csv_record_t_ csv_record_t;
typedef struct _csv_t_ csv_t;
@@ -185,4 +189,8 @@ void csv_clone_record(csv_t *csv, csv_record_t *in_rec, csv_record_t **out_rec);
*/
int csv_num_records(csv_t *csv);
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/lib/db.h b/lib/db.h
index 8c936ec4ba..884c7377f2 100644
--- a/lib/db.h
+++ b/lib/db.h
@@ -38,6 +38,10 @@
#include <sqlite3.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
extern int db_init(const char *path_fmt, ...);
extern int db_close(void);
extern int db_bindf(struct sqlite3_stmt *ss, const char *fmt, ...);
@@ -48,5 +52,9 @@ extern int db_loadf(struct sqlite3_stmt *ss, const char *fmt, ...);
extern void db_finalize(struct sqlite3_stmt **ss);
extern int db_execute(const char *stmt_fmt, ...);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* HAVE_SQLITE3 */
#endif /* _FRR_DB_H_ */
diff --git a/lib/debug.h b/lib/debug.h
index d0fa27d3fe..ace060d057 100644
--- a/lib/debug.h
+++ b/lib/debug.h
@@ -24,6 +24,10 @@
#include "command.h"
#include "frratomic.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/*
* Debugging modes.
*
@@ -76,7 +80,7 @@
* Human-readable description of this debugging record.
*/
struct debug {
- _Atomic uint32_t flags;
+ atomic_uint_fast32_t flags;
const char *desc;
};
@@ -231,4 +235,8 @@ struct debug_callbacks {
*/
void debug_init(const struct debug_callbacks *cb);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _FRRDEBUG_H */
diff --git a/lib/distribute.h b/lib/distribute.h
index 44c699b38a..4016d3b133 100644
--- a/lib/distribute.h
+++ b/lib/distribute.h
@@ -25,6 +25,10 @@
#include "if.h"
#include "filter.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* Disctirubte list types. */
enum distribute_type {
DISTRIBUTE_V4_IN,
@@ -81,4 +85,8 @@ extern enum filter_type distribute_apply_in(struct interface *,
extern enum filter_type distribute_apply_out(struct interface *,
struct prefix *);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _ZEBRA_DISTRIBUTE_H */
diff --git a/lib/event_counter.h b/lib/event_counter.h
index de5dbc0665..8ae276ffef 100644
--- a/lib/event_counter.h
+++ b/lib/event_counter.h
@@ -43,6 +43,10 @@
#ifndef _ZEBRA_EVENT_COUNTER_H
#define _ZEBRA_EVENT_COUNTER_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct event_counter {
unsigned long long count;
time_t last;
@@ -51,4 +55,8 @@ struct event_counter {
void event_counter_inc(struct event_counter *counter);
const char *event_counter_format(const struct event_counter *counter);
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/lib/ferr.h b/lib/ferr.h
index 335875c166..93d0ced538 100644
--- a/lib/ferr.h
+++ b/lib/ferr.h
@@ -27,6 +27,10 @@
#include "vty.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* return type when this error indication stuff is used.
*
* guaranteed to have boolean evaluation to "false" when OK, "true" when error
@@ -253,4 +257,8 @@ DEFUN("bla")
#endif /* THIS_IS_AN_EXAMPLE */
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _FERR_H */
diff --git a/lib/fifo.h b/lib/fifo.h
index f59e4dc6cd..6f9c59b5c1 100644
--- a/lib/fifo.h
+++ b/lib/fifo.h
@@ -20,6 +20,10 @@
#ifndef __LIB_FIFO_H__
#define __LIB_FIFO_H__
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* FIFO -- first in first out structure and macros. */
struct fifo {
struct fifo *next;
@@ -55,4 +59,8 @@ struct fifo {
#define FIFO_TOP(F) (FIFO_EMPTY(F) ? NULL : ((struct fifo *)(F))->next)
+#ifdef __cplusplus
+}
+#endif
+
#endif /* __LIB_FIFO_H__ */
diff --git a/lib/filter.h b/lib/filter.h
index 97854b1e97..3dd2eaaf15 100644
--- a/lib/filter.h
+++ b/lib/filter.h
@@ -24,6 +24,10 @@
#include "if.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* Maximum ACL name length */
#define ACL_NAMSIZ 128
@@ -62,4 +66,8 @@ extern struct access_list *access_list_lookup(afi_t, const char *);
extern enum filter_type access_list_apply(struct access_list *access,
const void *object);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _ZEBRA_FILTER_H */
diff --git a/lib/freebsd-queue.h b/lib/freebsd-queue.h
index 4fcfe85a68..793cfff8d3 100644
--- a/lib/freebsd-queue.h
+++ b/lib/freebsd-queue.h
@@ -33,6 +33,10 @@
#ifndef _SYS_QUEUE_H_
#define _SYS_QUEUE_H_
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/*
* This file defines four types of data structures: singly-linked lists,
* singly-linked tail queues, lists and tail queues.
@@ -675,4 +679,8 @@ struct qm_trace {
(head2)->tqh_last = &(head2)->tqh_first; \
} while (0)
+#ifdef __cplusplus
+}
+#endif
+
#endif /* !_SYS_QUEUE_H_ */
diff --git a/lib/frr_pthread.c b/lib/frr_pthread.c
index fe18eb1051..d7f655271b 100644
--- a/lib/frr_pthread.c
+++ b/lib/frr_pthread.c
@@ -83,9 +83,9 @@ struct frr_pthread *frr_pthread_new(struct frr_pthread_attr *attr,
name = (name ? name : "Anonymous thread");
fpt->name = XSTRDUP(MTYPE_FRR_PTHREAD, name);
if (os_name)
- snprintf(fpt->os_name, OS_THREAD_NAMELEN, "%s", os_name);
+ strlcpy(fpt->os_name, os_name, OS_THREAD_NAMELEN);
else
- snprintf(fpt->os_name, OS_THREAD_NAMELEN, "%s", name);
+ strlcpy(fpt->os_name, name, OS_THREAD_NAMELEN);
/* initialize startup synchronization primitives */
fpt->running_cond_mtx = XCALLOC(
MTYPE_PTHREAD_PRIM, sizeof(pthread_mutex_t));
diff --git a/lib/frr_pthread.h b/lib/frr_pthread.h
index e6b3f031b3..9bc7b94033 100644
--- a/lib/frr_pthread.h
+++ b/lib/frr_pthread.h
@@ -25,6 +25,10 @@
#include "memory.h"
#include "thread.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
DECLARE_MTYPE(FRR_PTHREAD);
DECLARE_MTYPE(PTHREAD_PRIM);
@@ -73,7 +77,7 @@ struct frr_pthread {
*/
pthread_cond_t *running_cond;
pthread_mutex_t *running_cond_mtx;
- _Atomic bool running;
+ atomic_bool running;
/*
* Fake thread-specific storage. No constraints on usage. Helpful when
@@ -211,4 +215,8 @@ void frr_pthread_stop_all(void);
#define pthread_condattr_setclock(A, B)
#endif
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _FRR_PTHREAD_H */
diff --git a/lib/frr_zmq.h b/lib/frr_zmq.h
index 1146b87964..4303df9ccd 100644
--- a/lib/frr_zmq.h
+++ b/lib/frr_zmq.h
@@ -23,6 +23,10 @@
#include "thread.h"
#include <zmq.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* linking/packaging note: this is a separate library that needs to be
* linked into any daemon/library/module that wishes to use its
* functionality. The purpose of this is to encapsulate the libzmq
@@ -124,4 +128,8 @@ extern void frrzmq_thread_cancel(struct frrzmq_cb **cb, struct cb_core *core);
extern void frrzmq_check_events(struct frrzmq_cb **cbp, struct cb_core *core,
int event);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _FRRZMQ_H */
diff --git a/lib/frratomic.h b/lib/frratomic.h
index 1f1d1b569a..e86030f83c 100644
--- a/lib/frratomic.h
+++ b/lib/frratomic.h
@@ -26,7 +26,23 @@
#endif
/* ISO C11 */
-#ifdef HAVE_STDATOMIC_H
+#ifdef __cplusplus
+#include <stdint.h>
+#include <atomic>
+using std::atomic_int;
+using std::memory_order;
+using std::memory_order_relaxed;
+using std::memory_order_acquire;
+using std::memory_order_release;
+using std::memory_order_acq_rel;
+using std::memory_order_consume;
+using std::memory_order_seq_cst;
+
+typedef std::atomic<bool> atomic_bool;
+typedef std::atomic<size_t> atomic_size_t;
+typedef std::atomic<uint_fast32_t> atomic_uint_fast32_t;
+
+#elif defined(HAVE_STDATOMIC_H)
#include <stdatomic.h>
/* These are available in gcc, but not in stdatomic */
@@ -39,6 +55,7 @@
#elif defined(HAVE___ATOMIC)
#define _Atomic volatile
+#define _ATOMIC_WANT_TYPEDEFS
#define memory_order_relaxed __ATOMIC_RELAXED
#define memory_order_consume __ATOMIC_CONSUME
@@ -74,6 +91,7 @@
#elif defined(HAVE___SYNC)
#define _Atomic volatile
+#define _ATOMIC_WANT_TYPEDEFS
#define memory_order_relaxed 0
#define memory_order_consume 0
@@ -198,4 +216,15 @@
#error no atomic functions...
#endif
+#ifdef _ATOMIC_WANT_TYPEDEFS
+#undef _ATOMIC_WANT_TYPEDEFS
+
+#include <stdint.h>
+#include <stdbool.h>
+
+typedef _Atomic bool atomic_bool;
+typedef _Atomic size_t atomic_size_t;
+typedef _Atomic uint_fast32_t atomic_uint_fast32_t;
+#endif
+
#endif /* _FRRATOMIC_H */
diff --git a/lib/frrstr.h b/lib/frrstr.h
index 891a3f337c..8b591849a3 100644
--- a/lib/frrstr.h
+++ b/lib/frrstr.h
@@ -27,6 +27,10 @@
#include "vector.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/*
* Tokenizes a string, storing tokens in a vector. Whitespace is ignored.
* Delimiter characters are not included.
@@ -108,4 +112,8 @@ bool begins_with(const char *str, const char *prefix);
*/
int all_digit(const char *str);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _FRRSTR_H_ */
diff --git a/lib/graph.h b/lib/graph.h
index 87262a07b8..8e126e6be4 100644
--- a/lib/graph.h
+++ b/lib/graph.h
@@ -28,6 +28,10 @@
#include "vector.h"
#include "buffer.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct graph {
vector nodes;
};
@@ -164,4 +168,9 @@ char *graph_dump_dot(struct graph *graph, struct graph_node *start,
void (*pcb)(struct graph_node *, struct buffer *buf));
#endif /* BUILDING_CLIPPY */
+
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _ZEBRA_COMMAND_GRAPH_H */
diff --git a/lib/hash.h b/lib/hash.h
index 45ae6ce60a..8c695d2381 100644
--- a/lib/hash.h
+++ b/lib/hash.h
@@ -24,6 +24,10 @@
#include "memory.h"
#include "frratomic.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
DECLARE_MTYPE(HASH)
DECLARE_MTYPE(HASH_BACKET)
@@ -54,9 +58,9 @@ struct hash_backet {
struct hashstats {
/* number of empty hash buckets */
- _Atomic uint_fast32_t empty;
+ atomic_uint_fast32_t empty;
/* sum of squares of bucket length */
- _Atomic uint_fast32_t ssq;
+ atomic_uint_fast32_t ssq;
};
struct hash {
@@ -325,4 +329,8 @@ extern unsigned int string_hash_make(const char *);
*/
extern void hash_cmd_init(void);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _ZEBRA_HASH_H */
diff --git a/lib/hook.h b/lib/hook.h
index 96fec97d7e..f7fb7b8a5c 100644
--- a/lib/hook.h
+++ b/lib/hook.h
@@ -22,6 +22,10 @@
#include "module.h"
#include "memory.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* type-safe subscribable hook points
*
* where "type-safe" applies to the function pointers used for subscriptions
@@ -219,4 +223,8 @@ extern void _hook_unregister(struct hook *hook, void *funcptr, void *arg,
#define DEFINE_KOOH(hookname, arglist, passlist) \
DEFINE_HOOK_INT(hookname, arglist, passlist, true)
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _FRR_HOOK_H */
diff --git a/lib/id_alloc.h b/lib/id_alloc.h
index efe355658a..8705ffb37d 100644
--- a/lib/id_alloc.h
+++ b/lib/id_alloc.h
@@ -24,6 +24,10 @@
#include <limits.h>
#include <stdint.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#define IDALLOC_INVALID 0
#define IDALLOC_DIR_BITS 8
@@ -87,4 +91,8 @@ uint32_t idalloc_reserve(struct id_alloc *alloc, uint32_t id);
struct id_alloc *idalloc_new(const char *name);
void idalloc_destroy(struct id_alloc *alloc);
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/lib/if.c b/lib/if.c
index 0fd65da03a..48841c7ee8 100644
--- a/lib/if.c
+++ b/lib/if.c
@@ -1160,7 +1160,7 @@ DEFPY (no_interface,
if (!vrfname)
vrfname = VRF_DEFAULT_NAME;
- nb_cli_enqueue_change(vty, ".", NB_OP_DELETE, NULL);
+ nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
return nb_cli_apply_changes(
vty, "/frr-interface:lib/interface[name='%s'][vrf='%s']",
@@ -1207,7 +1207,7 @@ DEFPY (no_interface_desc,
NO_STR
"Interface specific description\n")
{
- nb_cli_enqueue_change(vty, "./description", NB_OP_DELETE, NULL);
+ nb_cli_enqueue_change(vty, "./description", NB_OP_DESTROY, NULL);
return nb_cli_apply_changes(vty, NULL);
}
@@ -1379,13 +1379,13 @@ const struct frr_yang_module_info frr_interface_info = {
{
.xpath = "/frr-interface:lib/interface",
.cbs.create = lib_interface_create,
- .cbs.delete = lib_interface_delete,
+ .cbs.destroy = lib_interface_delete,
.cbs.cli_show = cli_show_interface,
},
{
.xpath = "/frr-interface:lib/interface/description",
.cbs.modify = lib_interface_description_modify,
- .cbs.delete = lib_interface_description_delete,
+ .cbs.destroy = lib_interface_description_delete,
.cbs.cli_show = cli_show_interface_desc,
},
{
diff --git a/lib/if.h b/lib/if.h
index 5b46ed8204..6689769beb 100644
--- a/lib/if.h
+++ b/lib/if.h
@@ -27,6 +27,10 @@
#include "qobj.h"
#include "hook.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
DECLARE_MTYPE(IF)
DECLARE_MTYPE(CONNECTED_LABEL)
@@ -290,9 +294,9 @@ struct interface {
};
RB_HEAD(if_name_head, interface);
-RB_PROTOTYPE(if_name_head, interface, name_entry, if_cmp_func);
+RB_PROTOTYPE(if_name_head, interface, name_entry, if_cmp_func)
RB_HEAD(if_index_head, interface);
-RB_PROTOTYPE(if_index_head, interface, index_entry, if_cmp_func);
+RB_PROTOTYPE(if_index_head, interface, index_entry, if_cmp_func)
DECLARE_QOBJ_TYPE(interface)
#define IFNAME_RB_INSERT(vrf, ifp) \
@@ -545,4 +549,8 @@ void if_link_params_free(struct interface *);
extern void if_cmd_init(void);
extern const struct frr_yang_module_info frr_interface_info;
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _ZEBRA_IF_H */
diff --git a/lib/if_rmap.h b/lib/if_rmap.h
index 4468b9fb9c..8dded2cb48 100644
--- a/lib/if_rmap.h
+++ b/lib/if_rmap.h
@@ -21,6 +21,10 @@
#ifndef _ZEBRA_IF_RMAP_H
#define _ZEBRA_IF_RMAP_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
enum if_rmap_type { IF_RMAP_IN, IF_RMAP_OUT, IF_RMAP_MAX };
struct if_rmap {
@@ -37,4 +41,8 @@ extern void if_rmap_hook_delete(void (*)(struct if_rmap *));
extern struct if_rmap *if_rmap_lookup(const char *);
extern int config_write_if_rmap(struct vty *);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _ZEBRA_IF_RMAP_H */
diff --git a/lib/imsg.h b/lib/imsg.h
index eed7074e4a..3f81b76bea 100644
--- a/lib/imsg.h
+++ b/lib/imsg.h
@@ -21,6 +21,10 @@
#ifndef _IMSG_H_
#define _IMSG_H_
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#define IBUF_READ_SIZE 65535
#define IMSG_HEADER_SIZE sizeof(struct imsg_hdr)
#define MAX_IMSGSIZE 16384
@@ -108,4 +112,8 @@ void imsg_free(struct imsg *);
int imsg_flush(struct imsgbuf *);
void imsg_clear(struct imsgbuf *);
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/lib/ipaddr.h b/lib/ipaddr.h
index 7f2d06548b..f4ddadc66e 100644
--- a/lib/ipaddr.h
+++ b/lib/ipaddr.h
@@ -25,6 +25,10 @@
#include <zebra.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/*
* Generic IP address - union of IPv4 and IPv6 address.
*/
@@ -112,4 +116,8 @@ static inline void ipv4_mapped_ipv6_to_ipv4(struct in6_addr *in6,
memcpy(in, (char *)in6 + 12, sizeof(struct in_addr));
}
+#ifdef __cplusplus
+}
+#endif
+
#endif /* __IPADDR_H__ */
diff --git a/lib/jhash.h b/lib/jhash.h
index f8ab4209a8..977421495c 100644
--- a/lib/jhash.h
+++ b/lib/jhash.h
@@ -20,6 +20,10 @@
#ifndef _QUAGGA_JHASH_H
#define _QUAGGA_JHASH_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* The most generic version, hashes an arbitrary sequence
* of bytes. No alignment or length assumptions are made about
* the input key.
@@ -42,4 +46,8 @@ extern uint32_t jhash_3words(uint32_t a, uint32_t b, uint32_t c,
extern uint32_t jhash_2words(uint32_t a, uint32_t b, uint32_t initval);
extern uint32_t jhash_1word(uint32_t a, uint32_t initval);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _QUAGGA_JHASH_H */
diff --git a/lib/json.h b/lib/json.h
index d349162304..a5251662be 100644
--- a/lib/json.h
+++ b/lib/json.h
@@ -21,6 +21,10 @@
#ifndef _QUAGGA_JSON_H
#define _QUAGGA_JSON_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#if defined(HAVE_JSON_C_JSON_H)
#include <json-c/json.h>
@@ -81,4 +85,8 @@ extern void json_object_free(struct json_object *obj);
#define JSON_C_TO_STRING_NOSLASHESCAPE (1<<4)
#endif
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _QUAGGA_JSON_H */
diff --git a/lib/keychain.h b/lib/keychain.h
index 49da9ba459..e5cf39f7c6 100644
--- a/lib/keychain.h
+++ b/lib/keychain.h
@@ -23,6 +23,10 @@
#include "qobj.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct keychain {
char *name;
@@ -57,4 +61,8 @@ extern struct key *key_lookup_for_accept(const struct keychain *, uint32_t);
extern struct key *key_match_for_accept(const struct keychain *, const char *);
extern struct key *key_lookup_for_send(const struct keychain *);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _ZEBRA_KEYCHAIN_H */
diff --git a/lib/lib_errors.h b/lib/lib_errors.h
index 86a83df46c..fc405c2098 100644
--- a/lib/lib_errors.h
+++ b/lib/lib_errors.h
@@ -23,6 +23,10 @@
#include "lib/ferr.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
enum lib_log_refs {
EC_LIB_PRIVILEGES = LIB_FERR_START,
EC_LIB_VRF_START,
@@ -82,4 +86,8 @@ enum lib_log_refs {
extern void lib_error_init(void);
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/lib/libfrr.h b/lib/libfrr.h
index 2705397b85..891e2c1282 100644
--- a/lib/libfrr.h
+++ b/lib/libfrr.h
@@ -30,6 +30,10 @@
#include "hook.h"
#include "northbound.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* The following options disable specific command line options that
* are not applicable for a particular daemon.
*/
@@ -152,4 +156,8 @@ extern char frr_protonameinst[];
extern bool debug_memstats_at_exit;
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _ZEBRA_FRR_H */
diff --git a/lib/libospf.h b/lib/libospf.h
index 45aedb6a7d..d2bb29d80e 100644
--- a/lib/libospf.h
+++ b/lib/libospf.h
@@ -22,6 +22,10 @@
#ifndef _LIBOSPFD_H
#define _LIBOSPFD_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* IP precedence. */
#ifndef IPTOS_PREC_INTERNETCONTROL
#define IPTOS_PREC_INTERNETCONTROL 0xC0
@@ -94,4 +98,8 @@
#define OSPF_LSA_MAXAGE_CHECK_INTERVAL 30
#define OSPF_LSA_MAXAGE_REMOVE_DELAY_DEFAULT 60
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _LIBOSPFD_H */
diff --git a/lib/linklist.h b/lib/linklist.h
index 0475391e9f..76fad45d08 100644
--- a/lib/linklist.h
+++ b/lib/linklist.h
@@ -21,6 +21,10 @@
#ifndef _ZEBRA_LINKLIST_H
#define _ZEBRA_LINKLIST_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* listnodes must always contain data to be valid. Adding an empty node
* to a list is invalid
*/
@@ -291,7 +295,8 @@ extern void list_add_list(struct list *list, struct list *add);
#define ALL_LIST_ELEMENTS(list, node, nextnode, data) \
(node) = listhead(list), ((data) = NULL); \
(node) != NULL \
- && ((data) = listgetdata(node), (nextnode) = node->next, 1); \
+ && ((data) = static_cast(data, listgetdata(node)), \
+ (nextnode) = node->next, 1); \
(node) = (nextnode), ((data) = NULL)
/* read-only list iteration macro.
@@ -302,7 +307,7 @@ extern void list_add_list(struct list *list, struct list *add);
*/
#define ALL_LIST_ELEMENTS_RO(list, node, data) \
(node) = listhead(list), ((data) = NULL); \
- (node) != NULL && ((data) = listgetdata(node), 1); \
+ (node) != NULL && ((data) = static_cast(data, listgetdata(node)), 1); \
(node) = listnextnode(node), ((data) = NULL)
/* these *do not* cleanup list nodes and referenced data, as the functions
@@ -336,4 +341,8 @@ extern void list_add_list(struct list *list, struct list *add);
(L)->count--; \
} while (0)
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _ZEBRA_LINKLIST_H */
diff --git a/lib/log.c b/lib/log.c
index 12a1d7fbe0..c424a5bc98 100644
--- a/lib/log.c
+++ b/lib/log.c
@@ -29,6 +29,7 @@
#include "memory.h"
#include "command.h"
#include "lib_errors.h"
+#include "lib/hook.h"
#ifndef SUNOS_5
#include <sys/un.h>
@@ -46,6 +47,10 @@
DEFINE_MTYPE_STATIC(LIB, ZLOG, "Logging")
+/* hook for external logging */
+DEFINE_HOOK(zebra_ext_log, (int priority, const char *format, va_list args),
+ (priority, format, args));
+
static int logfile_fd = -1; /* Used in signal handler. */
struct zlog *zlog_default = NULL;
@@ -213,6 +218,9 @@ void vzlog(int priority, const char *format, va_list args)
tsctl.already_rendered = 0;
struct zlog *zl = zlog_default;
+ /* call external hook */
+ hook_call(zebra_ext_log, priority, format, args);
+
/* When zlog_default is also NULL, use stderr for logging. */
if (zl == NULL) {
tsctl.precision = 0;
@@ -1019,6 +1027,7 @@ static const struct zebra_desc_table command_types[] = {
DESC_ENTRY(ZEBRA_RELEASE_LABEL_CHUNK),
DESC_ENTRY(ZEBRA_ADVERTISE_ALL_VNI),
DESC_ENTRY(ZEBRA_ADVERTISE_DEFAULT_GW),
+ DESC_ENTRY(ZEBRA_ADVERTISE_SVI_MACIP),
DESC_ENTRY(ZEBRA_ADVERTISE_SUBNET),
DESC_ENTRY(ZEBRA_LOCAL_ES_ADD),
DESC_ENTRY(ZEBRA_LOCAL_ES_DEL),
diff --git a/lib/log.h b/lib/log.h
index be1d9fb592..189857a907 100644
--- a/lib/log.h
+++ b/lib/log.h
@@ -26,6 +26,16 @@
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
+#include <stdarg.h>
+#include "lib/hook.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Hook for external logging function */
+DECLARE_HOOK(zebra_ext_log, (int priority, const char *format, va_list args),
+ (priority, format, args));
/* Here is some guidance on logging levels to use:
*
@@ -87,11 +97,11 @@ extern void zlog_debug(const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
/* For logs which have error codes associated with them */
#define flog_err(ferr_id, format, ...) \
- zlog_err("[EC %"PRIu32"] " format, ferr_id, ##__VA_ARGS__)
+ zlog_err("[EC %" PRIu32 "] " format, ferr_id, ##__VA_ARGS__)
#define flog_err_sys(ferr_id, format, ...) \
flog_err(ferr_id, format, ##__VA_ARGS__)
#define flog_warn(ferr_id, format, ...) \
- zlog_warn("[EC %"PRIu32"] " format, ferr_id, ##__VA_ARGS__)
+ zlog_warn("[EC %" PRIu32 "] " format, ferr_id, ##__VA_ARGS__)
extern void zlog_thread_info(int log_level);
@@ -190,4 +200,8 @@ struct timestamp_control {
"Local use\n" \
"Local use\n"
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _ZEBRA_LOG_H */
diff --git a/lib/log_int.h b/lib/log_int.h
index a7f8be9ae7..58ae031e1b 100644
--- a/lib/log_int.h
+++ b/lib/log_int.h
@@ -24,6 +24,10 @@
#include "log.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct zlog {
const char *ident; /* daemon name (first arg to openlog) */
const char *protoname;
@@ -49,4 +53,8 @@ extern const char *zlog_priority[];
extern void vzlog(int priority, const char *format, va_list args);
extern void zlog(int priority, const char *format, ...) PRINTF_ATTRIBUTE(2, 3);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _ZEBRA_LOG_PRIVATE_H */
diff --git a/lib/logicalrouter.h b/lib/logicalrouter.h
index 5a0780c009..d18832ef70 100644
--- a/lib/logicalrouter.h
+++ b/lib/logicalrouter.h
@@ -20,6 +20,10 @@
#ifndef _ZEBRA_LOGICAL_ROUTER_H
#define _ZEBRA_LOGICAL_ROUTER_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* Logical Router Backend defines */
#define LOGICALROUTER_BACKEND_OFF 0
#define LOGICALROUTER_BACKEND_NETNS 1
@@ -38,4 +42,8 @@ extern void logicalrouter_terminate(void);
*/
extern void logicalrouter_configure_backend(int backend_netns);
+#ifdef __cplusplus
+}
+#endif
+
#endif /*_ZEBRA_LOGICAL_ROUTER_H*/
diff --git a/lib/lua.h b/lib/lua.h
index 8020a22711..a864ab30e0 100644
--- a/lib/lua.h
+++ b/lib/lua.h
@@ -29,6 +29,10 @@
#include <lualib.h>
#include <lauxlib.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/*
* These functions are helper functions that
* try to glom some of the lua_XXX functionality
@@ -75,5 +79,10 @@ enum lua_rm_status lua_run_rm_rule(lua_State *L, const char *rule);
*/
const char *get_string(lua_State *L, const char *key);
int get_integer(lua_State *L, const char *key);
+
+#ifdef __cplusplus
+}
+#endif
+
#endif
#endif
diff --git a/lib/md5.h b/lib/md5.h
index 1dcbf45752..691a294333 100644
--- a/lib/md5.h
+++ b/lib/md5.h
@@ -38,6 +38,10 @@
#ifndef _LIBZEBRA_MD5_H_
#define _LIBZEBRA_MD5_H_
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#define MD5_BUFLEN 64
typedef struct {
@@ -82,4 +86,8 @@ extern void md5_result(uint8_t *, md5_ctxt *);
void hmac_md5(unsigned char *text, int text_len, unsigned char *key,
int key_len, uint8_t *digest);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* ! _LIBZEBRA_MD5_H_*/
diff --git a/lib/memory.c b/lib/memory.c
index fee23a75ac..149e294d50 100644
--- a/lib/memory.c
+++ b/lib/memory.c
@@ -35,7 +35,6 @@ struct memgroup **mg_insert = &mg_first;
DEFINE_MGROUP(LIB, "libfrr")
DEFINE_MTYPE(LIB, TMP, "Temporary memory")
-DEFINE_MTYPE(LIB, PREFIX_FLOWSPEC, "Prefix Flowspec")
static inline void mt_count_alloc(struct memtype *mt, size_t size, void *ptr)
{
diff --git a/lib/memory.h b/lib/memory.h
index 2d6c144778..91a02b7966 100644
--- a/lib/memory.h
+++ b/lib/memory.h
@@ -22,6 +22,10 @@
#include <frratomic.h>
#include "compiler.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#define array_size(ar) (sizeof(ar) / sizeof(ar[0]))
#if defined(HAVE_MALLOC_SIZE) && !defined(HAVE_MALLOC_USABLE_SIZE)
@@ -33,12 +37,12 @@
struct memtype {
struct memtype *next, **ref;
const char *name;
- _Atomic size_t n_alloc;
- _Atomic size_t n_max;
- _Atomic size_t size;
+ atomic_size_t n_alloc;
+ atomic_size_t n_max;
+ atomic_size_t size;
#ifdef HAVE_MALLOC_USABLE_SIZE
- _Atomic size_t total;
- _Atomic size_t max_size;
+ atomic_size_t total;
+ atomic_size_t max_size;
#endif
};
@@ -137,7 +141,6 @@ struct memgroup {
DECLARE_MGROUP(LIB)
DECLARE_MTYPE(TMP)
-DECLARE_MTYPE(PREFIX_FLOWSPEC)
extern void *qmalloc(struct memtype *mt, size_t size)
@@ -177,4 +180,8 @@ extern int log_memstats(FILE *fp, const char *);
extern void memory_oom(size_t size, const char *name);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _QUAGGA_MEMORY_H */
diff --git a/lib/memory_vty.h b/lib/memory_vty.h
index b66c3b6d6e..941255be1d 100644
--- a/lib/memory_vty.h
+++ b/lib/memory_vty.h
@@ -23,9 +23,18 @@
#include "memory.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
extern void memory_init(void);
/* Human friendly string for given byte count */
#define MTYPE_MEMSTR_LEN 20
extern const char *mtype_memstr(char *, size_t, unsigned long);
+
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _ZEBRA_MEMORY_VTY_H */
diff --git a/lib/mlag.h b/lib/mlag.h
index 73725ca3fd..2b904d44f4 100644
--- a/lib/mlag.h
+++ b/lib/mlag.h
@@ -22,6 +22,10 @@
#ifndef __MLAG_H__
#define __MLAG_H__
+#ifdef __cplusplus
+extern "C" {
+#endif
+
enum mlag_role {
MLAG_ROLE_NONE,
MLAG_ROLE_PRIMARY,
@@ -29,4 +33,9 @@ enum mlag_role {
};
extern char *mlag_role2str(enum mlag_role role, char *buf, size_t size);
+
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/lib/module.h b/lib/module.h
index 68ed959270..c5f96db85b 100644
--- a/lib/module.h
+++ b/lib/module.h
@@ -20,6 +20,10 @@
#include <stdint.h>
#include <stdbool.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#if !defined(__GNUC__)
#error module code needs GCC visibility extensions
#elif __GNUC__ < 4
@@ -78,9 +82,10 @@ extern union _frrmod_runtime_u _frrmod_this_module;
#define FRR_COREMOD_SETUP(...) \
static const struct frrmod_info _frrmod_info = {__VA_ARGS__}; \
- DSO_LOCAL union _frrmod_runtime_u _frrmod_this_module = { \
- .r.info = &_frrmod_info, \
- };
+ DSO_LOCAL union _frrmod_runtime_u _frrmod_this_module = {{ \
+ NULL, \
+ &_frrmod_info, \
+ }};
#define FRR_MODULE_SETUP(...) \
FRR_COREMOD_SETUP(__VA_ARGS__) \
DSO_SELF struct frrmod_runtime *frr_module = &_frrmod_this_module.r;
@@ -95,4 +100,8 @@ extern struct frrmod_runtime *frrmod_load(const char *spec, const char *dir,
extern void frrmod_unload(struct frrmod_runtime *module);
#endif
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _FRR_MODULE_H */
diff --git a/lib/monotime.h b/lib/monotime.h
index 00b9400462..6aac966ea1 100644
--- a/lib/monotime.h
+++ b/lib/monotime.h
@@ -21,6 +21,10 @@
#include <time.h>
#include <sys/time.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#ifndef TIMESPEC_TO_TIMEVAL
/* should be in sys/time.h on BSD & Linux libcs */
#define TIMESPEC_TO_TIMEVAL(tv, ts) \
@@ -91,4 +95,8 @@ static inline char *time_to_string(time_t ts)
return ctime(&tbuf);
}
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _FRR_MONOTIME_H */
diff --git a/lib/mpls.h b/lib/mpls.h
index 6146985610..b140c8e317 100644
--- a/lib/mpls.h
+++ b/lib/mpls.h
@@ -25,6 +25,10 @@
#include <zebra.h>
#include <arpa/inet.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#ifdef MPLS_LABEL_MAX
#undef MPLS_LABEL_MAX
#endif
@@ -209,4 +213,8 @@ int mpls_str2label(const char *label_str, uint8_t *num_labels,
char *mpls_label2str(uint8_t num_labels, mpls_label_t *labels, char *buf,
int len, int pretty);
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/lib/network.h b/lib/network.h
index 4703dc9b63..a00c5a0a65 100644
--- a/lib/network.h
+++ b/lib/network.h
@@ -22,6 +22,10 @@
#ifndef _ZEBRA_NETWORK_H
#define _ZEBRA_NETWORK_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* Both readn and writen are deprecated and will be removed. They are not
suitable for use with non-blocking file descriptors.
*/
@@ -41,4 +45,8 @@ extern int set_cloexec(int fd);
extern float htonf(float);
extern float ntohf(float);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _ZEBRA_NETWORK_H */
diff --git a/lib/nexthop.h b/lib/nexthop.h
index e4af405d5f..c79ec590a8 100644
--- a/lib/nexthop.h
+++ b/lib/nexthop.h
@@ -26,6 +26,10 @@
#include "prefix.h"
#include "mpls.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* Maximum next hop string length - gateway + ifindex */
#define NEXTHOP_STRLEN (INET6_ADDRSTRLEN + 30)
@@ -146,4 +150,9 @@ extern int nexthop_same_firsthop(struct nexthop *next1, struct nexthop *next2);
extern const char *nexthop2str(const struct nexthop *nexthop, char *str, int size);
extern struct nexthop *nexthop_next(struct nexthop *nexthop);
extern unsigned int nexthop_level(struct nexthop *nexthop);
+
+#ifdef __cplusplus
+}
+#endif
+
#endif /*_LIB_NEXTHOP_H */
diff --git a/lib/nexthop_group.h b/lib/nexthop_group.h
index 473ecb34fc..b14cbb5b5c 100644
--- a/lib/nexthop_group.h
+++ b/lib/nexthop_group.h
@@ -23,6 +23,10 @@
#include <vty.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/*
* What is a nexthop group?
*
@@ -92,12 +96,12 @@ DECLARE_QOBJ_TYPE(nexthop_group_cmd)
* code
*/
void nexthop_group_init(
- void (*new)(const char *name),
+ void (*create)(const char *name),
void (*add_nexthop)(const struct nexthop_group_cmd *nhgc,
const struct nexthop *nhop),
void (*del_nexthop)(const struct nexthop_group_cmd *nhgc,
const struct nexthop *nhop),
- void (*delete)(const char *name));
+ void (*destroy)(const char *name));
void nexthop_group_enable_vrf(struct vrf *vrf);
void nexthop_group_disable_vrf(struct vrf *vrf);
@@ -110,4 +114,9 @@ extern struct nexthop *nexthop_exists(struct nexthop_group *nhg,
extern struct nexthop_group_cmd *nhgc_find(const char *name);
extern void nexthop_group_write_nexthop(struct vty *vty, struct nexthop *nh);
+
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/lib/northbound.c b/lib/northbound.c
index 6fe612d72a..15139aa8d0 100644
--- a/lib/northbound.c
+++ b/lib/northbound.c
@@ -184,8 +184,8 @@ static unsigned int nb_node_validate_cbs(const struct nb_node *nb_node)
!!nb_node->cbs.create, false);
error += nb_node_validate_cb(nb_node, NB_OP_MODIFY,
!!nb_node->cbs.modify, false);
- error += nb_node_validate_cb(nb_node, NB_OP_DELETE,
- !!nb_node->cbs.delete, false);
+ error += nb_node_validate_cb(nb_node, NB_OP_DESTROY,
+ !!nb_node->cbs.destroy, false);
error += nb_node_validate_cb(nb_node, NB_OP_MOVE, !!nb_node->cbs.move,
false);
error += nb_node_validate_cb(nb_node, NB_OP_APPLY_FINISH,
@@ -417,7 +417,7 @@ static void nb_config_diff(const struct nb_config *config1,
break;
case LYD_DIFF_DELETED:
dnode = diff->first[i];
- operation = NB_OP_DELETE;
+ operation = NB_OP_DESTROY;
break;
case LYD_DIFF_CHANGED:
dnode = diff->second[i];
@@ -485,7 +485,7 @@ int nb_candidate_edit(struct nb_config *candidate,
lyd_validate(&dnode, LYD_OPT_CONFIG, ly_native_ctx);
}
break;
- case NB_OP_DELETE:
+ case NB_OP_DESTROY:
dnode = yang_dnode_get(candidate->dnode, xpath_edit);
if (!dnode)
/*
@@ -741,8 +741,8 @@ static int nb_configuration_callback(const enum nb_event event,
case NB_OP_MODIFY:
ret = (*nb_node->cbs.modify)(event, dnode, resource);
break;
- case NB_OP_DELETE:
- ret = (*nb_node->cbs.delete)(event, dnode);
+ case NB_OP_DESTROY:
+ ret = (*nb_node->cbs.destroy)(event, dnode);
break;
case NB_OP_MOVE:
ret = (*nb_node->cbs.move)(event, dnode);
@@ -912,7 +912,7 @@ static void nb_transaction_apply_finish(struct nb_transaction *transaction)
* (the 'apply_finish' callbacks from the node ancestors should
* be called though).
*/
- if (change->cb.operation == NB_OP_DELETE) {
+ if (change->cb.operation == NB_OP_DESTROY) {
char xpath[XPATH_MAXLEN];
dnode = dnode->parent;
@@ -1359,7 +1359,7 @@ bool nb_operation_is_valid(enum nb_operation operation,
return false;
}
return true;
- case NB_OP_DELETE:
+ case NB_OP_DESTROY:
if (!CHECK_FLAG(snode->flags, LYS_CONFIG_W))
return false;
@@ -1511,8 +1511,8 @@ const char *nb_operation_name(enum nb_operation operation)
return "create";
case NB_OP_MODIFY:
return "modify";
- case NB_OP_DELETE:
- return "delete";
+ case NB_OP_DESTROY:
+ return "destroy";
case NB_OP_MOVE:
return "move";
case NB_OP_APPLY_FINISH:
diff --git a/lib/northbound.h b/lib/northbound.h
index 9d35a4e64a..bb6b62af7d 100644
--- a/lib/northbound.h
+++ b/lib/northbound.h
@@ -27,6 +27,10 @@
#include "yang.h"
#include "yang_translator.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* Forward declaration(s). */
struct vty;
@@ -65,7 +69,7 @@ enum nb_event {
enum nb_operation {
NB_OP_CREATE,
NB_OP_MODIFY,
- NB_OP_DELETE,
+ NB_OP_DESTROY,
NB_OP_MOVE,
NB_OP_APPLY_FINISH,
NB_OP_GET_ELEM,
@@ -168,7 +172,7 @@ struct nb_callbacks {
* - NB_ERR_INCONSISTENCY when an inconsistency was detected.
* - NB_ERR for other errors.
*/
- int (*delete)(enum nb_event event, const struct lyd_node *dnode);
+ int (*destroy)(enum nb_event event, const struct lyd_node *dnode);
/*
* Configuration callback.
@@ -839,4 +843,8 @@ extern void nb_init(struct thread_master *tm, const struct frr_yang_module_info
*/
extern void nb_terminate(void);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _FRR_NORTHBOUND_H_ */
diff --git a/lib/northbound_cli.h b/lib/northbound_cli.h
index 884f250941..209239ca63 100644
--- a/lib/northbound_cli.h
+++ b/lib/northbound_cli.h
@@ -22,6 +22,10 @@
#include "northbound.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* Possible formats in which a configuration can be displayed. */
enum nb_cfg_format {
NB_CFG_FMT_CMDS = 0,
@@ -111,4 +115,8 @@ extern void nb_cli_install_default(int node);
extern void nb_cli_init(struct thread_master *tm);
extern void nb_cli_terminate(void);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _FRR_NORTHBOUND_CLI_H_ */
diff --git a/lib/northbound_confd.c b/lib/northbound_confd.c
index 53149d0fd2..a8e0017819 100644
--- a/lib/northbound_confd.c
+++ b/lib/northbound_confd.c
@@ -228,7 +228,7 @@ frr_confd_cdb_diff_iter(confd_hkeypath_t *kp, enum cdb_iter_op cdb_op,
nb_op = NB_OP_CREATE;
break;
case MOP_DELETED:
- nb_op = NB_OP_DELETE;
+ nb_op = NB_OP_DESTROY;
break;
case MOP_VALUE_SET:
if (nb_operation_is_valid(NB_OP_MODIFY, nb_node->snode))
diff --git a/lib/northbound_db.h b/lib/northbound_db.h
index ad60966441..14df09caa3 100644
--- a/lib/northbound_db.h
+++ b/lib/northbound_db.h
@@ -22,6 +22,10 @@
#include "northbound.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/*
* Initialize the northbound database.
*
@@ -101,4 +105,8 @@ extern int nb_db_transactions_iterate(
const char *date, const char *comment),
void *arg);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _FRR_NORTHBOUND_DB_H_ */
diff --git a/lib/northbound_sysrepo.c b/lib/northbound_sysrepo.c
index 860c27edbd..f426f52bd9 100644
--- a/lib/northbound_sysrepo.c
+++ b/lib/northbound_sysrepo.c
@@ -202,10 +202,10 @@ static int frr_sr_process_change(struct nb_config *candidate,
* notified about the removal of all of its leafs, even the ones
* that are non-optional. We need to ignore these notifications.
*/
- if (!nb_operation_is_valid(NB_OP_DELETE, nb_node->snode))
+ if (!nb_operation_is_valid(NB_OP_DESTROY, nb_node->snode))
return NB_OK;
- nb_op = NB_OP_DELETE;
+ nb_op = NB_OP_DESTROY;
break;
case SR_OP_MOVED:
nb_op = NB_OP_MOVE;
diff --git a/lib/ns.h b/lib/ns.h
index b3810f069b..f3ad837889 100644
--- a/lib/ns.h
+++ b/lib/ns.h
@@ -26,6 +26,10 @@
#include "linklist.h"
#include "vty.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
typedef uint32_t ns_id_t;
/* the default NS ID */
@@ -174,4 +178,8 @@ extern int ns_enable(struct ns *ns, void (*func)(ns_id_t, void *));
extern struct ns *ns_get_created(struct ns *ns, char *name, ns_id_t ns_id);
extern void ns_disable(struct ns *ns);
+#ifdef __cplusplus
+}
+#endif
+
#endif /*_ZEBRA_NS_H*/
diff --git a/lib/openbsd-queue.h b/lib/openbsd-queue.h
index e09cc3d4e5..d4c08a3be8 100644
--- a/lib/openbsd-queue.h
+++ b/lib/openbsd-queue.h
@@ -35,6 +35,10 @@
#ifndef _SYS_QUEUE_H_
#define _SYS_QUEUE_H_
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/*
* This file defines five types of data structures: singly-linked lists,
* lists, simple queues, tail queues and XOR simple queues.
@@ -572,4 +576,8 @@
} \
} while (0)
+#ifdef __cplusplus
+}
+#endif
+
#endif /* !_SYS_QUEUE_H_ */
diff --git a/lib/openbsd-tree.h b/lib/openbsd-tree.h
index 1383ef6de0..d2f0781333 100644
--- a/lib/openbsd-tree.h
+++ b/lib/openbsd-tree.h
@@ -27,6 +27,10 @@
#ifndef _SYS_TREE_H_
#define _SYS_TREE_H_
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/*
* This file defines data structures for different types of trees:
* splay trees and red-black trees.
@@ -397,31 +401,36 @@ int _rb_check(const struct rb_type *, void *, unsigned long);
__attribute__((__unused__)) static inline struct _type \
*_name##_RB_INSERT(struct _name *head, struct _type *elm) \
{ \
- return _rb_insert(_name##_RB_TYPE, &head->rbh_root, elm); \
+ return (struct _type *)_rb_insert( \
+ _name##_RB_TYPE, &head->rbh_root, elm); \
} \
\
__attribute__((__unused__)) static inline struct _type \
*_name##_RB_REMOVE(struct _name *head, struct _type *elm) \
{ \
- return _rb_remove(_name##_RB_TYPE, &head->rbh_root, elm); \
+ return (struct _type *)_rb_remove( \
+ _name##_RB_TYPE, &head->rbh_root, elm); \
} \
\
__attribute__((__unused__)) static inline struct _type \
*_name##_RB_FIND(struct _name *head, const struct _type *key) \
{ \
- return _rb_find(_name##_RB_TYPE, &head->rbh_root, key); \
+ return (struct _type *)_rb_find( \
+ _name##_RB_TYPE, &head->rbh_root, key); \
} \
\
__attribute__((__unused__)) static inline struct _type \
*_name##_RB_NFIND(struct _name *head, const struct _type *key) \
{ \
- return _rb_nfind(_name##_RB_TYPE, &head->rbh_root, key); \
+ return (struct _type *)_rb_nfind( \
+ _name##_RB_TYPE, &head->rbh_root, key); \
} \
\
__attribute__((__unused__)) static inline struct _type \
*_name##_RB_ROOT(struct _name *head) \
{ \
- return _rb_root(_name##_RB_TYPE, &head->rbh_root); \
+ return (struct _type *)_rb_root( \
+ _name##_RB_TYPE, &head->rbh_root); \
} \
\
__attribute__((__unused__)) static inline int _name##_RB_EMPTY( \
@@ -433,43 +442,45 @@ int _rb_check(const struct rb_type *, void *, unsigned long);
__attribute__((__unused__)) static inline struct _type \
*_name##_RB_MIN(struct _name *head) \
{ \
- return _rb_min(_name##_RB_TYPE, &head->rbh_root); \
+ return (struct _type *)_rb_min( \
+ _name##_RB_TYPE, &head->rbh_root); \
} \
\
__attribute__((__unused__)) static inline struct _type \
*_name##_RB_MAX(struct _name *head) \
{ \
- return _rb_max(_name##_RB_TYPE, &head->rbh_root); \
+ return (struct _type *)_rb_max( \
+ _name##_RB_TYPE, &head->rbh_root); \
} \
\
__attribute__((__unused__)) static inline struct _type \
*_name##_RB_NEXT(struct _type *elm) \
{ \
- return _rb_next(_name##_RB_TYPE, elm); \
+ return (struct _type *)_rb_next(_name##_RB_TYPE, elm); \
} \
\
__attribute__((__unused__)) static inline struct _type \
*_name##_RB_PREV(struct _type *elm) \
{ \
- return _rb_prev(_name##_RB_TYPE, elm); \
+ return (struct _type *)_rb_prev(_name##_RB_TYPE, elm); \
} \
\
__attribute__((__unused__)) static inline struct _type \
*_name##_RB_LEFT(struct _type *elm) \
{ \
- return _rb_left(_name##_RB_TYPE, elm); \
+ return (struct _type *)_rb_left(_name##_RB_TYPE, elm); \
} \
\
__attribute__((__unused__)) static inline struct _type \
*_name##_RB_RIGHT(struct _type *elm) \
{ \
- return _rb_right(_name##_RB_TYPE, elm); \
+ return (struct _type *)_rb_right(_name##_RB_TYPE, elm); \
} \
\
__attribute__((__unused__)) static inline struct _type \
*_name##_RB_PARENT(struct _type *elm) \
{ \
- return _rb_parent(_name##_RB_TYPE, elm); \
+ return (struct _type *)_rb_parent(_name##_RB_TYPE, elm); \
} \
\
__attribute__((__unused__)) static inline void _name##_RB_SET_LEFT( \
@@ -560,4 +571,8 @@ int _rb_check(const struct rb_type *, void *, unsigned long);
for ((_e) = RB_MAX(_name, (_head)); \
(_e) != NULL && ((_n) = RB_PREV(_name, (_e)), 1); (_e) = (_n))
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _SYS_TREE_H_ */
diff --git a/lib/pbr.h b/lib/pbr.h
index 90997348cf..1425e679c5 100644
--- a/lib/pbr.h
+++ b/lib/pbr.h
@@ -24,6 +24,10 @@
#include "stream.h"
#include "prefix.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#define PBR_STR "Policy Based Routing\n"
/*
@@ -121,4 +125,8 @@ struct pbr_rule {
extern int zapi_pbr_rule_encode(uint8_t cmd, struct stream *s,
struct pbr_rule *zrule);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _PBR_H */
diff --git a/lib/plist.h b/lib/plist.h
index 8a4fa8d3ce..ba2846d74a 100644
--- a/lib/plist.h
+++ b/lib/plist.h
@@ -27,6 +27,10 @@
#include "stream.h"
#include "vty.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
enum prefix_list_type {
PREFIX_DENY,
PREFIX_PERMIT,
@@ -75,4 +79,8 @@ extern void prefix_bgp_orf_remove_all(afi_t, char *);
extern int prefix_bgp_show_prefix_list(struct vty *vty, afi_t afi, char *name,
bool use_json);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _QUAGGA_PLIST_H */
diff --git a/lib/plist_int.h b/lib/plist_int.h
index 6bc2d034d6..443b0c614d 100644
--- a/lib/plist_int.h
+++ b/lib/plist_int.h
@@ -22,6 +22,10 @@
#ifndef _QUAGGA_PLIST_INT_H
#define _QUAGGA_PLIST_INT_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
enum prefix_name_type { PREFIX_TYPE_STRING, PREFIX_TYPE_NUMBER };
struct pltrie_table;
@@ -68,4 +72,8 @@ struct prefix_list_entry {
struct prefix_list_entry *next_best;
};
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _QUAGGA_PLIST_INT_H */
diff --git a/lib/pqueue.h b/lib/pqueue.h
index 53e5aa8332..032ee9db4c 100644
--- a/lib/pqueue.h
+++ b/lib/pqueue.h
@@ -21,6 +21,10 @@
#ifndef _ZEBRA_PQUEUE_H
#define _ZEBRA_PQUEUE_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct pqueue {
void **array;
int array_size;
@@ -43,4 +47,8 @@ extern void pqueue_remove(void *data, struct pqueue *queue);
extern void trickle_down(int index, struct pqueue *queue);
extern void trickle_up(int index, struct pqueue *queue);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _ZEBRA_PQUEUE_H */
diff --git a/lib/prefix.c b/lib/prefix.c
index 07eb1785b7..babd4304d1 100644
--- a/lib/prefix.c
+++ b/lib/prefix.c
@@ -30,6 +30,7 @@
#include "lib_errors.h"
DEFINE_MTYPE_STATIC(LIB, PREFIX, "Prefix")
+DEFINE_MTYPE_STATIC(LIB, PREFIX_FLOWSPEC, "Prefix Flowspec")
/* Maskbit. */
static const uint8_t maskbit[] = {0x00, 0x80, 0xc0, 0xe0, 0xf0,
diff --git a/lib/prefix.h b/lib/prefix.h
index aaffb1e0c5..ae931288c0 100644
--- a/lib/prefix.h
+++ b/lib/prefix.h
@@ -35,6 +35,10 @@
#include "ipaddr.h"
#include "compiler.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#ifndef ETH_ALEN
#define ETH_ALEN 6
#endif
@@ -276,20 +280,29 @@ struct prefix_sg {
* side, which strips type safety since the cast will accept any pointer
* type.)
*/
+#ifndef __cplusplus
+#define prefixtype(uname, typename, fieldname) \
+ typename *fieldname;
+#else
+#define prefixtype(uname, typename, fieldname) \
+ typename *fieldname; \
+ uname(typename *x) { this->fieldname = x; }
+#endif
+
union prefixptr {
- struct prefix *p;
- struct prefix_ipv4 *p4;
- struct prefix_ipv6 *p6;
- struct prefix_evpn *evp;
- const struct prefix_fs *fs;
+ prefixtype(prefixptr, struct prefix, p)
+ prefixtype(prefixptr, struct prefix_ipv4, p4)
+ prefixtype(prefixptr, struct prefix_ipv6, p6)
+ prefixtype(prefixptr, struct prefix_evpn, evp)
+ prefixtype(prefixptr, struct prefix_fs, fs)
} __attribute__((transparent_union));
union prefixconstptr {
- const struct prefix *p;
- const struct prefix_ipv4 *p4;
- const struct prefix_ipv6 *p6;
- const struct prefix_evpn *evp;
- const struct prefix_fs *fs;
+ prefixtype(prefixconstptr, const struct prefix, p)
+ prefixtype(prefixconstptr, const struct prefix_ipv4, p4)
+ prefixtype(prefixconstptr, const struct prefix_ipv6, p6)
+ prefixtype(prefixconstptr, const struct prefix_evpn, evp)
+ prefixtype(prefixconstptr, const struct prefix_fs, fs)
} __attribute__((transparent_union));
#ifndef INET_ADDRSTRLEN
@@ -497,4 +510,9 @@ static inline int is_host_route(struct prefix *p)
return (p->prefixlen == IPV6_MAX_BITLEN);
return 0;
}
+
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _ZEBRA_PREFIX_H */
diff --git a/lib/privs.c b/lib/privs.c
index 838ff8fc92..2932800070 100644
--- a/lib/privs.c
+++ b/lib/privs.c
@@ -789,7 +789,7 @@ void zprivs_preinit(struct zebra_privs_t *zprivs)
void zprivs_init(struct zebra_privs_t *zprivs)
{
- gid_t groups[NGROUPS_MAX];
+ gid_t groups[NGROUPS_MAX] = {};
int i, ngroups = 0;
int found = 0;
@@ -799,7 +799,7 @@ void zprivs_init(struct zebra_privs_t *zprivs)
return;
if (zprivs->user) {
- ngroups = sizeof(groups);
+ ngroups = array_size(groups);
if (getgrouplist(zprivs->user, zprivs_state.zgid, groups,
&ngroups)
< 0) {
diff --git a/lib/privs.h b/lib/privs.h
index b061370b75..1fee423a95 100644
--- a/lib/privs.h
+++ b/lib/privs.h
@@ -23,6 +23,10 @@
#ifndef _ZEBRA_PRIVS_H
#define _ZEBRA_PRIVS_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* list of zebra capabilities */
typedef enum {
ZCAP_SETID,
@@ -120,4 +124,8 @@ extern void _zprivs_lower(struct zebra_privs_t **privs);
_zprivs_raise(privs, __func__); \
_once == NULL; _once = (void *)1)
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _ZEBRA_PRIVS_H */
diff --git a/lib/ptm_lib.h b/lib/ptm_lib.h
index fc4d520dcb..c2170407c0 100644
--- a/lib/ptm_lib.h
+++ b/lib/ptm_lib.h
@@ -20,6 +20,10 @@
#ifndef __PTM_LIB_H__
#define __PTM_LIB_H__
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#define PTMLIB_MSG_SZ 1024
#define PTMLIB_MSG_HDR_LEN 37
#define PTMLIB_MSG_VERSION 2
@@ -65,4 +69,8 @@ int ptm_lib_append_msg(ptm_lib_handle_t *, void *, const char *, const char *);
int ptm_lib_complete_msg(ptm_lib_handle_t *, void *, char *, int *);
int ptm_lib_cleanup_msg(ptm_lib_handle_t *, void *);
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/lib/pw.h b/lib/pw.h
index 2cfaa47e5d..42b3ee2155 100644
--- a/lib/pw.h
+++ b/lib/pw.h
@@ -20,6 +20,10 @@
#ifndef _FRR_PW_H
#define _FRR_PW_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* L2VPN name length. */
#define L2VPN_NAME_LEN 32
@@ -44,9 +48,10 @@ union pw_protocol_fields {
uint32_t pwid;
char vpn_name[L2VPN_NAME_LEN];
} ldp;
- struct {
- /* TODO */
- } bgp;
};
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _FRR_PW_H */
diff --git a/lib/qobj.h b/lib/qobj.h
index b701eeec5f..d63988cbab 100644
--- a/lib/qobj.h
+++ b/lib/qobj.h
@@ -21,6 +21,10 @@
#include <stdlib.h>
#include <stddef.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* reserve a specific amount of bytes for a struct, which can grow up to
* that size (or be dummy'd out if not needed)
*
@@ -28,11 +32,17 @@
* this is intentional to prevent the struct from growing beyond the allocated
* space.
*/
+#ifndef __cplusplus
#define RESERVED_SPACE_STRUCT(name, fieldname, size) \
struct { \
struct name fieldname; \
char padding##fieldname[size - sizeof(struct name)]; \
};
+#else
+#define RESERVED_SPACE_STRUCT(name, fieldname, size) \
+ struct name fieldname; \
+ char padding##fieldname[size - sizeof(struct name)];
+#endif
/* don't need struct definitions for these here. code actually using
* these needs to define the struct *before* including this header.
@@ -127,4 +137,8 @@ void *qobj_get_typed(uint64_t id, struct qobj_nodetype *type);
void qobj_init(void);
void qobj_finish(void);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _QOBJ_H */
diff --git a/lib/queue.h b/lib/queue.h
index 11e28b4c91..dab43e3c54 100644
--- a/lib/queue.h
+++ b/lib/queue.h
@@ -19,6 +19,10 @@
#ifndef _FRR_QUEUE_H
#define _FRR_QUEUE_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#if defined(__OpenBSD__) && !defined(STAILQ_HEAD)
#include "openbsd-queue.h"
@@ -85,4 +89,8 @@
}; _elm; })
#endif
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _FRR_QUEUE_H */
diff --git a/lib/ringbuf.h b/lib/ringbuf.h
index 15049e3eea..b8f4d9798d 100644
--- a/lib/ringbuf.h
+++ b/lib/ringbuf.h
@@ -25,6 +25,10 @@
#include "memory.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct ringbuf {
size_t size;
ssize_t start;
@@ -122,4 +126,8 @@ void ringbuf_reset(struct ringbuf *buf);
*/
void ringbuf_wipe(struct ringbuf *buf);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _FRR_RINGBUF_H_ */
diff --git a/lib/route_types.pl b/lib/route_types.pl
index 7435272761..f297096633 100755
--- a/lib/route_types.pl
+++ b/lib/route_types.pl
@@ -121,7 +121,7 @@ sub codelist {
}
$str =~ s/ $//;
push @lines, $str . "\\n\" \\\n";
- push @lines, " \" > - selected route, * - FIB route, q - queued route, f - failed route\\n\\n\"";
+ push @lines, " \" > - selected route, * - FIB route, q - queued route, r - rejected route\\n\\n\"";
return join("", @lines);
}
diff --git a/lib/routemap.c b/lib/routemap.c
index 5c6d106d83..61e597520e 100644
--- a/lib/routemap.c
+++ b/lib/routemap.c
@@ -1007,6 +1007,34 @@ static int vty_show_route_map(struct vty *vty, const char *name)
return CMD_SUCCESS;
}
+/* Unused route map details */
+static int vty_show_unused_route_map(struct vty *vty)
+{
+ struct list *maplist = list_new();
+ struct listnode *ln;
+ struct route_map *map;
+
+ for (map = route_map_master.head; map; map = map->next) {
+ /* If use_count is zero, No protocol is using this routemap.
+ * so adding to the list.
+ */
+ if (!map->use_count)
+ listnode_add(maplist, map);
+ }
+
+ if (maplist->count > 0) {
+ vty_out(vty, "\n%s:\n", frr_protonameinst);
+ list_sort(maplist, sort_route_map);
+
+ for (ALL_LIST_ELEMENTS_RO(maplist, ln, map))
+ vty_show_route_map_entry(vty, map);
+ } else {
+ vty_out(vty, "\n%s: None\n", frr_protonameinst);
+ }
+
+ list_delete(&maplist);
+ return CMD_SUCCESS;
+}
/* New route map allocation. Please note route map's name must be
specified. */
@@ -2759,6 +2787,15 @@ DEFUN (rmap_show_name,
return vty_show_route_map(vty, name);
}
+DEFUN (rmap_show_unused,
+ rmap_show_unused_cmd,
+ "show route-map-unused",
+ SHOW_STR
+ "unused route-map information\n")
+{
+ return vty_show_unused_route_map(vty);
+}
+
DEFUN (rmap_call,
rmap_call_cmd,
"call WORD",
@@ -2949,6 +2986,23 @@ static void rmap_autocomplete(vector comps, struct cmd_token *token)
vector_set(comps, XSTRDUP(MTYPE_COMPLETION, map->name));
}
+/* Increment the use_count counter while attaching the route map */
+void route_map_counter_increment(struct route_map *map)
+{
+ if (map)
+ map->use_count++;
+}
+
+/* Decrement the use_count counter while detaching the route map. */
+void route_map_counter_decrement(struct route_map *map)
+{
+ if (map) {
+ if (map->use_count <= 0)
+ return;
+ map->use_count--;
+ }
+}
+
static const struct cmd_variable_handler rmap_var_handlers[] = {
{/* "route-map WORD" */
.varname = "route_map",
@@ -3006,6 +3060,7 @@ void route_map_init(void)
/* Install show command */
install_element(ENABLE_NODE, &rmap_show_name_cmd);
+ install_element(ENABLE_NODE, &rmap_show_unused_cmd);
install_element(RMAP_NODE, &match_interface_cmd);
install_element(RMAP_NODE, &no_match_interface_cmd);
diff --git a/lib/routemap.h b/lib/routemap.h
index 463aa91725..e43e74a633 100644
--- a/lib/routemap.h
+++ b/lib/routemap.h
@@ -26,6 +26,10 @@
#include "qobj.h"
#include "vty.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
DECLARE_MTYPE(ROUTE_MAP_NAME)
DECLARE_MTYPE(ROUTE_MAP_RULE)
DECLARE_MTYPE(ROUTE_MAP_COMPILED)
@@ -169,6 +173,9 @@ struct route_map {
/* How many times have we applied this route-map */
uint64_t applied;
+ /* Counter to track active usage of this route-map */
+ uint16_t use_count;
+
QOBJ_FIELDS
};
DECLARE_QOBJ_TYPE(route_map)
@@ -379,4 +386,14 @@ extern void route_map_no_set_tag_hook(int (*func)(struct vty *vty,
extern void *route_map_rule_tag_compile(const char *arg);
extern void route_map_rule_tag_free(void *rule);
+/* Increment the route-map used counter */
+extern void route_map_counter_increment(struct route_map *map);
+
+/* Decrement the route-map used counter */
+extern void route_map_counter_decrement(struct route_map *map);
+
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _ZEBRA_ROUTEMAP_H */
diff --git a/lib/sbuf.h b/lib/sbuf.h
index c38e96912f..b1518a3aa8 100644
--- a/lib/sbuf.h
+++ b/lib/sbuf.h
@@ -23,6 +23,10 @@
#ifndef SBUF_H
#define SBUF_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/*
* sbuf provides a simple string buffer. One application where this comes
* in handy is the parsing of binary data: If there is an error in the parsing
@@ -76,4 +80,8 @@ void sbuf_free(struct sbuf *buf);
void sbuf_push(struct sbuf *buf, int indent, const char *format, ...)
PRINTF_ATTRIBUTE(3, 4);
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/lib/sha256.h b/lib/sha256.h
index 2473da7bda..c93d253051 100644
--- a/lib/sha256.h
+++ b/lib/sha256.h
@@ -29,6 +29,10 @@
#ifndef _SHA256_H_
#define _SHA256_H_
+#ifdef __cplusplus
+extern "C" {
+#endif
+
typedef struct SHA256Context {
uint32_t state[8];
uint32_t count[2];
@@ -55,4 +59,8 @@ void HMAC__SHA256_Final(unsigned char[32], HMAC_SHA256_CTX *);
void PBKDF2_SHA256(const uint8_t *, size_t, const uint8_t *, size_t, uint64_t,
uint8_t *, size_t);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* !_SHA256_H_ */
diff --git a/lib/sigevent.h b/lib/sigevent.h
index d4ab5741ac..a0ad88fcaa 100644
--- a/lib/sigevent.h
+++ b/lib/sigevent.h
@@ -25,6 +25,10 @@
#include <thread.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#define QUAGGA_SIGNAL_TIMER_INTERVAL 2L
struct quagga_signal_t {
@@ -47,4 +51,8 @@ extern void signal_init(struct thread_master *m, int sigc,
/* check whether there are signals to handle, process any found */
extern int quagga_sigevent_process(void);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _QUAGGA_SIGNAL_H */
diff --git a/lib/skiplist.h b/lib/skiplist.h
index a2e8c374b1..2ab37331c9 100644
--- a/lib/skiplist.h
+++ b/lib/skiplist.h
@@ -31,6 +31,10 @@
#ifndef _ZEBRA_SKIPLIST_H
#define _ZEBRA_SKIPLIST_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#define SKIPLIST_0TIMER_DEBUG 1
/*
@@ -122,4 +126,8 @@ extern void skiplist_debug(struct vty *vty, struct skiplist *l);
extern void skiplist_test(struct vty *vty);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _ZEBRA_SKIPLIST_H */
diff --git a/lib/smux.h b/lib/smux.h
index 9adfacb3e4..3f860db0dc 100644
--- a/lib/smux.h
+++ b/lib/smux.h
@@ -26,6 +26,10 @@
#include "thread.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* Structures here are mostly compatible with UCD SNMP 4.1.1 */
#define MATCH_FAILED (-1)
#define MATCH_SUCCEEDED 0
@@ -103,4 +107,8 @@ extern void oid2in_addr(oid[], int, struct in_addr *);
extern void *oid_copy(void *, const void *, size_t);
extern void oid_copy_addr(oid[], struct in_addr *, int);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _ZEBRA_SNMP_H */
diff --git a/lib/sockopt.h b/lib/sockopt.h
index f54f60ffd7..8fa5987cff 100644
--- a/lib/sockopt.h
+++ b/lib/sockopt.h
@@ -23,6 +23,10 @@
#include "sockunion.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
extern void setsockopt_so_recvbuf(int sock, int size);
extern void setsockopt_so_sendbuf(const int sock, int size);
extern int getsockopt_so_sendbuf(const int sock);
@@ -98,4 +102,9 @@ extern void sockopt_iphdrincl_swab_systoh(struct ip *iph);
extern int sockopt_tcp_rtt(int);
extern int sockopt_tcp_signature(int sock, union sockunion *su,
const char *password);
+
+#ifdef __cplusplus
+}
+#endif
+
#endif /*_ZEBRA_SOCKOPT_H */
diff --git a/lib/sockunion.h b/lib/sockunion.h
index b585aee5b4..d7d26ba85a 100644
--- a/lib/sockunion.h
+++ b/lib/sockunion.h
@@ -28,6 +28,10 @@
#include <netmpls/mpls.h>
#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
+
union sockunion {
struct sockaddr sa;
struct sockaddr_in sin;
@@ -99,4 +103,8 @@ extern union sockunion *sockunion_dup(const union sockunion *);
extern void sockunion_free(union sockunion *);
extern void sockunion_init(union sockunion *);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _ZEBRA_SOCKUNION_H */
diff --git a/lib/spf_backoff.h b/lib/spf_backoff.h
index 6de5804ace..11b2701e3e 100644
--- a/lib/spf_backoff.h
+++ b/lib/spf_backoff.h
@@ -26,6 +26,10 @@
#ifndef _ZEBRA_SPF_BACKOFF_H
#define _ZEBRA_SPF_BACKOFF_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct spf_backoff;
struct thread_master;
struct vty;
@@ -58,4 +62,8 @@ long spf_backoff_long_delay(struct spf_backoff *backoff);
long spf_backoff_holddown(struct spf_backoff *backoff);
long spf_backoff_timetolearn(struct spf_backoff *backoff);
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/lib/srcdest_table.h b/lib/srcdest_table.h
index 54acb51b03..8845931de7 100644
--- a/lib/srcdest_table.h
+++ b/lib/srcdest_table.h
@@ -46,6 +46,10 @@
#include "prefix.h"
#include "table.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#define SRCDEST2STR_BUFFER (2*PREFIX2STR_BUFFER + sizeof(" from "))
/* extended route node for IPv6 srcdest routing */
@@ -84,7 +88,8 @@ static inline int rnode_is_srcnode(struct route_node *rn)
static inline struct route_table *srcdest_rnode_table(struct route_node *rn)
{
if (rnode_is_srcnode(rn)) {
- struct route_node *dst_rn = route_table_get_info(rn->table);
+ struct route_node *dst_rn =
+ (struct route_node *)route_table_get_info(rn->table);
return dst_rn->table;
} else {
return rn->table;
@@ -95,4 +100,8 @@ static inline void *srcdest_rnode_table_info(struct route_node *rn)
return route_table_get_info(srcdest_rnode_table(rn));
}
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _ZEBRA_SRC_DEST_TABLE_H */
diff --git a/lib/stream.h b/lib/stream.h
index 32b6fb5af1..5341bfa40b 100644
--- a/lib/stream.h
+++ b/lib/stream.h
@@ -28,6 +28,10 @@
#include "mpls.h"
#include "prefix.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/*
* A stream is an arbitrary buffer, whose contents generally are assumed to
* be in network order.
@@ -115,9 +119,9 @@ struct stream_fifo {
pthread_mutex_t mtx;
/* number of streams in this fifo */
- _Atomic size_t count;
+ atomic_size_t count;
#if defined DEV_BUILD
- _Atomic size_t max_count;
+ atomic_size_t max_count;
#endif
struct stream *head;
@@ -404,4 +408,8 @@ static inline uint8_t *ptr_get_be32(uint8_t *ptr, uint32_t *out)
goto stream_failure; \
} while (0)
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _ZEBRA_STREAM_H */
diff --git a/lib/subdir.am b/lib/subdir.am
index ccbe13bca6..f245560c45 100644
--- a/lib/subdir.am
+++ b/lib/subdir.am
@@ -3,7 +3,7 @@
#
lib_LTLIBRARIES += lib/libfrr.la
lib_libfrr_la_LDFLAGS = -version-info 0:0:0 -Xlinker -e_libfrr_version
-lib_libfrr_la_LIBADD = @LIBCAP@ $(UNWIND_LIBS) -lyang
+lib_libfrr_la_LIBADD = $(LIBCAP) $(UNWIND_LIBS) $(LIBYANG_LIBS)
lib_libfrr_la_SOURCES = \
lib/agg_table.c \
@@ -116,7 +116,7 @@ vtysh_scan += \
vtysh_scan += $(top_srcdir)/lib/agentx.c
if SQLITE3
-lib_libfrr_la_LIBADD += -lsqlite3
+lib_libfrr_la_LIBADD += $(SQLITE3_LIBS)
lib_libfrr_la_SOURCES += lib/db.c
endif
@@ -289,7 +289,7 @@ endif
lib_confd_la_CFLAGS = $(WERROR) $(CONFD_CFLAGS)
lib_confd_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
-lib_confd_la_LIBADD = lib/libfrr.la -lconfd
+lib_confd_la_LIBADD = lib/libfrr.la $(CONFD_LIBS)
lib_confd_la_SOURCES = lib/northbound_confd.c
#
@@ -299,9 +299,9 @@ if SYSREPO
module_LTLIBRARIES += lib/sysrepo.la
endif
-lib_sysrepo_la_CFLAGS = $(WERROR)
+lib_sysrepo_la_CFLAGS = $(WERROR) $(SYSREPO_CFLAGS)
lib_sysrepo_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
-lib_sysrepo_la_LIBADD = lib/libfrr.la -lsysrepo
+lib_sysrepo_la_LIBADD = lib/libfrr.la $(SYSREPO_LIBS)
lib_sysrepo_la_SOURCES = lib/northbound_sysrepo.c
#
@@ -387,11 +387,13 @@ lib/command_lex.h: lib/command_lex.c
@if test ! -f $@; then $(MAKE) $(AM_MAKEFLAGS) "lib/command_lex.c"; else :; fi
lib/command_lex.lo: lib/command_parse.h
lib/command_parse.lo: lib/command_lex.h
+lib/clippy-command_lex.$(OBJEXT): lib/command_parse.h
+lib/clippy-command_parse.$(OBJEXT): lib/command_lex.h
lib/lib_clippy-command_lex.$(OBJEXT): lib/command_parse.h
lib/lib_clippy-command_parse.$(OBJEXT): lib/command_lex.h
lib/route_types.h: $(top_srcdir)/lib/route_types.txt $(top_srcdir)/lib/route_types.pl
- @PERL@ $(top_srcdir)/lib/route_types.pl < $(top_srcdir)/lib/route_types.txt > $@
+ $(PERL) $(top_srcdir)/lib/route_types.pl < $(top_srcdir)/lib/route_types.txt > $@
DISTCLEANFILES += lib/route_types.h
if GIT_VERSION
@@ -405,7 +407,7 @@ PHONY_GITVERSION=lib/gitversion.h.tmp
.SILENT: lib/gitversion.h lib/gitversion.h.tmp
GITH=lib/gitversion.h
lib/gitversion.h.tmp: $(top_srcdir)/.git
- @PERL@ $(top_srcdir)/lib/gitversion.pl $(top_srcdir) > ${GITH}.tmp
+ $(PERL) $(top_srcdir)/lib/gitversion.pl $(top_srcdir) > ${GITH}.tmp
lib/gitversion.h: lib/gitversion.h.tmp
{ test -f ${GITH} && diff -s -q ${GITH}.tmp ${GITH}; } || cp ${GITH}.tmp ${GITH}
diff --git a/lib/systemd.h b/lib/systemd.h
index a13ea7bfdd..6e43df527d 100644
--- a/lib/systemd.h
+++ b/lib/systemd.h
@@ -19,6 +19,10 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/*
* Wrapper functions to systemd calls.
*
@@ -37,3 +41,7 @@ void systemd_send_stopping(void);
* process?
*/
void systemd_send_started(struct thread_master *master, int the_process);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/lib/table.h b/lib/table.h
index 541d74d77b..ce578e795c 100644
--- a/lib/table.h
+++ b/lib/table.h
@@ -25,6 +25,11 @@
#include "memory.h"
#include "hash.h"
#include "prefix.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
DECLARE_MTYPE(ROUTE_TABLE)
DECLARE_MTYPE(ROUTE_NODE)
@@ -318,4 +323,8 @@ static inline int route_table_iter_started(route_table_iter_t *iter)
return iter->state != RT_ITER_STATE_INIT;
}
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _ZEBRA_TABLE_H */
diff --git a/lib/termtable.h b/lib/termtable.h
index ca5cc1df9f..491010a856 100644
--- a/lib/termtable.h
+++ b/lib/termtable.h
@@ -22,6 +22,10 @@
#include <zebra.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
enum ttable_align {
LEFT,
RIGHT,
@@ -294,4 +298,8 @@ void ttable_rowseps(struct ttable *tt, unsigned int row,
*/
char *ttable_dump(struct ttable *tt, const char *newline);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _TERMTABLE_H */
diff --git a/lib/thread.c b/lib/thread.c
index ae8e375a27..8c1b3ff06d 100644
--- a/lib/thread.c
+++ b/lib/thread.c
@@ -93,7 +93,8 @@ static void cpu_record_hash_free(void *a)
static void vty_out_cpu_thread_history(struct vty *vty,
struct cpu_thread_history *a)
{
- vty_out(vty, "%5d %10lu.%03lu %9u %8lu %9lu %8lu %9lu", a->total_active,
+ vty_out(vty, "%5"PRIdFAST32" %10lu.%03lu %9"PRIuFAST32
+ " %8lu %9lu %8lu %9lu", 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);
diff --git a/lib/thread.h b/lib/thread.h
index f404d92755..ec774a6543 100644
--- a/lib/thread.h
+++ b/lib/thread.h
@@ -27,6 +27,10 @@
#include "monotime.h"
#include "frratomic.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct rusage_t {
struct rusage cpu;
struct timeval real;
@@ -119,13 +123,13 @@ struct thread {
struct cpu_thread_history {
int (*func)(struct thread *);
- _Atomic unsigned int total_calls;
- _Atomic unsigned int total_active;
+ atomic_uint_fast32_t total_calls;
+ atomic_uint_fast32_t total_active;
struct time_stats {
- _Atomic unsigned long total, max;
+ atomic_size_t total, max;
} real;
struct time_stats cpu;
- _Atomic uint32_t types;
+ atomic_uint_fast32_t types;
const char *funcname;
};
@@ -233,4 +237,8 @@ extern unsigned long thread_consumed_time(RUSAGE_T *after, RUSAGE_T *before,
/* only for use in logging functions! */
extern pthread_key_t thread_current;
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _ZEBRA_THREAD_H */
diff --git a/lib/vector.h b/lib/vector.h
index 97e15da040..d5857eb599 100644
--- a/lib/vector.h
+++ b/lib/vector.h
@@ -24,6 +24,10 @@
#include "memory.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* struct for vector */
struct _vector {
unsigned int active; /* number of active slots */
@@ -63,4 +67,9 @@ extern void *vector_lookup(vector, unsigned int);
extern void *vector_lookup_ensure(vector, unsigned int);
extern void vector_to_array(vector v, void ***dest, int *argc);
extern vector array_to_vector(void **src, int argc);
+
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _ZEBRA_VECTOR_H */
diff --git a/lib/vlan.h b/lib/vlan.h
index 6d15e62dfc..eea2633d4e 100644
--- a/lib/vlan.h
+++ b/lib/vlan.h
@@ -22,8 +22,16 @@
#ifndef __VLAN_H__
#define __VLAN_H__
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* VLAN Identifier */
typedef uint16_t vlanid_t;
#define VLANID_MAX 4095
+#ifdef __cplusplus
+}
+#endif
+
#endif /* __VLAN_H__ */
diff --git a/lib/vrf.c b/lib/vrf.c
index f9f14822cb..df93bc33b9 100644
--- a/lib/vrf.c
+++ b/lib/vrf.c
@@ -471,7 +471,7 @@ static const struct cmd_variable_handler vrf_var_handlers[] = {
/* Initialize VRF module. */
void vrf_init(int (*create)(struct vrf *), int (*enable)(struct vrf *),
- int (*disable)(struct vrf *), int (*delete)(struct vrf *),
+ int (*disable)(struct vrf *), int (*destroy)(struct vrf *),
int ((*update)(struct vrf *)))
{
struct vrf *default_vrf;
@@ -485,7 +485,7 @@ void vrf_init(int (*create)(struct vrf *), int (*enable)(struct vrf *),
vrf_master.vrf_new_hook = create;
vrf_master.vrf_enable_hook = enable;
vrf_master.vrf_disable_hook = disable;
- vrf_master.vrf_delete_hook = delete;
+ vrf_master.vrf_delete_hook = destroy;
vrf_master.vrf_update_name_hook = update;
/* The default VRF always exists. */
diff --git a/lib/vrf.h b/lib/vrf.h
index e80796f480..b947ab1d52 100644
--- a/lib/vrf.h
+++ b/lib/vrf.h
@@ -28,6 +28,10 @@
#include "vty.h"
#include "ns.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* The default VRF ID */
#define VRF_UNKNOWN UINT32_MAX
@@ -200,7 +204,7 @@ extern int vrf_bitmap_check(vrf_bitmap_t, vrf_id_t);
* the system ( 2 and 3 ) above.
*/
extern void vrf_init(int (*create)(struct vrf *vrf), int (*enable)(struct vrf *vrf),
- int (*disable)(struct vrf *vrf), int (*delete)(struct vrf *vrf),
+ int (*disable)(struct vrf *vrf), int (*destroy)(struct vrf *vrf),
int (*update)(struct vrf *vrf));
/*
@@ -292,4 +296,8 @@ extern int vrf_enable(struct vrf *vrf);
extern void vrf_delete(struct vrf *vrf);
extern vrf_id_t vrf_generate_id(void);
+#ifdef __cplusplus
+}
+#endif
+
#endif /*_ZEBRA_VRF_H*/
diff --git a/lib/vrf_int.h b/lib/vrf_int.h
index d7fe735817..8dc078e4f3 100644
--- a/lib/vrf_int.h
+++ b/lib/vrf_int.h
@@ -25,6 +25,10 @@
#include "vrf.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/*
* These functions should only be called by:
* zebra/if_netlink.c -> The interface from OS into Zebra
@@ -52,4 +56,8 @@ extern int vrf_enable(struct vrf *);
*/
extern void vrf_delete(struct vrf *);
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/lib/vty.h b/lib/vty.h
index 79b1bd5e93..ca5a2003c4 100644
--- a/lib/vty.h
+++ b/lib/vty.h
@@ -31,6 +31,10 @@
#include "compiler.h"
#include "northbound.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#define VTY_BUFSIZ 4096
#define VTY_MAXHIST 20
#define VTY_MAXDEPTH 8
@@ -333,4 +337,8 @@ extern void vty_stdio_close(void);
an async-signal-safe function. */
extern void vty_log_fixed(char *buf, size_t len);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _ZEBRA_VTY_H */
diff --git a/lib/vxlan.h b/lib/vxlan.h
index bcf8354539..2a8077f8cf 100644
--- a/lib/vxlan.h
+++ b/lib/vxlan.h
@@ -22,6 +22,10 @@
#ifndef __VXLAN_H__
#define __VXLAN_H__
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* VxLAN Network Identifier - 24-bit (RFC 7348) */
typedef uint32_t vni_t;
#define VNI_MAX 16777215 /* (2^24 - 1) */
@@ -35,4 +39,9 @@ enum vxlan_flood_control {
VXLAN_FLOOD_HEAD_END_REPL = 0,
VXLAN_FLOOD_DISABLED,
};
+
+#ifdef __cplusplus
+}
+#endif
+
#endif /* __VXLAN_H__ */
diff --git a/lib/wheel.h b/lib/wheel.h
index c8e83fafcb..e66751c1d0 100644
--- a/lib/wheel.h
+++ b/lib/wheel.h
@@ -20,6 +20,10 @@
#ifndef __WHEEL_H__
#define __WHEEL_H__
+#ifdef __cplusplus
+extern "C" {
+#endif
+
struct timer_wheel {
char *name;
struct thread_master *master;
@@ -115,4 +119,8 @@ int wheel_add_item(struct timer_wheel *wheel, void *item);
*/
int wheel_remove_item(struct timer_wheel *wheel, void *item);
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/lib/workqueue.c b/lib/workqueue.c
index 24ef24c774..fa69ec600e 100644
--- a/lib/workqueue.c
+++ b/lib/workqueue.c
@@ -99,8 +99,10 @@ struct work_queue *work_queue_new(struct thread_master *m,
return new;
}
-void work_queue_free_original(struct work_queue *wq)
+void work_queue_free_and_null(struct work_queue **wqp)
{
+ struct work_queue *wq = *wqp;
+
if (wq->thread != NULL)
thread_cancel(wq->thread);
@@ -114,13 +116,8 @@ void work_queue_free_original(struct work_queue *wq)
XFREE(MTYPE_WORK_QUEUE_NAME, wq->name);
XFREE(MTYPE_WORK_QUEUE, wq);
- return;
-}
-void work_queue_free_and_null(struct work_queue **wq)
-{
- work_queue_free_original(*wq);
- *wq = NULL;
+ *wqp = NULL;
}
bool work_queue_is_scheduled(struct work_queue *wq)
diff --git a/lib/workqueue.h b/lib/workqueue.h
index 7c84655063..7c610f5dd6 100644
--- a/lib/workqueue.h
+++ b/lib/workqueue.h
@@ -25,6 +25,11 @@
#include "memory.h"
#include "queue.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
DECLARE_MTYPE(WORK_QUEUE)
/* Hold time for the initial schedule of a queue run, in millisec */
@@ -159,19 +164,10 @@ extern struct work_queue *work_queue_new(struct thread_master *, const char *);
* The usage of work_queue_free is being transitioned to pass
* in the double pointer to remove use after free's.
*/
-#if CONFDATE > 20190205
-CPP_NOTICE("work_queue_free without double pointer is deprecated, please fixup")
-#endif
-extern void work_queue_free_and_null(struct work_queue **);
-extern void work_queue_free_original(struct work_queue *);
-#define work_queue_free(X) \
- do { \
- work_queue_free_original((X)); \
- CPP_WARN("Please use work_queue_free_and_null"); \
- } while (0)
+extern void work_queue_free_and_null(struct work_queue **wqp);
/* Add the supplied data as an item onto the workqueue */
-extern void work_queue_add(struct work_queue *, void *);
+extern void work_queue_add(struct work_queue *wq, void *item);
/* plug the queue, ie prevent it from being drained / processed */
extern void work_queue_plug(struct work_queue *wq);
@@ -185,4 +181,8 @@ extern int work_queue_run(struct thread *);
extern void workqueue_cmd_init(void);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _QUAGGA_WORK_QUEUE_H */
diff --git a/lib/yang.h b/lib/yang.h
index 3259189e98..4680db08d4 100644
--- a/lib/yang.h
+++ b/lib/yang.h
@@ -29,6 +29,10 @@
#include "yang_wrappers.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
DECLARE_MTYPE(YANG_MODULE)
DECLARE_MTYPE(YANG_DATA)
@@ -521,4 +525,8 @@ extern void yang_init(void);
*/
extern void yang_terminate(void);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _FRR_YANG_H_ */
diff --git a/lib/yang_translator.h b/lib/yang_translator.h
index 6b49d1acf3..55f396a434 100644
--- a/lib/yang_translator.h
+++ b/lib/yang_translator.h
@@ -20,6 +20,10 @@
#ifndef _FRR_YANG_TRANSLATOR_H_
#define _FRR_YANG_TRANSLATOR_H_
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#define YANG_TRANSLATE_TO_NATIVE 0
#define YANG_TRANSLATE_FROM_NATIVE 1
#define YANG_TRANSLATE_MAX 2
@@ -141,4 +145,8 @@ extern void yang_translator_init(void);
*/
extern void yang_translator_terminate(void);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _FRR_YANG_TRANSLATOR_H_ */
diff --git a/lib/zclient.c b/lib/zclient.c
index a01da77669..9db1dd74f2 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -414,9 +414,6 @@ void zclient_send_reg_requests(struct zclient *zclient, vrf_id_t vrf_id)
/* We need router-id information. */
zebra_message_send(zclient, ZEBRA_ROUTER_ID_ADD, vrf_id);
- /* We need interface information. */
- zebra_message_send(zclient, ZEBRA_INTERFACE_ADD, vrf_id);
-
/* Set unwanted redistribute route. */
for (afi = AFI_IP; afi < AFI_MAX; afi++)
vrf_bitmap_set(zclient->redist[afi][zclient->redist_default],
@@ -481,9 +478,6 @@ void zclient_send_dereg_requests(struct zclient *zclient, vrf_id_t vrf_id)
/* We need router-id information. */
zebra_message_send(zclient, ZEBRA_ROUTER_ID_DELETE, vrf_id);
- /* We need interface information. */
- zebra_message_send(zclient, ZEBRA_INTERFACE_DELETE, vrf_id);
-
/* Set unwanted redistribute route. */
for (afi = AFI_IP; afi < AFI_MAX; afi++)
vrf_bitmap_unset(zclient->redist[afi][zclient->redist_default],
@@ -596,6 +590,8 @@ int zclient_start(struct zclient *zclient)
zebra_hello_send(zclient);
+ zebra_message_send(zclient, ZEBRA_INTERFACE_ADD, VRF_DEFAULT);
+
/* Inform the successful connection. */
if (zclient->zebra_connected)
(*zclient->zebra_connected)(zclient);
diff --git a/lib/zclient.h b/lib/zclient.h
index e00821f2f6..3a054e5e72 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -125,6 +125,7 @@ typedef enum {
ZEBRA_FEC_UNREGISTER,
ZEBRA_FEC_UPDATE,
ZEBRA_ADVERTISE_DEFAULT_GW,
+ ZEBRA_ADVERTISE_SVI_MACIP,
ZEBRA_ADVERTISE_SUBNET,
ZEBRA_ADVERTISE_ALL_VNI,
ZEBRA_LOCAL_ES_ADD,
diff --git a/lib/zebra.h b/lib/zebra.h
index 43ab4309c2..b96fb5a206 100644
--- a/lib/zebra.h
+++ b/lib/zebra.h
@@ -232,6 +232,15 @@ typedef unsigned char uint8_t;
#include "zassert.h"
+/*
+ * Add explicit static cast only when using a C++ compiler.
+ */
+#ifdef __cplusplus
+#define static_cast(l, r) static_cast<decltype(l)>((r))
+#else
+#define static_cast(l, r) (r)
+#endif
+
#ifndef HAVE_STRLCAT
size_t strlcat(char *__restrict dest,
const char *__restrict src, size_t destsize);
diff --git a/nhrpd/subdir.am b/nhrpd/subdir.am
index 758c22e2be..6e2b91780f 100644
--- a/nhrpd/subdir.am
+++ b/nhrpd/subdir.am
@@ -8,8 +8,8 @@ vtysh_scan += $(top_srcdir)/nhrpd/nhrp_vty.c
man8 += $(MANBUILD)/nhrpd.8
endif
-nhrpd_nhrpd_LDADD = lib/libfrr.la @LIBCAP@ @CARES_LIBS@
-nhrpd_nhrpd_CFLAGS = $(AM_CFLAGS) @CARES_CFLAGS@
+nhrpd_nhrpd_LDADD = lib/libfrr.la $(LIBCAP) $(CARES_LIBS)
+nhrpd_nhrpd_CFLAGS = $(AM_CFLAGS) $(CARES_CFLAGS)
nhrpd_nhrpd_SOURCES = \
nhrpd/linux.c \
nhrpd/netlink_arp.c \
diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c
index 671267aa05..3153c29aa1 100644
--- a/ospf6d/ospf6_asbr.c
+++ b/ospf6d/ospf6_asbr.c
@@ -856,16 +856,22 @@ void ospf6_asbr_lsentry_remove(struct ospf6_route *asbr_entry)
static void ospf6_asbr_routemap_set(int type, const char *mapname)
{
- if (ospf6->rmap[type].name)
+ if (ospf6->rmap[type].name) {
+ route_map_counter_decrement(ospf6->rmap[type].map);
free(ospf6->rmap[type].name);
+ }
ospf6->rmap[type].name = strdup(mapname);
ospf6->rmap[type].map = route_map_lookup_by_name(mapname);
+ route_map_counter_increment(ospf6->rmap[type].map);
}
static void ospf6_asbr_routemap_unset(int type)
{
if (ospf6->rmap[type].name)
free(ospf6->rmap[type].name);
+
+ route_map_counter_decrement(ospf6->rmap[type].map);
+
ospf6->rmap[type].name = NULL;
ospf6->rmap[type].map = NULL;
}
@@ -939,6 +945,10 @@ static void ospf6_asbr_routemap_update(const char *mapname)
"%s: route-map %s update, reset redist %s",
__PRETTY_FUNCTION__, mapname,
ZROUTE_NAME(type));
+
+ route_map_counter_increment(
+ ospf6->rmap[type].map);
+
ospf6_asbr_distribute_list_update(type);
}
} else
diff --git a/ospf6d/subdir.am b/ospf6d/subdir.am
index d9c29f2651..eac0eee45f 100644
--- a/ospf6d/subdir.am
+++ b/ospf6d/subdir.am
@@ -73,7 +73,7 @@ noinst_HEADERS += \
ospf6d/ospf6d.h \
# end
-ospf6d_ospf6d_LDADD = ospf6d/libospf6.a lib/libfrr.la @LIBCAP@
+ospf6d_ospf6d_LDADD = ospf6d/libospf6.a lib/libfrr.la $(LIBCAP)
ospf6d_ospf6d_SOURCES = \
ospf6d/ospf6_main.c \
# end
diff --git a/ospfclient/subdir.am b/ospfclient/subdir.am
index c05d920d5f..94d489358c 100644
--- a/ospfclient/subdir.am
+++ b/ospfclient/subdir.am
@@ -23,7 +23,7 @@ endif
ospfclient_ospfclient_LDADD = \
ospfclient/libfrrospfapiclient.la \
- @LIBCAP@ \
+ $(LIBCAP) \
# end
if STATIC_BIN
diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c
index 30f5a2a80e..ecc55c2ee5 100644
--- a/ospfd/ospf_packet.c
+++ b/ospfd/ospf_packet.c
@@ -2098,10 +2098,22 @@ static void ospf_ls_upd(struct ospf *ospf, struct ip *iph,
if (current == NULL
|| (ret = ospf_lsa_more_recent(current, lsa)) < 0) {
+ /* CVE-2017-3224 */
+ if (current && (lsa->data->ls_seqnum ==
+ htonl(OSPF_MAX_SEQUENCE_NUMBER)
+ && !IS_LSA_MAXAGE(lsa))) {
+ zlog_debug(
+ "Link State Update[%s]: has Max Seq but not MaxAge. Dropping it",
+ dump_lsa_key(lsa));
+
+ DISCARD_LSA(lsa, 4);
+ continue;
+ }
+
/* Actual flooding procedure. */
if (ospf_flood(oi->ospf, nbr, current, lsa)
< 0) /* Trap NSSA later. */
- DISCARD_LSA(lsa, 4);
+ DISCARD_LSA(lsa, 5);
continue;
}
@@ -2158,7 +2170,7 @@ static void ospf_ls_upd(struct ospf *ospf, struct ip *iph,
oi->ls_ack,
ospf_lsa_lock(lsa));
- DISCARD_LSA(lsa, 5);
+ DISCARD_LSA(lsa, 6);
} else
/* Acknowledge the receipt of the LSA by sending a
Link State Acknowledgment packet back out the
@@ -2166,7 +2178,7 @@ static void ospf_ls_upd(struct ospf *ospf, struct ip *iph,
interface. */
{
ospf_ls_ack_send(nbr, lsa);
- DISCARD_LSA(lsa, 6);
+ DISCARD_LSA(lsa, 7);
}
}
@@ -2183,7 +2195,7 @@ static void ospf_ls_upd(struct ospf *ospf, struct ip *iph,
if (IS_LSA_MAXAGE(current)
&& current->data->ls_seqnum
== htonl(OSPF_MAX_SEQUENCE_NUMBER)) {
- DISCARD_LSA(lsa, 7);
+ DISCARD_LSA(lsa, 8);
}
/* Otherwise, as long as the database copy has not been
sent in a
@@ -2206,7 +2218,7 @@ static void ospf_ls_upd(struct ospf *ospf, struct ip *iph,
ospf_ls_upd_send_lsa(
nbr, current,
OSPF_SEND_PACKET_DIRECT);
- DISCARD_LSA(lsa, 8);
+ DISCARD_LSA(lsa, 9);
}
}
}
diff --git a/ospfd/ospf_routemap.c b/ospfd/ospf_routemap.c
index 54009639fc..a15e605aca 100644
--- a/ospfd/ospf_routemap.c
+++ b/ospfd/ospf_routemap.c
@@ -70,11 +70,19 @@ static void ospf_route_map_update(const char *name)
/* Keep old route-map. */
struct route_map *old = ROUTEMAP(red);
- /* Update route-map. */
- ROUTEMAP(red) =
- route_map_lookup_by_name(
- ROUTEMAP_NAME(red));
-
+ if (!old) {
+ /* Route-map creation */
+ /* Update route-map. */
+ ROUTEMAP(red) =
+ route_map_lookup_by_name(
+ ROUTEMAP_NAME(red));
+
+ route_map_counter_increment(
+ ROUTEMAP(red));
+ } else {
+ /* Route-map deletion */
+ ROUTEMAP(red) = NULL;
+ }
/* No update for this distribute type.
*/
if (old == NULL
diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c
index a86800f901..ea2c492e18 100644
--- a/ospfd/ospf_zebra.c
+++ b/ospfd/ospf_zebra.c
@@ -983,17 +983,22 @@ int ospf_redistribute_check(struct ospf *ospf, struct external_info *ei,
/* OSPF route-map set for redistribution */
void ospf_routemap_set(struct ospf_redist *red, const char *name)
{
- if (ROUTEMAP_NAME(red))
+ if (ROUTEMAP_NAME(red)) {
+ route_map_counter_decrement(ROUTEMAP(red));
free(ROUTEMAP_NAME(red));
+ }
ROUTEMAP_NAME(red) = strdup(name);
ROUTEMAP(red) = route_map_lookup_by_name(name);
+ route_map_counter_increment(ROUTEMAP(red));
}
void ospf_routemap_unset(struct ospf_redist *red)
{
- if (ROUTEMAP_NAME(red))
+ if (ROUTEMAP_NAME(red)) {
+ route_map_counter_decrement(ROUTEMAP(red));
free(ROUTEMAP_NAME(red));
+ }
ROUTEMAP_NAME(red) = NULL;
ROUTEMAP(red) = NULL;
diff --git a/ospfd/subdir.am b/ospfd/subdir.am
index 3ad1b870b4..48dd741b24 100644
--- a/ospfd/subdir.am
+++ b/ospfd/subdir.am
@@ -98,7 +98,7 @@ noinst_HEADERS += \
ospfd/ospf_zebra.h \
# end
-ospfd_ospfd_LDADD = ospfd/libfrrospf.a lib/libfrr.la @LIBCAP@ @LIBM@
+ospfd_ospfd_LDADD = ospfd/libfrrospf.a lib/libfrr.la $(LIBCAP) $(LIBM)
ospfd_ospfd_SOURCES = ospfd/ospf_main.c
ospfd_ospfd_snmp_la_SOURCES = ospfd/ospf_snmp.c
diff --git a/pbrd/pbr_map.c b/pbrd/pbr_map.c
index eb2c082fb9..950ce8dfe1 100644
--- a/pbrd/pbr_map.c
+++ b/pbrd/pbr_map.c
@@ -409,7 +409,8 @@ void pbr_map_schedule_policy_from_nhg(const char *nh_group)
pbrm->name);
for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms)) {
DEBUGD(&pbr_dbg_map, "\tNH Grp name: %s",
- pbrms->nhgrp_name ? pbrms->nhgrp_name : "NULL");
+ pbrms->nhgrp_name ?
+ pbrms->nhgrp_name : pbrms->internal_nhg_name);
if (pbrms->nhgrp_name
&& (strcmp(nh_group, pbrms->nhgrp_name) == 0)) {
@@ -526,12 +527,9 @@ void pbr_map_check(struct pbr_map_sequence *pbrms)
DEBUGD(&pbr_dbg_map, "%s: for %s(%u)", __PRETTY_FUNCTION__,
pbrm->name, pbrms->seqno);
if (pbr_map_check_valid(pbrm->name))
- DEBUGD(&pbr_dbg_map, "We are totally valid %s\n",
+ DEBUGD(&pbr_dbg_map, "We are totally valid %s",
pbrm->name);
- DEBUGD(&pbr_dbg_map, "%s: Installing %s(%u) reason: %" PRIu64,
- __PRETTY_FUNCTION__, pbrm->name, pbrms->seqno, pbrms->reason);
-
if (pbrms->reason == PBR_MAP_VALID_SEQUENCE_NUMBER) {
install = true;
DEBUGD(&pbr_dbg_map, "%s: Installing %s(%u) reason: %" PRIu64,
diff --git a/pbrd/pbr_zebra.c b/pbrd/pbr_zebra.c
index 7974bbfb4e..425bc04b4d 100644
--- a/pbrd/pbr_zebra.c
+++ b/pbrd/pbr_zebra.c
@@ -69,6 +69,9 @@ static int interface_add(int command, struct zclient *zclient,
if (!ifp)
return 0;
+ DEBUGD(&pbr_dbg_zebra,
+ "%s: %s", __PRETTY_FUNCTION__, ifp->name);
+
if (!ifp->info)
pbr_if_new(ifp);
@@ -89,6 +92,9 @@ static int interface_delete(int command, struct zclient *zclient,
if (ifp == NULL)
return 0;
+ DEBUGD(&pbr_dbg_zebra,
+ "%s: %s", __PRETTY_FUNCTION__, ifp->name);
+
if_set_index(ifp, IFINDEX_INTERNAL);
return 0;
@@ -97,7 +103,14 @@ static int interface_delete(int command, struct zclient *zclient,
static int interface_address_add(int command, struct zclient *zclient,
zebra_size_t length, vrf_id_t vrf_id)
{
- zebra_interface_address_read(command, zclient->ibuf, vrf_id);
+ struct connected *c;
+ char buf[PREFIX_STRLEN];
+
+ c = zebra_interface_address_read(command, zclient->ibuf, vrf_id);
+
+ DEBUGD(&pbr_dbg_zebra,
+ "%s: %s added %s", __PRETTY_FUNCTION__, c->ifp->name,
+ prefix2str(c->address, buf, sizeof(buf)));
return 0;
}
@@ -106,12 +119,17 @@ static int interface_address_delete(int command, struct zclient *zclient,
zebra_size_t length, vrf_id_t vrf_id)
{
struct connected *c;
+ char buf[PREFIX_STRLEN];
c = zebra_interface_address_read(command, zclient->ibuf, vrf_id);
if (!c)
return 0;
+ DEBUGD(&pbr_dbg_zebra,
+ "%s: %s deleted %s", __PRETTY_FUNCTION__, c->ifp->name,
+ prefix2str(c->address, buf, sizeof(buf)));
+
connected_free(c);
return 0;
}
@@ -119,8 +137,12 @@ static int interface_address_delete(int command, struct zclient *zclient,
static int interface_state_up(int command, struct zclient *zclient,
zebra_size_t length, vrf_id_t vrf_id)
{
+ struct interface *ifp;
+
+ ifp = zebra_interface_state_read(zclient->ibuf, vrf_id);
- zebra_interface_state_read(zclient->ibuf, vrf_id);
+ DEBUGD(&pbr_dbg_zebra,
+ "%s: %s is up", __PRETTY_FUNCTION__, ifp->name);
return 0;
}
@@ -128,8 +150,12 @@ static int interface_state_up(int command, struct zclient *zclient,
static int interface_state_down(int command, struct zclient *zclient,
zebra_size_t length, vrf_id_t vrf_id)
{
+ struct interface *ifp;
- zebra_interface_state_read(zclient->ibuf, vrf_id);
+ ifp = zebra_interface_state_read(zclient->ibuf, vrf_id);
+
+ DEBUGD(&pbr_dbg_zebra,
+ "%s: %s is down", __PRETTY_FUNCTION__, ifp->name);
return 0;
}
@@ -142,11 +168,11 @@ static int route_notify_owner(int command, struct zclient *zclient,
uint32_t table_id;
char buf[PREFIX_STRLEN];
- prefix2str(&p, buf, sizeof(buf));
-
if (!zapi_route_notify_decode(zclient->ibuf, &p, &table_id, &note))
return -1;
+ prefix2str(&p, buf, sizeof(buf));
+
switch (note) {
case ZAPI_ROUTE_FAIL_INSTALL:
DEBUGD(&pbr_dbg_zebra,
@@ -207,20 +233,20 @@ static int rule_notify_owner(int command, struct zclient *zclient,
switch (note) {
case ZAPI_RULE_FAIL_INSTALL:
- DEBUGD(&pbr_dbg_zebra, "%s: Received RULE_FAIL_INSTALL",
- __PRETTY_FUNCTION__);
pbrms->installed &= ~installed;
+ DEBUGD(&pbr_dbg_zebra, "%s: Received RULE_FAIL_INSTALL: %lu",
+ __PRETTY_FUNCTION__, pbrms->installed);
break;
case ZAPI_RULE_INSTALLED:
pbrms->installed |= installed;
- DEBUGD(&pbr_dbg_zebra, "%s: Received RULE_INSTALLED",
- __PRETTY_FUNCTION__);
+ DEBUGD(&pbr_dbg_zebra, "%s: Received RULE_INSTALLED: %lu",
+ __PRETTY_FUNCTION__, pbrms->installed);
break;
case ZAPI_RULE_FAIL_REMOVE:
case ZAPI_RULE_REMOVED:
pbrms->installed &= ~installed;
- DEBUGD(&pbr_dbg_zebra, "%s: Received RULE REMOVED",
- __PRETTY_FUNCTION__);
+ DEBUGD(&pbr_dbg_zebra, "%s: Received RULE REMOVED: %lu",
+ __PRETTY_FUNCTION__, pbrms->installed);
break;
}
@@ -229,6 +255,8 @@ static int rule_notify_owner(int command, struct zclient *zclient,
static void zebra_connected(struct zclient *zclient)
{
+ DEBUGD(&pbr_dbg_zebra, "%s: Registering for fun and profit",
+ __PRETTY_FUNCTION__);
zclient_send_reg_requests(zclient, VRF_DEFAULT);
}
@@ -236,11 +264,15 @@ static void route_add_helper(struct zapi_route *api, struct nexthop_group nhg,
uint8_t install_afi)
{
struct zapi_nexthop *api_nh;
+ char buf[PREFIX_STRLEN];
struct nexthop *nhop;
int i;
api->prefix.family = install_afi;
+ DEBUGD(&pbr_dbg_zebra, "\tEncoding %s",
+ prefix2str(&api->prefix, buf, sizeof(buf)));
+
i = 0;
for (ALL_NEXTHOPS(nhg, nhop)) {
api_nh = &api->nexthops[i];
@@ -284,6 +316,9 @@ void route_add(struct pbr_nexthop_group_cache *pnhgc, struct nexthop_group nhg,
{
struct zapi_route api;
+ DEBUGD(&pbr_dbg_zebra, "%s for Table: %d", __PRETTY_FUNCTION__,
+ pnhgc->table_id);
+
memset(&api, 0, sizeof(api));
api.vrf_id = VRF_DEFAULT;
@@ -323,6 +358,9 @@ void route_delete(struct pbr_nexthop_group_cache *pnhgc, afi_t afi)
{
struct zapi_route api;
+ DEBUGD(&pbr_dbg_zebra, "%s for Table: %d", __PRETTY_FUNCTION__,
+ pnhgc->table_id);
+
memset(&api, 0, sizeof(api));
api.vrf_id = VRF_DEFAULT;
api.type = ZEBRA_ROUTE_PBR;
diff --git a/pbrd/subdir.am b/pbrd/subdir.am
index 7947559034..0f2e7ad8bd 100644
--- a/pbrd/subdir.am
+++ b/pbrd/subdir.am
@@ -38,5 +38,5 @@ pbrd/pbr_debug_clippy.c: $(CLIPPY_DEPS)
pbrd/pbr_debug.$(OBJEXT): pbrd/pbr_debug_clippy.c
pbrd_pbrd_SOURCES = pbrd/pbr_main.c
-pbrd_pbrd_LDADD = pbrd/libpbr.a lib/libfrr.la @LIBCAP@
+pbrd_pbrd_LDADD = pbrd/libpbr.a lib/libfrr.la $(LIBCAP)
diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c
index 7089e21513..d2d2445a15 100644
--- a/pimd/pim_cmd.c
+++ b/pimd/pim_cmd.c
@@ -62,6 +62,10 @@
#include "pim_bfd.h"
#include "bfd.h"
+#ifndef VTYSH_EXTRACT_PL
+#include "pimd/pim_cmd_clippy.c"
+#endif
+
static struct cmd_node interface_node = {
INTERFACE_NODE, "%s(config-if)# ", 1 /* vtysh ? yes */
};
@@ -5138,6 +5142,12 @@ static int pim_rp_cmd_worker(struct pim_instance *pim, struct vty *vty,
return CMD_WARNING_CONFIG_FAILED;
}
+ if (result == PIM_GROUP_BAD_ADDR_MASK_COMBO) {
+ vty_out(vty, "%% Inconsistent address and mask: %s\n",
+ group);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
return CMD_SUCCESS;
}
@@ -6394,6 +6404,31 @@ static int pim_cmd_interface_add(struct interface *ifp)
return 1;
}
+DEFPY_HIDDEN (interface_ip_pim_activeactive,
+ interface_ip_pim_activeactive_cmd,
+ "[no$no] ip pim active-active",
+ NO_STR
+ IP_STR
+ PIM_STR
+ "Mark interface as Active-Active for MLAG operations, Hidden because not finished yet\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ struct pim_interface *pim_ifp;
+
+ if (!no && !pim_cmd_interface_add(ifp)) {
+ vty_out(vty, "Could not enable PIM SM active-active on interface\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ pim_ifp = ifp->info;
+ if (no)
+ pim_ifp->activeactive = false;
+ else
+ pim_ifp->activeactive = true;
+
+ return CMD_SUCCESS;
+}
+
DEFUN_HIDDEN (interface_ip_pim_ssm,
interface_ip_pim_ssm_cmd,
"ip pim ssm",
@@ -8722,6 +8757,7 @@ void pim_cmd_init(void)
&interface_ip_igmp_query_max_response_time_dsec_cmd);
install_element(INTERFACE_NODE,
&interface_no_ip_igmp_query_max_response_time_dsec_cmd);
+ install_element(INTERFACE_NODE, &interface_ip_pim_activeactive_cmd);
install_element(INTERFACE_NODE, &interface_ip_pim_ssm_cmd);
install_element(INTERFACE_NODE, &interface_no_ip_pim_ssm_cmd);
install_element(INTERFACE_NODE, &interface_ip_pim_sm_cmd);
diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c
index 0451ab1e71..6933f4d5bd 100644
--- a/pimd/pim_iface.c
+++ b/pimd/pim_iface.c
@@ -170,6 +170,8 @@ struct pim_interface *pim_if_new(struct interface *ifp, bool igmp, bool pim,
pim_ifp->sec_addr_list->cmp =
(int (*)(void *, void *))pim_sec_addr_comp;
+ pim_ifp->activeactive = false;
+
RB_INIT(pim_ifchannel_rb, &pim_ifp->ifchannel_rb);
ifp->info = pim_ifp;
diff --git a/pimd/pim_iface.h b/pimd/pim_iface.h
index a7dc097f88..5066998cb5 100644
--- a/pimd/pim_iface.h
+++ b/pimd/pim_iface.h
@@ -124,6 +124,9 @@ struct pim_interface {
/* boundary prefix-list */
char *boundary_oil_plist;
+ /* Turn on Active-Active for this interface */
+ bool activeactive;
+
int64_t pim_ifstat_start; /* start timestamp for stats */
uint32_t pim_ifstat_hello_sent;
uint32_t pim_ifstat_hello_sendfail;
diff --git a/pimd/pim_oil.c b/pimd/pim_oil.c
index 1290bfe56b..2e12d728cf 100644
--- a/pimd/pim_oil.c
+++ b/pimd/pim_oil.c
@@ -392,8 +392,10 @@ int pim_channel_add_oif(struct channel_oil *channel_oil, struct interface *oif,
if (channel_oil->oif_flags[pim_ifp->mroute_vif_index]
& PIM_OIF_FLAG_PROTO_ANY) {
- channel_oil->oif_creation[pim_ifp->mroute_vif_index] =
- pim_time_monotonic_sec();
+ /* Updating time here is not required as this time has to
+ * indicate when the interface is added
+ */
+
channel_oil->oif_flags[pim_ifp->mroute_vif_index] |= proto_mask;
/* Check the OIF really exists before returning, and only log
warning otherwise */
diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c
index 6b76794b75..08f2ffc4ea 100644
--- a/pimd/pim_rp.c
+++ b/pimd/pim_rp.c
@@ -345,6 +345,7 @@ int pim_rp_new(struct pim_instance *pim, const char *rp,
struct rp_info *tmp_rp_info;
char buffer[BUFSIZ];
struct prefix nht_p;
+ struct prefix temp;
struct pim_nexthop_cache pnc;
struct route_node *rn;
@@ -352,8 +353,17 @@ int pim_rp_new(struct pim_instance *pim, const char *rp,
if (group_range == NULL)
result = str2prefix("224.0.0.0/4", &rp_info->group);
- else
+ else {
result = str2prefix(group_range, &rp_info->group);
+ if (result) {
+ prefix_copy(&temp, &rp_info->group);
+ apply_mask(&temp);
+ if (!prefix_same(&rp_info->group, &temp)) {
+ XFREE(MTYPE_PIM_RP, rp_info);
+ return PIM_GROUP_BAD_ADDR_MASK_COMBO;
+ }
+ }
+ }
if (!result) {
XFREE(MTYPE_PIM_RP, rp_info);
diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c
index f6385a0ac9..6495788748 100644
--- a/pimd/pim_vty.c
+++ b/pimd/pim_vty.c
@@ -362,6 +362,9 @@ int pim_interface_config_write(struct vty *vty)
}
}
+ if (pim_ifp->activeactive)
+ vty_out(vty, " ip pim active-active\n");
+
/* boundary */
if (pim_ifp->boundary_oil_plist) {
vty_out(vty,
diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c
index b7111cf7bf..11ca6e8a10 100644
--- a/pimd/pim_zebra.c
+++ b/pimd/pim_zebra.c
@@ -267,6 +267,27 @@ static int pim_zebra_if_state_down(int command, struct zclient *zclient,
return 0;
}
+static int pim_zebra_interface_vrf_update(int command, struct zclient *zclient,
+ zebra_size_t length, vrf_id_t vrf_id)
+{
+ struct interface *ifp;
+ vrf_id_t new_vrf_id;
+
+ ifp = zebra_interface_vrf_update_read(zclient->ibuf, vrf_id,
+ &new_vrf_id);
+ if (!ifp)
+ return 0;
+
+ if (PIM_DEBUG_ZEBRA)
+ zlog_debug("%s: %s updating from %u to %u",
+ __PRETTY_FUNCTION__,
+ ifp->name, vrf_id, new_vrf_id);
+
+ if_update_to_new_vrf(ifp, new_vrf_id);
+
+ return 0;
+}
+
#ifdef PIM_DEBUG_IFADDR_DUMP
static void dump_if_address(struct interface *ifp)
{
@@ -762,6 +783,7 @@ void pim_zebra_init(void)
zclient->interface_down = pim_zebra_if_state_down;
zclient->interface_address_add = pim_zebra_if_address_add;
zclient->interface_address_delete = pim_zebra_if_address_del;
+ zclient->interface_vrf_update = pim_zebra_interface_vrf_update;
zclient->nexthop_update = pim_parse_nexthop_update;
zclient_init(zclient, ZEBRA_ROUTE_PIM, 0, &pimd_privs);
diff --git a/pimd/pimd.h b/pimd/pimd.h
index 73ea9f82c4..50c19658da 100644
--- a/pimd/pimd.h
+++ b/pimd/pimd.h
@@ -116,16 +116,17 @@
/* Remember 32 bits!!! */
/* PIM error codes */
-#define PIM_SUCCESS 0
-#define PIM_GROUP_BAD_ADDRESS -2
-#define PIM_GROUP_OVERLAP -3
-#define PIM_GROUP_PFXLIST_OVERLAP -4
-#define PIM_RP_BAD_ADDRESS -5
-#define PIM_RP_NO_PATH -6
-#define PIM_RP_NOT_FOUND -7
-#define PIM_RP_PFXLIST_IN_USE -8
-#define PIM_IFACE_NOT_FOUND -9
-#define PIM_UPDATE_SOURCE_DUP -10
+#define PIM_SUCCESS 0
+#define PIM_GROUP_BAD_ADDRESS -2
+#define PIM_GROUP_OVERLAP -3
+#define PIM_GROUP_PFXLIST_OVERLAP -4
+#define PIM_RP_BAD_ADDRESS -5
+#define PIM_RP_NO_PATH -6
+#define PIM_RP_NOT_FOUND -7
+#define PIM_RP_PFXLIST_IN_USE -8
+#define PIM_IFACE_NOT_FOUND -9
+#define PIM_UPDATE_SOURCE_DUP -10
+#define PIM_GROUP_BAD_ADDR_MASK_COMBO -11
const char *const PIM_ALL_SYSTEMS;
const char *const PIM_ALL_ROUTERS;
diff --git a/pimd/subdir.am b/pimd/subdir.am
index fef8e36577..7d8df7d105 100644
--- a/pimd/subdir.am
+++ b/pimd/subdir.am
@@ -115,7 +115,10 @@ noinst_HEADERS += \
pimd/mtracebis_routeget.h \
# end
-pimd_pimd_LDADD = pimd/libpim.a lib/libfrr.la @LIBCAP@
+pimd/pim_cmd_clippy.c: $(CLIPPY_DEPS)
+pimd/pim_cmd.$(OBJEXT): pimd/pim_cmd_clippy.c
+
+pimd_pimd_LDADD = pimd/libpim.a lib/libfrr.la $(LIBCAP)
pimd_pimd_SOURCES = pimd/pim_main.c
pimd_test_igmpv3_join_LDADD = lib/libfrr.la
diff --git a/redhat/frr.service b/redhat/frr.service
index 3ae0aabfe2..01934a94e2 100644
--- a/redhat/frr.service
+++ b/redhat/frr.service
@@ -1,6 +1,8 @@
[Unit]
Description=FRRouting (FRR)
-After=syslog.target networking.service
+Wants=network.target
+After=network-pre.target systemd-sysctl.service
+Before=network.target
OnFailure=heartbeat-failed@%n.service
[Service]
@@ -19,5 +21,4 @@ ExecStop=/usr/lib/frr/frr stop
ExecReload=/usr/lib/frr/frr reload
[Install]
-WantedBy=network-online.target
-
+WantedBy=multi-user.target
diff --git a/redhat/frr.spec.in b/redhat/frr.spec.in
index 7a6344aa4c..6d18c005b9 100644
--- a/redhat/frr.spec.in
+++ b/redhat/frr.spec.in
@@ -171,6 +171,7 @@ BuildRequires: python27-sphinx
BuildRequires: python-devel >= 2.7
BuildRequires: python-sphinx
%endif
+Requires: initscripts
%if %{with_pam}
BuildRequires: pam-devel
%endif
@@ -188,7 +189,6 @@ Requires(post): chkconfig
Requires(preun): chkconfig
# Initscripts > 5.60 is required for IPv6 support
Requires(pre): initscripts >= 5.60
-Requires: initscripts
%endif
Provides: routingdaemon = %{version}-%{release}
Obsoletes: gated mrt zebra frr-sysvinit
diff --git a/ripd/rip_cli.c b/ripd/rip_cli.c
index 5bb81ef157..6fbcdc059b 100644
--- a/ripd/rip_cli.c
+++ b/ripd/rip_cli.c
@@ -62,7 +62,7 @@ DEFPY (no_router_rip,
"Enable a routing process\n"
"Routing Information Protocol (RIP)\n")
{
- nb_cli_enqueue_change(vty, "/frr-ripd:ripd/instance", NB_OP_DELETE,
+ nb_cli_enqueue_change(vty, "/frr-ripd:ripd/instance", NB_OP_DESTROY,
NULL);
return nb_cli_apply_changes(vty, NULL);
@@ -213,9 +213,9 @@ DEFPY (rip_distance_source,
nb_cli_enqueue_change(vty, "./distance", NB_OP_MODIFY,
distance_str);
nb_cli_enqueue_change(vty, "./access-list",
- acl ? NB_OP_MODIFY : NB_OP_DELETE, acl);
+ acl ? NB_OP_MODIFY : NB_OP_DESTROY, acl);
} else
- nb_cli_enqueue_change(vty, ".", NB_OP_DELETE, NULL);
+ nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
return nb_cli_apply_changes(vty, "./distance/source[prefix='%s']",
prefix_str);
@@ -244,7 +244,7 @@ DEFPY (rip_neighbor,
"Neighbor address\n")
{
nb_cli_enqueue_change(vty, "./explicit-neighbor",
- no ? NB_OP_DELETE : NB_OP_CREATE, neighbor_str);
+ no ? NB_OP_DESTROY : NB_OP_CREATE, neighbor_str);
return nb_cli_apply_changes(vty, NULL);
}
@@ -266,7 +266,7 @@ DEFPY (rip_network_prefix,
"IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
{
nb_cli_enqueue_change(vty, "./network",
- no ? NB_OP_DELETE : NB_OP_CREATE, network_str);
+ no ? NB_OP_DESTROY : NB_OP_CREATE, network_str);
return nb_cli_apply_changes(vty, NULL);
}
@@ -288,7 +288,7 @@ DEFPY (rip_network_if,
"Interface name\n")
{
nb_cli_enqueue_change(vty, "./interface",
- no ? NB_OP_DELETE : NB_OP_CREATE, network);
+ no ? NB_OP_DESTROY : NB_OP_CREATE, network);
return nb_cli_apply_changes(vty, NULL);
}
@@ -319,7 +319,7 @@ DEFPY (rip_offset_list,
nb_cli_enqueue_change(vty, "./metric", NB_OP_MODIFY,
metric_str);
} else
- nb_cli_enqueue_change(vty, ".", NB_OP_DELETE, NULL);
+ nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
return nb_cli_apply_changes(
vty, "./offset-list[interface='%s'][direction='%s']",
@@ -379,9 +379,9 @@ DEFPY (rip_passive_interface,
"Interface name\n")
{
nb_cli_enqueue_change(vty, "./passive-interface",
- no ? NB_OP_DELETE : NB_OP_CREATE, ifname);
+ no ? NB_OP_DESTROY : NB_OP_CREATE, ifname);
nb_cli_enqueue_change(vty, "./non-passive-interface",
- no ? NB_OP_CREATE : NB_OP_DELETE, ifname);
+ no ? NB_OP_CREATE : NB_OP_DESTROY, ifname);
return nb_cli_apply_changes(vty, NULL);
}
@@ -417,13 +417,13 @@ DEFPY (rip_redistribute,
if (!no) {
nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL);
nb_cli_enqueue_change(vty, "./route-map",
- route_map ? NB_OP_MODIFY : NB_OP_DELETE,
+ route_map ? NB_OP_MODIFY : NB_OP_DESTROY,
route_map);
nb_cli_enqueue_change(vty, "./metric",
- metric_str ? NB_OP_MODIFY : NB_OP_DELETE,
+ metric_str ? NB_OP_MODIFY : NB_OP_DESTROY,
metric_str);
} else
- nb_cli_enqueue_change(vty, ".", NB_OP_DELETE, NULL);
+ nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
return nb_cli_apply_changes(vty, "./redistribute[protocol='%s']",
protocol);
@@ -454,7 +454,7 @@ DEFPY (rip_route,
"IP prefix <network>/<length>\n")
{
nb_cli_enqueue_change(vty, "./static-route",
- no ? NB_OP_DELETE : NB_OP_CREATE, route_str);
+ no ? NB_OP_DESTROY : NB_OP_CREATE, route_str);
return nb_cli_apply_changes(vty, NULL);
}
@@ -942,7 +942,7 @@ DEFPY (no_ip_rip_authentication_key_chain,
"Authentication key-chain\n"
"name of key-chain\n")
{
- nb_cli_enqueue_change(vty, "./authentication-key-chain", NB_OP_DELETE,
+ nb_cli_enqueue_change(vty, "./authentication-key-chain", NB_OP_DESTROY,
NULL);
return nb_cli_apply_changes(vty, "./frr-ripd:rip");
diff --git a/ripd/rip_northbound.c b/ripd/rip_northbound.c
index 4e445bd46d..1e5f86eff8 100644
--- a/ripd/rip_northbound.c
+++ b/ripd/rip_northbound.c
@@ -1305,7 +1305,7 @@ const struct frr_yang_module_info frr_ripd_info = {
{
.xpath = "/frr-ripd:ripd/instance",
.cbs.create = ripd_instance_create,
- .cbs.delete = ripd_instance_delete,
+ .cbs.destroy = ripd_instance_delete,
.cbs.cli_show = cli_show_router_rip,
},
{
@@ -1331,7 +1331,7 @@ const struct frr_yang_module_info frr_ripd_info = {
{
.xpath = "/frr-ripd:ripd/instance/distance/source",
.cbs.create = ripd_instance_distance_source_create,
- .cbs.delete = ripd_instance_distance_source_delete,
+ .cbs.destroy = ripd_instance_distance_source_delete,
.cbs.cli_show = cli_show_rip_distance_source,
},
{
@@ -1341,30 +1341,30 @@ const struct frr_yang_module_info frr_ripd_info = {
{
.xpath = "/frr-ripd:ripd/instance/distance/source/access-list",
.cbs.modify = ripd_instance_distance_source_access_list_modify,
- .cbs.delete = ripd_instance_distance_source_access_list_delete,
+ .cbs.destroy = ripd_instance_distance_source_access_list_delete,
},
{
.xpath = "/frr-ripd:ripd/instance/explicit-neighbor",
.cbs.create = ripd_instance_explicit_neighbor_create,
- .cbs.delete = ripd_instance_explicit_neighbor_delete,
+ .cbs.destroy = ripd_instance_explicit_neighbor_delete,
.cbs.cli_show = cli_show_rip_neighbor,
},
{
.xpath = "/frr-ripd:ripd/instance/network",
.cbs.create = ripd_instance_network_create,
- .cbs.delete = ripd_instance_network_delete,
+ .cbs.destroy = ripd_instance_network_delete,
.cbs.cli_show = cli_show_rip_network_prefix,
},
{
.xpath = "/frr-ripd:ripd/instance/interface",
.cbs.create = ripd_instance_interface_create,
- .cbs.delete = ripd_instance_interface_delete,
+ .cbs.destroy = ripd_instance_interface_delete,
.cbs.cli_show = cli_show_rip_network_interface,
},
{
.xpath = "/frr-ripd:ripd/instance/offset-list",
.cbs.create = ripd_instance_offset_list_create,
- .cbs.delete = ripd_instance_offset_list_delete,
+ .cbs.destroy = ripd_instance_offset_list_delete,
.cbs.cli_show = cli_show_rip_offset_list,
},
{
@@ -1383,36 +1383,36 @@ const struct frr_yang_module_info frr_ripd_info = {
{
.xpath = "/frr-ripd:ripd/instance/passive-interface",
.cbs.create = ripd_instance_passive_interface_create,
- .cbs.delete = ripd_instance_passive_interface_delete,
+ .cbs.destroy = ripd_instance_passive_interface_delete,
.cbs.cli_show = cli_show_rip_passive_interface,
},
{
.xpath = "/frr-ripd:ripd/instance/non-passive-interface",
.cbs.create = ripd_instance_non_passive_interface_create,
- .cbs.delete = ripd_instance_non_passive_interface_delete,
+ .cbs.destroy = ripd_instance_non_passive_interface_delete,
.cbs.cli_show = cli_show_rip_non_passive_interface,
},
{
.xpath = "/frr-ripd:ripd/instance/redistribute",
.cbs.create = ripd_instance_redistribute_create,
- .cbs.delete = ripd_instance_redistribute_delete,
+ .cbs.destroy = ripd_instance_redistribute_delete,
.cbs.apply_finish = ripd_instance_redistribute_apply_finish,
.cbs.cli_show = cli_show_rip_redistribute,
},
{
.xpath = "/frr-ripd:ripd/instance/redistribute/route-map",
.cbs.modify = ripd_instance_redistribute_route_map_modify,
- .cbs.delete = ripd_instance_redistribute_route_map_delete,
+ .cbs.destroy = ripd_instance_redistribute_route_map_delete,
},
{
.xpath = "/frr-ripd:ripd/instance/redistribute/metric",
.cbs.modify = ripd_instance_redistribute_metric_modify,
- .cbs.delete = ripd_instance_redistribute_metric_delete,
+ .cbs.destroy = ripd_instance_redistribute_metric_delete,
},
{
.xpath = "/frr-ripd:ripd/instance/static-route",
.cbs.create = ripd_instance_static_route_create,
- .cbs.delete = ripd_instance_static_route_delete,
+ .cbs.destroy = ripd_instance_static_route_delete,
.cbs.cli_show = cli_show_rip_route,
},
{
@@ -1475,18 +1475,18 @@ const struct frr_yang_module_info frr_ripd_info = {
{
.xpath = "/frr-interface:lib/interface/frr-ripd:rip/authentication-scheme/md5-auth-length",
.cbs.modify = lib_interface_rip_authentication_scheme_md5_auth_length_modify,
- .cbs.delete = lib_interface_rip_authentication_scheme_md5_auth_length_delete,
+ .cbs.destroy = lib_interface_rip_authentication_scheme_md5_auth_length_delete,
},
{
.xpath = "/frr-interface:lib/interface/frr-ripd:rip/authentication-password",
.cbs.modify = lib_interface_rip_authentication_password_modify,
- .cbs.delete = lib_interface_rip_authentication_password_delete,
+ .cbs.destroy = lib_interface_rip_authentication_password_delete,
.cbs.cli_show = cli_show_ip_rip_authentication_string,
},
{
.xpath = "/frr-interface:lib/interface/frr-ripd:rip/authentication-key-chain",
.cbs.modify = lib_interface_rip_authentication_key_chain_modify,
- .cbs.delete = lib_interface_rip_authentication_key_chain_delete,
+ .cbs.destroy = lib_interface_rip_authentication_key_chain_delete,
.cbs.cli_show = cli_show_ip_rip_authentication_key_chain,
},
{
diff --git a/ripd/ripd.c b/ripd/ripd.c
index 0ce5324057..38b4aed5bc 100644
--- a/ripd/ripd.c
+++ b/ripd/ripd.c
@@ -3438,10 +3438,13 @@ static void rip_routemap_update_redistribute(void)
if (rip) {
for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
- if (rip->route_map[i].name)
+ if (rip->route_map[i].name) {
rip->route_map[i].map =
route_map_lookup_by_name(
rip->route_map[i].name);
+ route_map_counter_increment(
+ rip->route_map[i].map);
+ }
}
}
}
diff --git a/ripd/subdir.am b/ripd/subdir.am
index 1c2f8d64c8..2a63cc5229 100644
--- a/ripd/subdir.am
+++ b/ripd/subdir.am
@@ -44,7 +44,7 @@ noinst_HEADERS += \
ripd/ripd.h \
# end
-ripd_ripd_LDADD = ripd/librip.a lib/libfrr.la @LIBCAP@
+ripd_ripd_LDADD = ripd/librip.a lib/libfrr.la $(LIBCAP)
ripd_ripd_SOURCES = \
ripd/rip_main.c \
# end
diff --git a/ripngd/ripng_cli.c b/ripngd/ripng_cli.c
index a187e80fd7..23a4803170 100644
--- a/ripngd/ripng_cli.c
+++ b/ripngd/ripng_cli.c
@@ -62,7 +62,7 @@ DEFPY (no_router_ripng,
"Enable a routing process\n"
"Make RIPng instance command\n")
{
- nb_cli_enqueue_change(vty, "/frr-ripngd:ripngd/instance", NB_OP_DELETE,
+ nb_cli_enqueue_change(vty, "/frr-ripngd:ripngd/instance", NB_OP_DESTROY,
NULL);
return nb_cli_apply_changes(vty, NULL);
@@ -170,7 +170,7 @@ DEFPY (ripng_network_prefix,
"IPv6 network\n")
{
nb_cli_enqueue_change(vty, "./network",
- no ? NB_OP_DELETE : NB_OP_CREATE, network_str);
+ no ? NB_OP_DESTROY : NB_OP_CREATE, network_str);
return nb_cli_apply_changes(vty, NULL);
}
@@ -192,7 +192,7 @@ DEFPY (ripng_network_if,
"Interface name\n")
{
nb_cli_enqueue_change(vty, "./interface",
- no ? NB_OP_DELETE : NB_OP_CREATE, network);
+ no ? NB_OP_DESTROY : NB_OP_CREATE, network);
return nb_cli_apply_changes(vty, NULL);
}
@@ -223,7 +223,7 @@ DEFPY (ripng_offset_list,
nb_cli_enqueue_change(vty, "./metric", NB_OP_MODIFY,
metric_str);
} else
- nb_cli_enqueue_change(vty, ".", NB_OP_DELETE, NULL);
+ nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
return nb_cli_apply_changes(
vty, "./offset-list[interface='%s'][direction='%s']",
@@ -257,7 +257,7 @@ DEFPY (ripng_passive_interface,
"Interface name\n")
{
nb_cli_enqueue_change(vty, "./passive-interface",
- no ? NB_OP_DELETE : NB_OP_CREATE, ifname);
+ no ? NB_OP_DESTROY : NB_OP_CREATE, ifname);
return nb_cli_apply_changes(vty, NULL);
}
@@ -286,13 +286,13 @@ DEFPY (ripng_redistribute,
if (!no) {
nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL);
nb_cli_enqueue_change(vty, "./route-map",
- route_map ? NB_OP_MODIFY : NB_OP_DELETE,
+ route_map ? NB_OP_MODIFY : NB_OP_DESTROY,
route_map);
nb_cli_enqueue_change(vty, "./metric",
- metric_str ? NB_OP_MODIFY : NB_OP_DELETE,
+ metric_str ? NB_OP_MODIFY : NB_OP_DESTROY,
metric_str);
} else
- nb_cli_enqueue_change(vty, ".", NB_OP_DELETE, NULL);
+ nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
return nb_cli_apply_changes(vty, "./redistribute[protocol='%s']",
protocol);
@@ -323,7 +323,7 @@ DEFPY (ripng_route,
"Set static RIPng route announcement\n")
{
nb_cli_enqueue_change(vty, "./static-route",
- no ? NB_OP_DELETE : NB_OP_CREATE, route_str);
+ no ? NB_OP_DESTROY : NB_OP_CREATE, route_str);
return nb_cli_apply_changes(vty, NULL);
}
@@ -345,7 +345,7 @@ DEFPY (ripng_aggregate_address,
"Aggregate network\n")
{
nb_cli_enqueue_change(vty, "./aggregate-address",
- no ? NB_OP_DELETE : NB_OP_CREATE,
+ no ? NB_OP_DESTROY : NB_OP_CREATE,
aggregate_address_str);
return nb_cli_apply_changes(vty, NULL);
diff --git a/ripngd/ripng_northbound.c b/ripngd/ripng_northbound.c
index 7993714e8d..b6998b4ddb 100644
--- a/ripngd/ripng_northbound.c
+++ b/ripngd/ripng_northbound.c
@@ -845,7 +845,7 @@ const struct frr_yang_module_info frr_ripngd_info = {
{
.xpath = "/frr-ripngd:ripngd/instance",
.cbs.create = ripngd_instance_create,
- .cbs.delete = ripngd_instance_delete,
+ .cbs.destroy = ripngd_instance_delete,
.cbs.cli_show = cli_show_router_ripng,
},
{
@@ -866,19 +866,19 @@ const struct frr_yang_module_info frr_ripngd_info = {
{
.xpath = "/frr-ripngd:ripngd/instance/network",
.cbs.create = ripngd_instance_network_create,
- .cbs.delete = ripngd_instance_network_delete,
+ .cbs.destroy = ripngd_instance_network_delete,
.cbs.cli_show = cli_show_ripng_network_prefix,
},
{
.xpath = "/frr-ripngd:ripngd/instance/interface",
.cbs.create = ripngd_instance_interface_create,
- .cbs.delete = ripngd_instance_interface_delete,
+ .cbs.destroy = ripngd_instance_interface_delete,
.cbs.cli_show = cli_show_ripng_network_interface,
},
{
.xpath = "/frr-ripngd:ripngd/instance/offset-list",
.cbs.create = ripngd_instance_offset_list_create,
- .cbs.delete = ripngd_instance_offset_list_delete,
+ .cbs.destroy = ripngd_instance_offset_list_delete,
.cbs.cli_show = cli_show_ripng_offset_list,
},
{
@@ -892,36 +892,36 @@ const struct frr_yang_module_info frr_ripngd_info = {
{
.xpath = "/frr-ripngd:ripngd/instance/passive-interface",
.cbs.create = ripngd_instance_passive_interface_create,
- .cbs.delete = ripngd_instance_passive_interface_delete,
+ .cbs.destroy = ripngd_instance_passive_interface_delete,
.cbs.cli_show = cli_show_ripng_passive_interface,
},
{
.xpath = "/frr-ripngd:ripngd/instance/redistribute",
.cbs.create = ripngd_instance_redistribute_create,
- .cbs.delete = ripngd_instance_redistribute_delete,
+ .cbs.destroy = ripngd_instance_redistribute_delete,
.cbs.apply_finish = ripngd_instance_redistribute_apply_finish,
.cbs.cli_show = cli_show_ripng_redistribute,
},
{
.xpath = "/frr-ripngd:ripngd/instance/redistribute/route-map",
.cbs.modify = ripngd_instance_redistribute_route_map_modify,
- .cbs.delete = ripngd_instance_redistribute_route_map_delete,
+ .cbs.destroy = ripngd_instance_redistribute_route_map_delete,
},
{
.xpath = "/frr-ripngd:ripngd/instance/redistribute/metric",
.cbs.modify = ripngd_instance_redistribute_metric_modify,
- .cbs.delete = ripngd_instance_redistribute_metric_delete,
+ .cbs.destroy = ripngd_instance_redistribute_metric_delete,
},
{
.xpath = "/frr-ripngd:ripngd/instance/static-route",
.cbs.create = ripngd_instance_static_route_create,
- .cbs.delete = ripngd_instance_static_route_delete,
+ .cbs.destroy = ripngd_instance_static_route_delete,
.cbs.cli_show = cli_show_ripng_route,
},
{
.xpath = "/frr-ripngd:ripngd/instance/aggregate-address",
.cbs.create = ripngd_instance_aggregate_address_create,
- .cbs.delete = ripngd_instance_aggregate_address_delete,
+ .cbs.destroy = ripngd_instance_aggregate_address_delete,
.cbs.cli_show = cli_show_ripng_aggregate_address,
},
{
diff --git a/ripngd/ripngd.c b/ripngd/ripngd.c
index 0022c726c5..70655beff1 100644
--- a/ripngd/ripngd.c
+++ b/ripngd/ripngd.c
@@ -2522,10 +2522,13 @@ static void ripng_routemap_update_redistribute(void)
if (ripng) {
for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
- if (ripng->route_map[i].name)
+ if (ripng->route_map[i].name) {
ripng->route_map[i].map =
route_map_lookup_by_name(
ripng->route_map[i].name);
+ route_map_counter_increment(
+ ripng->route_map[i].map);
+ }
}
}
}
diff --git a/ripngd/subdir.am b/ripngd/subdir.am
index d401e9bbf6..ea0ccf1482 100644
--- a/ripngd/subdir.am
+++ b/ripngd/subdir.am
@@ -40,7 +40,7 @@ noinst_HEADERS += \
ripngd/ripngd.h \
# end
-ripngd_ripngd_LDADD = ripngd/libripng.a lib/libfrr.la @LIBCAP@
+ripngd_ripngd_LDADD = ripngd/libripng.a lib/libfrr.la $(LIBCAP)
ripngd_ripngd_SOURCES = \
ripngd/ripng_main.c \
# end
diff --git a/sharpd/Makefile b/sharpd/Makefile
new file mode 100644
index 0000000000..6a904d1a6d
--- /dev/null
+++ b/sharpd/Makefile
@@ -0,0 +1,10 @@
+all: ALWAYS
+ @$(MAKE) -s -C .. sharpd/sharpd
+%: ALWAYS
+ @$(MAKE) -s -C .. sharpd/$@
+
+Makefile:
+ #nothing
+ALWAYS:
+.PHONY: ALWAYS makefiles
+.SUFFIXES:
diff --git a/sharpd/sharp_globals.h b/sharpd/sharp_globals.h
new file mode 100644
index 0000000000..065fb092d4
--- /dev/null
+++ b/sharpd/sharp_globals.h
@@ -0,0 +1,55 @@
+/*
+ * SHARP - code to track globals
+ * Copyright (C) 2019 Cumulus Networks, Inc.
+ * Donald Sharp
+ *
+ * This file is part of FRR.
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef __SHARP_GLOBAL_H__
+#define __SHARP_GLOBAL_H__
+
+DECLARE_MGROUP(SHARPD)
+
+struct sharp_routes {
+ /* The original prefix for route installation */
+ struct prefix orig_prefix;
+
+ /* The nexthop group we are using for installation */
+ struct nexthop nhop;
+ struct nexthop_group nhop_group;
+
+ uint32_t total_routes;
+ uint32_t installed_routes;
+ uint32_t removed_routes;
+ int32_t repeat;
+
+ uint8_t inst;
+
+ struct timeval t_start;
+ struct timeval t_end;
+};
+
+struct sharp_global {
+ /* Global data about route install/deletions */
+ struct sharp_routes r;
+
+ /* The list of nexthops that we are watching and data about them */
+ struct list *nhs;
+};
+
+extern struct sharp_global sg;
+#endif
diff --git a/sharpd/sharp_main.c b/sharpd/sharp_main.c
index 175a276089..39453ee9ad 100644
--- a/sharpd/sharp_main.c
+++ b/sharpd/sharp_main.c
@@ -46,10 +46,9 @@
#include "sharp_zebra.h"
#include "sharp_vty.h"
+#include "sharp_globals.h"
-uint32_t total_routes = 0;
-uint32_t installed_routes = 0;
-uint32_t removed_routes = 0;
+DEFINE_MGROUP(SHARPD, "sharpd")
zebra_capabilities_t _caps_p[] = {
};
@@ -125,7 +124,13 @@ FRR_DAEMON_INFO(sharpd, SHARP, .vty_port = SHARP_VTY_PORT,
.privs = &sharp_privs, .yang_modules = sharpd_yang_modules,
.n_yang_modules = array_size(sharpd_yang_modules), )
-extern void sharp_vty_init(void);
+struct sharp_global sg;
+
+static void sharp_global_init(void)
+{
+ memset(&sg, 0, sizeof(sg));
+ sg.nhs = list_new();
+}
int main(int argc, char **argv, char **envp)
{
@@ -151,6 +156,8 @@ int main(int argc, char **argv, char **envp)
master = frr_init();
+ sharp_global_init();
+
nexthop_group_init(NULL, NULL, NULL, NULL);
vrf_init(NULL, NULL, NULL, NULL, NULL);
diff --git a/sharpd/sharp_nht.c b/sharpd/sharp_nht.c
new file mode 100644
index 0000000000..174f186863
--- /dev/null
+++ b/sharpd/sharp_nht.c
@@ -0,0 +1,67 @@
+/*
+ * SHARP - code to track nexthops
+ * Copyright (C) Cumulus Networks, Inc.
+ * Donald Sharp
+ *
+ * This file is part of FRR.
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <zebra.h>
+
+#include "memory.h"
+#include "nexthop.h"
+#include "nexthop_group.h"
+#include "vty.h"
+
+#include "sharp_nht.h"
+#include "sharp_globals.h"
+
+DEFINE_MTYPE_STATIC(SHARPD, NH_TRACKER, "Nexthop Tracker")
+
+struct sharp_nh_tracker *sharp_nh_tracker_get(struct prefix *p)
+{
+ struct listnode *node;
+ struct sharp_nh_tracker *nht;
+
+ for (ALL_LIST_ELEMENTS_RO(sg.nhs, node, nht)) {
+ if (prefix_same(&nht->p, p))
+ break;
+ }
+
+ if (nht)
+ return nht;
+
+ nht = XCALLOC(MTYPE_NH_TRACKER, sizeof(*nht));
+ prefix_copy(&nht->p, p);
+
+ listnode_add(sg.nhs, nht);
+ return nht;
+}
+
+void sharp_nh_tracker_dump(struct vty *vty)
+{
+ struct listnode *node;
+ struct sharp_nh_tracker *nht;
+
+ for (ALL_LIST_ELEMENTS_RO(sg.nhs, node, nht)) {
+ char buf[PREFIX_STRLEN];
+
+ vty_out(vty, "%s: Nexthops: %u Updates: %u\n",
+ prefix2str(&nht->p, buf, sizeof(buf)),
+ nht->nhop_num,
+ nht->updates);
+ }
+}
diff --git a/sharpd/sharp_nht.h b/sharpd/sharp_nht.h
new file mode 100644
index 0000000000..0b00774a81
--- /dev/null
+++ b/sharpd/sharp_nht.h
@@ -0,0 +1,38 @@
+/*
+ * SHARP - code to track nexthops
+ * Copyright (C) Cumulus Networks, Inc.
+ * Donald Sharp
+ *
+ * This file is part of FRR.
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef __SHARP_NHT_H__
+#define __SHARP_NHT_H__
+
+struct sharp_nh_tracker {
+ /* What are we watching */
+ struct prefix p;
+
+ /* Number of valid nexthops */
+ uint32_t nhop_num;
+
+ uint32_t updates;
+};
+
+extern struct sharp_nh_tracker *sharp_nh_tracker_get(struct prefix *p);
+
+extern void sharp_nh_tracker_dump(struct vty *vty);
+#endif
diff --git a/sharpd/sharp_vty.c b/sharpd/sharp_vty.c
index 86c8bfe1c2..9018cfb359 100644
--- a/sharpd/sharp_vty.c
+++ b/sharpd/sharp_vty.c
@@ -30,32 +30,31 @@
#include "zclient.h"
#include "nexthop_group.h"
+#include "sharpd/sharp_globals.h"
#include "sharpd/sharp_zebra.h"
+#include "sharpd/sharp_nht.h"
#include "sharpd/sharp_vty.h"
#ifndef VTYSH_EXTRACT_PL
#include "sharpd/sharp_vty_clippy.c"
#endif
-extern uint32_t total_routes;
-extern uint32_t installed_routes;
-extern uint32_t removed_routes;
-
-uint8_t inst;
-struct prefix prefix;
-struct prefix orig_prefix;
-struct nexthop nhop;
-struct nexthop_group nhop_group;
-uint32_t rts;
-int32_t repeat;
-
DEFPY(watch_nexthop_v6, watch_nexthop_v6_cmd,
- "sharp watch nexthop X:X::X:X$nhop",
+ "sharp watch <nexthop$n|import$import> X:X::X:X$nhop [connected$connected]",
"Sharp routing Protocol\n"
"Watch for changes\n"
"Watch for nexthop changes\n"
- "The v6 nexthop to signal for watching\n")
+ "Watch for import check changes\n"
+ "The v6 nexthop to signal for watching\n"
+ "Should the route be connected\n")
{
struct prefix p;
+ bool type_import;
+
+
+ if (n)
+ type_import = false;
+ else
+ type_import = true;
memset(&p, 0, sizeof(p));
@@ -63,27 +62,70 @@ DEFPY(watch_nexthop_v6, watch_nexthop_v6_cmd,
memcpy(&p.u.prefix6, &nhop, 16);
p.family = AF_INET6;
- sharp_zebra_nexthop_watch(&p, true);
+ sharp_nh_tracker_get(&p);
+ sharp_zebra_nexthop_watch(&p, type_import, true, !!connected);
return CMD_SUCCESS;
}
DEFPY(watch_nexthop_v4, watch_nexthop_v4_cmd,
- "sharp watch nexthop A.B.C.D$nhop",
+ "sharp watch <nexthop$n|import$import> A.B.C.D$nhop [connected$connected]",
"Sharp routing Protocol\n"
"Watch for changes\n"
"Watch for nexthop changes\n"
- "The v4 nexthop to signal for watching\n")
+ "Watch for import check changes\n"
+ "The v4 nexthop to signal for watching\n"
+ "Should the route be connected\n")
{
struct prefix p;
+ bool type_import;
memset(&p, 0, sizeof(p));
+ if (n)
+ type_import = false;
+ else
+ type_import = true;
+
p.prefixlen = 32;
p.u.prefix4 = nhop;
p.family = AF_INET;
- sharp_zebra_nexthop_watch(&p, true);
+ sharp_nh_tracker_get(&p);
+ sharp_zebra_nexthop_watch(&p, type_import, true, !!connected);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY(sharp_nht_data_dump,
+ sharp_nht_data_dump_cmd,
+ "sharp data nexthop",
+ "Sharp routing Protocol\n"
+ "Nexthop information\n"
+ "Data Dump\n")
+{
+ sharp_nh_tracker_dump(vty);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY (install_routes_data_dump,
+ install_routes_data_dump_cmd,
+ "sharp data route",
+ "Sharp routing Protocol\n"
+ "Data about what is going on\n"
+ "Route Install/Removal Information\n")
+{
+ char buf[PREFIX_STRLEN];
+ struct timeval r;
+
+ timersub(&sg.r.t_end, &sg.r.t_start, &r);
+ vty_out(vty, "Prefix: %s Total: %u %u %u Time: %ld.%ld\n",
+ prefix2str(&sg.r.orig_prefix, buf, sizeof(buf)),
+ sg.r.total_routes,
+ sg.r.installed_routes,
+ sg.r.removed_routes,
+ r.tv_sec, r.tv_usec);
return CMD_SUCCESS;
}
@@ -107,18 +149,21 @@ DEFPY (install_routes,
"Should we repeat this command\n"
"How many times to repeat this command\n")
{
- total_routes = routes;
- installed_routes = 0;
+ struct prefix prefix;
+ uint32_t rts;
+
+ sg.r.total_routes = routes;
+ sg.r.installed_routes = 0;
if (rpt >= 2)
- repeat = rpt * 2;
+ sg.r.repeat = rpt * 2;
else
- repeat = 0;
+ sg.r.repeat = 0;
memset(&prefix, 0, sizeof(prefix));
- memset(&orig_prefix, 0, sizeof(orig_prefix));
- memset(&nhop, 0, sizeof(nhop));
- memset(&nhop_group, 0, sizeof(nhop_group));
+ memset(&sg.r.orig_prefix, 0, sizeof(sg.r.orig_prefix));
+ memset(&sg.r.nhop, 0, sizeof(sg.r.nhop));
+ memset(&sg.r.nhop_group, 0, sizeof(sg.r.nhop_group));
if (start4.s_addr != 0) {
prefix.family = AF_INET;
@@ -129,7 +174,7 @@ DEFPY (install_routes,
prefix.prefixlen = 128;
prefix.u.prefix6 = start6;
}
- orig_prefix = prefix;
+ sg.r.orig_prefix = prefix;
if (nexthop_group) {
struct nexthop_group_cmd *nhgc = nhgc_find(nexthop_group);
@@ -140,22 +185,22 @@ DEFPY (install_routes,
return CMD_WARNING;
}
- nhop_group.nexthop = nhgc->nhg.nexthop;
+ sg.r.nhop_group.nexthop = nhgc->nhg.nexthop;
} else {
if (nexthop4.s_addr != INADDR_ANY) {
- nhop.gate.ipv4 = nexthop4;
- nhop.type = NEXTHOP_TYPE_IPV4;
+ sg.r.nhop.gate.ipv4 = nexthop4;
+ sg.r.nhop.type = NEXTHOP_TYPE_IPV4;
} else {
- nhop.gate.ipv6 = nexthop6;
- nhop.type = NEXTHOP_TYPE_IPV6;
+ sg.r.nhop.gate.ipv6 = nexthop6;
+ sg.r.nhop.type = NEXTHOP_TYPE_IPV6;
}
- nhop_group.nexthop = &nhop;
+ sg.r.nhop_group.nexthop = &sg.r.nhop;
}
- inst = instance;
+ sg.r.inst = instance;
rts = routes;
- sharp_install_routes_helper(&prefix, inst, &nhop_group, rts);
+ sharp_install_routes_helper(&prefix, sg.r.inst, &sg.r.nhop_group, rts);
return CMD_SUCCESS;
}
@@ -202,8 +247,11 @@ DEFPY (remove_routes,
"instance to use\n"
"Value of instance\n")
{
- total_routes = routes;
- removed_routes = 0;
+ struct prefix prefix;
+
+ sg.r.total_routes = routes;
+ sg.r.removed_routes = 0;
+ uint32_t rts;
memset(&prefix, 0, sizeof(prefix));
@@ -217,9 +265,9 @@ DEFPY (remove_routes,
prefix.u.prefix6 = start6;
}
- inst = instance;
+ sg.r.inst = instance;
rts = routes;
- sharp_remove_routes_helper(&prefix, inst, rts);
+ sharp_remove_routes_helper(&prefix, sg.r.inst, rts);
return CMD_SUCCESS;
}
@@ -238,9 +286,11 @@ DEFUN_NOSH (show_debugging_sharpd,
void sharp_vty_init(void)
{
+ install_element(ENABLE_NODE, &install_routes_data_dump_cmd);
install_element(ENABLE_NODE, &install_routes_cmd);
install_element(ENABLE_NODE, &remove_routes_cmd);
install_element(ENABLE_NODE, &vrf_label_cmd);
+ install_element(ENABLE_NODE, &sharp_nht_data_dump_cmd);
install_element(ENABLE_NODE, &watch_nexthop_v6_cmd);
install_element(ENABLE_NODE, &watch_nexthop_v4_cmd);
diff --git a/sharpd/sharp_zebra.c b/sharpd/sharp_zebra.c
index c9f333e34b..4682dbc73a 100644
--- a/sharpd/sharp_zebra.c
+++ b/sharpd/sharp_zebra.c
@@ -36,6 +36,8 @@
#include "nexthop.h"
#include "nexthop_group.h"
+#include "sharp_globals.h"
+#include "sharp_nht.h"
#include "sharp_zebra.h"
/* Zebra structure to hold current status. */
@@ -129,16 +131,6 @@ static int interface_state_down(int command, struct zclient *zclient,
return 0;
}
-static struct timeval t_start;
-static struct timeval t_end;
-extern uint32_t total_routes;
-extern uint32_t installed_routes;
-extern uint32_t removed_routes;
-extern int32_t repeat;
-extern struct prefix orig_prefix;
-extern struct nexthop_group nhop_group;
-extern uint8_t inst;
-
void sharp_install_routes_helper(struct prefix *p, uint8_t instance,
struct nexthop_group *nhg,
uint32_t routes)
@@ -154,7 +146,7 @@ void sharp_install_routes_helper(struct prefix *p, uint8_t instance,
} else
temp = ntohl(p->u.val32[3]);
- monotime(&t_start);
+ monotime(&sg.r.t_start);
for (i = 0; i < routes; i++) {
route_add(p, (uint8_t)instance, nhg);
if (v4)
@@ -178,7 +170,7 @@ void sharp_remove_routes_helper(struct prefix *p, uint8_t instance,
} else
temp = ntohl(p->u.val32[3]);
- monotime(&t_start);
+ monotime(&sg.r.t_start);
for (i = 0; i < routes; i++) {
route_delete(p, (uint8_t)instance);
if (v4)
@@ -190,21 +182,21 @@ void sharp_remove_routes_helper(struct prefix *p, uint8_t instance,
static void handle_repeated(bool installed)
{
- struct prefix p = orig_prefix;
- repeat--;
+ struct prefix p = sg.r.orig_prefix;
+ sg.r.repeat--;
- if (repeat <= 0)
+ if (sg.r.repeat <= 0)
return;
if (installed) {
- removed_routes = 0;
- sharp_remove_routes_helper(&p, inst, total_routes);
+ sg.r.removed_routes = 0;
+ sharp_remove_routes_helper(&p, sg.r.inst, sg.r.total_routes);
}
- if (!installed) {
- installed_routes = 0;
- sharp_install_routes_helper(&p, inst, &nhop_group,
- total_routes);
+ if (installed) {
+ sg.r.installed_routes = 0;
+ sharp_install_routes_helper(&p, sg.r.inst, &sg.r.nhop_group,
+ sg.r.total_routes);
}
}
@@ -221,10 +213,10 @@ static int route_notify_owner(int command, struct zclient *zclient,
switch (note) {
case ZAPI_ROUTE_INSTALLED:
- installed_routes++;
- if (total_routes == installed_routes) {
- monotime(&t_end);
- timersub(&t_end, &t_start, &r);
+ sg.r.installed_routes++;
+ if (sg.r.total_routes == sg.r.installed_routes) {
+ monotime(&sg.r.t_end);
+ timersub(&sg.r.t_end, &sg.r.t_start, &r);
zlog_debug("Installed All Items %ld.%ld", r.tv_sec,
r.tv_usec);
handle_repeated(true);
@@ -237,10 +229,10 @@ static int route_notify_owner(int command, struct zclient *zclient,
zlog_debug("Better Admin Distance won over us");
break;
case ZAPI_ROUTE_REMOVED:
- removed_routes++;
- if (total_routes == removed_routes) {
- monotime(&t_end);
- timersub(&t_end, &t_start, &r);
+ sg.r.removed_routes++;
+ if (sg.r.total_routes == sg.r.removed_routes) {
+ monotime(&sg.r.t_end);
+ timersub(&sg.r.t_end, &sg.r.t_start, &r);
zlog_debug("Removed all Items %ld.%ld", r.tv_sec,
r.tv_usec);
handle_repeated(false);
@@ -328,14 +320,24 @@ void route_delete(struct prefix *p, uint8_t instance)
return;
}
-void sharp_zebra_nexthop_watch(struct prefix *p, bool watch)
+void sharp_zebra_nexthop_watch(struct prefix *p, bool import,
+ bool watch, bool connected)
{
- int command = ZEBRA_NEXTHOP_REGISTER;
+ int command;
- if (!watch)
- command = ZEBRA_NEXTHOP_UNREGISTER;
+ if (!import) {
+ command = ZEBRA_NEXTHOP_REGISTER;
- if (zclient_send_rnh(zclient, command, p, true, VRF_DEFAULT) < 0)
+ if (!watch)
+ command = ZEBRA_NEXTHOP_UNREGISTER;
+ } else {
+ command = ZEBRA_IMPORT_ROUTE_REGISTER;
+
+ if (!watch)
+ command = ZEBRA_IMPORT_ROUTE_UNREGISTER;
+ }
+
+ if (zclient_send_rnh(zclient, command, p, connected, VRF_DEFAULT) < 0)
zlog_warn("%s: Failure to send nexthop to zebra",
__PRETTY_FUNCTION__);
}
@@ -343,6 +345,7 @@ void sharp_zebra_nexthop_watch(struct prefix *p, bool watch)
static int sharp_nexthop_update(int command, struct zclient *zclient,
zebra_size_t length, vrf_id_t vrf_id)
{
+ struct sharp_nh_tracker *nht;
struct zapi_route nhr;
char buf[PREFIX_STRLEN];
int i;
@@ -355,6 +358,11 @@ static int sharp_nexthop_update(int command, struct zclient *zclient,
zlog_debug("Received update for %s",
prefix2str(&nhr.prefix, buf, sizeof(buf)));
+
+ nht = sharp_nh_tracker_get(&nhr.prefix);
+ nht->nhop_num = nhr.nexthop_num;
+ nht->updates++;
+
for (i = 0; i < nhr.nexthop_num; i++) {
struct zapi_nexthop *znh = &nhr.nexthops[i];
@@ -407,4 +415,5 @@ void sharp_zebra_init(void)
zclient->interface_address_delete = interface_address_delete;
zclient->route_notify_owner = route_notify_owner;
zclient->nexthop_update = sharp_nexthop_update;
+ zclient->import_check_update = sharp_nexthop_update;
}
diff --git a/sharpd/sharp_zebra.h b/sharpd/sharp_zebra.h
index 7326056cae..b219022f02 100644
--- a/sharpd/sharp_zebra.h
+++ b/sharpd/sharp_zebra.h
@@ -28,7 +28,8 @@ extern void vrf_label_add(vrf_id_t vrf_id, afi_t afi, mpls_label_t label);
extern void route_add(struct prefix *p, uint8_t instance,
struct nexthop_group *nhg);
extern void route_delete(struct prefix *p, uint8_t instance);
-extern void sharp_zebra_nexthop_watch(struct prefix *p, bool watch);
+extern void sharp_zebra_nexthop_watch(struct prefix *p, bool import,
+ bool watch, bool connected);
extern void sharp_install_routes_helper(struct prefix *p, uint8_t instance,
struct nexthop_group *nhg,
diff --git a/sharpd/subdir.am b/sharpd/subdir.am
index 2a34aecfb3..4a9028f6fe 100644
--- a/sharpd/subdir.am
+++ b/sharpd/subdir.am
@@ -11,12 +11,15 @@ man8 += $(MANBUILD)/sharpd.8
endif
sharpd_libsharp_a_SOURCES = \
+ sharpd/sharp_nht.c \
sharpd/sharp_zebra.c \
sharpd/sharp_vty.c \
# end
noinst_HEADERS += \
+ sharpd/sharp_nht.h \
sharpd/sharp_vty.h \
+ sharpd/sharp_globals.h \
sharpd/sharp_zebra.h \
# end
@@ -24,5 +27,5 @@ sharpd/sharp_vty_clippy.c: $(CLIPPY_DEPS)
sharpd/sharp_vty.$(OBJEXT): sharpd/sharp_vty_clippy.c
sharpd_sharpd_SOURCES = sharpd/sharp_main.c
-sharpd_sharpd_LDADD = sharpd/libsharp.a lib/libfrr.la @LIBCAP@
+sharpd_sharpd_LDADD = sharpd/libsharp.a lib/libfrr.la $(LIBCAP)
diff --git a/staticd/subdir.am b/staticd/subdir.am
index 33cc0e2050..17c4536fe9 100644
--- a/staticd/subdir.am
+++ b/staticd/subdir.am
@@ -32,4 +32,4 @@ staticd/static_vty_clippy.c: $(CLIPPY_DEPS)
staticd/static_vty.$(OBJEXT): staticd/static_vty_clippy.c
staticd_staticd_SOURCES = staticd/static_main.c
-staticd_staticd_LDADD = staticd/libstatic.a lib/libfrr.la @LIBCAP@
+staticd_staticd_LDADD = staticd/libstatic.a lib/libfrr.la $(LIBCAP)
diff --git a/tests/.gitignore b/tests/.gitignore
index 5453c0d80a..de648015f1 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -19,6 +19,7 @@
/lib/cli/test_commands
/lib/cli/test_commands_defun.c
/lib/northbound/test_oper_data
+/lib/cxxcompat
/lib/test_buffer
/lib/test_checksum
/lib/test_graph
diff --git a/tests/Makefile.in b/tests/Makefile.in
new file mode 100644
index 0000000000..29d903e70a
--- /dev/null
+++ b/tests/Makefile.in
@@ -0,0 +1,1338 @@
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#
+# Automake fragment intended to be shared by Makefile.am files in the
+# tree.
+#
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+check_PROGRAMS = lib/test_buffer$(EXEEXT) lib/test_checksum$(EXEEXT) \
+ lib/test_heavy_thread$(EXEEXT) lib/test_heavy_wq$(EXEEXT) \
+ lib/test_heavy$(EXEEXT) lib/test_memory$(EXEEXT) \
+ lib/test_nexthop_iter$(EXEEXT) lib/test_privs$(EXEEXT) \
+ lib/test_ringbuf$(EXEEXT) lib/test_srcdest_table$(EXEEXT) \
+ lib/test_segv$(EXEEXT) lib/test_sig$(EXEEXT) \
+ lib/test_stream$(EXEEXT) lib/test_table$(EXEEXT) \
+ lib/test_timer_correctness$(EXEEXT) \
+ lib/test_timer_performance$(EXEEXT) lib/test_ttable$(EXEEXT) \
+ lib/cli/test_cli$(EXEEXT) lib/cli/test_commands$(EXEEXT) \
+ $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \
+ $(am__EXEEXT_4)
+@ZEROMQ_TRUE@am__append_1 = \
+@ZEROMQ_TRUE@ lib/test_zmq \
+@ZEROMQ_TRUE@ # end
+
+subdir = tests
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_compare_version.m4 \
+ $(top_srcdir)/m4/ax_pthread.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/pkg.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+@BGPD_TRUE@am__EXEEXT_1 = bgpd/test_aspath$(EXEEXT) \
+@BGPD_TRUE@ bgpd/test_capability$(EXEEXT) \
+@BGPD_TRUE@ bgpd/test_packet$(EXEEXT) \
+@BGPD_TRUE@ bgpd/test_ecommunity$(EXEEXT) \
+@BGPD_TRUE@ bgpd/test_mp_attr$(EXEEXT) bgpd/test_mpath$(EXEEXT)
+@ISISD_TRUE@@SOLARIS_FALSE@am__EXEEXT_2 = \
+@ISISD_TRUE@@SOLARIS_FALSE@ isisd/test_fuzz_isis_tlv$(EXEEXT) \
+@ISISD_TRUE@@SOLARIS_FALSE@ isisd/test_isis_vertex_queue$(EXEEXT)
+@OSPF6D_TRUE@am__EXEEXT_3 = ospf6d/test_lsdb$(EXEEXT)
+@ZEROMQ_TRUE@am__EXEEXT_4 = lib/test_zmq$(EXEEXT)
+am__dirstamp = $(am__leading_dot)dirstamp
+am_bgpd_test_aspath_OBJECTS = bgpd/test_aspath.$(OBJEXT)
+bgpd_test_aspath_OBJECTS = $(am_bgpd_test_aspath_OBJECTS)
+@ENABLE_BGP_VNC_TRUE@am__DEPENDENCIES_1 = \
+@ENABLE_BGP_VNC_TRUE@ @top_builddir@/$(LIBRFP)/librfp.a
+am__DEPENDENCIES_2 = ../lib/libfrr.la
+am__DEPENDENCIES_3 = ../bgpd/libbgp.a $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_2)
+bgpd_test_aspath_DEPENDENCIES = $(am__DEPENDENCIES_3)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+am_bgpd_test_capability_OBJECTS = bgpd/test_capability.$(OBJEXT)
+bgpd_test_capability_OBJECTS = $(am_bgpd_test_capability_OBJECTS)
+bgpd_test_capability_DEPENDENCIES = $(am__DEPENDENCIES_3)
+am_bgpd_test_ecommunity_OBJECTS = bgpd/test_ecommunity.$(OBJEXT)
+bgpd_test_ecommunity_OBJECTS = $(am_bgpd_test_ecommunity_OBJECTS)
+bgpd_test_ecommunity_DEPENDENCIES = $(am__DEPENDENCIES_3)
+am_bgpd_test_mp_attr_OBJECTS = bgpd/test_mp_attr.$(OBJEXT)
+bgpd_test_mp_attr_OBJECTS = $(am_bgpd_test_mp_attr_OBJECTS)
+bgpd_test_mp_attr_DEPENDENCIES = $(am__DEPENDENCIES_3)
+am_bgpd_test_mpath_OBJECTS = bgpd/test_mpath.$(OBJEXT)
+bgpd_test_mpath_OBJECTS = $(am_bgpd_test_mpath_OBJECTS)
+bgpd_test_mpath_DEPENDENCIES = $(am__DEPENDENCIES_3)
+am_bgpd_test_packet_OBJECTS = bgpd/test_packet.$(OBJEXT)
+bgpd_test_packet_OBJECTS = $(am_bgpd_test_packet_OBJECTS)
+bgpd_test_packet_DEPENDENCIES = $(am__DEPENDENCIES_3)
+am_isisd_test_fuzz_isis_tlv_OBJECTS = \
+ isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.$(OBJEXT)
+isisd_test_fuzz_isis_tlv_OBJECTS = \
+ $(am_isisd_test_fuzz_isis_tlv_OBJECTS)
+am__DEPENDENCIES_4 = ../isisd/libisis.a $(am__DEPENDENCIES_2)
+isisd_test_fuzz_isis_tlv_DEPENDENCIES = $(am__DEPENDENCIES_4)
+am_isisd_test_isis_vertex_queue_OBJECTS = \
+ isisd/test_isis_vertex_queue.$(OBJEXT)
+isisd_test_isis_vertex_queue_OBJECTS = \
+ $(am_isisd_test_isis_vertex_queue_OBJECTS)
+isisd_test_isis_vertex_queue_DEPENDENCIES = $(am__DEPENDENCIES_4)
+am_lib_cli_test_cli_OBJECTS = lib/cli/test_cli.$(OBJEXT) \
+ lib/cli/common_cli.$(OBJEXT)
+lib_cli_test_cli_OBJECTS = $(am_lib_cli_test_cli_OBJECTS)
+lib_cli_test_cli_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_lib_cli_test_commands_OBJECTS = \
+ lib/cli/test_commands_defun.$(OBJEXT) \
+ lib/cli/test_commands.$(OBJEXT) helpers/c/prng.$(OBJEXT)
+lib_cli_test_commands_OBJECTS = $(am_lib_cli_test_commands_OBJECTS)
+lib_cli_test_commands_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_lib_test_buffer_OBJECTS = lib/test_buffer.$(OBJEXT)
+lib_test_buffer_OBJECTS = $(am_lib_test_buffer_OBJECTS)
+lib_test_buffer_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_lib_test_checksum_OBJECTS = lib/test_checksum.$(OBJEXT)
+lib_test_checksum_OBJECTS = $(am_lib_test_checksum_OBJECTS)
+lib_test_checksum_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_lib_test_heavy_OBJECTS = lib/test_heavy.$(OBJEXT) \
+ helpers/c/main.$(OBJEXT)
+lib_test_heavy_OBJECTS = $(am_lib_test_heavy_OBJECTS)
+lib_test_heavy_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_lib_test_heavy_thread_OBJECTS = lib/test_heavy_thread.$(OBJEXT) \
+ helpers/c/main.$(OBJEXT)
+lib_test_heavy_thread_OBJECTS = $(am_lib_test_heavy_thread_OBJECTS)
+lib_test_heavy_thread_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_lib_test_heavy_wq_OBJECTS = lib/test_heavy_wq.$(OBJEXT) \
+ helpers/c/main.$(OBJEXT)
+lib_test_heavy_wq_OBJECTS = $(am_lib_test_heavy_wq_OBJECTS)
+lib_test_heavy_wq_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_lib_test_memory_OBJECTS = lib/test_memory.$(OBJEXT)
+lib_test_memory_OBJECTS = $(am_lib_test_memory_OBJECTS)
+lib_test_memory_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_lib_test_nexthop_iter_OBJECTS = lib/test_nexthop_iter.$(OBJEXT) \
+ helpers/c/prng.$(OBJEXT)
+lib_test_nexthop_iter_OBJECTS = $(am_lib_test_nexthop_iter_OBJECTS)
+lib_test_nexthop_iter_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_lib_test_privs_OBJECTS = lib/test_privs.$(OBJEXT)
+lib_test_privs_OBJECTS = $(am_lib_test_privs_OBJECTS)
+lib_test_privs_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_lib_test_ringbuf_OBJECTS = lib/test_ringbuf.$(OBJEXT)
+lib_test_ringbuf_OBJECTS = $(am_lib_test_ringbuf_OBJECTS)
+lib_test_ringbuf_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_lib_test_segv_OBJECTS = lib/test_segv.$(OBJEXT)
+lib_test_segv_OBJECTS = $(am_lib_test_segv_OBJECTS)
+lib_test_segv_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_lib_test_sig_OBJECTS = lib/test_sig.$(OBJEXT)
+lib_test_sig_OBJECTS = $(am_lib_test_sig_OBJECTS)
+lib_test_sig_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_lib_test_srcdest_table_OBJECTS = lib/test_srcdest_table.$(OBJEXT) \
+ helpers/c/prng.$(OBJEXT)
+lib_test_srcdest_table_OBJECTS = $(am_lib_test_srcdest_table_OBJECTS)
+lib_test_srcdest_table_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_lib_test_stream_OBJECTS = lib/test_stream.$(OBJEXT)
+lib_test_stream_OBJECTS = $(am_lib_test_stream_OBJECTS)
+lib_test_stream_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_lib_test_table_OBJECTS = lib/test_table.$(OBJEXT)
+lib_test_table_OBJECTS = $(am_lib_test_table_OBJECTS)
+lib_test_table_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_lib_test_timer_correctness_OBJECTS = \
+ lib/test_timer_correctness.$(OBJEXT) helpers/c/prng.$(OBJEXT)
+lib_test_timer_correctness_OBJECTS = \
+ $(am_lib_test_timer_correctness_OBJECTS)
+lib_test_timer_correctness_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_lib_test_timer_performance_OBJECTS = \
+ lib/test_timer_performance.$(OBJEXT) helpers/c/prng.$(OBJEXT)
+lib_test_timer_performance_OBJECTS = \
+ $(am_lib_test_timer_performance_OBJECTS)
+lib_test_timer_performance_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_lib_test_ttable_OBJECTS = lib/test_ttable.$(OBJEXT)
+lib_test_ttable_OBJECTS = $(am_lib_test_ttable_OBJECTS)
+lib_test_ttable_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_lib_test_zmq_OBJECTS = lib/lib_test_zmq-test_zmq.$(OBJEXT)
+lib_test_zmq_OBJECTS = $(am_lib_test_zmq_OBJECTS)
+am__DEPENDENCIES_5 =
+lib_test_zmq_DEPENDENCIES = ../lib/libfrrzmq.la $(am__DEPENDENCIES_2) \
+ $(am__DEPENDENCIES_5)
+lib_test_zmq_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(lib_test_zmq_CFLAGS) \
+ $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+am_ospf6d_test_lsdb_OBJECTS = ospf6d/test_lsdb.$(OBJEXT) \
+ lib/cli/common_cli.$(OBJEXT)
+ospf6d_test_lsdb_OBJECTS = $(am_ospf6d_test_lsdb_OBJECTS)
+am__DEPENDENCIES_6 = ../ospf6d/libospf6.a $(am__DEPENDENCIES_2)
+ospf6d_test_lsdb_DEPENDENCIES = $(am__DEPENDENCIES_6)
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(bgpd_test_aspath_SOURCES) $(bgpd_test_capability_SOURCES) \
+ $(bgpd_test_ecommunity_SOURCES) $(bgpd_test_mp_attr_SOURCES) \
+ $(bgpd_test_mpath_SOURCES) $(bgpd_test_packet_SOURCES) \
+ $(isisd_test_fuzz_isis_tlv_SOURCES) \
+ $(isisd_test_isis_vertex_queue_SOURCES) \
+ $(lib_cli_test_cli_SOURCES) $(lib_cli_test_commands_SOURCES) \
+ $(lib_test_buffer_SOURCES) $(lib_test_checksum_SOURCES) \
+ $(lib_test_heavy_SOURCES) $(lib_test_heavy_thread_SOURCES) \
+ $(lib_test_heavy_wq_SOURCES) $(lib_test_memory_SOURCES) \
+ $(lib_test_nexthop_iter_SOURCES) $(lib_test_privs_SOURCES) \
+ $(lib_test_ringbuf_SOURCES) $(lib_test_segv_SOURCES) \
+ $(lib_test_sig_SOURCES) $(lib_test_srcdest_table_SOURCES) \
+ $(lib_test_stream_SOURCES) $(lib_test_table_SOURCES) \
+ $(lib_test_timer_correctness_SOURCES) \
+ $(lib_test_timer_performance_SOURCES) \
+ $(lib_test_ttable_SOURCES) $(lib_test_zmq_SOURCES) \
+ $(ospf6d_test_lsdb_SOURCES)
+DIST_SOURCES = $(bgpd_test_aspath_SOURCES) \
+ $(bgpd_test_capability_SOURCES) \
+ $(bgpd_test_ecommunity_SOURCES) $(bgpd_test_mp_attr_SOURCES) \
+ $(bgpd_test_mpath_SOURCES) $(bgpd_test_packet_SOURCES) \
+ $(isisd_test_fuzz_isis_tlv_SOURCES) \
+ $(isisd_test_isis_vertex_queue_SOURCES) \
+ $(lib_cli_test_cli_SOURCES) $(lib_cli_test_commands_SOURCES) \
+ $(lib_test_buffer_SOURCES) $(lib_test_checksum_SOURCES) \
+ $(lib_test_heavy_SOURCES) $(lib_test_heavy_thread_SOURCES) \
+ $(lib_test_heavy_wq_SOURCES) $(lib_test_memory_SOURCES) \
+ $(lib_test_nexthop_iter_SOURCES) $(lib_test_privs_SOURCES) \
+ $(lib_test_ringbuf_SOURCES) $(lib_test_segv_SOURCES) \
+ $(lib_test_sig_SOURCES) $(lib_test_srcdest_table_SOURCES) \
+ $(lib_test_stream_SOURCES) $(lib_test_table_SOURCES) \
+ $(lib_test_timer_correctness_SOURCES) \
+ $(lib_test_timer_performance_SOURCES) \
+ $(lib_test_ttable_SOURCES) $(lib_test_zmq_SOURCES) \
+ $(ospf6d_test_lsdb_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/../common.am $(srcdir)/Makefile.in \
+ $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BGPD = @BGPD@
+BISON_CLOSEBRACE = @BISON_CLOSEBRACE@
+BISON_OPENBRACE = @BISON_OPENBRACE@
+BISON_VERBOSE = @BISON_VERBOSE@
+CARES_CFLAGS = @CARES_CFLAGS@
+CARES_LIBS = @CARES_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFG_MODULE = @CFG_MODULE@
+CFG_SBIN = @CFG_SBIN@
+CFG_STATE = @CFG_STATE@
+CFG_SYSCONF = @CFG_SYSCONF@
+CFLAGS = @CFLAGS@
+CONFDATE = @CONFDATE@
+CONFIG_ARGS = @CONFIG_ARGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CURSES = @CURSES@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@ $(LOCAL_OPTS) -DSYSCONFDIR=\"$(sysconfdir)/\"
+DEPDIR = @DEPDIR@
+DFLT_NAME = @DFLT_NAME@
+DLLTOOL = @DLLTOOL@
+DOC = @DOC@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+HAVE_LIBPCREPOSIX = @HAVE_LIBPCREPOSIX@
+HOSTTOOLS = @HOSTTOOLS@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCAP = @LIBCAP@
+LIBM = @LIBM@
+LIBOBJS = @LIBOBJS@
+LIBPAM = @LIBPAM@
+LIBREADLINE = @LIBREADLINE@
+LIBRFP = @LIBRFP@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NETSNMP_CONFIG = @NETSNMP_CONFIG@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_EXTRAVERSION = @PACKAGE_EXTRAVERSION@
+PACKAGE_FULLNAME = @PACKAGE_FULLNAME@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PROTOBUF_C_CFLAGS = @PROTOBUF_C_CFLAGS@
+PROTOBUF_C_LIBS = @PROTOBUF_C_LIBS@
+PROTOC_C = @PROTOC_C@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+PYTHONCONFIG = @PYTHONCONFIG@
+PYTHON_CFLAGS = @PYTHON_CFLAGS@
+PYTHON_LIBS = @PYTHON_LIBS@
+RANLIB = @RANLIB@
+RFPINC = @RFPINC@
+RFPTEST = @RFPTEST@
+RTRLIB_CFLAGS = @RTRLIB_CFLAGS@
+RTRLIB_LIBS = @RTRLIB_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SNMP_CFLAGS = @SNMP_CFLAGS@
+SNMP_LIBS = @SNMP_LIBS@
+SOLARIS = @SOLARIS@
+STRIP = @STRIP@
+VERSION = @VERSION@
+VNC_RFP_PATH = @VNC_RFP_PATH@
+VTYSH = @VTYSH@
+WERROR = @WERROR@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+ZEROMQ_CFLAGS = @ZEROMQ_CFLAGS@
+ZEROMQ_LIBS = @ZEROMQ_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_ct_PYTHONCONFIG = @ac_ct_PYTHONCONFIG@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+ax_pthread_config = @ax_pthread_config@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+enable_group = @enable_group@
+enable_user = @enable_user@
+enable_vty_group = @enable_vty_group@
+exampledir = @exampledir@
+exec_prefix = @exec_prefix@
+frr_statedir = @frr_statedir@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgsrcrcdir = @pkgsrcrcdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AM_V_CLIPPY = $(am__v_CLIPPY_$(V))
+am__v_CLIPPY_ = $(am__v_CLIPPY_$(AM_DEFAULT_VERBOSITY))
+am__v_CLIPPY_0 = @echo " CLIPPY " $@;
+am__v_CLIPPY_1 =
+CLIPPY_DEPS = $(HOSTTOOLS)lib/clippy $(top_srcdir)/python/clidef.py
+SUFFIXES = _clippy.c .proto .pb-c.c .pb-c.h .pb.h
+
+# Uncomment to use an non-system version of libprotobuf-c.
+#
+# Q_PROTOBUF_C_CLIENT_INCLUDES = -I$(top_srcdir)/third-party/protobuf-c/src
+# Q_PROTOBUF_C_CLIENT_LDOPTS = $(top_builddir)/third-party/protobuf-c/src/libprotobuf-c.la
+@HAVE_PROTOBUF_TRUE@Q_PROTOBUF_C_CLIENT_INCLUDES =
+@HAVE_PROTOBUF_TRUE@Q_PROTOBUF_C_CLIENT_LDOPTS = -lprotobuf-c
+@HAVE_PROTOBUF_TRUE@Q_PROTOC = protoc
+@HAVE_PROTOBUF_TRUE@Q_PROTOC_C = protoc-c
+@HAVE_PROTOBUF_TRUE@AM_V_PROTOC_C = $(am__v_PROTOC_C_$(V))
+@HAVE_PROTOBUF_TRUE@am__v_PROTOC_C_ = $(am__v_PROTOC_C_$(AM_DEFAULT_VERBOSITY))
+@HAVE_PROTOBUF_TRUE@am__v_PROTOC_C_0 = @echo " PROTOC_C" $@;
+@HAVE_PROTOBUF_TRUE@am__v_PROTOC_C_1 =
+
+#
+# Information about how to link to various libraries.
+#
+@HAVE_PROTOBUF_TRUE@Q_FRR_PB_CLIENT_LDOPTS = $(top_srcdir)/qpb/libfrr_pb.la $(Q_PROTOBUF_C_CLIENT_LDOPTS)
+@HAVE_PROTOBUF_TRUE@Q_FPM_PB_CLIENT_LDOPTS = $(top_srcdir)/fpm/libfrrfpm_pb.la $(Q_FRR_PB_CLIENT_LDOPTS)
+AUTOMAKE_OPTIONS = subdir-objects
+AM_CPPFLAGS = \
+ -I.. \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/lib \
+ -I$(top_builddir)/lib \
+ -I$(top_srcdir)/tests/helpers/c \
+ -I$(top_builddir)/tests/helpers/c \
+ -O
+
+@BGPD_FALSE@TESTS_BGPD =
+@BGPD_TRUE@TESTS_BGPD = \
+@BGPD_TRUE@ bgpd/test_aspath \
+@BGPD_TRUE@ bgpd/test_capability \
+@BGPD_TRUE@ bgpd/test_packet \
+@BGPD_TRUE@ bgpd/test_ecommunity \
+@BGPD_TRUE@ bgpd/test_mp_attr \
+@BGPD_TRUE@ bgpd/test_mpath
+
+@ISISD_FALSE@TESTS_ISISD =
+@ISISD_TRUE@@SOLARIS_FALSE@TESTS_ISISD = \
+@ISISD_TRUE@@SOLARIS_FALSE@ isisd/test_fuzz_isis_tlv \
+@ISISD_TRUE@@SOLARIS_FALSE@ isisd/test_isis_vertex_queue \
+@ISISD_TRUE@@SOLARIS_FALSE@ # end
+
+@ISISD_TRUE@@SOLARIS_TRUE@TESTS_ISISD =
+@OSPF6D_FALSE@TESTS_OSPF6D =
+@OSPF6D_TRUE@TESTS_OSPF6D = \
+@OSPF6D_TRUE@ ospf6d/test_lsdb \
+@OSPF6D_TRUE@ # end
+
+@ENABLE_BGP_VNC_FALSE@BGP_VNC_RFP_LIB =
+@ENABLE_BGP_VNC_TRUE@BGP_VNC_RFP_LIB = @top_builddir@/$(LIBRFP)/librfp.a
+noinst_HEADERS = \
+ ./helpers/c/prng.h \
+ ./helpers/c/tests.h \
+ ./lib/cli/common_cli.h
+
+lib_test_buffer_SOURCES = lib/test_buffer.c
+lib_test_checksum_SOURCES = lib/test_checksum.c
+lib_test_heavy_thread_SOURCES = lib/test_heavy_thread.c helpers/c/main.c
+lib_test_heavy_wq_SOURCES = lib/test_heavy_wq.c helpers/c/main.c
+lib_test_heavy_SOURCES = lib/test_heavy.c helpers/c/main.c
+lib_test_memory_SOURCES = lib/test_memory.c
+lib_test_nexthop_iter_SOURCES = lib/test_nexthop_iter.c helpers/c/prng.c
+lib_test_privs_SOURCES = lib/test_privs.c
+lib_test_srcdest_table_SOURCES = lib/test_srcdest_table.c \
+ helpers/c/prng.c
+
+lib_test_ringbuf_SOURCES = lib/test_ringbuf.c
+lib_test_segv_SOURCES = lib/test_segv.c
+lib_test_sig_SOURCES = lib/test_sig.c
+lib_test_stream_SOURCES = lib/test_stream.c
+lib_test_table_SOURCES = lib/test_table.c
+lib_test_timer_correctness_SOURCES = lib/test_timer_correctness.c \
+ helpers/c/prng.c
+
+lib_test_timer_performance_SOURCES = lib/test_timer_performance.c \
+ helpers/c/prng.c
+
+lib_test_ttable_SOURCES = lib/test_ttable.c
+lib_test_zmq_SOURCES = lib/test_zmq.c
+lib_test_zmq_CFLAGS = $(AM_CFLAGS) $(ZEROMQ_CFLAGS)
+lib_cli_test_cli_SOURCES = lib/cli/test_cli.c lib/cli/common_cli.c
+lib_cli_test_commands_SOURCES = lib/cli/test_commands_defun.c \
+ lib/cli/test_commands.c \
+ helpers/c/prng.c
+
+bgpd_test_aspath_SOURCES = bgpd/test_aspath.c
+bgpd_test_capability_SOURCES = bgpd/test_capability.c
+bgpd_test_packet_SOURCES = bgpd/test_packet.c
+bgpd_test_ecommunity_SOURCES = bgpd/test_ecommunity.c
+bgpd_test_mp_attr_SOURCES = bgpd/test_mp_attr.c
+bgpd_test_mpath_SOURCES = bgpd/test_mpath.c
+isisd_test_fuzz_isis_tlv_SOURCES = isisd/test_fuzz_isis_tlv.c
+isisd_test_fuzz_isis_tlv_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_builddir)/tests/isisd
+isisd_test_isis_vertex_queue_SOURCES = isisd/test_isis_vertex_queue.c
+ospf6d_test_lsdb_SOURCES = ospf6d/test_lsdb.c lib/cli/common_cli.c
+ALL_TESTS_LDADD = ../lib/libfrr.la @LIBCAP@
+BGP_TEST_LDADD = ../bgpd/libbgp.a $(BGP_VNC_RFP_LIB) $(ALL_TESTS_LDADD) -lm
+ISISD_TEST_LDADD = ../isisd/libisis.a $(ALL_TESTS_LDADD)
+OSPF6_TEST_LDADD = ../ospf6d/libospf6.a $(ALL_TESTS_LDADD)
+lib_test_buffer_LDADD = $(ALL_TESTS_LDADD)
+lib_test_checksum_LDADD = $(ALL_TESTS_LDADD)
+lib_test_heavy_thread_LDADD = $(ALL_TESTS_LDADD) -lm
+lib_test_heavy_wq_LDADD = $(ALL_TESTS_LDADD) -lm
+lib_test_heavy_LDADD = $(ALL_TESTS_LDADD) -lm
+lib_test_memory_LDADD = $(ALL_TESTS_LDADD)
+lib_test_nexthop_iter_LDADD = $(ALL_TESTS_LDADD)
+lib_test_privs_LDADD = $(ALL_TESTS_LDADD)
+lib_test_ringbuf_LDADD = $(ALL_TESTS_LDADD)
+lib_test_srcdest_table_LDADD = $(ALL_TESTS_LDADD)
+lib_test_segv_LDADD = $(ALL_TESTS_LDADD)
+lib_test_sig_LDADD = $(ALL_TESTS_LDADD)
+lib_test_stream_LDADD = $(ALL_TESTS_LDADD)
+lib_test_table_LDADD = $(ALL_TESTS_LDADD) -lm
+lib_test_timer_correctness_LDADD = $(ALL_TESTS_LDADD)
+lib_test_timer_performance_LDADD = $(ALL_TESTS_LDADD)
+lib_test_ttable_LDADD = $(ALL_TESTS_LDADD)
+lib_test_zmq_LDADD = ../lib/libfrrzmq.la $(ALL_TESTS_LDADD) $(ZEROMQ_LIBS)
+lib_cli_test_cli_LDADD = $(ALL_TESTS_LDADD)
+lib_cli_test_commands_LDADD = $(ALL_TESTS_LDADD)
+bgpd_test_aspath_LDADD = $(BGP_TEST_LDADD)
+bgpd_test_capability_LDADD = $(BGP_TEST_LDADD)
+bgpd_test_packet_LDADD = $(BGP_TEST_LDADD)
+bgpd_test_ecommunity_LDADD = $(BGP_TEST_LDADD)
+bgpd_test_mp_attr_LDADD = $(BGP_TEST_LDADD)
+bgpd_test_mpath_LDADD = $(BGP_TEST_LDADD)
+isisd_test_fuzz_isis_tlv_LDADD = $(ISISD_TEST_LDADD)
+isisd_test_isis_vertex_queue_LDADD = $(ISISD_TEST_LDADD)
+ospf6d_test_lsdb_LDADD = $(OSPF6_TEST_LDADD)
+EXTRA_DIST = \
+ runtests.py \
+ bgpd/test_aspath.py \
+ bgpd/test_capability.py \
+ bgpd/test_ecommunity.py \
+ bgpd/test_mp_attr.py \
+ bgpd/test_mpath.py \
+ helpers/python/frrsix.py \
+ helpers/python/frrtest.py \
+ isisd/test_fuzz_isis_tlv.py \
+ isisd/test_fuzz_isis_tlv_tests.h.gz \
+ isisd/test_isis_vertex_queue.py \
+ lib/cli/test_commands.in \
+ lib/cli/test_commands.py \
+ lib/cli/test_commands.refout \
+ lib/cli/test_cli.in \
+ lib/cli/test_cli.py \
+ lib/cli/test_cli.refout \
+ lib/test_nexthop_iter.py \
+ lib/test_ringbuf.py \
+ lib/test_srcdest_table.py \
+ lib/test_stream.py \
+ lib/test_stream.refout \
+ lib/test_table.py \
+ lib/test_timer_correctness.py \
+ lib/test_ttable.py \
+ lib/test_ttable.refout \
+ ospf6d/test_lsdb.py \
+ ospf6d/test_lsdb.in \
+ ospf6d/test_lsdb.refout \
+ # end
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: _clippy.c .proto .pb-c.c .pb-c.h .pb.h .c .l .lo .o .obj .y
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(srcdir)/../common.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu tests/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu tests/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+$(srcdir)/../common.am $(am__empty):
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-checkPROGRAMS:
+ @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+bgpd/$(am__dirstamp):
+ @$(MKDIR_P) bgpd
+ @: > bgpd/$(am__dirstamp)
+bgpd/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) bgpd/$(DEPDIR)
+ @: > bgpd/$(DEPDIR)/$(am__dirstamp)
+bgpd/test_aspath.$(OBJEXT): bgpd/$(am__dirstamp) \
+ bgpd/$(DEPDIR)/$(am__dirstamp)
+
+bgpd/test_aspath$(EXEEXT): $(bgpd_test_aspath_OBJECTS) $(bgpd_test_aspath_DEPENDENCIES) $(EXTRA_bgpd_test_aspath_DEPENDENCIES) bgpd/$(am__dirstamp)
+ @rm -f bgpd/test_aspath$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(bgpd_test_aspath_OBJECTS) $(bgpd_test_aspath_LDADD) $(LIBS)
+bgpd/test_capability.$(OBJEXT): bgpd/$(am__dirstamp) \
+ bgpd/$(DEPDIR)/$(am__dirstamp)
+
+bgpd/test_capability$(EXEEXT): $(bgpd_test_capability_OBJECTS) $(bgpd_test_capability_DEPENDENCIES) $(EXTRA_bgpd_test_capability_DEPENDENCIES) bgpd/$(am__dirstamp)
+ @rm -f bgpd/test_capability$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(bgpd_test_capability_OBJECTS) $(bgpd_test_capability_LDADD) $(LIBS)
+bgpd/test_ecommunity.$(OBJEXT): bgpd/$(am__dirstamp) \
+ bgpd/$(DEPDIR)/$(am__dirstamp)
+
+bgpd/test_ecommunity$(EXEEXT): $(bgpd_test_ecommunity_OBJECTS) $(bgpd_test_ecommunity_DEPENDENCIES) $(EXTRA_bgpd_test_ecommunity_DEPENDENCIES) bgpd/$(am__dirstamp)
+ @rm -f bgpd/test_ecommunity$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(bgpd_test_ecommunity_OBJECTS) $(bgpd_test_ecommunity_LDADD) $(LIBS)
+bgpd/test_mp_attr.$(OBJEXT): bgpd/$(am__dirstamp) \
+ bgpd/$(DEPDIR)/$(am__dirstamp)
+
+bgpd/test_mp_attr$(EXEEXT): $(bgpd_test_mp_attr_OBJECTS) $(bgpd_test_mp_attr_DEPENDENCIES) $(EXTRA_bgpd_test_mp_attr_DEPENDENCIES) bgpd/$(am__dirstamp)
+ @rm -f bgpd/test_mp_attr$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(bgpd_test_mp_attr_OBJECTS) $(bgpd_test_mp_attr_LDADD) $(LIBS)
+bgpd/test_mpath.$(OBJEXT): bgpd/$(am__dirstamp) \
+ bgpd/$(DEPDIR)/$(am__dirstamp)
+
+bgpd/test_mpath$(EXEEXT): $(bgpd_test_mpath_OBJECTS) $(bgpd_test_mpath_DEPENDENCIES) $(EXTRA_bgpd_test_mpath_DEPENDENCIES) bgpd/$(am__dirstamp)
+ @rm -f bgpd/test_mpath$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(bgpd_test_mpath_OBJECTS) $(bgpd_test_mpath_LDADD) $(LIBS)
+bgpd/test_packet.$(OBJEXT): bgpd/$(am__dirstamp) \
+ bgpd/$(DEPDIR)/$(am__dirstamp)
+
+bgpd/test_packet$(EXEEXT): $(bgpd_test_packet_OBJECTS) $(bgpd_test_packet_DEPENDENCIES) $(EXTRA_bgpd_test_packet_DEPENDENCIES) bgpd/$(am__dirstamp)
+ @rm -f bgpd/test_packet$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(bgpd_test_packet_OBJECTS) $(bgpd_test_packet_LDADD) $(LIBS)
+isisd/$(am__dirstamp):
+ @$(MKDIR_P) isisd
+ @: > isisd/$(am__dirstamp)
+isisd/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) isisd/$(DEPDIR)
+ @: > isisd/$(DEPDIR)/$(am__dirstamp)
+isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.$(OBJEXT): \
+ isisd/$(am__dirstamp) isisd/$(DEPDIR)/$(am__dirstamp)
+
+isisd/test_fuzz_isis_tlv$(EXEEXT): $(isisd_test_fuzz_isis_tlv_OBJECTS) $(isisd_test_fuzz_isis_tlv_DEPENDENCIES) $(EXTRA_isisd_test_fuzz_isis_tlv_DEPENDENCIES) isisd/$(am__dirstamp)
+ @rm -f isisd/test_fuzz_isis_tlv$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(isisd_test_fuzz_isis_tlv_OBJECTS) $(isisd_test_fuzz_isis_tlv_LDADD) $(LIBS)
+isisd/test_isis_vertex_queue.$(OBJEXT): isisd/$(am__dirstamp) \
+ isisd/$(DEPDIR)/$(am__dirstamp)
+
+isisd/test_isis_vertex_queue$(EXEEXT): $(isisd_test_isis_vertex_queue_OBJECTS) $(isisd_test_isis_vertex_queue_DEPENDENCIES) $(EXTRA_isisd_test_isis_vertex_queue_DEPENDENCIES) isisd/$(am__dirstamp)
+ @rm -f isisd/test_isis_vertex_queue$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(isisd_test_isis_vertex_queue_OBJECTS) $(isisd_test_isis_vertex_queue_LDADD) $(LIBS)
+lib/cli/$(am__dirstamp):
+ @$(MKDIR_P) lib/cli
+ @: > lib/cli/$(am__dirstamp)
+lib/cli/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) lib/cli/$(DEPDIR)
+ @: > lib/cli/$(DEPDIR)/$(am__dirstamp)
+lib/cli/test_cli.$(OBJEXT): lib/cli/$(am__dirstamp) \
+ lib/cli/$(DEPDIR)/$(am__dirstamp)
+lib/cli/common_cli.$(OBJEXT): lib/cli/$(am__dirstamp) \
+ lib/cli/$(DEPDIR)/$(am__dirstamp)
+
+lib/cli/test_cli$(EXEEXT): $(lib_cli_test_cli_OBJECTS) $(lib_cli_test_cli_DEPENDENCIES) $(EXTRA_lib_cli_test_cli_DEPENDENCIES) lib/cli/$(am__dirstamp)
+ @rm -f lib/cli/test_cli$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(lib_cli_test_cli_OBJECTS) $(lib_cli_test_cli_LDADD) $(LIBS)
+lib/cli/test_commands_defun.$(OBJEXT): lib/cli/$(am__dirstamp) \
+ lib/cli/$(DEPDIR)/$(am__dirstamp)
+lib/cli/test_commands.$(OBJEXT): lib/cli/$(am__dirstamp) \
+ lib/cli/$(DEPDIR)/$(am__dirstamp)
+helpers/c/$(am__dirstamp):
+ @$(MKDIR_P) helpers/c
+ @: > helpers/c/$(am__dirstamp)
+helpers/c/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) helpers/c/$(DEPDIR)
+ @: > helpers/c/$(DEPDIR)/$(am__dirstamp)
+helpers/c/prng.$(OBJEXT): helpers/c/$(am__dirstamp) \
+ helpers/c/$(DEPDIR)/$(am__dirstamp)
+
+lib/cli/test_commands$(EXEEXT): $(lib_cli_test_commands_OBJECTS) $(lib_cli_test_commands_DEPENDENCIES) $(EXTRA_lib_cli_test_commands_DEPENDENCIES) lib/cli/$(am__dirstamp)
+ @rm -f lib/cli/test_commands$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(lib_cli_test_commands_OBJECTS) $(lib_cli_test_commands_LDADD) $(LIBS)
+lib/$(am__dirstamp):
+ @$(MKDIR_P) lib
+ @: > lib/$(am__dirstamp)
+lib/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) lib/$(DEPDIR)
+ @: > lib/$(DEPDIR)/$(am__dirstamp)
+lib/test_buffer.$(OBJEXT): lib/$(am__dirstamp) \
+ lib/$(DEPDIR)/$(am__dirstamp)
+
+lib/test_buffer$(EXEEXT): $(lib_test_buffer_OBJECTS) $(lib_test_buffer_DEPENDENCIES) $(EXTRA_lib_test_buffer_DEPENDENCIES) lib/$(am__dirstamp)
+ @rm -f lib/test_buffer$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(lib_test_buffer_OBJECTS) $(lib_test_buffer_LDADD) $(LIBS)
+lib/test_checksum.$(OBJEXT): lib/$(am__dirstamp) \
+ lib/$(DEPDIR)/$(am__dirstamp)
+
+lib/test_checksum$(EXEEXT): $(lib_test_checksum_OBJECTS) $(lib_test_checksum_DEPENDENCIES) $(EXTRA_lib_test_checksum_DEPENDENCIES) lib/$(am__dirstamp)
+ @rm -f lib/test_checksum$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(lib_test_checksum_OBJECTS) $(lib_test_checksum_LDADD) $(LIBS)
+lib/test_heavy.$(OBJEXT): lib/$(am__dirstamp) \
+ lib/$(DEPDIR)/$(am__dirstamp)
+helpers/c/main.$(OBJEXT): helpers/c/$(am__dirstamp) \
+ helpers/c/$(DEPDIR)/$(am__dirstamp)
+
+lib/test_heavy$(EXEEXT): $(lib_test_heavy_OBJECTS) $(lib_test_heavy_DEPENDENCIES) $(EXTRA_lib_test_heavy_DEPENDENCIES) lib/$(am__dirstamp)
+ @rm -f lib/test_heavy$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(lib_test_heavy_OBJECTS) $(lib_test_heavy_LDADD) $(LIBS)
+lib/test_heavy_thread.$(OBJEXT): lib/$(am__dirstamp) \
+ lib/$(DEPDIR)/$(am__dirstamp)
+
+lib/test_heavy_thread$(EXEEXT): $(lib_test_heavy_thread_OBJECTS) $(lib_test_heavy_thread_DEPENDENCIES) $(EXTRA_lib_test_heavy_thread_DEPENDENCIES) lib/$(am__dirstamp)
+ @rm -f lib/test_heavy_thread$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(lib_test_heavy_thread_OBJECTS) $(lib_test_heavy_thread_LDADD) $(LIBS)
+lib/test_heavy_wq.$(OBJEXT): lib/$(am__dirstamp) \
+ lib/$(DEPDIR)/$(am__dirstamp)
+
+lib/test_heavy_wq$(EXEEXT): $(lib_test_heavy_wq_OBJECTS) $(lib_test_heavy_wq_DEPENDENCIES) $(EXTRA_lib_test_heavy_wq_DEPENDENCIES) lib/$(am__dirstamp)
+ @rm -f lib/test_heavy_wq$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(lib_test_heavy_wq_OBJECTS) $(lib_test_heavy_wq_LDADD) $(LIBS)
+lib/test_memory.$(OBJEXT): lib/$(am__dirstamp) \
+ lib/$(DEPDIR)/$(am__dirstamp)
+
+lib/test_memory$(EXEEXT): $(lib_test_memory_OBJECTS) $(lib_test_memory_DEPENDENCIES) $(EXTRA_lib_test_memory_DEPENDENCIES) lib/$(am__dirstamp)
+ @rm -f lib/test_memory$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(lib_test_memory_OBJECTS) $(lib_test_memory_LDADD) $(LIBS)
+lib/test_nexthop_iter.$(OBJEXT): lib/$(am__dirstamp) \
+ lib/$(DEPDIR)/$(am__dirstamp)
+
+lib/test_nexthop_iter$(EXEEXT): $(lib_test_nexthop_iter_OBJECTS) $(lib_test_nexthop_iter_DEPENDENCIES) $(EXTRA_lib_test_nexthop_iter_DEPENDENCIES) lib/$(am__dirstamp)
+ @rm -f lib/test_nexthop_iter$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(lib_test_nexthop_iter_OBJECTS) $(lib_test_nexthop_iter_LDADD) $(LIBS)
+lib/test_privs.$(OBJEXT): lib/$(am__dirstamp) \
+ lib/$(DEPDIR)/$(am__dirstamp)
+
+lib/test_privs$(EXEEXT): $(lib_test_privs_OBJECTS) $(lib_test_privs_DEPENDENCIES) $(EXTRA_lib_test_privs_DEPENDENCIES) lib/$(am__dirstamp)
+ @rm -f lib/test_privs$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(lib_test_privs_OBJECTS) $(lib_test_privs_LDADD) $(LIBS)
+lib/test_ringbuf.$(OBJEXT): lib/$(am__dirstamp) \
+ lib/$(DEPDIR)/$(am__dirstamp)
+
+lib/test_ringbuf$(EXEEXT): $(lib_test_ringbuf_OBJECTS) $(lib_test_ringbuf_DEPENDENCIES) $(EXTRA_lib_test_ringbuf_DEPENDENCIES) lib/$(am__dirstamp)
+ @rm -f lib/test_ringbuf$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(lib_test_ringbuf_OBJECTS) $(lib_test_ringbuf_LDADD) $(LIBS)
+lib/test_segv.$(OBJEXT): lib/$(am__dirstamp) \
+ lib/$(DEPDIR)/$(am__dirstamp)
+
+lib/test_segv$(EXEEXT): $(lib_test_segv_OBJECTS) $(lib_test_segv_DEPENDENCIES) $(EXTRA_lib_test_segv_DEPENDENCIES) lib/$(am__dirstamp)
+ @rm -f lib/test_segv$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(lib_test_segv_OBJECTS) $(lib_test_segv_LDADD) $(LIBS)
+lib/test_sig.$(OBJEXT): lib/$(am__dirstamp) \
+ lib/$(DEPDIR)/$(am__dirstamp)
+
+lib/test_sig$(EXEEXT): $(lib_test_sig_OBJECTS) $(lib_test_sig_DEPENDENCIES) $(EXTRA_lib_test_sig_DEPENDENCIES) lib/$(am__dirstamp)
+ @rm -f lib/test_sig$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(lib_test_sig_OBJECTS) $(lib_test_sig_LDADD) $(LIBS)
+lib/test_srcdest_table.$(OBJEXT): lib/$(am__dirstamp) \
+ lib/$(DEPDIR)/$(am__dirstamp)
+
+lib/test_srcdest_table$(EXEEXT): $(lib_test_srcdest_table_OBJECTS) $(lib_test_srcdest_table_DEPENDENCIES) $(EXTRA_lib_test_srcdest_table_DEPENDENCIES) lib/$(am__dirstamp)
+ @rm -f lib/test_srcdest_table$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(lib_test_srcdest_table_OBJECTS) $(lib_test_srcdest_table_LDADD) $(LIBS)
+lib/test_stream.$(OBJEXT): lib/$(am__dirstamp) \
+ lib/$(DEPDIR)/$(am__dirstamp)
+
+lib/test_stream$(EXEEXT): $(lib_test_stream_OBJECTS) $(lib_test_stream_DEPENDENCIES) $(EXTRA_lib_test_stream_DEPENDENCIES) lib/$(am__dirstamp)
+ @rm -f lib/test_stream$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(lib_test_stream_OBJECTS) $(lib_test_stream_LDADD) $(LIBS)
+lib/test_table.$(OBJEXT): lib/$(am__dirstamp) \
+ lib/$(DEPDIR)/$(am__dirstamp)
+
+lib/test_table$(EXEEXT): $(lib_test_table_OBJECTS) $(lib_test_table_DEPENDENCIES) $(EXTRA_lib_test_table_DEPENDENCIES) lib/$(am__dirstamp)
+ @rm -f lib/test_table$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(lib_test_table_OBJECTS) $(lib_test_table_LDADD) $(LIBS)
+lib/test_timer_correctness.$(OBJEXT): lib/$(am__dirstamp) \
+ lib/$(DEPDIR)/$(am__dirstamp)
+
+lib/test_timer_correctness$(EXEEXT): $(lib_test_timer_correctness_OBJECTS) $(lib_test_timer_correctness_DEPENDENCIES) $(EXTRA_lib_test_timer_correctness_DEPENDENCIES) lib/$(am__dirstamp)
+ @rm -f lib/test_timer_correctness$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(lib_test_timer_correctness_OBJECTS) $(lib_test_timer_correctness_LDADD) $(LIBS)
+lib/test_timer_performance.$(OBJEXT): lib/$(am__dirstamp) \
+ lib/$(DEPDIR)/$(am__dirstamp)
+
+lib/test_timer_performance$(EXEEXT): $(lib_test_timer_performance_OBJECTS) $(lib_test_timer_performance_DEPENDENCIES) $(EXTRA_lib_test_timer_performance_DEPENDENCIES) lib/$(am__dirstamp)
+ @rm -f lib/test_timer_performance$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(lib_test_timer_performance_OBJECTS) $(lib_test_timer_performance_LDADD) $(LIBS)
+lib/test_ttable.$(OBJEXT): lib/$(am__dirstamp) \
+ lib/$(DEPDIR)/$(am__dirstamp)
+
+lib/test_ttable$(EXEEXT): $(lib_test_ttable_OBJECTS) $(lib_test_ttable_DEPENDENCIES) $(EXTRA_lib_test_ttable_DEPENDENCIES) lib/$(am__dirstamp)
+ @rm -f lib/test_ttable$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(lib_test_ttable_OBJECTS) $(lib_test_ttable_LDADD) $(LIBS)
+lib/lib_test_zmq-test_zmq.$(OBJEXT): lib/$(am__dirstamp) \
+ lib/$(DEPDIR)/$(am__dirstamp)
+
+lib/test_zmq$(EXEEXT): $(lib_test_zmq_OBJECTS) $(lib_test_zmq_DEPENDENCIES) $(EXTRA_lib_test_zmq_DEPENDENCIES) lib/$(am__dirstamp)
+ @rm -f lib/test_zmq$(EXEEXT)
+ $(AM_V_CCLD)$(lib_test_zmq_LINK) $(lib_test_zmq_OBJECTS) $(lib_test_zmq_LDADD) $(LIBS)
+ospf6d/$(am__dirstamp):
+ @$(MKDIR_P) ospf6d
+ @: > ospf6d/$(am__dirstamp)
+ospf6d/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) ospf6d/$(DEPDIR)
+ @: > ospf6d/$(DEPDIR)/$(am__dirstamp)
+ospf6d/test_lsdb.$(OBJEXT): ospf6d/$(am__dirstamp) \
+ ospf6d/$(DEPDIR)/$(am__dirstamp)
+
+ospf6d/test_lsdb$(EXEEXT): $(ospf6d_test_lsdb_OBJECTS) $(ospf6d_test_lsdb_DEPENDENCIES) $(EXTRA_ospf6d_test_lsdb_DEPENDENCIES) ospf6d/$(am__dirstamp)
+ @rm -f ospf6d/test_lsdb$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(ospf6d_test_lsdb_OBJECTS) $(ospf6d_test_lsdb_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+ -rm -f bgpd/*.$(OBJEXT)
+ -rm -f helpers/c/*.$(OBJEXT)
+ -rm -f isisd/*.$(OBJEXT)
+ -rm -f lib/*.$(OBJEXT)
+ -rm -f lib/cli/*.$(OBJEXT)
+ -rm -f ospf6d/*.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@bgpd/$(DEPDIR)/test_aspath.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@bgpd/$(DEPDIR)/test_capability.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@bgpd/$(DEPDIR)/test_ecommunity.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@bgpd/$(DEPDIR)/test_mp_attr.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@bgpd/$(DEPDIR)/test_mpath.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@bgpd/$(DEPDIR)/test_packet.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@helpers/c/$(DEPDIR)/main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@helpers/c/$(DEPDIR)/prng.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@isisd/$(DEPDIR)/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@isisd/$(DEPDIR)/test_isis_vertex_queue.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/lib_test_zmq-test_zmq.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_buffer.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_checksum.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_heavy.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_heavy_thread.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_heavy_wq.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_memory.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_nexthop_iter.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_privs.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_ringbuf.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_segv.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_sig.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_srcdest_table.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_stream.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_table.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_timer_correctness.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_timer_performance.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/test_ttable.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/cli/$(DEPDIR)/common_cli.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/cli/$(DEPDIR)/test_cli.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/cli/$(DEPDIR)/test_commands.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/cli/$(DEPDIR)/test_commands_defun.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@ospf6d/$(DEPDIR)/test_lsdb.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.o: isisd/test_fuzz_isis_tlv.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(isisd_test_fuzz_isis_tlv_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.o -MD -MP -MF isisd/$(DEPDIR)/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.Tpo -c -o isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.o `test -f 'isisd/test_fuzz_isis_tlv.c' || echo '$(srcdir)/'`isisd/test_fuzz_isis_tlv.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) isisd/$(DEPDIR)/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.Tpo isisd/$(DEPDIR)/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='isisd/test_fuzz_isis_tlv.c' object='isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(isisd_test_fuzz_isis_tlv_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.o `test -f 'isisd/test_fuzz_isis_tlv.c' || echo '$(srcdir)/'`isisd/test_fuzz_isis_tlv.c
+
+isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.obj: isisd/test_fuzz_isis_tlv.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(isisd_test_fuzz_isis_tlv_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.obj -MD -MP -MF isisd/$(DEPDIR)/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.Tpo -c -o isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.obj `if test -f 'isisd/test_fuzz_isis_tlv.c'; then $(CYGPATH_W) 'isisd/test_fuzz_isis_tlv.c'; else $(CYGPATH_W) '$(srcdir)/isisd/test_fuzz_isis_tlv.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) isisd/$(DEPDIR)/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.Tpo isisd/$(DEPDIR)/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='isisd/test_fuzz_isis_tlv.c' object='isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(isisd_test_fuzz_isis_tlv_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.obj `if test -f 'isisd/test_fuzz_isis_tlv.c'; then $(CYGPATH_W) 'isisd/test_fuzz_isis_tlv.c'; else $(CYGPATH_W) '$(srcdir)/isisd/test_fuzz_isis_tlv.c'; fi`
+
+lib/lib_test_zmq-test_zmq.o: lib/test_zmq.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_test_zmq_CFLAGS) $(CFLAGS) -MT lib/lib_test_zmq-test_zmq.o -MD -MP -MF lib/$(DEPDIR)/lib_test_zmq-test_zmq.Tpo -c -o lib/lib_test_zmq-test_zmq.o `test -f 'lib/test_zmq.c' || echo '$(srcdir)/'`lib/test_zmq.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) lib/$(DEPDIR)/lib_test_zmq-test_zmq.Tpo lib/$(DEPDIR)/lib_test_zmq-test_zmq.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='lib/test_zmq.c' object='lib/lib_test_zmq-test_zmq.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_test_zmq_CFLAGS) $(CFLAGS) -c -o lib/lib_test_zmq-test_zmq.o `test -f 'lib/test_zmq.c' || echo '$(srcdir)/'`lib/test_zmq.c
+
+lib/lib_test_zmq-test_zmq.obj: lib/test_zmq.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_test_zmq_CFLAGS) $(CFLAGS) -MT lib/lib_test_zmq-test_zmq.obj -MD -MP -MF lib/$(DEPDIR)/lib_test_zmq-test_zmq.Tpo -c -o lib/lib_test_zmq-test_zmq.obj `if test -f 'lib/test_zmq.c'; then $(CYGPATH_W) 'lib/test_zmq.c'; else $(CYGPATH_W) '$(srcdir)/lib/test_zmq.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) lib/$(DEPDIR)/lib_test_zmq-test_zmq.Tpo lib/$(DEPDIR)/lib_test_zmq-test_zmq.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='lib/test_zmq.c' object='lib/lib_test_zmq-test_zmq.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_test_zmq_CFLAGS) $(CFLAGS) -c -o lib/lib_test_zmq-test_zmq.obj `if test -f 'lib/test_zmq.c'; then $(CYGPATH_W) 'lib/test_zmq.c'; else $(CYGPATH_W) '$(srcdir)/lib/test_zmq.c'; fi`
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+ -rm -rf bgpd/.libs bgpd/_libs
+ -rm -rf isisd/.libs isisd/_libs
+ -rm -rf lib/.libs lib/_libs
+ -rm -rf lib/cli/.libs lib/cli/_libs
+ -rm -rf ospf6d/.libs ospf6d/_libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+check: check-am
+all-am: Makefile $(HEADERS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+ -rm -f bgpd/$(DEPDIR)/$(am__dirstamp)
+ -rm -f bgpd/$(am__dirstamp)
+ -rm -f helpers/c/$(DEPDIR)/$(am__dirstamp)
+ -rm -f helpers/c/$(am__dirstamp)
+ -rm -f isisd/$(DEPDIR)/$(am__dirstamp)
+ -rm -f isisd/$(am__dirstamp)
+ -rm -f lib/$(DEPDIR)/$(am__dirstamp)
+ -rm -f lib/$(am__dirstamp)
+ -rm -f lib/cli/$(DEPDIR)/$(am__dirstamp)
+ -rm -f lib/cli/$(am__dirstamp)
+ -rm -f ospf6d/$(DEPDIR)/$(am__dirstamp)
+ -rm -f ospf6d/$(am__dirstamp)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf bgpd/$(DEPDIR) helpers/c/$(DEPDIR) isisd/$(DEPDIR) lib/$(DEPDIR) lib/cli/$(DEPDIR) ospf6d/$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf bgpd/$(DEPDIR) helpers/c/$(DEPDIR) isisd/$(DEPDIR) lib/$(DEPDIR) lib/cli/$(DEPDIR) ospf6d/$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: check-am install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean \
+ clean-checkPROGRAMS clean-generic clean-libtool cscopelist-am \
+ ctags ctags-am distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+.c_clippy.c:
+ @{ test -x $(top_builddir)/$(HOSTTOOLS)lib/clippy || $(MAKE) -C $(top_builddir)/$(HOSTTOOLS) lib/clippy; }
+ $(AM_V_CLIPPY)$(top_builddir)/$(HOSTTOOLS)lib/clippy $(top_srcdir)/python/clidef.py -o $@ $<
+
+.l.c:
+ $(AM_V_LEX)$(am__skiplex) $(LEXCOMPILE) $<
+.y.c:
+ $(AM_V_YACC)$(am__skipyacc) $(YACCCOMPILE) $<
+
+# Rules
+@HAVE_PROTOBUF_TRUE@.proto.pb.h:
+@HAVE_PROTOBUF_TRUE@ $(Q_PROTOC) -I$(top_srcdir) --cpp_out=$(top_srcdir) $(top_srcdir)/$^
+
+@HAVE_PROTOBUF_TRUE@.proto.pb-c.c:
+@HAVE_PROTOBUF_TRUE@ $(AM_V_PROTOC_C)$(Q_PROTOC_C) -I$(top_srcdir) --c_out=$(top_srcdir) $(top_srcdir)/$^
+@HAVE_PROTOBUF_TRUE@.pb-c.c.pb-c.h:
+@HAVE_PROTOBUF_TRUE@ @/bin/true
+
+PYTHON ?= python
+
+lib/cli/test_cli.o: lib/cli/test_cli_clippy.c
+ospf6d/test_lsdb.o: ospf6d/test_lsdb_clippy.c
+
+../vtysh/vtysh_cmd.c:
+ $(MAKE) -C ../vtysh vtysh_cmd.c
+
+lib/cli/test_commands_defun.c: ../vtysh/vtysh_cmd.c
+ sed \
+ -e 's/"vtysh\.h"/"tests.h"/' \
+ -e 's/vtysh_init_cmd/test_init_cmd/' \
+ -e 's/VTYSH_[A-Z][A-Z_0-9]*/0/g' \
+ < ../vtysh/vtysh_cmd.c \
+ > "$@"
+
+isisd/test_fuzz_isis_tlv_tests.h: $(top_srcdir)/tests/isisd/test_fuzz_isis_tlv_tests.h.gz
+ gzip -d < $(top_srcdir)/tests/isisd/test_fuzz_isis_tlv_tests.h.gz > "$@"
+isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.$(OBJEXT): \
+ isisd/test_fuzz_isis_tlv_tests.h
+
+.PHONY: tests.xml
+tests.xml: $(check_PROGRAMS)
+ $(PYTHON) $(srcdir)/runtests.py --junitxml=$@ -v $(srcdir)
+check: tests.xml
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/tests/lib/cxxcompat.c b/tests/lib/cxxcompat.c
new file mode 100644
index 0000000000..530468642e
--- /dev/null
+++ b/tests/lib/cxxcompat.c
@@ -0,0 +1,113 @@
+/*
+ * C++ compatibility compile-time smoketest
+ * Copyright (C) 2019 David Lamparter for NetDEF, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "lib/zebra.h"
+
+#include "lib/agg_table.h"
+#include "lib/bfd.h"
+#include "lib/bitfield.h"
+#include "lib/buffer.h"
+#include "lib/checksum.h"
+#include "lib/command.h"
+#include "lib/command_graph.h"
+#include "lib/command_match.h"
+#include "lib/compiler.h"
+#include "lib/csv.h"
+#include "lib/debug.h"
+#include "lib/distribute.h"
+#include "lib/event_counter.h"
+#include "lib/ferr.h"
+#include "lib/fifo.h"
+#include "lib/filter.h"
+#include "lib/frr_pthread.h"
+#include "lib/frratomic.h"
+#include "lib/frrstr.h"
+#include "lib/getopt.h"
+#include "lib/graph.h"
+#include "lib/hash.h"
+#include "lib/hook.h"
+#include "lib/id_alloc.h"
+#include "lib/if.h"
+#include "lib/if_rmap.h"
+#include "lib/imsg.h"
+#include "lib/ipaddr.h"
+#include "lib/jhash.h"
+#include "lib/json.h"
+#include "lib/keychain.h"
+#include "lib/lib_errors.h"
+#include "lib/libfrr.h"
+#include "lib/libospf.h"
+#include "lib/linklist.h"
+#include "lib/log.h"
+#include "lib/logicalrouter.h"
+#include "lib/md5.h"
+#include "lib/memory.h"
+#include "lib/memory_vty.h"
+#include "lib/mlag.h"
+#include "lib/module.h"
+#include "lib/monotime.h"
+#include "lib/mpls.h"
+#include "lib/network.h"
+#include "lib/nexthop.h"
+#include "lib/nexthop_group.h"
+#include "lib/northbound.h"
+#include "lib/northbound_cli.h"
+#include "lib/northbound_db.h"
+#include "lib/ns.h"
+#include "lib/openbsd-tree.h"
+#include "lib/pbr.h"
+#include "lib/plist.h"
+#include "lib/pqueue.h"
+#include "lib/prefix.h"
+#include "lib/privs.h"
+#include "lib/ptm_lib.h"
+#include "lib/pw.h"
+#include "lib/qobj.h"
+#include "lib/queue.h"
+#include "lib/ringbuf.h"
+#include "lib/routemap.h"
+#include "lib/sbuf.h"
+#include "lib/sha256.h"
+#include "lib/sigevent.h"
+#include "lib/skiplist.h"
+#include "lib/sockopt.h"
+#include "lib/sockunion.h"
+#include "lib/spf_backoff.h"
+#include "lib/srcdest_table.h"
+#include "lib/stream.h"
+#include "lib/table.h"
+#include "lib/termtable.h"
+#include "lib/thread.h"
+#include "lib/vector.h"
+#include "lib/vlan.h"
+#include "lib/vrf.h"
+#include "lib/vty.h"
+#include "lib/vxlan.h"
+#include "lib/wheel.h"
+/* #include "lib/workqueue.h" -- macro problem with STAILQ_LAST */
+#include "lib/yang.h"
+#include "lib/yang_translator.h"
+#include "lib/yang_wrappers.h"
+#include "lib/zassert.h"
+#include "lib/zclient.h"
+
+int main(int argc, char **argv)
+{
+ return 0;
+}
diff --git a/tests/subdir.am b/tests/subdir.am
index 7d2800a3a2..365fe00cc6 100644
--- a/tests/subdir.am
+++ b/tests/subdir.am
@@ -46,6 +46,7 @@ tests/ospf6d/tests_ospf6d_test_lsdb-test_lsdb.$(OBJEXT): tests/ospf6d/test_lsdb_
tests/ospf6d/test_lsdb-test_lsdb.$(OBJEXT): tests/ospf6d/test_lsdb_clippy.c
check_PROGRAMS = \
+ tests/lib/cxxcompat \
tests/lib/test_buffer \
tests/lib/test_checksum \
tests/lib/test_heavy_thread \
@@ -112,10 +113,13 @@ TESTS_CPPFLAGS = $(AM_CPPFLAGS) \
-I$(top_srcdir)/tests/helpers/c \
-I$(top_builddir)/tests/helpers/c \
# end
-TESTS_CFLAGS = $(SAN_FLAGS)
+TESTS_CFLAGS = \
+ $(LIBYANG_CFLAGS) \
+ $(SAN_FLAGS) \
+ # end
# note no -Werror
-ALL_TESTS_LDADD = lib/libfrr.la @LIBCAP@
+ALL_TESTS_LDADD = lib/libfrr.la $(LIBCAP)
BGP_TEST_LDADD = bgpd/libbgp.a $(RFPLDADD) $(ALL_TESTS_LDADD) -lm
ISISD_TEST_LDADD = isisd/libisis.a $(ALL_TESTS_LDADD)
OSPF6_TEST_LDADD = ospf6d/libospf6.a $(ALL_TESTS_LDADD)
@@ -167,6 +171,10 @@ tests_isisd_test_isis_vertex_queue_CPPFLAGS = $(TESTS_CPPFLAGS)
tests_isisd_test_isis_vertex_queue_LDADD = $(ISISD_TEST_LDADD)
tests_isisd_test_isis_vertex_queue_SOURCES = tests/isisd/test_isis_vertex_queue.c
+tests_lib_cxxcompat_CFLAGS = $(TESTS_CFLAGS) $(CXX_COMPAT_CFLAGS) $(WERROR)
+tests_lib_cxxcompat_CPPFLAGS = $(TESTS_CPPFLAGS)
+tests_lib_cxxcompat_SOURCES = tests/lib/cxxcompat.c
+tests_lib_cxxcompat_LDADD = $(ALL_TESTS_LDADD)
tests_lib_cli_test_cli_CFLAGS = $(TESTS_CFLAGS)
tests_lib_cli_test_cli_CPPFLAGS = $(TESTS_CPPFLAGS)
tests_lib_cli_test_cli_LDADD = $(ALL_TESTS_LDADD)
diff --git a/tests/topotests/GUIDELINES.md b/tests/topotests/GUIDELINES.md
deleted file mode 100644
index 4bd373796c..0000000000
--- a/tests/topotests/GUIDELINES.md
+++ /dev/null
@@ -1,571 +0,0 @@
-# Guidelines
-
-This document describes how to use the topotests testing framework.
-
-
-## Executing Tests
-
-To run the whole suite of tests the following commands must be executed at the
-top level directory of topotest:
-
-```shell
-$ # Change to the top level directory of topotests.
-$ cd path/to/topotests
-$ # Tests must be run as root, since Mininet requires it.
-$ sudo pytest
-```
-
-In order to run a specific test, you can use the following command:
-
-```shell
-$ # running a specific topology
-$ sudo pytest ospf-topo1/
-$ # or inside the test folder
-$ cd ospf-topo1
-$ sudo pytest # to run all tests inside the directory
-$ sudo pytest test_ospf_topo1.py # to run a specific test
-$ # or outside the test folder
-$ cd ..
-$ sudo pytest ospf-topo1/test_ospf_topo1.py # to run a specific one
-```
-
-The output of the tested daemons will be available at the temporary folder of
-your machine:
-
-```shell
-$ ls /tmp/topotest/ospf-topo1.test_ospf-topo1/r1
-...
-zebra.err # zebra stderr output
-zebra.log # zebra log file
-zebra.out # zebra stdout output
-...
-```
-
-You can also run memory leak tests to get reports:
-
-```shell
-$ # Set the environment variable to apply to a specific test...
-$ sudo env TOPOTESTS_CHECK_MEMLEAK="/tmp/memleak_report_" pytest ospf-topo1/test_ospf_topo1.py
-$ # ...or apply to all tests adding this line to the configuration file
-$ echo 'memleak_path = /tmp/memleak_report_' >> pytest.ini
-$ # You can also use your editor
-$ $EDITOR pytest.ini
-$ # After running tests you should see your files:
-$ ls /tmp/memleak_report_*
-memleak_report_test_ospf_topo1.txt
-```
-
-
-## Writing a New Test
-
-This section will guide you in all recommended steps to produce a standard
-topology test.
-
-This is the recommended test writing routine:
-
-* Write a topology (Graphviz recommended)
-* Obtain configuration files
-* Write the test itself
-* Create a Pull Request
-
-
-### Topotest File Hierarchy
-
-Before starting to write any tests one must know the file hierarchy. The
-repository hierarchy looks like this:
-
-```shell
-$ cd path/to/topotest
-$ find ./*
-...
-./README.md # repository read me
-./GUIDELINES.md # this file
-./conftest.py # test hooks - pytest related functions
-./example-test # example test folder
-./example-test/__init__.py # python package marker - must always exist.
-./example-test/test_template.jpg # generated topology picture - see next section
-./example-test/test_template.dot # Graphviz dot file
-./example-test/test_template.py # the topology plus the test
-...
-./ospf-topo1 # the ospf topology test
-./ospf-topo1/r1 # router 1 configuration files
-./ospf-topo1/r1/zebra.conf # zebra configuration file
-./ospf-topo1/r1/ospfd.conf # ospf configuration file
-./ospf-topo1/r1/ospfroute.txt # 'show ip ospf' output reference file
-# removed other for shortness sake
-...
-./lib # shared test/topology functions
-./lib/topogen.py # topogen implementation
-./lib/topotest.py # topotest implementation
-```
-
-Guidelines for creating/editing topotest:
-
-* New topologies that don't fit the existing directories should create its own
-* Always remember to add the `__init__.py` to new folders, this makes auto
- complete engines and pylint happy
-* Router (Quagga/FRR) specific code should go on topotest.py
-* Generic/repeated router actions should have an abstraction in
- topogen.TopoRouter.
-* Generic/repeated non-router code should go to topotest.py
-* pytest related code should go to conftest.py (e.g. specialized asserts)
-
-
-### Defining the Topology
-
-The first step to write a new test is to define the topology. This step can be
-done in many ways, but the recommended is to use Graphviz to generate a drawing
-of the Topology. It allows us to see the topology graphically and to see the
-names of equipments, links and addresses.
-
-Here is an example of Graphviz dot file that generates the
-[template topology](example-test/test_template.dot) (the inlined code might get
-outdated, please see the linked file):
-
-```dot
-graph template {
- label="template";
-
- # Routers
- r1 [
- shape=doubleoctagon,
- label="r1",
- fillcolor="#f08080",
- style=filled,
- ];
- r2 [
- shape=doubleoctagon,
- label="r2",
- fillcolor="#f08080",
- style=filled,
- ];
-
- # Switches
- s1 [
- shape=oval,
- label="s1\n192.168.0.0/24",
- fillcolor="#d0e0d0",
- style=filled,
- ];
- s2 [
- shape=oval,
- label="s2\n192.168.1.0/24",
- fillcolor="#d0e0d0",
- style=filled,
- ];
-
- # Connections
- r1 -- s1 [label="eth0\n.1"];
-
- r1 -- s2 [label="eth1\n.100"];
- r2 -- s2 [label="eth0\n.1"];
-}
-```
-
-Here is the produced graph:
-
-![template topology graph](example-test/test_template.jpg)
-
-
-### Generating / Obtaining Configuration Files
-
-In order to get the configuration files or command output for each router, we
-need to run the topology and execute commands in vtysh. The quickest way to
-achieve that is writing the topology building code and running the topology.
-
-To bootstrap your test topology, do the following steps:
-
-* Copy the template test
-
-```shell
-$ mkdir new-topo/
-$ touch new-topo/__init__.py
-$ cp example-test/test_template.py new-topo/test_new_topo.py
-```
-
-* Modify the template according to your dot file
-
-Here is the template topology described in the previous section in python code:
-
-```py
-class TemplateTopo(Topo):
- "Test topology builder"
- def build(self, *_args, **_opts):
- "Build function"
- tgen = get_topogen(self)
-
- # Create 2 routers
- for routern in range(1, 3):
- tgen.add_router('r{}'.format(routern))
-
- # Create a switch with just one router connected to it to simulate a
- # empty network.
- switch = tgen.add_switch('s1')
- switch.add_link(tgen.gears['r1'])
-
- # Create a connection between r1 and r2
- switch = tgen.add_switch('s2')
- switch.add_link(tgen.gears['r1'])
- switch.add_link(tgen.gears['r2'])
-```
-
-* Run the topology
-
-Topogen allows us to run the topology without running any tests, you can do that
-using the following example commands:
-
-```shell
-$ # Running your bootstraped topology
-$ sudo pytest -s --topology-only new-topo/test_new_topo.py
-$ # Running the test_template.py topology
-$ sudo pytest -s --topology-only example-test/test_template.py
-$ # Running the ospf_topo1.py topology
-$ sudo pytest -s --topology-only ospf-topo1/test_ospf_topo1.py
-```
-
-Parameters explanation:
-
-* `-s`: actives input/output capture. This is required by mininet in order to show
- the interactive shell.
-* `--topology-only`: don't run any tests, just build the topology.
-
-After executing the commands above, you should get the following terminal
-output:
-
-```shell
-=== test session starts ===
-platform linux2 -- Python 2.7.12, pytest-3.1.2, py-1.4.34, pluggy-0.4.0
-rootdir: /media/sf_src/topotests, inifile: pytest.ini
-collected 3 items
-
-ospf-topo1/test_ospf_topo1.py *** Starting controller
-
-*** Starting 6 switches
-switch1 switch2 switch3 switch4 switch5 switch6 ...
-r2: frr zebra started
-r2: frr ospfd started
-r3: frr zebra started
-r3: frr ospfd started
-r1: frr zebra started
-r1: frr ospfd started
-r4: frr zebra started
-r4: frr ospfd started
-*** Starting CLI:
-mininet>
-```
-
-The last line shows us that we are now using the Mininet CLI (Command Line
-Interface), from here you can call your router vtysh or even bash.
-
-Here are some commands example:
-
-```shell
-mininet> r1 ping 10.0.3.1
-PING 10.0.3.1 (10.0.3.1) 56(84) bytes of data.
-64 bytes from 10.0.3.1: icmp_seq=1 ttl=64 time=0.576 ms
-64 bytes from 10.0.3.1: icmp_seq=2 ttl=64 time=0.083 ms
-64 bytes from 10.0.3.1: icmp_seq=3 ttl=64 time=0.088 ms
-^C
---- 10.0.3.1 ping statistics ---
-3 packets transmitted, 3 received, 0% packet loss, time 1998ms
-rtt min/avg/max/mdev = 0.083/0.249/0.576/0.231 ms
-
-
-
-mininet> r1 ping 10.0.3.3
-PING 10.0.3.3 (10.0.3.3) 56(84) bytes of data.
-64 bytes from 10.0.3.3: icmp_seq=1 ttl=64 time=2.87 ms
-64 bytes from 10.0.3.3: icmp_seq=2 ttl=64 time=0.080 ms
-64 bytes from 10.0.3.3: icmp_seq=3 ttl=64 time=0.091 ms
-^C
---- 10.0.3.3 ping statistics ---
-3 packets transmitted, 3 received, 0% packet loss, time 2003ms
-rtt min/avg/max/mdev = 0.080/1.014/2.872/1.313 ms
-
-
-
-mininet> r3 vtysh
-
-Hello, this is FRRouting (version 3.1-devrzalamena-build).
-Copyright 1996-2005 Kunihiro Ishiguro, et al.
-
-frr-1# show running-config
-Building configuration...
-
-Current configuration:
-!
-frr version 3.1-devrzalamena-build
-frr defaults traditional
-hostname r3
-no service integrated-vtysh-config
-!
-log file zebra.log
-!
-log file ospfd.log
-!
-interface r3-eth0
- ip address 10.0.3.1/24
-!
-interface r3-eth1
- ip address 10.0.10.1/24
-!
-interface r3-eth2
- ip address 172.16.0.2/24
-!
-router ospf
- ospf router-id 10.0.255.3
- redistribute kernel
- redistribute connected
- redistribute static
- network 10.0.3.0/24 area 0
- network 10.0.10.0/24 area 0
- network 172.16.0.0/24 area 1
-!
-line vty
-!
-end
-frr-1#
-```
-
-After you successfully configured your topology, you can obtain the
-configuration files (per-daemon) using the following commands:
-
-```shell
-mininet> r3 vtysh -d ospfd
-
-Hello, this is FRRouting (version 3.1-devrzalamena-build).
-Copyright 1996-2005 Kunihiro Ishiguro, et al.
-
-frr-1# show running-config
-Building configuration...
-
-Current configuration:
-!
-frr version 3.1-devrzalamena-build
-frr defaults traditional
-no service integrated-vtysh-config
-!
-log file ospfd.log
-!
-router ospf
- ospf router-id 10.0.255.3
- redistribute kernel
- redistribute connected
- redistribute static
- network 10.0.3.0/24 area 0
- network 10.0.10.0/24 area 0
- network 172.16.0.0/24 area 1
-!
-line vty
-!
-end
-frr-1#
-```
-
-
-### Writing Tests
-
-Test topologies should always be bootstrapped from the
-[example-test/test_template.py](example-test/test_template.py),
-because it contains important boilerplate code that can't be avoided, like:
-
-* imports: os, sys, pytest, topotest/topogen and mininet topology class
-* The global variable CWD (Current Working directory): which is most likely
- going to be used to reference the routers configuration file location
-
- Example:
-
-```py
-# For all registered routers, load the zebra configuration file
-for rname, router in router_list.iteritems():
- router.load_config(
- TopoRouter.RD_ZEBRA,
- os.path.join(CWD, '{}/zebra.conf'.format(rname))
- )
- # os.path.join() joins the CWD string with arguments adding the necessary
- # slashes ('/'). Arguments must not begin with '/'.
-```
-
-* The topology class that inherits from Mininet Topo class
-
-```py
-class TemplateTopo(Topo):
- def build(self, *_args, **_opts):
- tgen = get_topogen(self)
- # topology build code
-```
-
-* pytest `setup_module()` and `teardown_module()` to start the topology
-
-```py
-def setup_module(_m):
- tgen = Topogen(TemplateTopo)
- tgen.start_topology('debug')
-
-def teardown_module(_m):
- tgen = get_topogen()
- tgen.stop_topology()
-```
-
-* `__main__` initialization code (to support running the script directly)
-
-```py
-if __name__ == '__main__':
- sys.exit(pytest.main(["-s"]))
-```
-
-Requirements:
-
-* Test code should always be declared inside functions that begin with the
- `test_` prefix. Functions beginning with different prefixes will not be run by
- pytest.
-* Configuration files and long output commands should go into separated files
- inside folders named after the equipment.
-* Tests must be able to run without any interaction. To make sure your test
- conforms with this, run it without the `-s` parameter.
-
-Tips:
-
-* Keep results in stack variables, so people inspecting code with `pdb` can
- easily print their values.
-
- Don't do this:
-
- ```py
- assert foobar(router1, router2)
- ```
-
- Do this instead:
-
- ```py
- result = foobar(router1, router2)
- assert result
- ```
-
-* Use `assert` messages to indicate where the test failed.
-
- Example:
-
- ```py
- for router in router_list:
- # ...
- assert condition, 'Router "{}" condition failed'.format(router.name)
- ```
-
-
-### Debugging Execution
-
-The most effective ways to inspect topology tests are:
-
-* Run pytest with `--pdb` option. This option will cause a pdb shell to appear
- when an assertion fails
-
- Example: `pytest -s --pdb ospf-topo1/test_ospf_topo1.py`
-
-* Set a breakpoint in the test code with `pdb`
-
- Example:
-
-```py
-# Add the pdb import at the beginning of the file
-import pdb
-# ...
-
-# Add a breakpoint where you think the problem is
-def test_bla():
- # ...
- pdb.set_trace()
- # ...
-```
-
-The [Python Debugger](https://docs.python.org/2.7/library/pdb.html) (pdb) shell
-allows us to run many useful operations like:
-
-* Setting breaking point on file/function/conditions (e.g. `break`, `condition`)
-* Inspecting variables (e.g. `p` (print), `pp` (pretty print))
-* Running python code
-
-TIP: The TopoGear (equipment abstraction class) implements the `__str__` method
-that allows the user to inspect equipment information.
-
-Example of pdb usage:
-
-```shell
-> /media/sf_src/topotests/ospf-topo1/test_ospf_topo1.py(121)test_ospf_convergence()
--> for rnum in range(1, 5):
-(Pdb) help
-Documented commands (type help <topic>):
-========================================
-EOF bt cont enable jump pp run unt
-a c continue exit l q s until
-alias cl d h list quit step up
-args clear debug help n r tbreak w
-b commands disable ignore next restart u whatis
-break condition down j p return unalias where
-
-Miscellaneous help topics:
-==========================
-exec pdb
-
-Undocumented commands:
-======================
-retval rv
-
-(Pdb) list
-116 title2="Expected output")
-117
-118 def test_ospf_convergence():
-119 "Test OSPF daemon convergence"
-120 pdb.set_trace()
-121 -> for rnum in range(1, 5):
-122 router = 'r{}'.format(rnum)
-123
-124 # Load expected results from the command
-125 reffile = os.path.join(CWD, '{}/ospfroute.txt'.format(router))
-126 expected = open(reffile).read()
-(Pdb) step
-> /media/sf_src/topotests/ospf-topo1/test_ospf_topo1.py(122)test_ospf_convergence()
--> router = 'r{}'.format(rnum)
-(Pdb) step
-> /media/sf_src/topotests/ospf-topo1/test_ospf_topo1.py(125)test_ospf_convergence()
--> reffile = os.path.join(CWD, '{}/ospfroute.txt'.format(router))
-(Pdb) print rnum
-1
-(Pdb) print router
-r1
-(Pdb) tgen = get_topogen()
-(Pdb) pp tgen.gears[router]
-<lib.topogen.TopoRouter object at 0x7f74e06c9850>
-(Pdb) pp str(tgen.gears[router])
-'TopoGear<name="r1",links=["r1-eth0"<->"s1-eth0","r1-eth1"<->"s3-eth0"]> TopoRouter<>'
-(Pdb) l 125
-120 pdb.set_trace()
-121 for rnum in range(1, 5):
-122 router = 'r{}'.format(rnum)
-123
-124 # Load expected results from the command
-125 -> reffile = os.path.join(CWD, '{}/ospfroute.txt'.format(router))
-126 expected = open(reffile).read()
-127
-128 # Run test function until we get an result. Wait at most 60 seconds.
-129 test_func = partial(compare_show_ip_ospf, router, expected)
-130 result, diff = topotest.run_and_expect(test_func, '',
-(Pdb) router1 = tgen.gears[router]
-(Pdb) router1.vtysh_cmd('show ip ospf route')
-'============ OSPF network routing table ============\r\nN 10.0.1.0/24 [10] area: 0.0.0.0\r\n directly attached to r1-eth0\r\nN 10.0.2.0/24 [20] area: 0.0.0.0\r\n via 10.0.3.3, r1-eth1\r\nN 10.0.3.0/24 [10] area: 0.0.0.0\r\n directly attached to r1-eth1\r\nN 10.0.10.0/24 [20] area: 0.0.0.0\r\n via 10.0.3.1, r1-eth1\r\nN IA 172.16.0.0/24 [20] area: 0.0.0.0\r\n via 10.0.3.1, r1-eth1\r\nN IA 172.16.1.0/24 [30] area: 0.0.0.0\r\n via 10.0.3.1, r1-eth1\r\n\r\n============ OSPF router routing table =============\r\nR 10.0.255.2 [10] area: 0.0.0.0, ASBR\r\n via 10.0.3.3, r1-eth1\r\nR 10.0.255.3 [10] area: 0.0.0.0, ABR, ASBR\r\n via 10.0.3.1, r1-eth1\r\nR 10.0.255.4 IA [20] area: 0.0.0.0, ASBR\r\n via 10.0.3.1, r1-eth1\r\n\r\n============ OSPF external routing table ===========\r\n\r\n\r\n'
-(Pdb) tgen.mininet_cli()
-*** Starting CLI:
-mininet>
-```
-
-To enable more debug messages in other Topogen subsystems (like Mininet), more
-logging messages can be displayed by modifying the test configuration file
-`pytest.ini`:
-
-```ini
-[topogen]
-# Change the default verbosity line from 'info'...
-#verbosity = info
-# ...to 'debug'
-verbosity = debug
-```
diff --git a/tests/topotests/README.md b/tests/topotests/README.md
index a495675ee9..d9d849b39f 100644
--- a/tests/topotests/README.md
+++ b/tests/topotests/README.md
@@ -1,199 +1 @@
-# FRRouting Topology Tests with Mininet
-
-## Running tests with docker
-
-There is a docker image which allows to run topotests. Instructions can be
-found [here](docker/README.md).
-
-## Guidelines
-
-Instructions for use, write or debug topologies can be found in the
-[guidelines](GUIDELINES.md). To learn/remember common code snippets see
-[here](SNIPPETS.md).
-
-Before creating a new topology, make sure that there isn't one already
-that does what you need. If nothing is similar, then you may create a
-new topology, preferably, using the newest
-[template](example-test/test_template.py).
-
-## Installation of Mininet for running tests
-Only tested with Ubuntu 16.04 and Ubuntu 18.04 (which uses Mininet 2.2.x)
-
-Instructions are the same for all setups (ie ExaBGP is only used for BGP
-tests)
-
-### Installing Mininet Infrastructure:
-
-1. apt-get install mininet
-2. apt-get install python-pip
-3. apt-get install iproute
-4. pip install ipaddr
-5. pip install pytest
-6. pip install exabgp==3.4.17
- (Newer 4.0 version of exabgp is not yet supported)
-7. useradd -d /var/run/exabgp/ -s /bin/false exabgp
-
-### Enable Coredumps
-Optional, will give better output
-
-1. apt-get install gdb
-2. disable apport (which move core files)
-
- Set `enabled=0` in `/etc/default/apport`
-
-3. Update security limits
-
- Add/change `/etc/security/limits.conf` to
-
- #<domain> <type> <item> <value>
- * soft core unlimited
- root soft core unlimited
- * hard core unlimited
- root hard core unlimited
-
-4. reboot (for options to take effect)
-
-## FRRouting (FRR) Installation
-FRR needs to be installed separatly. It is assume to be configured
-like the standard Ubuntu Packages:
-
-- Binaries in /usr/lib/frr
-- State Directory /var/run/frr
-- Running under user frr, group frr
-- vtygroup: frrvty
-- config directory: /etc/frr
-- For FRR Packages, install the dbg package as well for coredump decoding
-
-No FRR config needs to be done and no FRR daemons should be run ahead
-of the test. They are all started as part of the test
-
-#### Manual FRRouting (FRR) build
-
-If you prefer to manually build FRR, then use the following suggested config:
-
- ./configure \
- --prefix=/usr \
- --localstatedir=/var/run/frr \
- --sbindir=/usr/lib/frr \
- --sysconfdir=/etc/frr \
- --enable-vtysh \
- --enable-pimd \
- --enable-multipath=64 \
- --enable-user=frr \
- --enable-group=frr \
- --enable-vty-group=frrvty \
- --with-pkg-extra-version=-my-manual-build
-
-And create frr User and frrvty group as follows:
-
- addgroup --system --gid 92 frr
- addgroup --system --gid 85 frrvty
- adduser --system --ingroup frr --home /var/run/frr/ \
- --gecos "FRRouting suite" --shell /bin/false frr
- usermod -G frrvty frr
-
-## Executing Tests
-
-#### Execute all tests with output to console
-
- py.test -s -v --tb=no
-
-All test_* scripts in subdirectories are detected and executed (unless
-disabled in `pytest.ini` file)
-
-`--tb=no` disables the python traceback which might be irrelevant unless the
-test script itself is debugged
-
-#### Execute single test
-
- cd test_to_be_run
- ./test_to_be_run.py
-
-For further options, refer to pytest documentation
-
-Test will set exit code which can be used with `git bisect`
-
-For the simulated topology, see the description in the python file
-
-If you need to clear the mininet setup between tests (if it isn't cleanly
-shutdown), then use the `mn -c` command to clean up the environment
-
-#### (Optional) StdErr log from daemos after exit
-
-To enable the reporting of any messages seen on StdErr after the
-daemons exit, the following env variable can be set.
-
- export TOPOTESTS_CHECK_STDERR=Yes
-
-(The value doesn't matter at this time. The check is if the env variable
-exists or not)
-There is no pass/fail on this reporting. The Output will be reported to
-the console
-
- export TOPOTESTS_CHECK_MEMLEAK="/home/mydir/memleak_"
-
-This will enable the check and output to console and the writing of
-the information to files with the given prefix (followed by testname),
-ie `/home/mydir/memcheck_test_bgp_multiview_topo1.txt` in case of a
-memory leak.
-
-#### (Optional) Collect Memory Leak Information
-
-FreeRangeRouting processes have the capabilities to report remaining memory
-allocations upon exit. To enable the reporting of the memory, define an
-enviroment variable `TOPOTESTS_CHECK_MEMLEAK` with the file prefix, ie
-
- export TOPOTESTS_CHECK_MEMLEAK="/home/mydir/memleak_"
-
-This will enable the check and output to console and the writing of
-the information to files with the given prefix (followed by testname),
-ie `/home/mydir/memcheck_test_bgp_multiview_topo1.txt` in case of a
-memory leak.
-
-#### (Optional) Run topotests with GCC AddressSanitizer enabled
-
-Topotests can be run with the GCC AddressSanitizer. It requires GCC 4.8 or
-newer. (Ubuntu 16.04 as suggested here is fine with GCC 5 as default)
-For more information on AddressSanitizer, see
-https://github.com/google/sanitizers/wiki/AddressSanitizer
-
-The checks are done automatically in the library call of `checkRouterRunning`
-(ie at beginning of tests when there is a check for all daemons running).
-No changes or extra configuration for topotests is required beside compiling
-the suite with AddressSanitizer enabled.
-
-If a daemon crashed, then the errorlog is checked for AddressSanitizer
-output. If found, then this is added with context (calling test) to
-`/tmp/AddressSanitizer.txt` in markdown compatible format.
-
-Compiling for GCC AddressSanitizer requires to use gcc as a linker as well
-(instead of ld). Here is a suggest way to compile frr with AddressSanitizer
-for `stable/3.0` branch:
-
- git clone https://github.com/FRRouting/frr.git
- cd frr
- git checkout stable/3.0
- ./bootstrap.sh
- export CC=gcc
- export CFLAGS="-O1 -g -fsanitize=address -fno-omit-frame-pointer"
- export LD=gcc
- export LDFLAGS="-g -fsanitize=address -ldl"
- ./configure --enable-shared=no \
- --prefix=/usr/lib/frr --sysconfdir=/etc/frr \
- --localstatedir=/var/run/frr \
- --sbindir=/usr/lib/frr --bindir=/usr/lib/frr \
- --enable-exampledir=/usr/lib/frr/examples \
- --with-moduledir=/usr/lib/frr/modules \
- --enable-multipath=0 --enable-rtadv \
- --enable-tcp-zebra --enable-fpm --enable-pimd
- make
- sudo make install
- # Create symlink for vtysh, so topotest finds it in /usr/lib/frr
- sudo ln -s /usr/lib/frr/vtysh /usr/bin/
-
-and create `frr` user and `frrvty` group as shown above
-
-## License
-
-All the configs and scripts are licensed under a ISC-style license. See
-Python scripts for details.
+Documentation is located in /doc/developer/topotests.rst
diff --git a/tests/topotests/SNIPPETS.md b/tests/topotests/SNIPPETS.md
deleted file mode 100644
index 6c16c44af6..0000000000
--- a/tests/topotests/SNIPPETS.md
+++ /dev/null
@@ -1,275 +0,0 @@
-# Snippets
-
-This document will describe common snippets of code that are frequently
-needed to perform some test checks.
-
-
-## Checking for router / test failures
-
-The following check uses the topogen API to check for software failure
-(e.g. zebra died) and/or for errors manually set by `Topogen.set_error()`.
-
-```py
-# Get the topology reference
-tgen = get_topogen()
-
-# Check for errors in the topology
-if tgen.routers_have_failure():
- # Skip the test with the topology errors as reason
- pytest.skip(tgen.errors)
-```
-
-
-## Checking FRR routers version
-
-This code snippet is usually run after the topology setup to make sure
-all routers instantiated in the topology have the correct software
-version.
-
-```py
-# Get the topology reference
-tgen = get_topogen()
-
-# Get the router list
-router_list = tgen.routers()
-
-# Run the check for all routers
-for router in router_list.values():
- if router.has_version('<', '3'):
- # Set topology error, so the next tests are skipped
- tgen.set_error('unsupported version')
-```
-
-A sample of this snippet in a test can be found
-[here](ldp-vpls-topo1/test_ldp_vpls_topo1.py).
-
-
-## Interacting with equipments
-
-You might want to interact with the topology equipments during the tests
-and there are different ways to do so.
-
-Notes:
-
-1.
-> When using the Topogen API, all the equipments code derive from
-> `Topogear` ([lib/topogen.py](lib/topogen.py)). If you feel brave you
-> can look by yourself how the abstractions that will be mentioned here
-> works.
-
-2.
-> When not using the `Topogen` API there is only one way to interact
-> with the equipments, which is by calling the `mininet` API functions
-> directly to spawn commands.
-
-
-### Interacting with the Linux sandbox
-
-*Without `Topogen`*
-
-```py
-global net
-output = net['r1'].cmd('echo "foobar"')
-print 'output is: {}'.format(output)
-```
-
----
-
-*With `Topogen`*
-
-```py
-tgen = get_topogen()
-output = tgen.gears['r1'].run('echo "foobar"')
-print 'output is: {}'.format(output)
-```
-
-
-### Interacting with VTYSH
-
-*Without `Topogen`*
-
-```py
-global net
-output = net['r1'].cmd('vtysh "show ip route" 2>/dev/null')
-print 'output is: {}'.format(output)
-```
-
----
-
-*With `Topogen`*
-
-```py
-tgen = get_topogen()
-output = tgen.gears['r1'].vtysh_cmd("show ip route")
-print 'output is: {}'.format(output)
-```
-
-`Topogen` also supports sending multiple lines of command:
-
-```py
-tgen = get_topogen()
-output = tgen.gears['r1'].vtysh_cmd("""
-configure terminal
-router bgp 10
- bgp router-id 10.0.255.1
- neighbor 1.2.3.4 remote-as 10
- !
-router bgp 11
- bgp router-id 10.0.255.2
- !
-""")
-print 'output is: {}'.format(output)
-```
-
-You might also want to run multiple commands and get only the commands
-that failed:
-
-```py
-tgen = get_topogen()
-output = tgen.gears['r1'].vtysh_multicmd("""
-configure terminal
-router bgp 10
- bgp router-id 10.0.255.1
- neighbor 1.2.3.4 remote-as 10
- !
-router bgp 11
- bgp router-id 10.0.255.2
- !
-""", pretty_output=false)
-print 'output is: {}'.format(output)
-```
-
-Translating vtysh JSON output into Python structures:
-```py
-tgen = get_topogen()
-json_output = tgen.gears['r1'].vtysh_cmd("show ip route json", isjson=True)
-output = json.dumps(json_output, indent=4)
-print 'output is: {}'.format(output)
-
-# You can also access the data structure as normal. For example:
-# protocol = json_output['1.1.1.1/32']['protocol']
-# assert protocol == "ospf", "wrong protocol"
-```
-
-*NOTE:* `vtysh_(multi)cmd` is only available for router type of
-equipments.
-
-
-### Invoking `mininet` CLI
-
-*Without `Topogen`*
-
-```py
-CLI(net)
-```
-
----
-
-*With `Topogen`*
-```py
-tgen = get_topogen()
-tgen.mininet_cli()
-```
-
-
-## Reading files
-
-Loading a normal text file content in the current directory:
-
-```py
-# If you are using Topogen
-# CURDIR = CWD
-#
-# Otherwise find the directory manually:
-CURDIR = os.path.dirname(os.path.realpath(__file__))
-
-file_name = '{}/r1/show_ip_route.txt'.format(CURDIR)
-file_content = open(file_name).read()
-```
-
-Loading JSON from a file:
-
-```py
-import json
-
-file_name = '{}/r1/show_ip_route.json'.format(CURDIR)
-file_content = json.loads(open(file_name).read())
-```
-
-
-## Comparing JSON output
-
-After obtaining JSON output formated with Python data structures, you
-may use it to assert a minimalist schema:
-
-```py
-tgen = get_topogen()
-json_output = tgen.gears['r1'].vtysh_cmd("show ip route json", isjson=True)
-
-expect = {
- '1.1.1.1/32': {
- 'protocol': 'ospf'
- }
-}
-
-assertmsg = "route 1.1.1.1/32 was not learned through OSPF"
-assert json_cmp(json_output, expect) is None, assertmsg
-```
-
-`json_cmp` function description (it might be outdated, you can find the
-latest description in the source code at [lib/topotest.py](lib/topotest.py)):
-
-```text
- JSON compare function. Receives two parameters:
- * `d1`: json value
- * `d2`: json subset which we expect
-
- Returns `None` when all keys that `d1` has matches `d2`,
- otherwise a string containing what failed.
-
- Note: key absence can be tested by adding a key with value `None`.
-```
-
-
-## Pausing execution
-
-Preferably, choose the `sleep` function that `topotest` provides, as it
-prints a notice during the test execution to help debug topology test
-execution time.
-
-```py
-# Using the topotest sleep
-from lib import topotest
-
-topotest.sleep(10, 'waiting 10 seconds for bla')
-# or just tell it the time:
-# topotest.sleep(10)
-# It will print 'Sleeping for 10 seconds'.
-
-# Or you can also use the Python sleep, but it won't show anything
-from time import sleep
-sleep(5)
-```
-
-
-## `ip route` Linux command as JSON
-
-`topotest` has two helpers implemented that parses the output of
-`ip route` commands to JSON. It might simplify your comparison needs by
-only needing to provide a Python dictionary.
-
-```py
-from lib import topotest
-
-tgen = get_topogen()
-routes = topotest.ip4_route(tgen.gears['r1'])
-expected = {
- '10.0.1.0/24': {},
- '10.0.2.0/24': {
- 'dev': 'r1-eth0'
- }
-}
-
-assertmsg = "failed to find 10.0.1.0/24 and/or 10.0.2.0/24"
-assert json_cmp(routes, expected) is None, assertmsg
-```
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py
index 31e23faede..ce542413ba 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py
+++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py
@@ -141,7 +141,10 @@ class ThisTestTopo(Topo):
switch[1].add_link(tgen.gears['r2'], nodeif='r2-eth2')
switch[1].add_link(tgen.gears['r3'], nodeif='r3-eth1')
+l3mdev_accept = 0
+
def ltemplatePreRouterStartHook():
+ global l3mdev_accept
cc = ltemplateRtrCmd()
krel = platform.release()
tgen = get_topogen()
@@ -172,7 +175,7 @@ def ltemplatePreRouterStartHook():
'ip ru add oif {0}-cust1 table 10',
'ip ru add iif {0}-cust1 table 10',
'ip link set dev {0}-cust1 up',
- 'sysctl -w net.ipv4.udp_l3mdev_accept={}'.format(l3mdev_accept)]
+ 'sysctl -w net.ipv4.tcp_l3mdev_accept={}'.format(l3mdev_accept)]
for rtr in rtrs:
router = tgen.gears[rtr]
for cmd in cmds:
@@ -202,7 +205,7 @@ def ltemplatePreRouterStartHook():
'ip ru add oif {0}-cust2 table 20',
'ip ru add iif {0}-cust2 table 20',
'ip link set dev {0}-cust2 up',
- 'sysctl -w net.ipv4.udp_l3mdev_accept={}'.format(l3mdev_accept)]
+ 'sysctl -w net.ipv4.tcp_l3mdev_accept={}'.format(l3mdev_accept)]
for rtr in rtrs:
for cmd in cmds:
cc.doCmd(tgen, rtr, cmd.format(rtr))
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py
index 778d504040..f5d73a8c49 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py
+++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py
@@ -1,11 +1,12 @@
from lutil import luCommand
-
-rtrs = ['r1', 'r3', 'r4', 'ce1', 'ce2', 'ce3', 'ce4']
-for rtr in rtrs:
+from customize import l3mdev_accept
+l3mdev_rtrs = ['r1', 'r3', 'r4', 'ce4']
+for rtr in l3mdev_rtrs:
luCommand(rtr,'sysctl net.ipv4.tcp_l3mdev_accept',' = \d*','none','')
found = luLast()
- luCommand(rtr,'ss -aep',':bgp','pass','IPv4:bgp, l3mdev%s' % found.group(0))
- luCommand(rtr,'ss -aep',':.:bgp','pass','IPv6:bgp')
+ luCommand(rtr,'ss -naep',':179','pass','IPv4:bgp, l3mdev{}'.format(found.group(0)))
+ luCommand(rtr,'ss -naep',':.*:179','pass','IPv6:bgp')
+ luCommand(rtr,'sysctl net.ipv4.tcp_l3mdev_accept',' = {}'.format(l3mdev_accept),'pass','l3mdev matches expected (real/expected{}/{})'.format(found.group(0),l3mdev_accept))
rtrs = ['r1', 'r3', 'r4']
for rtr in rtrs:
diff --git a/tests/topotests/eigrp-topo1/r1/show_ip_route.json_ref b/tests/topotests/eigrp-topo1/r1/show_ip_route.json_ref
index 36dd5da597..26fa7ca415 100644
--- a/tests/topotests/eigrp-topo1/r1/show_ip_route.json_ref
+++ b/tests/topotests/eigrp-topo1/r1/show_ip_route.json_ref
@@ -3,7 +3,7 @@
{
"prefix":"192.168.1.0/24",
"protocol":"eigrp",
- "metric":0,
+ "metric":28160,
"nexthops":[
{
"directlyConnected":true,
@@ -31,7 +31,7 @@
"prefix":"192.168.3.0/24",
"protocol":"eigrp",
"selected":true,
- "metric":0,
+ "metric":33280,
"nexthops":[
{
"fib":true,
@@ -47,7 +47,7 @@
{
"prefix":"193.1.1.0/26",
"protocol":"eigrp",
- "metric":0,
+ "metric":28160,
"nexthops":[
{
"directlyConnected":true,
@@ -75,7 +75,7 @@
"prefix":"193.1.2.0/24",
"protocol":"eigrp",
"selected":true,
- "metric":0,
+ "metric":30720,
"nexthops":[
{
"fib":true,
diff --git a/tests/topotests/eigrp-topo1/r1/zebra.conf b/tests/topotests/eigrp-topo1/r1/zebra.conf
index 8537f6dd80..56ae4a66f4 100644
--- a/tests/topotests/eigrp-topo1/r1/zebra.conf
+++ b/tests/topotests/eigrp-topo1/r1/zebra.conf
@@ -1,4 +1,5 @@
log file zebra.log
+debug zebra rib detail
!
hostname r1
!
diff --git a/tests/topotests/eigrp-topo1/r2/show_ip_route.json_ref b/tests/topotests/eigrp-topo1/r2/show_ip_route.json_ref
index 44903ce3ff..71c931b17a 100644
--- a/tests/topotests/eigrp-topo1/r2/show_ip_route.json_ref
+++ b/tests/topotests/eigrp-topo1/r2/show_ip_route.json_ref
@@ -4,7 +4,7 @@
"prefix":"192.168.1.0/24",
"protocol":"eigrp",
"selected":true,
- "metric":0,
+ "metric":30720,
"nexthops":[
{
"fib":true,
@@ -21,7 +21,7 @@
"prefix":"192.168.3.0/24",
"protocol":"eigrp",
"selected":true,
- "metric":0,
+ "metric":30720,
"nexthops":[
{
"fib":true,
@@ -37,7 +37,7 @@
{
"prefix":"193.1.1.0/26",
"protocol":"eigrp",
- "metric":0,
+ "metric":28160,
"nexthops":[
{
"directlyConnected":true,
@@ -64,7 +64,7 @@
{
"prefix":"193.1.2.0/24",
"protocol":"eigrp",
- "metric":0,
+ "metric":28160,
"nexthops":[
{
"directlyConnected":true,
diff --git a/tests/topotests/eigrp-topo1/r3/show_ip_route.json_ref b/tests/topotests/eigrp-topo1/r3/show_ip_route.json_ref
index d80e1d97e6..5e0b79d811 100644
--- a/tests/topotests/eigrp-topo1/r3/show_ip_route.json_ref
+++ b/tests/topotests/eigrp-topo1/r3/show_ip_route.json_ref
@@ -4,7 +4,7 @@
"prefix":"192.168.1.0/24",
"protocol":"eigrp",
"selected":true,
- "metric":0,
+ "metric":33280,
"nexthops":[
{
"fib":true,
@@ -38,7 +38,7 @@
{
"prefix":"192.168.3.0/24",
"protocol":"eigrp",
- "metric":0,
+ "metric":28160,
"nexthops":[
{
"directlyConnected":true,
@@ -66,7 +66,7 @@
"prefix":"193.1.1.0/26",
"protocol":"eigrp",
"selected":true,
- "metric":0,
+ "metric":30720,
"nexthops":[
{
"fib":true,
@@ -82,7 +82,7 @@
{
"prefix":"193.1.2.0/24",
"protocol":"eigrp",
- "metric":0,
+ "metric":28160,
"nexthops":[
{
"directlyConnected":true,
diff --git a/tests/topotests/eigrp-topo1/test_eigrp_topo1.py b/tests/topotests/eigrp-topo1/test_eigrp_topo1.py
index de8cb81f8f..1c00face43 100755
--- a/tests/topotests/eigrp-topo1/test_eigrp_topo1.py
+++ b/tests/topotests/eigrp-topo1/test_eigrp_topo1.py
@@ -153,7 +153,6 @@ def test_eigrp_routes():
assertmsg = '"show ip eigrp topo" mismatches on {}'.format(router.name)
assert topotest.json_cmp(actual, expected) is None, assertmsg
-
def test_zebra_ipv4_routingTable():
"Test 'show ip route'"
@@ -172,6 +171,16 @@ def test_zebra_ipv4_routingTable():
assertmsg = 'Zebra IPv4 Routing Table verification failed for router {}'.format(router.name)
assert topotest.json_cmp(output, expected) is None, assertmsg
+def test_shut_interface_and_recover():
+ "Test shutdown of an interface and recovery of the interface"
+
+ tgen = get_topogen()
+ router = tgen.gears['r1']
+ router.run('ip link set r1-eth1 down')
+ topotest.sleep(5, 'Waiting for EIGRP convergence')
+ router.run('ip link set r1-eth1 up')
+
+
def test_shutdown_check_stderr():
if os.environ.get('TOPOTESTS_CHECK_STDERR') is None:
diff --git a/tests/topotests/ospf-topo1-vrf/r1/zebra.conf b/tests/topotests/ospf-topo1-vrf/r1/zebra.conf
index b1cf342898..e826793657 100644
--- a/tests/topotests/ospf-topo1-vrf/r1/zebra.conf
+++ b/tests/topotests/ospf-topo1-vrf/r1/zebra.conf
@@ -1,3 +1,7 @@
+debug zebra kernel
+debug zebra dplane detail
+debug zebra rib
+debug zebra event
!
hostname r1
password zebra
diff --git a/tools/frr.service b/tools/frr.service
index c7568593b3..aa45f420fe 100644
--- a/tools/frr.service
+++ b/tools/frr.service
@@ -1,7 +1,9 @@
[Unit]
Description=FRRouting
Documentation=https://frrouting.readthedocs.io/en/latest/setup.html
-After=networking.service
+Wants=network.target
+After=network-pre.target systemd-sysctl.service
+Before=network.target
OnFailure=heartbeat-failed@%n.service
[Service]
@@ -20,4 +22,4 @@ ExecStop=/usr/lib/frr/frrinit.sh stop
ExecReload=/usr/lib/frr/frrinit.sh reload
[Install]
-WantedBy=network-online.target
+WantedBy=multi-user.target
diff --git a/tools/gen_northbound_callbacks.c b/tools/gen_northbound_callbacks.c
index eded87c12e..f6c757f5d7 100644
--- a/tools/gen_northbound_callbacks.c
+++ b/tools/gen_northbound_callbacks.c
@@ -54,7 +54,7 @@ static struct nb_callback_info {
"enum nb_event event, const struct lyd_node *dnode, union nb_resource *resource",
},
{
- .operation = NB_OP_DELETE,
+ .operation = NB_OP_DESTROY,
.return_type = "int ",
.return_value = "NB_OK",
.arguments =
diff --git a/tools/subdir.am b/tools/subdir.am
index ff41fe2c63..7713bb1ade 100644
--- a/tools/subdir.am
+++ b/tools/subdir.am
@@ -23,10 +23,10 @@ tools_permutations_SOURCES = tools/permutations.c
tools_permutations_LDADD = lib/libfrr.la
tools_gen_northbound_callbacks_SOURCES = tools/gen_northbound_callbacks.c
-tools_gen_northbound_callbacks_LDADD = lib/libfrr.la -lyang
+tools_gen_northbound_callbacks_LDADD = lib/libfrr.la $(LIBYANG_LIBS)
tools_gen_yang_deviations_SOURCES = tools/gen_yang_deviations.c
-tools_gen_yang_deviations_LDADD = lib/libfrr.la -lyang
+tools_gen_yang_deviations_LDADD = lib/libfrr.la $(LIBYANG_LIBS)
tools_ssd_SOURCES = tools/start-stop-daemon.c
diff --git a/vtysh/subdir.am b/vtysh/subdir.am
index c9cdb58543..74595788b0 100644
--- a/vtysh/subdir.am
+++ b/vtysh/subdir.am
@@ -24,7 +24,7 @@ noinst_HEADERS += \
vtysh/vtysh_user.h \
# end
-vtysh_vtysh_LDADD = lib/libfrr.la @LIBCAP@ @LIBREADLINE@ @LIBS@ @LIBPAM@
+vtysh_vtysh_LDADD = lib/libfrr.la $(LIBCAP) $(LIBREADLINE) $(LIBS) $(LIBPAM)
AM_V_EXTRACT = $(am__v_EXTRACT_$(V))
am__v_EXTRACT_ = $(am__v_EXTRACT_$(AM_DEFAULT_VERBOSITY))
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
index 340c9be601..41fd6ed7d6 100644
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -3330,7 +3330,7 @@ static void vtysh_client_sorted_insert(struct vtysh_client *head_client,
#define MAXIMUM_INSTANCES 10
-static void vtysh_update_all_insances(struct vtysh_client *head_client)
+static void vtysh_update_all_instances(struct vtysh_client *head_client)
{
struct vtysh_client *client;
DIR *dir;
@@ -3373,7 +3373,7 @@ static int vtysh_connect_all_instances(struct vtysh_client *head_client)
struct vtysh_client *client;
int rc = 0;
- vtysh_update_all_insances(head_client);
+ vtysh_update_all_instances(head_client);
client = head_client->next;
while (client) {
diff --git a/watchfrr/subdir.am b/watchfrr/subdir.am
index f0b49c9a84..c27491e55c 100644
--- a/watchfrr/subdir.am
+++ b/watchfrr/subdir.am
@@ -13,7 +13,7 @@ noinst_HEADERS += \
watchfrr/watchfrr_errors.h \
# end
-watchfrr_watchfrr_LDADD = lib/libfrr.la @LIBCAP@
+watchfrr_watchfrr_LDADD = lib/libfrr.la $(LIBCAP)
watchfrr_watchfrr_SOURCES = \
watchfrr/watchfrr.c \
watchfrr/watchfrr_errors.c \
diff --git a/yang/libyang_plugins/subdir.am b/yang/libyang_plugins/subdir.am
index 7164789083..fe5f34a28a 100644
--- a/yang/libyang_plugins/subdir.am
+++ b/yang/libyang_plugins/subdir.am
@@ -8,7 +8,7 @@ else
libyang_plugins_LTLIBRARIES += yang/libyang_plugins/frr_user_types.la
endif
-yang_libyang_plugins_frr_user_types_la_CFLAGS = $(WERROR)
+yang_libyang_plugins_frr_user_types_la_CFLAGS = $(WERROR) $(LIBYANG_CFLAGS)
yang_libyang_plugins_frr_user_types_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
yang_libyang_plugins_frr_user_types_la_LIBADD =
yang_libyang_plugins_frr_user_types_la_SOURCES = yang/libyang_plugins/frr_user_types.c
diff --git a/zebra/debug.c b/zebra/debug.c
index 0eb06d7f25..87999a1bbc 100644
--- a/zebra/debug.c
+++ b/zebra/debug.c
@@ -23,6 +23,10 @@
#include "command.h"
#include "debug.h"
+#ifndef VTYSH_EXTRACT_PL
+#include "zebra/debug_clippy.c"
+#endif
+
/* For debug statement. */
unsigned long zebra_debug_event;
unsigned long zebra_debug_packet;
@@ -34,6 +38,7 @@ unsigned long zebra_debug_mpls;
unsigned long zebra_debug_vxlan;
unsigned long zebra_debug_pw;
unsigned long zebra_debug_dplane;
+unsigned long zebra_debug_mlag;
DEFINE_HOOK(zebra_debug_show_debugging, (struct vty *vty), (vty));
@@ -94,6 +99,8 @@ DEFUN_NOSH (show_debugging_zebra,
vty_out(vty, " Zebra detailed dataplane debugging is on\n");
else if (IS_ZEBRA_DEBUG_DPLANE)
vty_out(vty, " Zebra dataplane debugging is on\n");
+ if (IS_ZEBRA_DEBUG_MLAG)
+ vty_out(vty, " Zebra mlag debugging is on\n");
hook_call(zebra_debug_show_debugging, vty);
return CMD_SUCCESS;
@@ -284,6 +291,21 @@ DEFUN (debug_zebra_dplane,
return CMD_SUCCESS;
}
+DEFPY (debug_zebra_mlag,
+ debug_zebra_mlag_cmd,
+ "[no$no] debug zebra mlag",
+ NO_STR
+ DEBUG_STR
+ "Zebra configuration\n"
+ "Debug option set for mlag events\n")
+{
+ if (no)
+ UNSET_FLAG(zebra_debug_mlag, ZEBRA_DEBUG_MLAG);
+ else
+ SET_FLAG(zebra_debug_mlag, ZEBRA_DEBUG_MLAG);
+ return CMD_SUCCESS;
+}
+
DEFUN (no_debug_zebra_events,
no_debug_zebra_events_cmd,
"no debug zebra events",
@@ -507,6 +529,7 @@ void zebra_debug_init(void)
zebra_debug_vxlan = 0;
zebra_debug_pw = 0;
zebra_debug_dplane = 0;
+ zebra_debug_mlag = 0;
install_node(&debug_node, config_write_debug);
@@ -523,6 +546,7 @@ void zebra_debug_init(void)
install_element(ENABLE_NODE, &debug_zebra_rib_cmd);
install_element(ENABLE_NODE, &debug_zebra_fpm_cmd);
install_element(ENABLE_NODE, &debug_zebra_dplane_cmd);
+ install_element(ENABLE_NODE, &debug_zebra_mlag_cmd);
install_element(ENABLE_NODE, &no_debug_zebra_events_cmd);
install_element(ENABLE_NODE, &no_debug_zebra_nht_cmd);
install_element(ENABLE_NODE, &no_debug_zebra_mpls_cmd);
diff --git a/zebra/debug.h b/zebra/debug.h
index cd15441ec8..c79cd96c21 100644
--- a/zebra/debug.h
+++ b/zebra/debug.h
@@ -51,6 +51,8 @@
#define ZEBRA_DEBUG_DPLANE 0x01
#define ZEBRA_DEBUG_DPLANE_DETAILED 0x02
+#define ZEBRA_DEBUG_MLAG 0x01
+
/* Debug related macro. */
#define IS_ZEBRA_DEBUG_EVENT (zebra_debug_event & ZEBRA_DEBUG_EVENT)
@@ -79,6 +81,8 @@
#define IS_ZEBRA_DEBUG_DPLANE_DETAIL \
(zebra_debug_dplane & ZEBRA_DEBUG_DPLANE_DETAILED)
+#define IS_ZEBRA_DEBUG_MLAG (zebra_debug_mlag & ZEBRA_DEBUG_MLAG)
+
extern unsigned long zebra_debug_event;
extern unsigned long zebra_debug_packet;
extern unsigned long zebra_debug_kernel;
@@ -89,6 +93,7 @@ extern unsigned long zebra_debug_mpls;
extern unsigned long zebra_debug_vxlan;
extern unsigned long zebra_debug_pw;
extern unsigned long zebra_debug_dplane;
+extern unsigned long zebra_debug_mlag;
extern void zebra_debug_init(void);
diff --git a/zebra/interface.c b/zebra/interface.c
index 8bb5c6e8ef..229f9c1da4 100644
--- a/zebra/interface.c
+++ b/zebra/interface.c
@@ -41,7 +41,7 @@
#include "zebra/interface.h"
#include "zebra/rib.h"
#include "zebra/rt.h"
-#include "zebra/zserv.h"
+#include "zebra/zebra_router.h"
#include "zebra/redistribute.h"
#include "zebra/debug.h"
#include "zebra/irdp.h"
@@ -135,6 +135,8 @@ static int if_zebra_new_hook(struct interface *ifp)
rtadv->DefaultPreference = RTADV_PREF_MEDIUM;
rtadv->AdvPrefixList = list_new();
+ rtadv->AdvRDNSSList = list_new();
+ rtadv->AdvDNSSLList = list_new();
}
#endif /* HAVE_RTADV */
@@ -153,7 +155,7 @@ static int if_zebra_new_hook(struct interface *ifp)
* of seconds and ask again. Hopefully it's all settled
* down upon startup.
*/
- thread_add_timer(zebrad.master, if_zebra_speed_update, ifp, 15,
+ thread_add_timer(zrouter.master, if_zebra_speed_update, ifp, 15,
&zebra_if->speed_update);
return 0;
}
@@ -175,6 +177,8 @@ static int if_zebra_delete_hook(struct interface *ifp)
rtadv = &zebra_if->rtadv;
list_delete(&rtadv->AdvPrefixList);
+ list_delete(&rtadv->AdvRDNSSList);
+ list_delete(&rtadv->AdvDNSSLList);
#endif /* HAVE_RTADV */
THREAD_OFF(zebra_if->speed_update);
diff --git a/zebra/interface.h b/zebra/interface.h
index 01dd697772..1dbcf33fad 100644
--- a/zebra/interface.h
+++ b/zebra/interface.h
@@ -168,6 +168,22 @@ struct rtadvconf {
int DefaultPreference;
#define RTADV_PREF_MEDIUM 0x0 /* Per RFC4191. */
+ /*
+ * List of recursive DNS servers to include in the RDNSS option.
+ * See [RFC8106 5.1]
+ *
+ * Default: empty list; do not emit RDNSS option
+ */
+ struct list *AdvRDNSSList;
+
+ /*
+ * List of DNS search domains to include in the DNSSL option.
+ * See [RFC8106 5.2]
+ *
+ * Default: empty list; do not emit DNSSL option
+ */
+ struct list *AdvDNSSLList;
+
uint8_t inFastRexmit; /* True if we're rexmits faster than usual */
/* Track if RA was configured by BGP or by the Operator or both */
@@ -182,6 +198,41 @@ struct rtadvconf {
#define RTADV_NUM_FAST_REXMITS 4 /* Fast Rexmit RA 4 times on certain events */
};
+struct rtadv_rdnss {
+ /* Address of recursive DNS server to advertise */
+ struct in6_addr addr;
+
+ /*
+ * Lifetime in seconds; all-ones means infinity, zero
+ * stop using it.
+ */
+ uint32_t lifetime;
+
+ /* If lifetime not set, use a default of 3*MaxRtrAdvInterval */
+ int lifetime_set;
+};
+
+/*
+ * [RFC1035 2.3.4] sets the maximum length of a domain name (a sequence of
+ * labels, each prefixed by a length octet) at 255 octets.
+ */
+#define RTADV_MAX_ENCODED_DOMAIN_NAME 255
+
+struct rtadv_dnssl {
+ /* Domain name without trailing root zone dot (NUL-terminated) */
+ char name[RTADV_MAX_ENCODED_DOMAIN_NAME - 1];
+
+ /* Name encoded as in [RFC1035 3.1] */
+ uint8_t encoded_name[RTADV_MAX_ENCODED_DOMAIN_NAME];
+
+ /* Actual length of encoded_name */
+ size_t encoded_len;
+
+ /* Lifetime as for RDNSS */
+ uint32_t lifetime;
+ int lifetime_set;
+};
+
#endif /* HAVE_RTADV */
/* Zebra interface type - ones of interest. */
diff --git a/zebra/irdp_interface.c b/zebra/irdp_interface.c
index ffc49d2c13..c0b772cd01 100644
--- a/zebra/irdp_interface.c
+++ b/zebra/irdp_interface.c
@@ -45,7 +45,7 @@
#include "zebra/interface.h"
#include "zebra/rtadv.h"
#include "zebra/rib.h"
-#include "zebra/zserv.h"
+#include "zebra/zebra_router.h"
#include "zebra/redistribute.h"
#include "zebra/irdp.h"
#include "zebra/zebra_errors.h"
@@ -285,7 +285,7 @@ static void irdp_if_start(struct interface *ifp, int multicast,
timer);
irdp->t_advertise = NULL;
- thread_add_timer(zebrad.master, irdp_send_thread, ifp, timer,
+ thread_add_timer(zrouter.master, irdp_send_thread, ifp, timer,
&irdp->t_advertise);
}
diff --git a/zebra/irdp_main.c b/zebra/irdp_main.c
index 9300ba6034..a9734056bc 100644
--- a/zebra/irdp_main.c
+++ b/zebra/irdp_main.c
@@ -56,7 +56,7 @@
#include "zebra/interface.h"
#include "zebra/rtadv.h"
#include "zebra/rib.h"
-#include "zebra/zserv.h"
+#include "zebra/zebra_router.h"
#include "zebra/redistribute.h"
#include "zebra/irdp.h"
#include "zebra/zebra_errors.h"
@@ -113,7 +113,7 @@ int irdp_sock_init(void)
};
t_irdp_raw = NULL;
- thread_add_read(zebrad.master, irdp_read_raw, NULL, sock, &t_irdp_raw);
+ thread_add_read(zrouter.master, irdp_read_raw, NULL, sock, &t_irdp_raw);
return sock;
}
@@ -245,7 +245,7 @@ int irdp_send_thread(struct thread *t_advert)
timer);
irdp->t_advertise = NULL;
- thread_add_timer(zebrad.master, irdp_send_thread, ifp, timer,
+ thread_add_timer(zrouter.master, irdp_send_thread, ifp, timer,
&irdp->t_advertise);
return 0;
}
@@ -306,7 +306,7 @@ void process_solicit(struct interface *ifp)
timer = (random() % MAX_RESPONSE_DELAY) + 1;
irdp->t_advertise = NULL;
- thread_add_timer(zebrad.master, irdp_send_thread, ifp, timer,
+ thread_add_timer(zrouter.master, irdp_send_thread, ifp, timer,
&irdp->t_advertise);
}
diff --git a/zebra/irdp_packet.c b/zebra/irdp_packet.c
index bebccd7168..774d84d66d 100644
--- a/zebra/irdp_packet.c
+++ b/zebra/irdp_packet.c
@@ -58,7 +58,7 @@
#include "zebra/interface.h"
#include "zebra/rtadv.h"
#include "zebra/rib.h"
-#include "zebra/zserv.h"
+#include "zebra/zebra_router.h"
#include "zebra/redistribute.h"
#include "zebra/irdp.h"
#include "zebra/zebra_errors.h"
@@ -230,7 +230,7 @@ int irdp_read_raw(struct thread *r)
int irdp_sock = THREAD_FD(r);
t_irdp_raw = NULL;
- thread_add_read(zebrad.master, irdp_read_raw, NULL, irdp_sock,
+ thread_add_read(zrouter.master, irdp_read_raw, NULL, irdp_sock,
&t_irdp_raw);
ret = irdp_recvmsg(irdp_sock, (uint8_t *)buf, IRDP_RX_BUF, &ifindex);
diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c
index c88bfbb101..2f850c6338 100644
--- a/zebra/kernel_netlink.c
+++ b/zebra/kernel_netlink.c
@@ -43,7 +43,8 @@
#include "mpls.h"
#include "lib_errors.h"
-#include "zebra/zserv.h"
+//#include "zebra/zserv.h"
+#include "zebra/zebra_router.h"
#include "zebra/zebra_ns.h"
#include "zebra/zebra_vrf.h"
#include "zebra/rt.h"
@@ -388,7 +389,7 @@ static int kernel_read(struct thread *thread)
netlink_parse_info(netlink_information_fetch, &zns->netlink, &dp_info,
5, 0);
zns->t_netlink = NULL;
- thread_add_read(zebrad.master, kernel_read, zns, zns->netlink.sock,
+ thread_add_read(zrouter.master, kernel_read, zns, zns->netlink.sock,
&zns->t_netlink);
return 0;
@@ -1158,7 +1159,7 @@ void kernel_init(struct zebra_ns *zns)
zns->t_netlink = NULL;
- thread_add_read(zebrad.master, kernel_read, zns,
+ thread_add_read(zrouter.master, kernel_read, zns,
zns->netlink.sock, &zns->t_netlink);
rt_netlink_init();
diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c
index acd7f911dc..792756efeb 100644
--- a/zebra/kernel_socket.c
+++ b/zebra/kernel_socket.c
@@ -43,7 +43,7 @@
#include "zebra/rt.h"
#include "zebra/interface.h"
-#include "zebra/zserv.h"
+#include "zebra/zebra_router.h"
#include "zebra/debug.h"
#include "zebra/kernel_socket.h"
#include "zebra/rib.h"
@@ -1372,7 +1372,7 @@ static int kernel_read(struct thread *thread)
return 0;
}
- thread_add_read(zebrad.master, kernel_read, NULL, sock, NULL);
+ thread_add_read(zrouter.master, kernel_read, NULL, sock, NULL);
if (IS_ZEBRA_DEBUG_KERNEL)
rtmsg_debug(&buf.r.rtm);
@@ -1445,7 +1445,7 @@ static void routing_socket(struct zebra_ns *zns)
zlog_warn ("Can't set O_NONBLOCK to routing socket");*/
/* kernel_read needs rewrite. */
- thread_add_read(zebrad.master, kernel_read, NULL, routing_sock, NULL);
+ thread_add_read(zrouter.master, kernel_read, NULL, routing_sock, NULL);
}
/* Exported interface function. This function simply calls
diff --git a/zebra/label_manager.c b/zebra/label_manager.c
index 13472059a0..1b17845e41 100644
--- a/zebra/label_manager.c
+++ b/zebra/label_manager.c
@@ -34,7 +34,8 @@
#include "lib/zclient.h"
#include "lib/libfrr.h"
-#include "zebra/zserv.h"
+//#include "zebra/zserv.h"
+#include "zebra/zebra_router.h"
#include "zebra/label_manager.h"
#include "zebra/zebra_errors.h"
@@ -294,7 +295,7 @@ static int lm_zclient_connect(struct thread *t)
if (zclient_socket_connect(zclient) < 0) {
flog_err(EC_ZEBRA_LM_CLIENT_CONNECTION_FAILED,
"Error connecting synchronous zclient!");
- thread_add_timer(zebrad.master, lm_zclient_connect, zclient,
+ thread_add_timer(zrouter.master, lm_zclient_connect, zclient,
CONNECTION_DELAY, &zclient->t_connect);
return -1;
}
@@ -318,7 +319,7 @@ static void lm_zclient_init(char *lm_zserv_path)
lm_zserv_path);
/* Set default values. */
- zclient = zclient_new(zebrad.master, &zclient_options_default);
+ zclient = zclient_new(zrouter.master, &zclient_options_default);
zclient->privs = &zserv_privs;
zclient->sock = -1;
zclient->t_connect = NULL;
diff --git a/zebra/main.c b/zebra/main.c
index b54c36c109..c605050c57 100644
--- a/zebra/main.c
+++ b/zebra/main.c
@@ -62,12 +62,6 @@
#define ZEBRA_PTM_SUPPORT
-/* Zebra instance */
-struct zebra_t zebrad = {
- .rtm_table_default = 0,
- .packets_to_process = ZEBRA_ZAPI_PACKETS_TO_PROCESS,
-};
-
/* process id. */
pid_t pid;
@@ -156,10 +150,10 @@ static void sigint(void)
zebra_dplane_pre_finish();
- for (ALL_LIST_ELEMENTS(zebrad.client_list, ln, nn, client))
+ for (ALL_LIST_ELEMENTS(zrouter.client_list, ln, nn, client))
zserv_close_client(client);
- list_delete_all_node(zebrad.client_list);
+ list_delete_all_node(zrouter.client_list);
zebra_ptm_finish();
if (retain_mode)
@@ -168,8 +162,8 @@ static void sigint(void)
if (zvrf)
SET_FLAG(zvrf->flags, ZEBRA_VRF_RETAIN);
}
- if (zebrad.lsp_process_q)
- work_queue_free_and_null(&zebrad.lsp_process_q);
+ if (zrouter.lsp_process_q)
+ work_queue_free_and_null(&zrouter.lsp_process_q);
vrf_terminate();
ns_walk_func(zebra_ns_early_shutdown);
@@ -179,7 +173,7 @@ static void sigint(void)
prefix_list_reset();
route_map_finish();
- list_delete(&zebrad.client_list);
+ list_delete(&zrouter.client_list);
/* Indicate that all new dplane work has been enqueued. When that
* work is complete, the dataplane will enqueue an event
@@ -202,9 +196,6 @@ int zebra_finalize(struct thread *dummy)
/* Stop dplane thread and finish any cleanup */
zebra_dplane_shutdown();
- work_queue_free_and_null(&zebrad.ribq);
- meta_queue_free(zebrad.mq);
-
zebra_router_terminate();
frr_fini();
@@ -391,7 +382,7 @@ int main(int argc, char **argv)
}
}
- zebrad.master = frr_init();
+ zrouter.master = frr_init();
/* Initialize pthread library */
frr_pthread_init();
@@ -479,7 +470,7 @@ int main(int argc, char **argv)
#endif /* HANDLE_NETLINK_FUZZING */
- frr_run(zebrad.master);
+ frr_run(zrouter.master);
/* Not reached... */
return 0;
diff --git a/zebra/redistribute.c b/zebra/redistribute.c
index c5769ae06f..f98a4c02c3 100644
--- a/zebra/redistribute.c
+++ b/zebra/redistribute.c
@@ -33,7 +33,7 @@
#include "srcdest_table.h"
#include "zebra/rib.h"
-#include "zebra/zserv.h"
+#include "zebra/zebra_router.h"
#include "zebra/zebra_ns.h"
#include "zebra/zebra_vrf.h"
#include "zebra/zebra_routemap.h"
@@ -159,10 +159,10 @@ void redistribute_update(const struct prefix *p, const struct prefix *src_p,
if (IS_ZEBRA_DEBUG_RIB) {
zlog_debug(
- "%u:%s: Redist update re %p (type %d), old %p (type %d)",
+ "%u:%s: Redist update re %p (%s), old %p (%s)",
re->vrf_id, prefix2str(p, buf, sizeof(buf)),
- re, re->type, prev_re,
- prev_re ? prev_re->type : -1);
+ re, zebra_route_string(re->type), prev_re,
+ prev_re ? zebra_route_string(prev_re->type) : "None");
}
afi = family2afi(p->family);
@@ -173,7 +173,7 @@ void redistribute_update(const struct prefix *p, const struct prefix *src_p,
return;
}
- for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) {
+ for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) {
send_redistribute = 0;
if (is_default_prefix(p)
@@ -229,8 +229,9 @@ void redistribute_delete(const struct prefix *p, const struct prefix *src_p,
if (IS_ZEBRA_DEBUG_RIB) {
inet_ntop(p->family, &p->u.prefix, buf, INET6_ADDRSTRLEN);
- zlog_debug("%u:%s/%d: Redist delete re %p (type %d)",
- re->vrf_id, buf, p->prefixlen, re, re->type);
+ zlog_debug("%u:%s/%d: Redist delete re %p (%s)",
+ re->vrf_id, buf, p->prefixlen, re,
+ zebra_route_string(re->type));
}
/* Add DISTANCE_INFINITY check. */
@@ -245,7 +246,7 @@ void redistribute_delete(const struct prefix *p, const struct prefix *src_p,
return;
}
- for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) {
+ for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) {
if ((is_default_prefix(p)
&& vrf_bitmap_check(client->redist_default[afi],
re->vrf_id))
@@ -404,12 +405,12 @@ void zebra_interface_up_update(struct interface *ifp)
ifp->name, ifp->vrf_id);
if (ifp->ptm_status || !ifp->ptm_enable) {
- for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client))
- if (vrf_bitmap_check(client->ifinfo, ifp->vrf_id)) {
- zsend_interface_update(ZEBRA_INTERFACE_UP,
- client, ifp);
- zsend_interface_link_params(client, ifp);
- }
+ for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode,
+ client)) {
+ zsend_interface_update(ZEBRA_INTERFACE_UP,
+ client, ifp);
+ zsend_interface_link_params(client, ifp);
+ }
}
}
@@ -423,7 +424,7 @@ void zebra_interface_down_update(struct interface *ifp)
zlog_debug("MESSAGE: ZEBRA_INTERFACE_DOWN %s(%u)",
ifp->name, ifp->vrf_id);
- for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) {
+ for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) {
zsend_interface_update(ZEBRA_INTERFACE_DOWN, client, ifp);
}
}
@@ -438,12 +439,11 @@ void zebra_interface_add_update(struct interface *ifp)
zlog_debug("MESSAGE: ZEBRA_INTERFACE_ADD %s(%u)", ifp->name,
ifp->vrf_id);
- for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client))
- if (vrf_bitmap_check(client->ifinfo, ifp->vrf_id)) {
- client->ifadd_cnt++;
- zsend_interface_add(client, ifp);
- zsend_interface_link_params(client, ifp);
- }
+ for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) {
+ client->ifadd_cnt++;
+ zsend_interface_add(client, ifp);
+ zsend_interface_link_params(client, ifp);
+ }
}
void zebra_interface_delete_update(struct interface *ifp)
@@ -455,7 +455,7 @@ void zebra_interface_delete_update(struct interface *ifp)
zlog_debug("MESSAGE: ZEBRA_INTERFACE_DELETE %s(%u)",
ifp->name, ifp->vrf_id);
- for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) {
+ for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) {
client->ifdel_cnt++;
zsend_interface_delete(client, ifp);
}
@@ -487,7 +487,7 @@ void zebra_interface_address_add_update(struct interface *ifp,
router_id_add_address(ifc);
- for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client))
+ for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client))
if (CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL)) {
client->connected_rt_add_cnt++;
zsend_interface_address(ZEBRA_INTERFACE_ADDRESS_ADD,
@@ -516,7 +516,7 @@ void zebra_interface_address_delete_update(struct interface *ifp,
router_id_del_address(ifc);
- for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client))
+ for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client))
if (CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL)) {
client->connected_rt_del_cnt++;
zsend_interface_address(ZEBRA_INTERFACE_ADDRESS_DELETE,
@@ -537,7 +537,7 @@ void zebra_interface_vrf_update_del(struct interface *ifp, vrf_id_t new_vrf_id)
"MESSAGE: ZEBRA_INTERFACE_VRF_UPDATE/DEL %s VRF Id %u -> %u",
ifp->name, ifp->vrf_id, new_vrf_id);
- for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) {
+ for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) {
/* Need to delete if the client is not interested in the new
* VRF. */
zsend_interface_update(ZEBRA_INTERFACE_DOWN, client, ifp);
@@ -560,7 +560,7 @@ void zebra_interface_vrf_update_add(struct interface *ifp, vrf_id_t old_vrf_id)
"MESSAGE: ZEBRA_INTERFACE_VRF_UPDATE/ADD %s VRF Id %u -> %u",
ifp->name, old_vrf_id, ifp->vrf_id);
- for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) {
+ for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) {
/* Need to add if the client is interested in the new VRF. */
client->ifadd_cnt++;
zsend_interface_add(client, ifp);
@@ -612,7 +612,7 @@ int zebra_add_import_table_entry(struct route_node *rn, struct route_entry *re,
newre->flags = re->flags;
newre->metric = re->metric;
newre->mtu = re->mtu;
- newre->table = zebrad.rtm_table_default;
+ newre->table = zrouter.rtm_table_default;
newre->nexthop_num = 0;
newre->uptime = time(NULL);
newre->instance = re->table;
@@ -633,7 +633,7 @@ int zebra_del_import_table_entry(struct route_node *rn, struct route_entry *re)
rib_delete(afi, SAFI_UNICAST, re->vrf_id, ZEBRA_ROUTE_TABLE, re->table,
re->flags, &p, NULL, re->ng.nexthop,
- zebrad.rtm_table_default, re->metric, re->distance, false);
+ zrouter.rtm_table_default, re->metric, re->distance, false);
return 0;
}
@@ -648,7 +648,7 @@ int zebra_import_table(afi_t afi, uint32_t table_id, uint32_t distance,
if (!is_zebra_valid_kernel_table(table_id)
|| ((table_id == RT_TABLE_MAIN)
- || (table_id == zebrad.rtm_table_default)))
+ || (table_id == zrouter.rtm_table_default)))
return (-1);
if (afi >= AFI_MAX)
@@ -811,7 +811,6 @@ void zebra_interface_parameters_update(struct interface *ifp)
zlog_debug("MESSAGE: ZEBRA_INTERFACE_LINK_PARAMS %s(%u)",
ifp->name, ifp->vrf_id);
- for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client))
- if (vrf_bitmap_check(client->ifinfo, ifp->vrf_id))
- zsend_interface_link_params(client, ifp);
+ for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client))
+ zsend_interface_link_params(client, ifp);
}
diff --git a/zebra/router-id.c b/zebra/router-id.c
index c500f79a6c..569ffbab41 100644
--- a/zebra/router-id.c
+++ b/zebra/router-id.c
@@ -38,15 +38,12 @@
#include "rib.h"
#include "vrf.h"
-#include "zebra/zserv.h"
+#include "zebra/zebra_router.h"
#include "zebra/zapi_msg.h"
#include "zebra/zebra_vrf.h"
#include "zebra/router-id.h"
#include "zebra/redistribute.h"
-/* master zebra server structure */
-extern struct zebra_t zebrad;
-
static struct connected *router_id_find_node(struct list *l,
struct connected *ifc)
{
@@ -114,7 +111,7 @@ static void router_id_set(struct prefix *p, vrf_id_t vrf_id)
router_id_get(&p2, vrf_id);
- for (ALL_LIST_ELEMENTS_RO(zebrad.client_list, node, client))
+ for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client))
zsend_router_id_update(client, &p2, vrf_id);
}
@@ -145,7 +142,7 @@ void router_id_add_address(struct connected *ifc)
if (prefix_same(&before, &after))
return;
- for (ALL_LIST_ELEMENTS_RO(zebrad.client_list, node, client))
+ for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client))
zsend_router_id_update(client, &after, zvrf_id(zvrf));
}
@@ -177,7 +174,7 @@ void router_id_del_address(struct connected *ifc)
if (prefix_same(&before, &after))
return;
- for (ALL_LIST_ELEMENTS_RO(zebrad.client_list, node, client))
+ for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client))
zsend_router_id_update(client, &after, zvrf_id(zvrf));
}
diff --git a/zebra/rt.h b/zebra/rt.h
index 0b14a3ef36..4080b0ccb2 100644
--- a/zebra/rt.h
+++ b/zebra/rt.h
@@ -32,7 +32,7 @@
#include "zebra/zebra_dplane.h"
/*
- * Update or delete a route or LSP from the kernel,
+ * Update or delete a route, LSP, or pseudowire from the kernel,
* using info from a dataplane context.
*/
extern enum zebra_dplane_result kernel_route_update(
@@ -41,6 +41,8 @@ extern enum zebra_dplane_result kernel_route_update(
extern enum zebra_dplane_result kernel_lsp_update(
struct zebra_dplane_ctx *ctx);
+enum zebra_dplane_result kernel_pw_update(struct zebra_dplane_ctx *ctx);
+
extern int kernel_address_add_ipv4(struct interface *, struct connected *);
extern int kernel_address_delete_ipv4(struct interface *, struct connected *);
extern int kernel_address_add_ipv6(struct interface *, struct connected *);
@@ -67,6 +69,8 @@ extern int kernel_del_mac(struct interface *ifp, vlanid_t vid,
extern int kernel_add_neigh(struct interface *ifp, struct ipaddr *ip,
struct ethaddr *mac, uint8_t flags);
extern int kernel_del_neigh(struct interface *ifp, struct ipaddr *ip);
+extern int kernel_upd_neigh(struct interface *ifp, struct ipaddr *ip,
+ struct ethaddr *mac, uint8_t flags, uint16_t state);
/*
* Southbound Initialization routines to get initial starting
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index ce2d25862d..3868412b20 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -556,6 +556,9 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
parse_encap_mpls(tb[RTA_ENCAP], labels);
}
+ if (rtm->rtm_flags & RTNH_F_ONLINK)
+ SET_FLAG(nh.flags, NEXTHOP_FLAG_ONLINK);
+
if (num_labels)
nexthop_add_labels(&nh, ZEBRA_LSP_STATIC,
num_labels, labels);
@@ -663,6 +666,10 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
nexthop_add_labels(nh, ZEBRA_LSP_STATIC,
num_labels, labels);
+ if (nh && (rtnh->rtnh_flags & RTNH_F_ONLINK))
+ SET_FLAG(nh->flags,
+ NEXTHOP_FLAG_ONLINK);
+
if (rtnh->rtnh_len == 0)
break;
@@ -1133,8 +1140,7 @@ static void _netlink_route_build_singlepath(const char *routedesc, int bytelen,
if (nexthop->type != NEXTHOP_TYPE_BLACKHOLE)
addattr32(nlmsg, req_size, RTA_OIF, nexthop->ifindex);
- if (nexthop->type == NEXTHOP_TYPE_IFINDEX
- || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) {
+ if (nexthop->type == NEXTHOP_TYPE_IFINDEX) {
if (cmd == RTM_NEWROUTE) {
if (nexthop->rmap_src.ipv4.s_addr)
addattr_l(nlmsg, req_size, RTA_PREFSRC,
@@ -1150,23 +1156,6 @@ static void _netlink_route_build_singlepath(const char *routedesc, int bytelen,
"nexthop via if %u(%u)",
routedesc, nexthop->ifindex, nexthop->vrf_id);
}
-
- if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) {
- if (cmd == RTM_NEWROUTE) {
- if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->rmap_src.ipv6))
- addattr_l(nlmsg, req_size, RTA_PREFSRC,
- &nexthop->rmap_src.ipv6, bytelen);
- else if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->src.ipv6))
- addattr_l(nlmsg, req_size, RTA_PREFSRC,
- &nexthop->src.ipv6, bytelen);
- }
-
- if (IS_ZEBRA_DEBUG_KERNEL)
- zlog_debug(
- "netlink_route_multipath() (%s): "
- "nexthop via if %u(%u)",
- routedesc, nexthop->ifindex, nexthop->vrf_id);
- }
}
/* This function takes a nexthop as argument and
@@ -1338,8 +1327,7 @@ static void _netlink_route_build_multipath(const char *routedesc, int bytelen,
rtnh->rtnh_ifindex = nexthop->ifindex;
/* ifindex */
- if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
- || nexthop->type == NEXTHOP_TYPE_IFINDEX) {
+ if (nexthop->type == NEXTHOP_TYPE_IFINDEX) {
if (nexthop->rmap_src.ipv4.s_addr)
*src = &nexthop->rmap_src;
else if (nexthop->src.ipv4.s_addr)
@@ -2713,12 +2701,12 @@ static int netlink_neigh_update2(struct interface *ifp, struct ipaddr *ip,
addattr_l(&req.n, sizeof(req), NDA_LLADDR, mac, 6);
if (IS_ZEBRA_DEBUG_KERNEL)
- zlog_debug("Tx %s family %s IF %s(%u) Neigh %s MAC %s flags 0x%x",
+ zlog_debug("Tx %s family %s IF %s(%u) Neigh %s MAC %s flags 0x%x state 0x%x",
nl_msg_type_to_str(cmd),
nl_family_to_str(req.ndm.ndm_family), ifp->name,
ifp->ifindex, ipaddr2str(ip, buf, sizeof(buf)),
mac ? prefix_mac2str(mac, buf2, sizeof(buf2))
- : "null", flags);
+ : "null", flags, state);
return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns,
0);
@@ -2749,6 +2737,13 @@ int kernel_del_neigh(struct interface *ifp, struct ipaddr *ip)
return netlink_neigh_update2(ifp, ip, NULL, 0, 0, RTM_DELNEIGH);
}
+int kernel_upd_neigh(struct interface *ifp, struct ipaddr *ip,
+ struct ethaddr *mac, uint8_t flags, uint16_t state)
+{
+ return netlink_neigh_update2(ifp, ip, mac, flags,
+ state, RTM_NEWNEIGH);
+}
+
/*
* MPLS label forwarding table change via netlink interface, using dataplane
* context information.
diff --git a/zebra/rtadv.c b/zebra/rtadv.c
index a22f6395c9..5088e2e8e1 100644
--- a/zebra/rtadv.c
+++ b/zebra/rtadv.c
@@ -66,6 +66,9 @@ extern struct zebra_privs_t zserv_privs;
#define ALLNODE "ff02::1"
#define ALLROUTER "ff02::2"
+DEFINE_MTYPE_STATIC(ZEBRA, RTADV_RDNSS, "Router Advertisement RDNSS")
+DEFINE_MTYPE_STATIC(ZEBRA, RTADV_DNSSL, "Router Advertisement DNSSL")
+
/* Order is intentional. Matches RFC4191. This array is also used for
command matching, so only modify with care. */
const char *rtadv_pref_strs[] = {"medium", "high", "INVALID", "low", 0};
@@ -355,6 +358,78 @@ static void rtadv_send_packet(int sock, struct interface *ifp)
len += sizeof(struct nd_opt_mtu);
}
+ /*
+ * There is no limit on the number of configurable recursive DNS
+ * servers or search list entries. We don't want the RA message
+ * to exceed the link's MTU (risking fragmentation) or even
+ * blow the stack buffer allocated for it.
+ */
+ size_t max_len = MIN(ifp->mtu6 - 40, sizeof(buf));
+
+ /* Recursive DNS servers */
+ struct rtadv_rdnss *rdnss;
+
+ for (ALL_LIST_ELEMENTS_RO(zif->rtadv.AdvRDNSSList, node, rdnss)) {
+ size_t opt_len =
+ sizeof(struct nd_opt_rdnss) + sizeof(struct in6_addr);
+
+ if (len + opt_len > max_len) {
+ zlog_warn(
+ "%s(%u): Tx RA: RDNSS option would exceed MTU, omitting it",
+ ifp->name, ifp->ifindex);
+ goto no_more_opts;
+ }
+ struct nd_opt_rdnss *opt = (struct nd_opt_rdnss *)(buf + len);
+
+ opt->nd_opt_rdnss_type = ND_OPT_RDNSS;
+ opt->nd_opt_rdnss_len = opt_len / 8;
+ opt->nd_opt_rdnss_reserved = 0;
+ opt->nd_opt_rdnss_lifetime = htonl(
+ rdnss->lifetime_set
+ ? rdnss->lifetime
+ : MAX(1, 0.003 * zif->rtadv.MaxRtrAdvInterval));
+
+ len += sizeof(struct nd_opt_rdnss);
+
+ IPV6_ADDR_COPY(buf + len, &rdnss->addr);
+ len += sizeof(struct in6_addr);
+ }
+
+ /* DNS search list */
+ struct rtadv_dnssl *dnssl;
+
+ for (ALL_LIST_ELEMENTS_RO(zif->rtadv.AdvDNSSLList, node, dnssl)) {
+ size_t opt_len = sizeof(struct nd_opt_dnssl)
+ + ((dnssl->encoded_len + 7) & ~7);
+
+ if (len + opt_len > max_len) {
+ zlog_warn(
+ "%s(%u): Tx RA: DNSSL option would exceed MTU, omitting it",
+ ifp->name, ifp->ifindex);
+ goto no_more_opts;
+ }
+ struct nd_opt_dnssl *opt = (struct nd_opt_dnssl *)(buf + len);
+
+ opt->nd_opt_dnssl_type = ND_OPT_DNSSL;
+ opt->nd_opt_dnssl_len = opt_len / 8;
+ opt->nd_opt_dnssl_reserved = 0;
+ opt->nd_opt_dnssl_lifetime = htonl(
+ dnssl->lifetime_set
+ ? dnssl->lifetime
+ : MAX(1, 0.003 * zif->rtadv.MaxRtrAdvInterval));
+
+ len += sizeof(struct nd_opt_dnssl);
+
+ memcpy(buf + len, dnssl->encoded_name, dnssl->encoded_len);
+ len += dnssl->encoded_len;
+
+ /* Zero-pad to 8-octet boundary */
+ while (len % 8)
+ buf[len++] = '\0';
+ }
+
+no_more_opts:
+
msg.msg_name = (void *)&addr;
msg.msg_namelen = sizeof(struct sockaddr_in6);
msg.msg_iov = &iov;
@@ -1533,6 +1608,308 @@ DEFUN (no_ipv6_nd_mtu,
return CMD_SUCCESS;
}
+static struct rtadv_rdnss *rtadv_rdnss_new(void)
+{
+ return XCALLOC(MTYPE_RTADV_RDNSS, sizeof(struct rtadv_rdnss));
+}
+
+static void rtadv_rdnss_free(struct rtadv_rdnss *rdnss)
+{
+ XFREE(MTYPE_RTADV_RDNSS, rdnss);
+}
+
+static struct rtadv_rdnss *rtadv_rdnss_lookup(struct list *list,
+ struct rtadv_rdnss *rdnss)
+{
+ struct listnode *node;
+ struct rtadv_rdnss *p;
+
+ for (ALL_LIST_ELEMENTS_RO(list, node, p))
+ if (IPV6_ADDR_SAME(&p->addr, &rdnss->addr))
+ return p;
+ return NULL;
+}
+
+static struct rtadv_rdnss *rtadv_rdnss_get(struct list *list,
+ struct rtadv_rdnss *rdnss)
+{
+ struct rtadv_rdnss *p;
+
+ p = rtadv_rdnss_lookup(list, rdnss);
+ if (p)
+ return p;
+
+ p = rtadv_rdnss_new();
+ memcpy(p, rdnss, sizeof(struct rtadv_rdnss));
+ listnode_add(list, p);
+
+ return p;
+}
+
+static void rtadv_rdnss_set(struct zebra_if *zif, struct rtadv_rdnss *rdnss)
+{
+ struct rtadv_rdnss *p;
+
+ p = rtadv_rdnss_get(zif->rtadv.AdvRDNSSList, rdnss);
+ p->lifetime = rdnss->lifetime;
+ p->lifetime_set = rdnss->lifetime_set;
+}
+
+static int rtadv_rdnss_reset(struct zebra_if *zif, struct rtadv_rdnss *rdnss)
+{
+ struct rtadv_rdnss *p;
+
+ p = rtadv_rdnss_lookup(zif->rtadv.AdvRDNSSList, rdnss);
+ if (p) {
+ listnode_delete(zif->rtadv.AdvRDNSSList, p);
+ rtadv_rdnss_free(p);
+ return 1;
+ }
+
+ return 0;
+}
+
+static struct rtadv_dnssl *rtadv_dnssl_new(void)
+{
+ return XCALLOC(MTYPE_RTADV_DNSSL, sizeof(struct rtadv_dnssl));
+}
+
+static void rtadv_dnssl_free(struct rtadv_dnssl *dnssl)
+{
+ XFREE(MTYPE_RTADV_DNSSL, dnssl);
+}
+
+static struct rtadv_dnssl *rtadv_dnssl_lookup(struct list *list,
+ struct rtadv_dnssl *dnssl)
+{
+ struct listnode *node;
+ struct rtadv_dnssl *p;
+
+ for (ALL_LIST_ELEMENTS_RO(list, node, p))
+ if (!strcasecmp(p->name, dnssl->name))
+ return p;
+ return NULL;
+}
+
+static struct rtadv_dnssl *rtadv_dnssl_get(struct list *list,
+ struct rtadv_dnssl *dnssl)
+{
+ struct rtadv_dnssl *p;
+
+ p = rtadv_dnssl_lookup(list, dnssl);
+ if (p)
+ return p;
+
+ p = rtadv_dnssl_new();
+ memcpy(p, dnssl, sizeof(struct rtadv_dnssl));
+ listnode_add(list, p);
+
+ return p;
+}
+
+static void rtadv_dnssl_set(struct zebra_if *zif, struct rtadv_dnssl *dnssl)
+{
+ struct rtadv_dnssl *p;
+
+ p = rtadv_dnssl_get(zif->rtadv.AdvDNSSLList, dnssl);
+ memcpy(p, dnssl, sizeof(struct rtadv_dnssl));
+}
+
+static int rtadv_dnssl_reset(struct zebra_if *zif, struct rtadv_dnssl *dnssl)
+{
+ struct rtadv_dnssl *p;
+
+ p = rtadv_dnssl_lookup(zif->rtadv.AdvDNSSLList, dnssl);
+ if (p) {
+ listnode_delete(zif->rtadv.AdvDNSSLList, p);
+ rtadv_dnssl_free(p);
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * Convert dotted domain name (with or without trailing root zone dot) to
+ * sequence of length-prefixed labels, as described in [RFC1035 3.1]. Write up
+ * to strlen(in) + 2 octets to out.
+ *
+ * Returns the number of octets written to out or -1 if in does not constitute
+ * a valid domain name.
+ */
+static int rtadv_dnssl_encode(uint8_t *out, const char *in)
+{
+ const char *label_start, *label_end;
+ size_t outp;
+
+ outp = 0;
+ label_start = in;
+
+ while (*label_start) {
+ size_t label_len;
+
+ label_end = strchr(label_start, '.');
+ if (label_end == NULL)
+ label_end = label_start + strlen(label_start);
+
+ label_len = label_end - label_start;
+ if (label_len >= 64)
+ return -1; /* labels must be 63 octets or less */
+
+ out[outp++] = (uint8_t)label_len;
+ memcpy(out + outp, label_start, label_len);
+ outp += label_len;
+ label_start += label_len;
+ if (*label_start == '.')
+ label_start++;
+ }
+
+ out[outp++] = '\0';
+ return outp;
+}
+
+DEFUN(ipv6_nd_rdnss,
+ ipv6_nd_rdnss_cmd,
+ "ipv6 nd rdnss X:X::X:X [<(0-4294967295)|infinite>]",
+ "Interface IPv6 config commands\n"
+ "Neighbor discovery\n"
+ "Recursive DNS server information\n"
+ "IPv6 address\n"
+ "Valid lifetime in seconds\n"
+ "Infinite valid lifetime\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ struct zebra_if *zif = ifp->info;
+ struct rtadv_rdnss rdnss = {};
+
+ if (inet_pton(AF_INET6, argv[3]->arg, &rdnss.addr) != 1) {
+ vty_out(vty, "Malformed IPv6 address\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ if (argc > 4) {
+ char *lifetime = argv[4]->type == RANGE_TKN ? argv[4]->arg
+ : argv[4]->text;
+ rdnss.lifetime = strmatch(lifetime, "infinite")
+ ? UINT32_MAX
+ : strtoll(lifetime, NULL, 10);
+ rdnss.lifetime_set = 1;
+ }
+
+ rtadv_rdnss_set(zif, &rdnss);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(no_ipv6_nd_rdnss,
+ no_ipv6_nd_rdnss_cmd,
+ "no ipv6 nd rdnss X:X::X:X [<(0-4294967295)|infinite>]",
+ NO_STR
+ "Interface IPv6 config commands\n"
+ "Neighbor discovery\n"
+ "Recursive DNS server information\n"
+ "IPv6 address\n"
+ "Valid lifetime in seconds\n"
+ "Infinite valid lifetime\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ struct zebra_if *zif = ifp->info;
+ struct rtadv_rdnss rdnss = {};
+
+ if (inet_pton(AF_INET6, argv[4]->arg, &rdnss.addr) != 1) {
+ vty_out(vty, "Malformed IPv6 address\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ if (rtadv_rdnss_reset(zif, &rdnss) != 1) {
+ vty_out(vty, "Non-existant RDNSS address\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(ipv6_nd_dnssl,
+ ipv6_nd_dnssl_cmd,
+ "ipv6 nd dnssl SUFFIX [<(0-4294967295)|infinite>]",
+ "Interface IPv6 config commands\n"
+ "Neighbor discovery\n"
+ "DNS search list information\n"
+ "Domain name suffix\n"
+ "Valid lifetime in seconds\n"
+ "Infinite valid lifetime\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ struct zebra_if *zif = ifp->info;
+ struct rtadv_dnssl dnssl = {};
+ size_t len;
+ int ret;
+
+ len = strlcpy(dnssl.name, argv[3]->arg, sizeof(dnssl.name));
+ if (len == 0 || len >= sizeof(dnssl.name)) {
+ vty_out(vty, "Malformed DNS search domain\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ if (dnssl.name[len - 1] == '.') {
+ /*
+ * Allow, but don't require, a trailing dot signifying the root
+ * zone. Canonicalize by cutting it off if present.
+ */
+ dnssl.name[len - 1] = '\0';
+ len--;
+ }
+ if (argc > 4) {
+ char *lifetime = argv[4]->type == RANGE_TKN ? argv[4]->arg
+ : argv[4]->text;
+ dnssl.lifetime = strmatch(lifetime, "infinite")
+ ? UINT32_MAX
+ : strtoll(lifetime, NULL, 10);
+ dnssl.lifetime_set = 1;
+ }
+
+ ret = rtadv_dnssl_encode(dnssl.encoded_name, dnssl.name);
+ if (ret < 0) {
+ vty_out(vty, "Malformed DNS search domain\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ dnssl.encoded_len = ret;
+ rtadv_dnssl_set(zif, &dnssl);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(no_ipv6_nd_dnssl,
+ no_ipv6_nd_dnssl_cmd,
+ "no ipv6 nd dnssl SUFFIX [<(0-4294967295)|infinite>]",
+ NO_STR
+ "Interface IPv6 config commands\n"
+ "Neighbor discovery\n"
+ "DNS search list information\n"
+ "Domain name suffix\n"
+ "Valid lifetime in seconds\n"
+ "Infinite valid lifetime\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ struct zebra_if *zif = ifp->info;
+ struct rtadv_dnssl dnssl = {};
+ size_t len;
+
+ len = strlcpy(dnssl.name, argv[4]->arg, sizeof(dnssl.name));
+ if (len == 0 || len >= sizeof(dnssl.name)) {
+ vty_out(vty, "Malformed DNS search domain\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ if (dnssl.name[len - 1] == '.') {
+ dnssl.name[len - 1] = '\0';
+ len--;
+ }
+ if (rtadv_dnssl_reset(zif, &dnssl) != 1) {
+ vty_out(vty, "Non-existant DNS search domain\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ return CMD_SUCCESS;
+}
+
+
/* Dump interface ND information to vty. */
static int nd_dump_vty(struct vty *vty, struct interface *ifp)
{
@@ -1607,6 +1984,8 @@ static int rtadv_config_write(struct vty *vty, struct interface *ifp)
struct zebra_if *zif;
struct listnode *node;
struct rtadv_prefix *rprefix;
+ struct rtadv_rdnss *rdnss;
+ struct rtadv_dnssl *dnssl;
char buf[PREFIX_STRLEN];
int interval;
@@ -1688,6 +2067,29 @@ static int rtadv_config_write(struct vty *vty, struct interface *ifp)
vty_out(vty, " router-address");
vty_out(vty, "\n");
}
+ for (ALL_LIST_ELEMENTS_RO(zif->rtadv.AdvRDNSSList, node, rdnss)) {
+ char buf[INET6_ADDRSTRLEN];
+
+ vty_out(vty, " ipv6 nd rdnss %s",
+ inet_ntop(AF_INET6, &rdnss->addr, buf, sizeof(buf)));
+ if (rdnss->lifetime_set) {
+ if (rdnss->lifetime == UINT32_MAX)
+ vty_out(vty, " infinite");
+ else
+ vty_out(vty, " %u", rdnss->lifetime);
+ }
+ vty_out(vty, "\n");
+ }
+ for (ALL_LIST_ELEMENTS_RO(zif->rtadv.AdvDNSSLList, node, dnssl)) {
+ vty_out(vty, " ipv6 nd dnssl %s", dnssl->name);
+ if (dnssl->lifetime_set) {
+ if (dnssl->lifetime == UINT32_MAX)
+ vty_out(vty, " infinite");
+ else
+ vty_out(vty, " %u", dnssl->lifetime);
+ }
+ vty_out(vty, "\n");
+ }
return 0;
}
@@ -1698,9 +2100,9 @@ static void rtadv_event(struct zebra_ns *zns, enum rtadv_event event, int val)
switch (event) {
case RTADV_START:
- thread_add_read(zebrad.master, rtadv_read, zns, val,
+ thread_add_read(zrouter.master, rtadv_read, zns, val,
&rtadv->ra_read);
- thread_add_event(zebrad.master, rtadv_timer, zns, 0,
+ thread_add_event(zrouter.master, rtadv_timer, zns, 0,
&rtadv->ra_timer);
break;
case RTADV_STOP:
@@ -1714,15 +2116,15 @@ static void rtadv_event(struct zebra_ns *zns, enum rtadv_event event, int val)
}
break;
case RTADV_TIMER:
- thread_add_timer(zebrad.master, rtadv_timer, zns, val,
+ thread_add_timer(zrouter.master, rtadv_timer, zns, val,
&rtadv->ra_timer);
break;
case RTADV_TIMER_MSEC:
- thread_add_timer_msec(zebrad.master, rtadv_timer, zns, val,
+ thread_add_timer_msec(zrouter.master, rtadv_timer, zns, val,
&rtadv->ra_timer);
break;
case RTADV_READ:
- thread_add_read(zebrad.master, rtadv_read, zns, val,
+ thread_add_read(zrouter.master, rtadv_read, zns, val,
&rtadv->ra_read);
break;
default:
@@ -1782,6 +2184,10 @@ void rtadv_cmd_init(void)
install_element(INTERFACE_NODE, &no_ipv6_nd_router_preference_cmd);
install_element(INTERFACE_NODE, &ipv6_nd_mtu_cmd);
install_element(INTERFACE_NODE, &no_ipv6_nd_mtu_cmd);
+ install_element(INTERFACE_NODE, &ipv6_nd_rdnss_cmd);
+ install_element(INTERFACE_NODE, &no_ipv6_nd_rdnss_cmd);
+ install_element(INTERFACE_NODE, &ipv6_nd_dnssl_cmd);
+ install_element(INTERFACE_NODE, &no_ipv6_nd_dnssl_cmd);
}
static int if_join_all_router(int sock, struct interface *ifp)
diff --git a/zebra/rtadv.h b/zebra/rtadv.h
index 03db13fd69..f7c27ebcb3 100644
--- a/zebra/rtadv.h
+++ b/zebra/rtadv.h
@@ -91,6 +91,37 @@ struct nd_opt_homeagent_info { /* Home Agent info */
} __attribute__((__packed__));
#endif
+#ifndef ND_OPT_RDNSS
+#define ND_OPT_RDNSS 25
+#endif
+#ifndef ND_OPT_DNSSL
+#define ND_OPT_DNSSL 31
+#endif
+
+#ifndef HAVE_STRUCT_ND_OPT_RDNSS
+struct nd_opt_rdnss { /* Recursive DNS server option [RFC8106 5.1] */
+ uint8_t nd_opt_rdnss_type;
+ uint8_t nd_opt_rdnss_len;
+ uint16_t nd_opt_rdnss_reserved;
+ uint32_t nd_opt_rdnss_lifetime;
+ /* Followed by one or more IPv6 addresses */
+} __attribute__((__packed__));
+#endif
+
+#ifndef HAVE_STRUCT_ND_OPT_DNSSL
+struct nd_opt_dnssl { /* DNS search list option [RFC8106 5.2] */
+ uint8_t nd_opt_dnssl_type;
+ uint8_t nd_opt_dnssl_len;
+ uint16_t nd_opt_dnssl_reserved;
+ uint32_t nd_opt_dnssl_lifetime;
+ /*
+ * Followed by one or more domain names encoded as in [RFC1035 3.1].
+ * Multiple domain names are concatenated after encoding. In any case,
+ * the result is zero-padded to a multiple of 8 octets.
+ */
+} __attribute__((__packed__));
+#endif
+
extern const char *rtadv_pref_strs[];
#endif /* HAVE_RTADV */
diff --git a/zebra/subdir.am b/zebra/subdir.am
index daa7946bc0..1e36d020a3 100644
--- a/zebra/subdir.am
+++ b/zebra/subdir.am
@@ -95,6 +95,9 @@ zebra_zebra_SOURCES = \
zebra/zebra_errors.c \
# end
+zebra/debug_clippy.c: $(CLIPPY_DEPS)
+zebra/debug.$(OBJEXT): zebra/debug_clippy.c
+
zebra/zebra_mlag_clippy.c: $(CLIPPY_DEPS)
zebra/zebra_mlag.$(OBJEXT): zebra/zebra_mlag_clippy.c
diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c
index 951a411f25..9b91289dec 100644
--- a/zebra/zapi_msg.c
+++ b/zebra/zapi_msg.c
@@ -42,6 +42,7 @@
#include "lib/libfrr.h"
#include "lib/sockopt.h"
+#include "zebra/zebra_router.h"
#include "zebra/rib.h"
#include "zebra/zebra_memory.h"
#include "zebra/zebra_ns.h"
@@ -208,12 +209,6 @@ int zsend_interface_link_params(struct zserv *client, struct interface *ifp)
{
struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ);
- /* Check this client need interface information. */
- if (!vrf_bitmap_check(client->ifinfo, ifp->vrf_id)) {
- stream_free(s);
- return 0;
- }
-
if (!ifp->link_params) {
stream_free(s);
return 0;
@@ -365,7 +360,7 @@ static void zebra_interface_nbr_address_add_update(struct interface *ifp,
p->prefixlen, ifc->ifp->name);
}
- for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client))
+ for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client))
zsend_interface_nbr_address(ZEBRA_INTERFACE_NBR_ADDRESS_ADD,
client, ifp, ifc);
}
@@ -389,7 +384,7 @@ static void zebra_interface_nbr_address_delete_update(struct interface *ifp,
p->prefixlen, ifc->ifp->name);
}
- for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client))
+ for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client))
zsend_interface_nbr_address(ZEBRA_INTERFACE_NBR_ADDRESS_DELETE,
client, ifp, ifc);
}
@@ -768,7 +763,7 @@ void zsend_rule_notify_owner(struct zebra_pbr_rule *rule,
zlog_debug("%s: Notifying %u", __PRETTY_FUNCTION__,
rule->rule.unique);
- for (ALL_LIST_ELEMENTS_RO(zebrad.client_list, node, client)) {
+ for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) {
if (rule->sock == client->sock)
break;
}
@@ -804,7 +799,7 @@ void zsend_ipset_notify_owner(struct zebra_pbr_ipset *ipset,
zlog_debug("%s: Notifying %u", __PRETTY_FUNCTION__,
ipset->unique);
- for (ALL_LIST_ELEMENTS_RO(zebrad.client_list, node, client)) {
+ for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) {
if (ipset->sock == client->sock)
break;
}
@@ -834,7 +829,7 @@ void zsend_ipset_entry_notify_owner(struct zebra_pbr_ipset_entry *ipset,
zlog_debug("%s: Notifying %u", __PRETTY_FUNCTION__,
ipset->unique);
- for (ALL_LIST_ELEMENTS_RO(zebrad.client_list, node, client)) {
+ for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) {
if (ipset->sock == client->sock)
break;
}
@@ -864,7 +859,7 @@ void zsend_iptable_notify_owner(struct zebra_pbr_iptable *iptable,
zlog_debug("%s: Notifying %u", __PRETTY_FUNCTION__,
iptable->unique);
- for (ALL_LIST_ELEMENTS_RO(zebrad.client_list, node, client)) {
+ for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) {
if (iptable->sock == client->sock)
break;
}
@@ -1316,9 +1311,6 @@ static void zread_interface_add(ZAPI_HANDLER_ARGS)
struct vrf *vrf;
struct interface *ifp;
- /* Interface information is needed. */
- vrf_bitmap_set(client->ifinfo, zvrf_id(zvrf));
-
RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
FOR_ALL_INTERFACES (vrf, ifp) {
/* Skip pseudo interface. */
@@ -1335,7 +1327,6 @@ static void zread_interface_add(ZAPI_HANDLER_ARGS)
/* Unregister zebra server interface information. */
static void zread_interface_delete(ZAPI_HANDLER_ARGS)
{
- vrf_bitmap_unset(client->ifinfo, zvrf_id(zvrf));
}
void zserv_nexthop_num_warn(const char *caller, const struct prefix *p,
@@ -1674,6 +1665,18 @@ static void zsend_capabilities(struct zserv *client, struct zebra_vrf *zvrf)
zserv_send_message(client, s);
}
+void zsend_capabilities_all_clients(void)
+{
+ struct listnode *node, *nnode;
+ struct zebra_vrf *zvrf;
+ struct zserv *client;
+
+ zvrf = vrf_info_lookup(VRF_DEFAULT);
+ for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) {
+ zsend_capabilities(client, zvrf);
+ }
+}
+
/* Tie up route-type and client->sock */
static void zread_hello(ZAPI_HANDLER_ARGS)
{
@@ -1718,7 +1721,6 @@ static void zread_vrf_unregister(ZAPI_HANDLER_ARGS)
vrf_bitmap_unset(client->redist[afi][i], zvrf_id(zvrf));
vrf_bitmap_unset(client->redist_default[afi], zvrf_id(zvrf));
}
- vrf_bitmap_unset(client->ifinfo, zvrf_id(zvrf));
vrf_bitmap_unset(client->ridinfo, zvrf_id(zvrf));
}
@@ -2455,6 +2457,7 @@ void (*zserv_handlers[])(ZAPI_HANDLER_ARGS) = {
[ZEBRA_FEC_REGISTER] = zread_fec_register,
[ZEBRA_FEC_UNREGISTER] = zread_fec_unregister,
[ZEBRA_ADVERTISE_DEFAULT_GW] = zebra_vxlan_advertise_gw_macip,
+ [ZEBRA_ADVERTISE_SVI_MACIP] = zebra_vxlan_advertise_svi_macip,
[ZEBRA_ADVERTISE_SUBNET] = zebra_vxlan_advertise_subnet,
[ZEBRA_ADVERTISE_ALL_VNI] = zebra_vxlan_advertise_all_vni,
[ZEBRA_REMOTE_VTEP_ADD] = zebra_vxlan_remote_vtep_add,
diff --git a/zebra/zapi_msg.h b/zebra/zapi_msg.h
index 11b469e144..b770b8e881 100644
--- a/zebra/zapi_msg.h
+++ b/zebra/zapi_msg.h
@@ -84,3 +84,5 @@ extern void zsend_iptable_notify_owner(struct zebra_pbr_iptable *iptable,
enum zapi_iptable_notify_owner note);
extern void zserv_nexthop_num_warn(const char *caller, const struct prefix *p,
const unsigned int nexthop_num);
+
+extern void zsend_capabilities_all_clients(void);
diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c
index 6fbad2f71e..928169a862 100644
--- a/zebra/zebra_dplane.c
+++ b/zebra/zebra_dplane.c
@@ -26,7 +26,7 @@
#include "lib/zebra.h"
#include "zebra/zebra_router.h"
#include "zebra/zebra_memory.h"
-#include "zebra/zserv.h"
+#include "zebra/zebra_router.h"
#include "zebra/zebra_dplane.h"
#include "zebra/rt.h"
#include "zebra/debug.h"
@@ -102,6 +102,23 @@ struct dplane_route_info {
};
/*
+ * Pseudowire info for the dataplane
+ */
+struct dplane_pw_info {
+ char ifname[IF_NAMESIZE];
+ ifindex_t ifindex;
+ int type;
+ int af;
+ int status;
+ uint32_t flags;
+ union g_addr nexthop;
+ mpls_label_t local_label;
+ mpls_label_t remote_label;
+
+ union pw_protocol_fields fields;
+};
+
+/*
* The context block used to exchange info about route updates across
* the boundary between the zebra main context (and pthread) and the
* dataplane layer (and pthread).
@@ -136,6 +153,7 @@ struct zebra_dplane_ctx {
union {
struct dplane_route_info rinfo;
zebra_lsp_t lsp;
+ struct dplane_pw_info pw;
} u;
/* Namespace info, used especially for netlink kernel communication */
@@ -237,10 +255,11 @@ static struct zebra_dplane_globals {
_Atomic uint32_t dg_other_errors;
_Atomic uint32_t dg_lsps_in;
- _Atomic uint32_t dg_lsps_queued;
- _Atomic uint32_t dg_lsps_queued_max;
_Atomic uint32_t dg_lsp_errors;
+ _Atomic uint32_t dg_pws_in;
+ _Atomic uint32_t dg_pw_errors;
+
_Atomic uint32_t dg_update_yields;
/* Dataplane pthread */
@@ -276,6 +295,8 @@ static void dplane_info_from_zns(struct zebra_dplane_info *ns_info,
struct zebra_ns *zns);
static enum zebra_dplane_result lsp_update_internal(zebra_lsp_t *lsp,
enum dplane_op_e op);
+static enum zebra_dplane_result pw_update_internal(struct zebra_pw *pw,
+ enum dplane_op_e op);
/*
* Public APIs
@@ -363,6 +384,8 @@ static void dplane_ctx_free(struct zebra_dplane_ctx **pctx)
break;
}
+ case DPLANE_OP_PW_INSTALL:
+ case DPLANE_OP_PW_UNINSTALL:
case DPLANE_OP_NONE:
break;
}
@@ -490,6 +513,13 @@ const char *dplane_op2str(enum dplane_op_e op)
ret = "LSP_DELETE";
break;
+ case DPLANE_OP_PW_INSTALL:
+ ret = "PW_INSTALL";
+ break;
+ case DPLANE_OP_PW_UNINSTALL:
+ ret = "PW_UNINSTALL";
+ break;
+
};
return ret;
@@ -735,6 +765,71 @@ uint32_t dplane_ctx_get_lsp_num_ecmp(const struct zebra_dplane_ctx *ctx)
return ctx->u.lsp.num_ecmp;
}
+const char *dplane_ctx_get_pw_ifname(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.pw.ifname;
+}
+
+mpls_label_t dplane_ctx_get_pw_local_label(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.pw.local_label;
+}
+
+mpls_label_t dplane_ctx_get_pw_remote_label(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.pw.remote_label;
+}
+
+int dplane_ctx_get_pw_type(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.pw.type;
+}
+
+int dplane_ctx_get_pw_af(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.pw.af;
+}
+
+uint32_t dplane_ctx_get_pw_flags(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.pw.flags;
+}
+
+int dplane_ctx_get_pw_status(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.pw.status;
+}
+
+const union g_addr *dplane_ctx_get_pw_nexthop(
+ const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return &(ctx->u.pw.nexthop);
+}
+
+const union pw_protocol_fields *dplane_ctx_get_pw_proto(
+ const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return &(ctx->u.pw.fields);
+}
+
/*
* End of dplane context accessors
*/
@@ -938,6 +1033,47 @@ static int dplane_ctx_lsp_init(struct zebra_dplane_ctx *ctx,
}
/*
+ * Capture information for an LSP update in a dplane context.
+ */
+static int dplane_ctx_pw_init(struct zebra_dplane_ctx *ctx,
+ enum dplane_op_e op,
+ struct zebra_pw *pw)
+{
+ int ret = AOK;
+
+ if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
+ zlog_debug("init dplane ctx %s: pw '%s', loc %u, rem %u",
+ dplane_op2str(op), pw->ifname, pw->local_label,
+ pw->remote_label);
+
+ ctx->zd_op = op;
+ ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS;
+
+ /* Capture namespace info: no netlink support as of 12/18,
+ * but just in case...
+ */
+ dplane_ctx_ns_init(ctx, zebra_ns_lookup(NS_DEFAULT), false);
+
+ memset(&ctx->u.pw, 0, sizeof(ctx->u.pw));
+
+ /* This name appears to be c-string, so we use string copy. */
+ strlcpy(ctx->u.pw.ifname, pw->ifname, sizeof(ctx->u.pw.ifname));
+ ctx->zd_vrf_id = pw->vrf_id;
+ ctx->u.pw.ifindex = pw->ifindex;
+ ctx->u.pw.type = pw->type;
+ ctx->u.pw.af = pw->af;
+ ctx->u.pw.local_label = pw->local_label;
+ ctx->u.pw.remote_label = pw->remote_label;
+ ctx->u.pw.flags = pw->flags;
+
+ ctx->u.pw.nexthop = pw->nexthop;
+
+ ctx->u.pw.fields = pw->data;
+
+ return ret;
+}
+
+/*
* Enqueue a new route update,
* and ensure an event is active for the dataplane pthread.
*/
@@ -1141,6 +1277,22 @@ enum zebra_dplane_result dplane_lsp_delete(zebra_lsp_t *lsp)
}
/*
+ * Enqueue pseudowire install for the dataplane.
+ */
+enum zebra_dplane_result dplane_pw_install(struct zebra_pw *pw)
+{
+ return pw_update_internal(pw, DPLANE_OP_PW_INSTALL);
+}
+
+/*
+ * Enqueue pseudowire un-install for the dataplane.
+ */
+enum zebra_dplane_result dplane_pw_uninstall(struct zebra_pw *pw)
+{
+ return pw_update_internal(pw, DPLANE_OP_PW_UNINSTALL);
+}
+
+/*
* Common internal LSP update utility
*/
static enum zebra_dplane_result lsp_update_internal(zebra_lsp_t *lsp,
@@ -1181,6 +1333,45 @@ done:
}
/*
+ * Internal, common handler for pseudowire updates.
+ */
+static enum zebra_dplane_result pw_update_internal(struct zebra_pw *pw,
+ enum dplane_op_e op)
+{
+ enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
+ int ret;
+ struct zebra_dplane_ctx *ctx = NULL;
+
+ ctx = dplane_ctx_alloc();
+ if (ctx == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = dplane_ctx_pw_init(ctx, op, pw);
+ if (ret != AOK)
+ goto done;
+
+ ret = dplane_route_enqueue(ctx);
+
+done:
+ /* Update counter */
+ atomic_fetch_add_explicit(&zdplane_info.dg_pws_in, 1,
+ memory_order_relaxed);
+
+ if (ret == AOK)
+ result = ZEBRA_DPLANE_REQUEST_QUEUED;
+ else {
+ atomic_fetch_add_explicit(&zdplane_info.dg_pw_errors, 1,
+ memory_order_relaxed);
+ if (ctx)
+ dplane_ctx_free(&ctx);
+ }
+
+ return result;
+}
+
+/*
* Handler for 'show dplane'
*/
int dplane_show_helper(struct vty *vty, bool detailed)
@@ -1512,6 +1703,32 @@ kernel_dplane_lsp_update(struct zebra_dplane_ctx *ctx)
}
/*
+ * Handler for kernel pseudowire updates
+ */
+static enum zebra_dplane_result
+kernel_dplane_pw_update(struct zebra_dplane_ctx *ctx)
+{
+ enum zebra_dplane_result res;
+
+ if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
+ zlog_debug("Dplane pw %s: op %s af %d loc: %u rem: %u",
+ dplane_ctx_get_pw_ifname(ctx),
+ dplane_op2str(ctx->zd_op),
+ dplane_ctx_get_pw_af(ctx),
+ dplane_ctx_get_pw_local_label(ctx),
+ dplane_ctx_get_pw_remote_label(ctx));
+
+ res = kernel_pw_update(ctx);
+
+ if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
+ atomic_fetch_add_explicit(
+ &zdplane_info.dg_pw_errors, 1,
+ memory_order_relaxed);
+
+ return res;
+}
+
+/*
* Handler for kernel route updates
*/
static enum zebra_dplane_result
@@ -1577,6 +1794,11 @@ static int kernel_dplane_process_func(struct zebra_dplane_provider *prov)
res = kernel_dplane_lsp_update(ctx);
break;
+ case DPLANE_OP_PW_INSTALL:
+ case DPLANE_OP_PW_UNINSTALL:
+ res = kernel_dplane_pw_update(ctx);
+ break;
+
default:
atomic_fetch_add_explicit(
&zdplane_info.dg_other_errors, 1,
@@ -1802,7 +2024,7 @@ static int dplane_check_shutdown_status(struct thread *event)
/* We appear to be done - schedule a final callback event
* for the zebra main pthread.
*/
- thread_add_event(zebrad.master, zebra_finalize, NULL, 0, NULL);
+ thread_add_event(zrouter.master, zebra_finalize, NULL, 0, NULL);
}
return 0;
@@ -2052,7 +2274,7 @@ void zebra_dplane_shutdown(void)
/*
* Initialize the dataplane module during startup, internal/private version
*/
-static void zebra_dplane_init_internal(struct zebra_t *zebra)
+static void zebra_dplane_init_internal(void)
{
memset(&zdplane_info, 0, sizeof(zdplane_info));
@@ -2101,6 +2323,6 @@ void zebra_dplane_start(void)
*/
void zebra_dplane_init(int (*results_fp)(struct dplane_ctx_q *))
{
- zebra_dplane_init_internal(&zebrad);
+ zebra_dplane_init_internal();
zdplane_info.dg_results_cb = results_fp;
}
diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h
index 562a8499a2..81226961e8 100644
--- a/zebra/zebra_dplane.h
+++ b/zebra/zebra_dplane.h
@@ -105,7 +105,11 @@ enum dplane_op_e {
/* LSP update */
DPLANE_OP_LSP_INSTALL,
DPLANE_OP_LSP_UPDATE,
- DPLANE_OP_LSP_DELETE
+ DPLANE_OP_LSP_DELETE,
+
+ /* Pseudowire update */
+ DPLANE_OP_PW_INSTALL,
+ DPLANE_OP_PW_UNINSTALL,
};
/*
@@ -203,6 +207,19 @@ zebra_nhlfe_t *dplane_ctx_get_nhlfe(struct zebra_dplane_ctx *ctx);
zebra_nhlfe_t *dplane_ctx_get_best_nhlfe(struct zebra_dplane_ctx *ctx);
uint32_t dplane_ctx_get_lsp_num_ecmp(const struct zebra_dplane_ctx *ctx);
+/* Accessors for pseudowire information */
+const char *dplane_ctx_get_pw_ifname(const struct zebra_dplane_ctx *ctx);
+mpls_label_t dplane_ctx_get_pw_local_label(const struct zebra_dplane_ctx *ctx);
+mpls_label_t dplane_ctx_get_pw_remote_label(const struct zebra_dplane_ctx *ctx);
+int dplane_ctx_get_pw_type(const struct zebra_dplane_ctx *ctx);
+int dplane_ctx_get_pw_af(const struct zebra_dplane_ctx *ctx);
+uint32_t dplane_ctx_get_pw_flags(const struct zebra_dplane_ctx *ctx);
+int dplane_ctx_get_pw_status(const struct zebra_dplane_ctx *ctx);
+const union g_addr *dplane_ctx_get_pw_nexthop(
+ const struct zebra_dplane_ctx *ctx);
+const union pw_protocol_fields *dplane_ctx_get_pw_proto(
+ const struct zebra_dplane_ctx *ctx);
+
/* Namespace info - esp. for netlink communication */
const struct zebra_dplane_info *dplane_ctx_get_ns(
const struct zebra_dplane_ctx *ctx);
@@ -232,6 +249,12 @@ enum zebra_dplane_result dplane_lsp_add(zebra_lsp_t *lsp);
enum zebra_dplane_result dplane_lsp_update(zebra_lsp_t *lsp);
enum zebra_dplane_result dplane_lsp_delete(zebra_lsp_t *lsp);
+/*
+ * Enqueue pseudowire operations for the dataplane.
+ */
+enum zebra_dplane_result dplane_pw_install(struct zebra_pw *pw);
+enum zebra_dplane_result dplane_pw_uninstall(struct zebra_pw *pw);
+
/* Retrieve the limit on the number of pending, unprocessed updates. */
uint32_t dplane_get_in_queue_limit(void);
diff --git a/zebra/zebra_mlag.c b/zebra/zebra_mlag.c
index 35be07c024..5012cc2a49 100644
--- a/zebra/zebra_mlag.c
+++ b/zebra/zebra_mlag.c
@@ -25,16 +25,17 @@
#include "hook.h"
#include "zebra/zebra_mlag.h"
+#include "zebra/zebra_router.h"
+#include "zebra/zapi_msg.h"
+#include "zebra/debug.h"
#ifndef VTYSH_EXTRACT_PL
#include "zebra/zebra_mlag_clippy.c"
#endif
-enum mlag_role role = MLAG_ROLE_NONE;
-
enum mlag_role zebra_mlag_get_role(void)
{
- return role;
+ return zrouter.mlag_info.role;
}
DEFUN_HIDDEN (show_mlag,
@@ -47,7 +48,7 @@ DEFUN_HIDDEN (show_mlag,
char buf[80];
vty_out(vty, "MLag is configured to: %s\n",
- mlag_role2str(role, buf, sizeof(buf)));
+ mlag_role2str(zrouter.mlag_info.role, buf, sizeof(buf)));
return CMD_SUCCESS;
}
@@ -62,12 +63,23 @@ DEFPY_HIDDEN (test_mlag,
"Mlag is setup to be primary\n"
"Mlag is setup to be the secondary\n")
{
+ enum mlag_role orig = zrouter.mlag_info.role;
+ char buf1[80], buf2[80];
+
if (none)
- role = MLAG_ROLE_NONE;
+ zrouter.mlag_info.role = MLAG_ROLE_NONE;
if (primary)
- role = MLAG_ROLE_PRIMARY;
+ zrouter.mlag_info.role = MLAG_ROLE_PRIMARY;
if (secondary)
- role = MLAG_ROLE_SECONDARY;
+ zrouter.mlag_info.role = MLAG_ROLE_SECONDARY;
+
+ if (IS_ZEBRA_DEBUG_MLAG)
+ zlog_debug("Test: Changing role from %s to %s",
+ mlag_role2str(orig, buf1, sizeof(buf1)),
+ mlag_role2str(orig, buf2, sizeof(buf2)));
+
+ if (orig != zrouter.mlag_info.role)
+ zsend_capabilities_all_clients();
return CMD_SUCCESS;
}
diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c
index c255c68866..78c07f9aaf 100644
--- a/zebra/zebra_mpls.c
+++ b/zebra/zebra_mpls.c
@@ -40,6 +40,7 @@
#include "zebra/rt.h"
#include "zebra/interface.h"
#include "zebra/zserv.h"
+#include "zebra/zebra_router.h"
#include "zebra/redistribute.h"
#include "zebra/debug.h"
#include "zebra/zebra_memory.h"
@@ -56,9 +57,6 @@ DEFINE_MTYPE_STATIC(ZEBRA, SNHLFE_IFNAME, "MPLS static nexthop ifname")
int mpls_enabled;
-/* Default rtm_table for all clients */
-extern struct zebra_t zebrad;
-
/* static function declarations */
static void fec_evaluate(struct zebra_vrf *zvrf);
@@ -126,7 +124,6 @@ static zebra_snhlfe_t *snhlfe_add(zebra_slsp_t *slsp,
static int snhlfe_del(zebra_snhlfe_t *snhlfe);
static int snhlfe_del_all(zebra_slsp_t *slsp);
static char *snhlfe2str(zebra_snhlfe_t *snhlfe, char *buf, int size);
-static int mpls_processq_init(struct zebra_t *zebra);
/* Static functions */
@@ -1074,13 +1071,13 @@ static int lsp_processq_add(zebra_lsp_t *lsp)
if (CHECK_FLAG(lsp->flags, LSP_FLAG_SCHEDULED))
return 0;
- if (zebrad.lsp_process_q == NULL) {
+ if (zrouter.lsp_process_q == NULL) {
flog_err(EC_ZEBRA_WQ_NONEXISTENT,
"%s: work_queue does not exist!", __func__);
return -1;
}
- work_queue_add(zebrad.lsp_process_q, lsp);
+ work_queue_add(zrouter.lsp_process_q, lsp);
SET_FLAG(lsp->flags, LSP_FLAG_SCHEDULED);
return 0;
}
@@ -1714,21 +1711,21 @@ static char *snhlfe2str(zebra_snhlfe_t *snhlfe, char *buf, int size)
/*
* Initialize work queue for processing changed LSPs.
*/
-static int mpls_processq_init(struct zebra_t *zebra)
+static int mpls_processq_init(void)
{
- zebra->lsp_process_q = work_queue_new(zebra->master, "LSP processing");
- if (!zebra->lsp_process_q) {
+ zrouter.lsp_process_q = work_queue_new(zrouter.master, "LSP processing");
+ if (!zrouter.lsp_process_q) {
flog_err(EC_ZEBRA_WQ_NONEXISTENT,
"%s: could not initialise work queue!", __func__);
return -1;
}
- zebra->lsp_process_q->spec.workfunc = &lsp_process;
- zebra->lsp_process_q->spec.del_item_data = &lsp_processq_del;
- zebra->lsp_process_q->spec.errorfunc = NULL;
- zebra->lsp_process_q->spec.completion_func = &lsp_processq_complete;
- zebra->lsp_process_q->spec.max_retries = 0;
- zebra->lsp_process_q->spec.hold = 10;
+ zrouter.lsp_process_q->spec.workfunc = &lsp_process;
+ zrouter.lsp_process_q->spec.del_item_data = &lsp_processq_del;
+ zrouter.lsp_process_q->spec.errorfunc = NULL;
+ zrouter.lsp_process_q->spec.completion_func = &lsp_processq_complete;
+ zrouter.lsp_process_q->spec.max_retries = 0;
+ zrouter.lsp_process_q->spec.hold = 10;
return 0;
}
@@ -1803,9 +1800,10 @@ void zebra_mpls_lsp_dplane_result(struct zebra_dplane_ctx *ctx)
break;
case DPLANE_OP_LSP_DELETE:
- flog_warn(EC_ZEBRA_LSP_DELETE_FAILURE,
- "LSP Deletion Failure: in-label %u",
- dplane_ctx_get_in_label(ctx));
+ if (status != ZEBRA_DPLANE_REQUEST_SUCCESS)
+ flog_warn(EC_ZEBRA_LSP_DELETE_FAILURE,
+ "LSP Deletion Failure: in-label %u",
+ dplane_ctx_get_in_label(ctx));
break;
default:
@@ -3062,7 +3060,7 @@ void zebra_mpls_init(void)
return;
}
- if (!mpls_processq_init(&zebrad))
+ if (!mpls_processq_init())
mpls_enabled = 1;
hook_register(zserv_client_close, zebra_mpls_cleanup_fecs_for_client);
diff --git a/zebra/zebra_mpls_netlink.c b/zebra/zebra_mpls_netlink.c
index d8b5ef4ce1..a9233530dc 100644
--- a/zebra/zebra_mpls_netlink.c
+++ b/zebra/zebra_mpls_netlink.c
@@ -61,6 +61,16 @@ done:
ZEBRA_DPLANE_REQUEST_SUCCESS : ZEBRA_DPLANE_REQUEST_FAILURE);
}
+/*
+ * Pseudowire update api - not supported by netlink as of 12/18,
+ * but note that the default has been to report 'success' for pw updates
+ * on unsupported platforms.
+ */
+enum zebra_dplane_result kernel_pw_update(struct zebra_dplane_ctx *ctx)
+{
+ return ZEBRA_DPLANE_REQUEST_SUCCESS;
+}
+
int mpls_kernel_init(void)
{
struct stat st;
diff --git a/zebra/zebra_mpls_null.c b/zebra/zebra_mpls_null.c
index 409432c4fb..2cc3f3b69d 100644
--- a/zebra/zebra_mpls_null.c
+++ b/zebra/zebra_mpls_null.c
@@ -29,6 +29,15 @@ int mpls_kernel_init(void)
return -1;
};
+/*
+ * Pseudowire update api - note that the default has been
+ * to report 'success' for pw updates on unsupported platforms.
+ */
+enum zebra_dplane_result kernel_pw_update(struct zebra_dplane_ctx *ctx)
+{
+ return ZEBRA_DPLANE_REQUEST_SUCCESS;
+}
+
enum zebra_dplane_result kernel_lsp_update(struct zebra_dplane_ctx *ctx)
{
return ZEBRA_DPLANE_REQUEST_FAILURE;
diff --git a/zebra/zebra_mpls_openbsd.c b/zebra/zebra_mpls_openbsd.c
index da76c6ebf9..72c8f73522 100644
--- a/zebra/zebra_mpls_openbsd.c
+++ b/zebra/zebra_mpls_openbsd.c
@@ -314,16 +314,17 @@ enum zebra_dplane_result kernel_lsp_update(struct zebra_dplane_ctx *ctx)
ZEBRA_DPLANE_REQUEST_SUCCESS : ZEBRA_DPLANE_REQUEST_FAILURE);
}
-static int kmpw_install(struct zebra_pw *pw)
+static enum zebra_dplane_result kmpw_install(struct zebra_dplane_ctx *ctx)
{
struct ifreq ifr;
struct ifmpwreq imr;
struct sockaddr_storage ss;
struct sockaddr_in *sa_in = (struct sockaddr_in *)&ss;
struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)&ss;
+ const union g_addr *gaddr;
memset(&imr, 0, sizeof(imr));
- switch (pw->type) {
+ switch (dplane_ctx_get_pw_type(ctx)) {
case PW_TYPE_ETHERNET:
imr.imr_type = IMR_TYPE_ETHERNET;
break;
@@ -332,67 +333,91 @@ static int kmpw_install(struct zebra_pw *pw)
break;
default:
zlog_debug("%s: unhandled pseudowire type (%#X)", __func__,
- pw->type);
- return -1;
+ dplane_ctx_get_pw_type(ctx));
+ return ZEBRA_DPLANE_REQUEST_FAILURE;
}
- if (pw->flags & F_PSEUDOWIRE_CWORD)
+ if (dplane_ctx_get_pw_flags(ctx) & F_PSEUDOWIRE_CWORD)
imr.imr_flags |= IMR_FLAG_CONTROLWORD;
/* pseudowire nexthop */
memset(&ss, 0, sizeof(ss));
- switch (pw->af) {
+ gaddr = dplane_ctx_get_pw_nexthop(ctx);
+ switch (dplane_ctx_get_pw_af(ctx)) {
case AF_INET:
sa_in->sin_family = AF_INET;
sa_in->sin_len = sizeof(struct sockaddr_in);
- sa_in->sin_addr = pw->nexthop.ipv4;
+ sa_in->sin_addr = gaddr->ipv4;
break;
case AF_INET6:
sa_in6->sin6_family = AF_INET6;
sa_in6->sin6_len = sizeof(struct sockaddr_in6);
- sa_in6->sin6_addr = pw->nexthop.ipv6;
+ sa_in6->sin6_addr = gaddr->ipv6;
break;
default:
zlog_debug("%s: unhandled pseudowire address-family (%u)",
- __func__, pw->af);
- return -1;
+ __func__, dplane_ctx_get_pw_af(ctx));
+ return ZEBRA_DPLANE_REQUEST_FAILURE;
}
memcpy(&imr.imr_nexthop, (struct sockaddr *)&ss,
sizeof(imr.imr_nexthop));
/* pseudowire local/remote labels */
- imr.imr_lshim.shim_label = pw->local_label;
- imr.imr_rshim.shim_label = pw->remote_label;
+ imr.imr_lshim.shim_label = dplane_ctx_get_pw_local_label(ctx);
+ imr.imr_rshim.shim_label = dplane_ctx_get_pw_remote_label(ctx);
/* ioctl */
memset(&ifr, 0, sizeof(ifr));
- strlcpy(ifr.ifr_name, pw->ifname, sizeof(ifr.ifr_name));
+ strlcpy(ifr.ifr_name, dplane_ctx_get_pw_ifname(ctx),
+ sizeof(ifr.ifr_name));
ifr.ifr_data = (caddr_t)&imr;
if (ioctl(kr_state.ioctl_fd, SIOCSETMPWCFG, &ifr) == -1) {
flog_err_sys(EC_LIB_SYSTEM_CALL, "ioctl SIOCSETMPWCFG: %s",
safe_strerror(errno));
- return -1;
+ return ZEBRA_DPLANE_REQUEST_FAILURE;
}
- return 0;
+ return ZEBRA_DPLANE_REQUEST_SUCCESS;
}
-static int kmpw_uninstall(struct zebra_pw *pw)
+static enum zebra_dplane_result kmpw_uninstall(struct zebra_dplane_ctx *ctx)
{
struct ifreq ifr;
struct ifmpwreq imr;
memset(&ifr, 0, sizeof(ifr));
memset(&imr, 0, sizeof(imr));
- strlcpy(ifr.ifr_name, pw->ifname, sizeof(ifr.ifr_name));
+ strlcpy(ifr.ifr_name, dplane_ctx_get_pw_ifname(ctx),
+ sizeof(ifr.ifr_name));
ifr.ifr_data = (caddr_t)&imr;
if (ioctl(kr_state.ioctl_fd, SIOCSETMPWCFG, &ifr) == -1) {
flog_err_sys(EC_LIB_SYSTEM_CALL, "ioctl SIOCSETMPWCFG: %s",
safe_strerror(errno));
- return -1;
+ return ZEBRA_DPLANE_REQUEST_FAILURE;
}
- return 0;
+ return ZEBRA_DPLANE_REQUEST_SUCCESS;
+}
+
+/*
+ * Pseudowire update api for openbsd.
+ */
+enum zebra_dplane_result kernel_pw_update(struct zebra_dplane_ctx *ctx)
+{
+ enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
+
+ switch (dplane_ctx_get_op(ctx)) {
+ case DPLANE_OP_PW_INSTALL:
+ result = kmpw_install(ctx);
+ break;
+ case DPLANE_OP_PW_UNINSTALL:
+ result = kmpw_uninstall(ctx);
+ break;
+ default:
+ break;
+ };
+
+ return result;
}
#define MAX_RTSOCK_BUF 128 * 1024
@@ -431,10 +456,6 @@ int mpls_kernel_init(void)
kr_state.rtseq = 1;
- /* register hook to install/uninstall pseudowires */
- hook_register(pw_install, kmpw_install);
- hook_register(pw_uninstall, kmpw_uninstall);
-
return 0;
}
diff --git a/zebra/zebra_netns_notify.c b/zebra/zebra_netns_notify.c
index ef31fcf45d..476638591b 100644
--- a/zebra/zebra_netns_notify.c
+++ b/zebra/zebra_netns_notify.c
@@ -36,7 +36,7 @@
#include "memory.h"
#include "lib_errors.h"
-#include "zserv.h"
+#include "zebra_router.h"
#include "zebra_memory.h"
#endif /* defined(HAVE_NETLINK) */
@@ -121,7 +121,7 @@ static int zebra_ns_continue_read(struct zebra_netns_info *zns_info,
XFREE(MTYPE_NETNS_MISC, zns_info);
return 0;
}
- thread_add_timer_msec(zebrad.master, zebra_ns_ready_read,
+ thread_add_timer_msec(zrouter.master, zebra_ns_ready_read,
(void *)zns_info, ZEBRA_NS_POLLING_INTERVAL_MSEC,
NULL);
return 0;
@@ -242,7 +242,7 @@ static int zebra_ns_notify_read(struct thread *t)
ssize_t len;
zebra_netns_notify_current = thread_add_read(
- zebrad.master, zebra_ns_notify_read, NULL, fd_monitor, NULL);
+ zrouter.master, zebra_ns_notify_read, NULL, fd_monitor, NULL);
len = read(fd_monitor, buf, sizeof(buf));
if (len < 0) {
flog_err_sys(EC_ZEBRA_NS_NOTIFY_READ,
@@ -284,7 +284,7 @@ static int zebra_ns_notify_read(struct thread *t)
sizeof(struct zebra_netns_info));
netnsinfo->retries = ZEBRA_NS_POLLING_MAX_RETRIES;
netnsinfo->netnspath = netnspath;
- thread_add_timer_msec(zebrad.master, zebra_ns_ready_read,
+ thread_add_timer_msec(zrouter.master, zebra_ns_ready_read,
(void *)netnsinfo, 0, NULL);
}
return 0;
@@ -355,7 +355,7 @@ void zebra_ns_notify_init(void)
safe_strerror(errno));
}
zebra_netns_notify_current = thread_add_read(
- zebrad.master, zebra_ns_notify_read, NULL, fd_monitor, NULL);
+ zrouter.master, zebra_ns_notify_read, NULL, fd_monitor, NULL);
}
void zebra_ns_notify_close(void)
diff --git a/zebra/zebra_ptm.c b/zebra/zebra_ptm.c
index e4a4adba05..1e942d6433 100644
--- a/zebra/zebra_ptm.c
+++ b/zebra/zebra_ptm.c
@@ -41,7 +41,7 @@
#include "zebra/zebra_errors.h"
#include "zebra/zebra_ptm.h"
#include "zebra/zebra_ptm_redistribute.h"
-#include "zebra/zserv.h"
+#include "zebra/zebra_router.h"
#include "zebra_vrf.h"
/*
@@ -187,12 +187,12 @@ static int zebra_ptm_flush_messages(struct thread *thread)
ptm_cb.ptm_sock = -1;
zebra_ptm_reset_status(0);
ptm_cb.t_timer = NULL;
- thread_add_timer(zebrad.master, zebra_ptm_connect, NULL,
+ thread_add_timer(zrouter.master, zebra_ptm_connect, NULL,
ptm_cb.reconnect_time, &ptm_cb.t_timer);
return (-1);
case BUFFER_PENDING:
ptm_cb.t_write = NULL;
- thread_add_write(zebrad.master, zebra_ptm_flush_messages, NULL,
+ thread_add_write(zrouter.master, zebra_ptm_flush_messages, NULL,
ptm_cb.ptm_sock, &ptm_cb.t_write);
break;
case BUFFER_EMPTY:
@@ -213,14 +213,14 @@ static int zebra_ptm_send_message(char *data, int size)
ptm_cb.ptm_sock = -1;
zebra_ptm_reset_status(0);
ptm_cb.t_timer = NULL;
- thread_add_timer(zebrad.master, zebra_ptm_connect, NULL,
+ thread_add_timer(zrouter.master, zebra_ptm_connect, NULL,
ptm_cb.reconnect_time, &ptm_cb.t_timer);
return -1;
case BUFFER_EMPTY:
THREAD_OFF(ptm_cb.t_write);
break;
case BUFFER_PENDING:
- thread_add_write(zebrad.master, zebra_ptm_flush_messages, NULL,
+ thread_add_write(zrouter.master, zebra_ptm_flush_messages, NULL,
ptm_cb.ptm_sock, &ptm_cb.t_write);
break;
}
@@ -240,7 +240,7 @@ int zebra_ptm_connect(struct thread *t)
if (ptm_cb.ptm_sock != -1) {
if (init) {
ptm_cb.t_read = NULL;
- thread_add_read(zebrad.master, zebra_ptm_sock_read,
+ thread_add_read(zrouter.master, zebra_ptm_sock_read,
NULL, ptm_cb.ptm_sock, &ptm_cb.t_read);
zebra_bfd_peer_replay_req();
}
@@ -252,7 +252,7 @@ int zebra_ptm_connect(struct thread *t)
ptm_cb.reconnect_time = ZEBRA_PTM_RECONNECT_TIME_MAX;
ptm_cb.t_timer = NULL;
- thread_add_timer(zebrad.master, zebra_ptm_connect, NULL,
+ thread_add_timer(zrouter.master, zebra_ptm_connect, NULL,
ptm_cb.reconnect_time, &ptm_cb.t_timer);
} else if (ptm_cb.reconnect_time >= ZEBRA_PTM_RECONNECT_TIME_MAX) {
ptm_cb.reconnect_time = ZEBRA_PTM_RECONNECT_TIME_INITIAL;
@@ -657,14 +657,14 @@ int zebra_ptm_sock_read(struct thread *thread)
ptm_cb.ptm_sock = -1;
zebra_ptm_reset_status(0);
ptm_cb.t_timer = NULL;
- thread_add_timer(zebrad.master, zebra_ptm_connect, NULL,
+ thread_add_timer(zrouter.master, zebra_ptm_connect, NULL,
ptm_cb.reconnect_time,
&ptm_cb.t_timer);
return (-1);
}
ptm_cb.t_read = NULL;
- thread_add_read(zebrad.master, zebra_ptm_sock_read, NULL,
+ thread_add_read(zrouter.master, zebra_ptm_sock_read, NULL,
ptm_cb.ptm_sock, &ptm_cb.t_read);
return 0;
@@ -700,7 +700,7 @@ void zebra_ptm_bfd_dst_register(ZAPI_HANDLER_ARGS)
if (ptm_cb.ptm_sock == -1) {
ptm_cb.t_timer = NULL;
- thread_add_timer(zebrad.master, zebra_ptm_connect, NULL,
+ thread_add_timer(zrouter.master, zebra_ptm_connect, NULL,
ptm_cb.reconnect_time, &ptm_cb.t_timer);
return;
}
@@ -854,7 +854,7 @@ void zebra_ptm_bfd_dst_deregister(ZAPI_HANDLER_ARGS)
if (ptm_cb.ptm_sock == -1) {
ptm_cb.t_timer = NULL;
- thread_add_timer(zebrad.master, zebra_ptm_connect, NULL,
+ thread_add_timer(zrouter.master, zebra_ptm_connect, NULL,
ptm_cb.reconnect_time, &ptm_cb.t_timer);
return;
}
@@ -981,7 +981,7 @@ void zebra_ptm_bfd_client_register(ZAPI_HANDLER_ARGS)
if (ptm_cb.ptm_sock == -1) {
ptm_cb.t_timer = NULL;
- thread_add_timer(zebrad.master, zebra_ptm_connect, NULL,
+ thread_add_timer(zrouter.master, zebra_ptm_connect, NULL,
ptm_cb.reconnect_time, &ptm_cb.t_timer);
return;
}
@@ -1039,7 +1039,7 @@ int zebra_ptm_bfd_client_deregister(struct zserv *client)
if (ptm_cb.ptm_sock == -1) {
ptm_cb.t_timer = NULL;
- thread_add_timer(zebrad.master, zebra_ptm_connect, NULL,
+ thread_add_timer(zrouter.master, zebra_ptm_connect, NULL,
ptm_cb.reconnect_time, &ptm_cb.t_timer);
return 0;
}
@@ -1276,7 +1276,7 @@ static void zebra_ptm_send_bfdd(struct stream *msg)
}
/* Send message to all running BFDd daemons. */
- for (ALL_LIST_ELEMENTS_RO(zebrad.client_list, node, client)) {
+ for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) {
if (client->proto != ZEBRA_ROUTE_BFD)
continue;
@@ -1308,7 +1308,7 @@ static void zebra_ptm_send_clients(struct stream *msg)
}
/* Send message to all running client daemons. */
- for (ALL_LIST_ELEMENTS_RO(zebrad.client_list, node, client)) {
+ for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) {
if (!IS_BFD_ENABLED_PROTOCOL(client->proto))
continue;
diff --git a/zebra/zebra_ptm_redistribute.c b/zebra/zebra_ptm_redistribute.c
index 3acbe3bf2c..01d5114b9f 100644
--- a/zebra/zebra_ptm_redistribute.c
+++ b/zebra/zebra_ptm_redistribute.c
@@ -22,7 +22,7 @@
#include "prefix.h"
#include "vty.h"
#include "stream.h"
-#include "zebra/zserv.h"
+#include "zebra/zebra_router.h"
#include "zebra/zapi_msg.h"
#include "zebra/zebra_ptm.h"
#include "zebra/zebra_ptm_redistribute.h"
@@ -36,10 +36,6 @@ static int zsend_interface_bfd_update(int cmd, struct zserv *client,
int blen;
struct stream *s;
- /* Check this client need interface information. */
- if (!vrf_bitmap_check(client->ifinfo, ifp->vrf_id))
- return 0;
-
s = stream_new(ZEBRA_MAX_PACKET_SIZ);
zclient_create_header(s, cmd, vrf_id);
@@ -76,7 +72,7 @@ void zebra_interface_bfd_update(struct interface *ifp, struct prefix *dp,
struct listnode *node, *nnode;
struct zserv *client;
- for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) {
+ for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) {
if (!IS_BFD_ENABLED_PROTOCOL(client->proto))
continue;
@@ -106,7 +102,7 @@ void zebra_bfd_peer_replay_req(void)
struct listnode *node, *nnode;
struct zserv *client;
- for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) {
+ for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) {
if (!IS_BFD_ENABLED_PROTOCOL(client->proto))
continue;
diff --git a/zebra/zebra_pw.c b/zebra/zebra_pw.c
index fb9a40fe3d..006c1da02b 100644
--- a/zebra/zebra_pw.c
+++ b/zebra/zebra_pw.c
@@ -27,7 +27,7 @@
#include "zebra/debug.h"
#include "zebra/rib.h"
-#include "zebra/zserv.h"
+#include "zebra/zebra_router.h"
#include "zebra/zapi_msg.h"
#include "zebra/zebra_rnh.h"
#include "zebra/zebra_vrf.h"
@@ -42,8 +42,6 @@ DEFINE_HOOK(pw_uninstall, (struct zebra_pw * pw), (pw))
#define MPLS_NO_LABEL MPLS_INVALID_LABEL
-extern struct zebra_t zebrad;
-
static int zebra_pw_enabled(struct zebra_pw *);
static void zebra_pw_install(struct zebra_pw *);
static void zebra_pw_uninstall(struct zebra_pw *);
@@ -98,9 +96,10 @@ void zebra_pw_del(struct zebra_vrf *zvrf, struct zebra_pw *pw)
zebra_deregister_rnh_pseudowire(pw->vrf_id, pw);
/* uninstall */
- if (pw->status == PW_STATUS_UP)
+ if (pw->status == PW_STATUS_UP) {
hook_call(pw_uninstall, pw);
- else if (pw->install_retry_timer)
+ dplane_pw_uninstall(pw);
+ } else if (pw->install_retry_timer)
THREAD_TIMER_OFF(pw->install_retry_timer);
/* unlink and release memory */
@@ -171,7 +170,8 @@ static void zebra_pw_install(struct zebra_pw *pw)
pw->vrf_id, pw->ifname,
zebra_route_string(pw->protocol));
- if (hook_call(pw_install, pw)) {
+ hook_call(pw_install, pw);
+ if (dplane_pw_install(pw) == ZEBRA_DPLANE_REQUEST_FAILURE) {
zebra_pw_install_failure(pw);
return;
}
@@ -192,6 +192,7 @@ static void zebra_pw_uninstall(struct zebra_pw *pw)
/* ignore any possible error */
hook_call(pw_uninstall, pw);
+ dplane_pw_uninstall(pw);
if (zebra_pw_enabled(pw))
zebra_pw_update_status(pw, PW_STATUS_DOWN);
@@ -213,7 +214,7 @@ void zebra_pw_install_failure(struct zebra_pw *pw)
/* schedule to retry later */
THREAD_TIMER_OFF(pw->install_retry_timer);
- thread_add_timer(zebrad.master, zebra_pw_install_retry, pw,
+ thread_add_timer(zrouter.master, zebra_pw_install_retry, pw,
PW_INSTALL_RETRY_INTERVAL, &pw->install_retry_timer);
zebra_pw_update_status(pw, PW_STATUS_DOWN);
diff --git a/zebra/zebra_pw.h b/zebra/zebra_pw.h
index e6e0a22c21..9692fb4d40 100644
--- a/zebra/zebra_pw.h
+++ b/zebra/zebra_pw.h
@@ -62,8 +62,8 @@ RB_PROTOTYPE(zebra_static_pw_head, zebra_pw, static_pw_entry, zebra_pw_compare);
DECLARE_HOOK(pw_install, (struct zebra_pw * pw), (pw))
DECLARE_HOOK(pw_uninstall, (struct zebra_pw * pw), (pw))
-struct zebra_pw *zebra_pw_add(struct zebra_vrf *, const char *, uint8_t,
- struct zserv *);
+struct zebra_pw *zebra_pw_add(struct zebra_vrf *zvrf, const char *ifname,
+ uint8_t protocol, struct zserv *client);
void zebra_pw_del(struct zebra_vrf *, struct zebra_pw *);
void zebra_pw_change(struct zebra_pw *, ifindex_t, int, int, union g_addr *,
uint32_t, uint32_t, uint8_t, union pw_protocol_fields *);
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index 3445136d1f..8afcc2b685 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -163,7 +163,7 @@ int is_zebra_valid_kernel_table(uint32_t table_id)
int is_zebra_main_routing_table(uint32_t table_id)
{
if ((table_id == RT_TABLE_MAIN)
- || (table_id == zebrad.rtm_table_default))
+ || (table_id == zrouter.rtm_table_default))
return 1;
return 0;
}
@@ -437,6 +437,14 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_EVPN_RVTEP))
return 1;
+ /*
+ * If the kernel has sent us a route, then
+ * by golly gee whiz it's a good route.
+ */
+ if (re->type == ZEBRA_ROUTE_KERNEL ||
+ re->type == ZEBRA_ROUTE_SYSTEM)
+ return 1;
+
/* Skip nexthops that have been filtered out due to route-map */
/* The nexthops are specific to this route and so the same */
/* nexthop for a different route may not have this flag set */
@@ -600,6 +608,9 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
if (!CHECK_FLAG(match->status,
ROUTE_ENTRY_INSTALLED))
continue;
+ if (CHECK_FLAG(newhop->flags,
+ NEXTHOP_FLAG_RECURSIVE))
+ continue;
if (set) {
SET_FLAG(nexthop->flags,
@@ -1078,7 +1089,7 @@ void rib_install_kernel(struct route_node *rn, struct route_entry *re,
hook_call(rib_update, rn, "installing in kernel");
/* Send add or update */
- if (old && (old != re))
+ if (old)
ret = dplane_route_update(rn, re, old);
else
ret = dplane_route_add(rn, re);
@@ -1266,8 +1277,9 @@ static void rib_process_add_fib(struct zebra_vrf *zvrf, struct route_node *rn,
if (IS_ZEBRA_DEBUG_RIB) {
char buf[SRCDEST2STR_BUFFER];
srcdest_rnode2str(rn, buf, sizeof(buf));
- zlog_debug("%u:%s: Adding route rn %p, re %p (type %d)",
- zvrf_id(zvrf), buf, rn, new, new->type);
+ zlog_debug("%u:%s: Adding route rn %p, re %p (%s)",
+ zvrf_id(zvrf), buf, rn, new,
+ zebra_route_string(new->type));
}
/* If labeled-unicast route, install transit LSP. */
@@ -1292,8 +1304,9 @@ static void rib_process_del_fib(struct zebra_vrf *zvrf, struct route_node *rn,
if (IS_ZEBRA_DEBUG_RIB) {
char buf[SRCDEST2STR_BUFFER];
srcdest_rnode2str(rn, buf, sizeof(buf));
- zlog_debug("%u:%s: Deleting route rn %p, re %p (type %d)",
- zvrf_id(zvrf), buf, rn, old, old->type);
+ zlog_debug("%u:%s: Deleting route rn %p, re %p (%s)",
+ zvrf_id(zvrf), buf, rn, old,
+ zebra_route_string(old->type));
}
/* If labeled-unicast route, uninstall transit LSP. */
@@ -1360,15 +1373,16 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf,
srcdest_rnode2str(rn, buf, sizeof(buf));
if (new != old)
zlog_debug(
- "%u:%s: Updating route rn %p, re %p (type %d) "
- "old %p (type %d)",
+ "%u:%s: Updating route rn %p, re %p (%s) old %p (%s)",
zvrf_id(zvrf), buf, rn, new,
- new->type, old, old->type);
+ zebra_route_string(new->type),
+ old,
+ zebra_route_string(old->type));
else
zlog_debug(
- "%u:%s: Updating route rn %p, re %p (type %d)",
+ "%u:%s: Updating route rn %p, re %p (%s)",
zvrf_id(zvrf), buf, rn, new,
- new->type);
+ zebra_route_string(new->type));
}
/* If labeled-unicast route, uninstall transit LSP. */
@@ -1430,15 +1444,16 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf,
srcdest_rnode2str(rn, buf, sizeof(buf));
if (new != old)
zlog_debug(
- "%u:%s: Deleting route rn %p, re %p (type %d) "
- "old %p (type %d) - nexthop inactive",
+ "%u:%s: Deleting route rn %p, re %p (%s) old %p (%s) - nexthop inactive",
zvrf_id(zvrf), buf, rn, new,
- new->type, old, old->type);
+ zebra_route_string(new->type),
+ old,
+ zebra_route_string(old->type));
else
zlog_debug(
- "%u:%s: Deleting route rn %p, re %p (type %d) - nexthop inactive",
+ "%u:%s: Deleting route rn %p, re %p (%s) - nexthop inactive",
zvrf_id(zvrf), buf, rn, new,
- new->type);
+ zebra_route_string(new->type));
}
/* If labeled-unicast route, uninstall transit LSP. */
@@ -1583,10 +1598,10 @@ static void rib_process(struct route_node *rn)
RNODE_FOREACH_RE_SAFE (rn, re, next) {
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug(
- "%u:%s: Examine re %p (type %d) status %x flags %x "
- "dist %d metric %d",
- vrf_id, buf, re, re->type, re->status,
- re->flags, re->distance, re->metric);
+ "%u:%s: Examine re %p (%s) status %x flags %x dist %d metric %d",
+ vrf_id, buf, re, zebra_route_string(re->type),
+ re->status, re->flags, re->distance,
+ re->metric);
UNSET_FLAG(re->status, ROUTE_ENTRY_NEXTHOPS_CHANGED);
@@ -2140,14 +2155,6 @@ static void do_nht_processing(void)
}
}
-/*
- * All meta queues have been processed. Trigger next-hop evaluation.
- */
-static void meta_queue_process_complete(struct work_queue *dummy)
-{
- do_nht_processing();
-}
-
/* Dispatch the meta queue by picking, processing and unlocking the next RN from
* a non-empty sub-queue with lowest priority. wq is equal to zebra->ribq and
* data
@@ -2168,8 +2175,8 @@ static wq_item_status meta_queue_process(struct work_queue *dummy, void *data)
queue_len, queue_limit);
/* Ensure that the meta-queue is actually enqueued */
- if (work_queue_empty(zebrad.ribq))
- work_queue_add(zebrad.ribq, zebrad.mq);
+ if (work_queue_empty(zrouter.ribq))
+ work_queue_add(zrouter.ribq, zrouter.mq);
return WQ_QUEUE_BLOCKED;
}
@@ -2258,7 +2265,7 @@ void rib_queue_add(struct route_node *rn)
return;
}
- if (zebrad.ribq == NULL) {
+ if (zrouter.ribq == NULL) {
flog_err(EC_ZEBRA_WQ_NONEXISTENT,
"%s: work_queue does not exist!", __func__);
return;
@@ -2272,10 +2279,10 @@ void rib_queue_add(struct route_node *rn)
* holder, if necessary, then push the work into it in any case.
* This semantics was introduced after 0.99.9 release.
*/
- if (work_queue_empty(zebrad.ribq))
- work_queue_add(zebrad.ribq, zebrad.mq);
+ if (work_queue_empty(zrouter.ribq))
+ work_queue_add(zrouter.ribq, zrouter.mq);
- rib_meta_queue_add(zebrad.mq, rn);
+ rib_meta_queue_add(zrouter.mq, rn);
return;
}
@@ -2309,27 +2316,25 @@ void meta_queue_free(struct meta_queue *mq)
}
/* initialise zebra rib work queue */
-static void rib_queue_init(struct zebra_t *zebra)
+static void rib_queue_init(void)
{
- assert(zebra);
-
- if (!(zebra->ribq =
- work_queue_new(zebra->master, "route_node processing"))) {
+ if (!(zrouter.ribq = work_queue_new(zrouter.master,
+ "route_node processing"))) {
flog_err(EC_ZEBRA_WQ_NONEXISTENT,
"%s: could not initialise work queue!", __func__);
return;
}
/* fill in the work queue spec */
- zebra->ribq->spec.workfunc = &meta_queue_process;
- zebra->ribq->spec.errorfunc = NULL;
- zebra->ribq->spec.completion_func = &meta_queue_process_complete;
+ zrouter.ribq->spec.workfunc = &meta_queue_process;
+ zrouter.ribq->spec.errorfunc = NULL;
+ zrouter.ribq->spec.completion_func = NULL;
/* XXX: TODO: These should be runtime configurable via vty */
- zebra->ribq->spec.max_retries = 3;
- zebra->ribq->spec.hold = ZEBRA_RIB_PROCESS_HOLD_TIME;
- zebra->ribq->spec.retry = ZEBRA_RIB_PROCESS_RETRY_TIME;
+ zrouter.ribq->spec.max_retries = 3;
+ zrouter.ribq->spec.hold = ZEBRA_RIB_PROCESS_HOLD_TIME;
+ zrouter.ribq->spec.retry = ZEBRA_RIB_PROCESS_RETRY_TIME;
- if (!(zebra->mq = meta_queue_new())) {
+ if (!(zrouter.mq = meta_queue_new())) {
flog_err(EC_ZEBRA_WQ_NONEXISTENT,
"%s: could not initialise meta queue!", __func__);
return;
@@ -2484,9 +2489,9 @@ void rib_delnode(struct route_node *rn, struct route_entry *re)
if (IS_ZEBRA_DEBUG_RIB) {
char buf[SRCDEST2STR_BUFFER];
srcdest_rnode2str(rn, buf, sizeof(buf));
- zlog_debug(
- "%u:%s: Freeing route rn %p, re %p (type %d)",
- re->vrf_id, buf, rn, re, re->type);
+ zlog_debug("%u:%s: Freeing route rn %p, re %p (%s)",
+ re->vrf_id, buf, rn, re,
+ zebra_route_string(re->type));
}
rib_unlink(rn, re);
@@ -2746,10 +2751,9 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
/* Link new re to node.*/
if (IS_ZEBRA_DEBUG_RIB) {
- rnode_debug(
- rn, re->vrf_id,
- "Inserting route rn %p, re %p (type %d) existing %p",
- (void *)rn, (void *)re, re->type, (void *)same);
+ rnode_debug(rn, re->vrf_id,
+ "Inserting route rn %p, re %p (%s) existing %p",
+ rn, re, zebra_route_string(re->type), same);
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
route_entry_dump(p, src_p, re);
@@ -2873,10 +2877,10 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
*/
if (fib && CHECK_FLAG(flags, ZEBRA_FLAG_SELFROUTE)) {
if (IS_ZEBRA_DEBUG_RIB) {
- rnode_debug(
- rn, vrf_id,
- "rn %p, re %p (type %d) was deleted from kernel, adding",
- rn, fib, fib->type);
+ rnode_debug(rn, vrf_id,
+ "rn %p, re %p (%s) was deleted from kernel, adding",
+ rn, fib,
+ zebra_route_string(fib->type));
}
if (allow_delete) {
UNSET_FLAG(fib->status, ROUTE_ENTRY_INSTALLED);
@@ -3225,6 +3229,34 @@ void rib_close_table(struct route_table *table)
}
/*
+ * Handler for async dataplane results after a pseudowire installation
+ */
+static int handle_pw_result(struct zebra_dplane_ctx *ctx)
+{
+ int ret = 0;
+ struct zebra_pw *pw;
+ struct zebra_vrf *vrf;
+
+ /* The pseudowire code assumes success - we act on an error
+ * result for installation attempts here.
+ */
+ if (dplane_ctx_get_op(ctx) != DPLANE_OP_PW_INSTALL)
+ goto done;
+
+ if (dplane_ctx_get_status(ctx) != ZEBRA_DPLANE_REQUEST_SUCCESS) {
+ vrf = zebra_vrf_lookup_by_id(dplane_ctx_get_vrf(ctx));
+ pw = zebra_pw_find(vrf, dplane_ctx_get_pw_ifname(ctx));
+ if (pw)
+ zebra_pw_install_failure(pw);
+ }
+
+done:
+
+ return ret;
+}
+
+
+/*
* Handle results from the dataplane system. Dequeue update context
* structs, dispatch to appropriate internal handlers.
*/
@@ -3235,8 +3267,6 @@ static int rib_process_dplane_results(struct thread *thread)
/* Dequeue a list of completed updates with one lock/unlock cycle */
- /* TODO -- dequeue a list with one lock/unlock cycle? */
-
do {
TAILQ_INIT(&ctxlist);
@@ -3269,6 +3299,11 @@ static int rib_process_dplane_results(struct thread *thread)
zebra_mpls_lsp_dplane_result(ctx);
break;
+ case DPLANE_OP_PW_INSTALL:
+ case DPLANE_OP_PW_UNINSTALL:
+ handle_pw_result(ctx);
+ break;
+
default:
/* Don't expect this: just return the struct? */
dplane_ctx_fini(&ctx);
@@ -3302,7 +3337,7 @@ static int rib_dplane_results(struct dplane_ctx_q *ctxlist)
pthread_mutex_unlock(&dplane_mutex);
/* Ensure event is signalled to zebra main pthread */
- thread_add_event(zebrad.master, rib_process_dplane_results, NULL, 0,
+ thread_add_event(zrouter.master, rib_process_dplane_results, NULL, 0,
&t_dplane);
return 0;
@@ -3311,7 +3346,7 @@ static int rib_dplane_results(struct dplane_ctx_q *ctxlist)
/* Routing information base initialize. */
void rib_init(void)
{
- rib_queue_init(&zebrad);
+ rib_queue_init();
/* Init dataplane, and register for results */
pthread_mutex_init(&dplane_mutex, NULL);
diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c
index 6d52e5f9e6..7d72583dd8 100644
--- a/zebra/zebra_routemap.c
+++ b/zebra/zebra_routemap.c
@@ -33,7 +33,7 @@
#include "vrf.h"
#include "frrstr.h"
-#include "zebra/zserv.h"
+#include "zebra/zebra_router.h"
#include "zebra/redistribute.h"
#include "zebra/debug.h"
#include "zebra/zebra_rnh.h"
@@ -327,10 +327,11 @@ static int ip_protocol_rm_add(struct zebra_vrf *zvrf, const char *rmap,
XFREE(MTYPE_ROUTE_MAP_NAME, PROTO_RM_NAME(zvrf, afi, rtype));
}
-
+ route_map_counter_decrement(PROTO_RM_MAP(zvrf, afi, rtype));
PROTO_RM_NAME(zvrf, afi, rtype) = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap);
PROTO_RM_MAP(zvrf, afi, rtype) =
route_map_lookup_by_name(PROTO_RM_NAME(zvrf, afi, rtype));
+ route_map_counter_increment(PROTO_RM_MAP(zvrf, afi, rtype));
if (PROTO_RM_MAP(zvrf, afi, rtype)) {
@@ -356,6 +357,8 @@ static int ip_protocol_rm_del(struct zebra_vrf *zvrf, const char *rmap,
return CMD_SUCCESS;
if (!rmap || strcmp(rmap, PROTO_RM_NAME(zvrf, afi, rtype)) == 0) {
+
+ route_map_counter_decrement(PROTO_RM_MAP(zvrf, afi, rtype));
if (PROTO_RM_MAP(zvrf, afi, rtype)) {
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug(
@@ -383,10 +386,11 @@ static int ip_nht_rm_add(struct zebra_vrf *zvrf, const char *rmap, int rtype,
XFREE(MTYPE_ROUTE_MAP_NAME, NHT_RM_NAME(zvrf, afi, rtype));
}
-
+ route_map_counter_decrement(NHT_RM_MAP(zvrf, afi, rtype));
NHT_RM_NAME(zvrf, afi, rtype) = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap);
NHT_RM_MAP(zvrf, afi, rtype) =
route_map_lookup_by_name(NHT_RM_NAME(zvrf, afi, rtype));
+ route_map_counter_increment(NHT_RM_MAP(zvrf, afi, rtype));
if (NHT_RM_MAP(zvrf, afi, rtype))
zebra_evaluate_rnh(zvrf, AFI_IP, 1, RNH_NEXTHOP_TYPE, NULL);
@@ -402,6 +406,7 @@ static int ip_nht_rm_del(struct zebra_vrf *zvrf, const char *rmap, int rtype,
return CMD_SUCCESS;
if (!rmap || strcmp(rmap, NHT_RM_NAME(zvrf, afi, rtype)) == 0) {
+ route_map_counter_decrement(NHT_RM_MAP(zvrf, afi, rtype));
if (NHT_RM_MAP(zvrf, afi, rtype)) {
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug(
@@ -1459,6 +1464,7 @@ static void zebra_rib_table_rm_update(const char *rmap)
char *rmap_name;
char afi_ip = 0;
char afi_ipv6 = 0;
+ struct route_map *old = NULL;
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
zvrf = vrf->info;
@@ -1473,8 +1479,19 @@ static void zebra_rib_table_rm_update(const char *rmap)
__func__, rmap,
zebra_route_string(i));
+ old = PROTO_RM_MAP(zvrf, AFI_IP, i);
+
PROTO_RM_MAP(zvrf, AFI_IP, i) =
route_map_lookup_by_name(rmap_name);
+ /* old is NULL. i.e Route map creation event.
+ * So update applied_counter.
+ * If Old is not NULL, i.e It may be routemap
+ * updation or deletion.
+ * So no need to update the counter.
+ */
+ if (!old)
+ route_map_counter_increment(
+ PROTO_RM_MAP(zvrf, AFI_IP, i));
/* There is single rib table for all protocols
*/
if (afi_ip == 0) {
@@ -1497,8 +1514,13 @@ static void zebra_rib_table_rm_update(const char *rmap)
__func__, rmap,
zebra_route_string(i));
+ old = PROTO_RM_MAP(zvrf, AFI_IP6, i);
+
PROTO_RM_MAP(zvrf, AFI_IP6, i) =
route_map_lookup_by_name(rmap_name);
+ if (!old)
+ route_map_counter_increment(
+ PROTO_RM_MAP(zvrf, AFI_IP6, i));
/* There is single rib table for all protocols
*/
if (afi_ipv6 == 0) {
@@ -1530,6 +1552,7 @@ static void zebra_nht_rm_update(const char *rmap)
char *rmap_name;
char afi_ip = 0;
char afi_ipv6 = 0;
+ struct route_map *old = NULL;
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
zvrf = vrf->info;
@@ -1544,8 +1567,13 @@ static void zebra_nht_rm_update(const char *rmap)
__func__, rmap,
zebra_route_string(i));
+ old = NHT_RM_MAP(zvrf, AFI_IP, i);
+
NHT_RM_MAP(zvrf, AFI_IP, i) =
route_map_lookup_by_name(rmap_name);
+ if (!old)
+ route_map_counter_increment(
+ NHT_RM_MAP(zvrf, AFI_IP, i));
/* There is single rib table for all protocols
*/
if (afi_ip == 0) {
@@ -1570,8 +1598,13 @@ static void zebra_nht_rm_update(const char *rmap)
__func__, rmap,
zebra_route_string(i));
+ old = NHT_RM_MAP(zvrf, AFI_IP6, i);
+
NHT_RM_MAP(zvrf, AFI_IP6, i) =
route_map_lookup_by_name(rmap_name);
+ if (!old)
+ route_map_counter_increment(
+ NHT_RM_MAP(zvrf, AFI_IP6, i));
/* There is single rib table for all protocols
*/
if (afi_ipv6 == 0) {
@@ -1745,7 +1778,7 @@ static void zebra_route_map_mark_update(const char *rmap_name)
/* rmap_update_timer of 0 means don't do route updates */
if (zebra_rmap_update_timer && !zebra_t_rmap_update) {
zebra_t_rmap_update = NULL;
- thread_add_timer(zebrad.master, zebra_route_map_update_timer,
+ thread_add_timer(zrouter.master, zebra_route_map_update_timer,
NULL, zebra_rmap_update_timer,
&zebra_t_rmap_update);
}
diff --git a/zebra/zebra_router.c b/zebra/zebra_router.c
index 3e94d6bca8..c3b861c242 100644
--- a/zebra/zebra_router.c
+++ b/zebra/zebra_router.c
@@ -188,6 +188,9 @@ void zebra_router_terminate(void)
zebra_router_free_table(zrt);
}
+ work_queue_free_and_null(&zrouter.ribq);
+ meta_queue_free(zrouter.mq);
+
zebra_vxlan_disable();
zebra_mlag_terminate();
@@ -206,6 +209,9 @@ void zebra_router_init(void)
{
zrouter.sequence_num = 0;
+ zrouter.rtm_table_default = 0;
+ zrouter.packets_to_process = ZEBRA_ZAPI_PACKETS_TO_PROCESS;
+
zebra_vxlan_init();
zebra_mlag_init();
diff --git a/zebra/zebra_router.h b/zebra/zebra_router.h
index f63dcd984e..fb28495917 100644
--- a/zebra/zebra_router.h
+++ b/zebra/zebra_router.h
@@ -22,6 +22,8 @@
#ifndef __ZEBRA_ROUTER_H__
#define __ZEBRA_ROUTER_H__
+#include "lib/mlag.h"
+
#include "zebra/zebra_ns.h"
/*
@@ -44,7 +46,24 @@ RB_HEAD(zebra_router_table_head, zebra_router_table);
RB_PROTOTYPE(zebra_router_table_head, zebra_router_table,
zebra_router_table_entry, zebra_router_table_entry_compare)
+struct zebra_mlag_info {
+ /* Role this zebra router is playing */
+ enum mlag_role role;
+
+ /* The peerlink being used for mlag */
+ char *peerlink;
+ ifindex_t peerlink_ifindex;
+
+ /* The system mac being used */
+ struct ethaddr mac;
+};
+
struct zebra_router {
+ /* Thread master */
+ struct thread_master *master;
+
+ /* Lists of clients who have connected to us */
+ struct list *client_list;
struct zebra_router_table_head tables;
@@ -65,6 +84,26 @@ struct zebra_router {
/* A sequence number used for tracking routes */
_Atomic uint32_t sequence_num;
+
+ /* The default table used for this router */
+ uint32_t rtm_table_default;
+
+ /* rib work queue */
+#define ZEBRA_RIB_PROCESS_HOLD_TIME 10
+#define ZEBRA_RIB_PROCESS_RETRY_TIME 1
+ struct work_queue *ribq;
+
+ /* Meta Queue Information */
+ struct meta_queue *mq;
+
+ /* LSP work queue */
+ struct work_queue *lsp_process_q;
+
+#define ZEBRA_ZAPI_PACKETS_TO_PROCESS 1000
+ _Atomic uint32_t packets_to_process;
+
+ /* Mlag information for the router */
+ struct zebra_mlag_info mlag_info;
};
extern struct zebra_router zrouter;
diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c
index f1458cb138..d18305495b 100644
--- a/zebra/zebra_vrf.c
+++ b/zebra/zebra_vrf.c
@@ -42,8 +42,6 @@
#include "zebra/zebra_netns_notify.h"
#include "zebra/zebra_routemap.h"
-extern struct zebra_t zebrad;
-
static void zebra_vrf_table_create(struct zebra_vrf *zvrf, afi_t afi,
safi_t safi);
static void zebra_rnhtable_node_cleanup(struct route_table *table,
@@ -58,7 +56,7 @@ static void zebra_vrf_add_update(struct zebra_vrf *zvrf)
if (IS_ZEBRA_DEBUG_EVENT)
zlog_debug("MESSAGE: ZEBRA_VRF_ADD %s", zvrf_name(zvrf));
- for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client))
+ for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client))
zsend_vrf_add(client, zvrf);
}
@@ -70,7 +68,7 @@ static void zebra_vrf_delete_update(struct zebra_vrf *zvrf)
if (IS_ZEBRA_DEBUG_EVENT)
zlog_debug("MESSAGE: ZEBRA_VRF_DELETE %s", zvrf_name(zvrf));
- for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client))
+ for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client))
zsend_vrf_delete(client, zvrf);
}
@@ -189,13 +187,13 @@ static int zebra_vrf_disable(struct vrf *vrf)
struct route_node *rnode;
rib_dest_t *dest;
- for (ALL_LIST_ELEMENTS(zebrad.mq->subq[i], lnode, nnode,
+ for (ALL_LIST_ELEMENTS(zrouter.mq->subq[i], lnode, nnode,
rnode)) {
dest = rib_dest_from_rnode(rnode);
if (dest && rib_dest_vrf(dest) == zvrf) {
route_unlock_node(rnode);
- list_delete_node(zebrad.mq->subq[i], lnode);
- zebrad.mq->size--;
+ list_delete_node(zrouter.mq->subq[i], lnode);
+ zrouter.mq->size--;
}
}
}
@@ -241,13 +239,13 @@ static int zebra_vrf_delete(struct vrf *vrf)
struct route_node *rnode;
rib_dest_t *dest;
- for (ALL_LIST_ELEMENTS(zebrad.mq->subq[i], lnode, nnode,
+ for (ALL_LIST_ELEMENTS(zrouter.mq->subq[i], lnode, nnode,
rnode)) {
dest = rib_dest_from_rnode(rnode);
if (dest && rib_dest_vrf(dest) == zvrf) {
route_unlock_node(rnode);
- list_delete_node(zebrad.mq->subq[i], lnode);
- zebrad.mq->size--;
+ list_delete_node(zrouter.mq->subq[i], lnode);
+ zrouter.mq->size--;
}
}
}
@@ -326,14 +324,14 @@ struct route_table *zebra_vrf_table_with_table_id(afi_t afi, safi_t safi,
if (vrf_id == VRF_DEFAULT) {
if (table_id == RT_TABLE_MAIN
- || table_id == zebrad.rtm_table_default)
+ || table_id == zrouter.rtm_table_default)
table = zebra_vrf_table(afi, safi, vrf_id);
else
table = zebra_vrf_other_route_table(afi, table_id,
vrf_id);
} else if (vrf_is_backend_netns()) {
if (table_id == RT_TABLE_MAIN
- || table_id == zebrad.rtm_table_default)
+ || table_id == zrouter.rtm_table_default)
table = zebra_vrf_table(afi, safi, vrf_id);
else
table = zebra_vrf_other_route_table(afi, table_id,
@@ -439,9 +437,9 @@ struct route_table *zebra_vrf_other_route_table(afi_t afi, uint32_t table_id,
return NULL;
if ((table_id != RT_TABLE_MAIN)
- && (table_id != zebrad.rtm_table_default)) {
+ && (table_id != zrouter.rtm_table_default)) {
if (zvrf->table_id == RT_TABLE_MAIN ||
- zvrf->table_id == zebrad.rtm_table_default) {
+ zvrf->table_id == zrouter.rtm_table_default) {
/* this VRF use default table
* so in all cases, it does not use specific table
* so it is possible to configure tables in this VRF
diff --git a/zebra/zebra_vrf.h b/zebra/zebra_vrf.h
index 2473299d17..e35101d833 100644
--- a/zebra/zebra_vrf.h
+++ b/zebra/zebra_vrf.h
@@ -122,6 +122,8 @@ struct zebra_vrf {
*/
int advertise_gw_macip;
+ int advertise_svi_macip;
+
/* l3-vni info */
vni_t l3vni;
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index 14288d7bc4..537820f7ea 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -164,7 +164,8 @@ DEFUN (show_ip_rpf_addr,
static char re_status_output_char(struct route_entry *re, struct nexthop *nhop)
{
if (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)) {
- if (!CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_DUPLICATE))
+ if (!CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_DUPLICATE) &&
+ !CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_RECURSIVE))
return '*';
else
return ' ';
@@ -174,7 +175,7 @@ static char re_status_output_char(struct route_entry *re, struct nexthop *nhop)
if (CHECK_FLAG(re->status, ROUTE_ENTRY_QUEUED))
return 'q';
- return 'f';
+ return 'r';
}
if (CHECK_FLAG(re->status, ROUTE_ENTRY_QUEUED))
@@ -2456,7 +2457,7 @@ DEFUN_HIDDEN (zebra_packet_process,
{
uint32_t packets = strtoul(argv[2]->arg, NULL, 10);
- atomic_store_explicit(&zebrad.packets_to_process, packets,
+ atomic_store_explicit(&zrouter.packets_to_process, packets,
memory_order_relaxed);
return CMD_SUCCESS;
@@ -2470,7 +2471,7 @@ DEFUN_HIDDEN (no_zebra_packet_process,
"Zapi Protocol\n"
"Number of packets to process before relinquishing thread\n")
{
- atomic_store_explicit(&zebrad.packets_to_process,
+ atomic_store_explicit(&zrouter.packets_to_process,
ZEBRA_ZAPI_PACKETS_TO_PROCESS,
memory_order_relaxed);
@@ -2485,7 +2486,7 @@ DEFUN_HIDDEN (zebra_workqueue_timer,
"Time in milliseconds\n")
{
uint32_t timer = strtoul(argv[2]->arg, NULL, 10);
- zebrad.ribq->spec.hold = timer;
+ zrouter.ribq->spec.hold = timer;
return CMD_SUCCESS;
}
@@ -2498,7 +2499,7 @@ DEFUN_HIDDEN (no_zebra_workqueue_timer,
"Work Queue\n"
"Time in milliseconds\n")
{
- zebrad.ribq->spec.hold = ZEBRA_RIB_PROCESS_HOLD_TIME;
+ zrouter.ribq->spec.hold = ZEBRA_RIB_PROCESS_HOLD_TIME;
return CMD_SUCCESS;
}
@@ -2548,12 +2549,12 @@ static int config_write_protocol(struct vty *vty)
if (zebra_rnh_ipv6_default_route)
vty_out(vty, "ipv6 nht resolve-via-default\n");
- if (zebrad.ribq->spec.hold != ZEBRA_RIB_PROCESS_HOLD_TIME)
- vty_out(vty, "zebra work-queue %u\n", zebrad.ribq->spec.hold);
+ if (zrouter.ribq->spec.hold != ZEBRA_RIB_PROCESS_HOLD_TIME)
+ vty_out(vty, "zebra work-queue %u\n", zrouter.ribq->spec.hold);
- if (zebrad.packets_to_process != ZEBRA_ZAPI_PACKETS_TO_PROCESS)
+ if (zrouter.packets_to_process != ZEBRA_ZAPI_PACKETS_TO_PROCESS)
vty_out(vty, "zebra zapi-packets %u\n",
- zebrad.packets_to_process);
+ zrouter.packets_to_process);
enum multicast_mode ipv4_multicast_mode = multicast_mode_ipv4_get();
@@ -2581,7 +2582,7 @@ DEFUN (show_table,
SHOW_STR
"default routing table to use for all clients\n")
{
- vty_out(vty, "table %d\n", zebrad.rtm_table_default);
+ vty_out(vty, "table %d\n", zrouter.rtm_table_default);
return CMD_SUCCESS;
}
@@ -2591,7 +2592,7 @@ DEFUN (config_table,
"Configure target kernel routing table\n"
"TABLE integer\n")
{
- zebrad.rtm_table_default = strtol(argv[1]->arg, (char **)0, 10);
+ zrouter.rtm_table_default = strtol(argv[1]->arg, (char **)0, 10);
return CMD_SUCCESS;
}
@@ -2602,7 +2603,7 @@ DEFUN (no_config_table,
"Configure target kernel routing table\n"
"TABLE integer\n")
{
- zebrad.rtm_table_default = 0;
+ zrouter.rtm_table_default = 0;
return CMD_SUCCESS;
}
#endif
@@ -2850,8 +2851,8 @@ DEFUN (zebra_show_routing_tables_summary,
/* Table configuration write function. */
static int config_write_table(struct vty *vty)
{
- if (zebrad.rtm_table_default)
- vty_out(vty, "table %d\n", zebrad.rtm_table_default);
+ if (zrouter.rtm_table_default)
+ vty_out(vty, "table %d\n", zrouter.rtm_table_default);
return 0;
}
diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c
index 49af4a9205..560cd89abd 100644
--- a/zebra/zebra_vxlan.c
+++ b/zebra/zebra_vxlan.c
@@ -50,7 +50,7 @@
#include "zebra/zebra_vrf.h"
#include "zebra/zebra_vxlan.h"
#include "zebra/zebra_vxlan_private.h"
-#include "zebra/zserv.h"
+#include "zebra/zebra_router.h"
DEFINE_MTYPE_STATIC(ZEBRA, HOST_PREFIX, "host prefix");
DEFINE_MTYPE_STATIC(ZEBRA, ZVNI, "VNI hash");
@@ -100,6 +100,7 @@ static int zvni_neigh_send_del_to_client(vni_t vni, struct ipaddr *ip,
uint8_t flags, int state);
static int zvni_neigh_install(zebra_vni_t *zvni, zebra_neigh_t *n);
static int zvni_neigh_uninstall(zebra_vni_t *zvni, zebra_neigh_t *n);
+static int zvni_neigh_probe(zebra_vni_t *zvni, zebra_neigh_t *n);
static zebra_vni_t *zvni_from_svi(struct interface *ifp,
struct interface *br_if);
static struct interface *zvni_map_to_svi(vlanid_t vid, struct interface *br_if);
@@ -179,6 +180,7 @@ static int zvni_gw_macip_del(struct interface *ifp, zebra_vni_t *zvni,
struct ipaddr *ip);
struct interface *zebra_get_vrr_intf_for_svi(struct interface *ifp);
static int advertise_gw_macip_enabled(zebra_vni_t *zvni);
+static int advertise_svi_macip_enabled(zebra_vni_t *zvni);
static int zebra_vxlan_ip_inherit_dad_from_mac(struct zebra_vrf *zvrf,
zebra_mac_t *old_zmac,
zebra_mac_t *new_zmac,
@@ -332,6 +334,20 @@ static int advertise_gw_macip_enabled(zebra_vni_t *zvni)
return 0;
}
+static int advertise_svi_macip_enabled(zebra_vni_t *zvni)
+{
+ struct zebra_vrf *zvrf;
+
+ zvrf = vrf_info_lookup(VRF_DEFAULT);
+ if (zvrf && zvrf->advertise_svi_macip)
+ return 1;
+
+ if (zvni && zvni->advertise_svi_macip)
+ return 1;
+
+ return 0;
+}
+
/* As part Duplicate Address Detection (DAD) for IP mobility
* MAC binding changes, ensure to inherit duplicate flag
* from MAC.
@@ -510,7 +526,7 @@ static void zebra_vxlan_dup_addr_detect_for_mac(struct zebra_vrf *zvrf,
sizeof(buf)),
mac->flags, zvrf->dad_freeze_time);
- thread_add_timer(zebrad.master,
+ thread_add_timer(zrouter.master,
zebra_vxlan_dad_mac_auto_recovery_exp,
mac, zvrf->dad_freeze_time,
&mac->dad_mac_auto_recovery_timer);
@@ -643,7 +659,7 @@ static void zebra_vxlan_dup_addr_detect_for_neigh(struct zebra_vrf *zvrf,
ipaddr2str(&nbr->ip, buf1, sizeof(buf1)),
nbr->flags, zvrf->dad_freeze_time);
- thread_add_timer(zebrad.master,
+ thread_add_timer(zrouter.master,
zebra_vxlan_dad_ip_auto_recovery_exp,
nbr, zvrf->dad_freeze_time,
&nbr->dad_ip_auto_recovery_timer);
@@ -2404,6 +2420,18 @@ static void zvni_process_neigh_on_remote_mac_del(zebra_vni_t *zvni,
/* NOTE: Currently a NO-OP. */
}
+static void zvni_probe_neigh_on_mac_add(zebra_vni_t *zvni, zebra_mac_t *zmac)
+{
+ zebra_neigh_t *nbr = NULL;
+ struct listnode *node = NULL;
+
+ for (ALL_LIST_ELEMENTS_RO(zmac->neigh_list, node, nbr)) {
+ if (CHECK_FLAG(nbr->flags, ZEBRA_NEIGH_LOCAL) &&
+ IS_ZEBRA_NEIGH_INACTIVE(nbr))
+ zvni_neigh_probe(zvni, nbr);
+ }
+}
+
/*
* Inform BGP about local neighbor addition.
*/
@@ -2501,6 +2529,32 @@ static int zvni_neigh_uninstall(zebra_vni_t *zvni, zebra_neigh_t *n)
}
/*
+ * Probe neighbor from the kernel.
+ */
+static int zvni_neigh_probe(zebra_vni_t *zvni, zebra_neigh_t *n)
+{
+ struct zebra_if *zif;
+ struct zebra_l2info_vxlan *vxl;
+ struct interface *vlan_if;
+
+ zif = zvni->vxlan_if->info;
+ if (!zif)
+ return -1;
+ vxl = &zif->l2info.vxl;
+
+ vlan_if = zvni_map_to_svi(vxl->access_vlan, zif->brslave_info.br_if);
+ if (!vlan_if)
+ return -1;
+
+#ifdef GNU_LINUX
+ return kernel_upd_neigh(vlan_if, &n->ip, &n->emac,
+ 0, NUD_PROBE);
+#else
+ return 0;
+#endif
+}
+
+/*
* Install neighbor hash entry - called upon access VLAN change.
*/
static void zvni_install_neigh_hash(struct hash_backet *backet, void *ctxt)
@@ -2835,10 +2889,48 @@ static void zvni_gw_macip_add_for_vni_hash(struct hash_backet *backet,
/* Add primary SVI MAC-IP */
zvni_add_macip_for_intf(vlan_if, zvni);
- /* Add VRR MAC-IP - if any*/
- vrr_if = zebra_get_vrr_intf_for_svi(vlan_if);
- if (vrr_if)
- zvni_add_macip_for_intf(vrr_if, zvni);
+ if (advertise_gw_macip_enabled(zvni)) {
+ /* Add VRR MAC-IP - if any*/
+ vrr_if = zebra_get_vrr_intf_for_svi(vlan_if);
+ if (vrr_if)
+ zvni_add_macip_for_intf(vrr_if, zvni);
+ }
+
+ return;
+}
+
+static void zvni_svi_macip_del_for_vni_hash(struct hash_backet *backet,
+ void *ctxt)
+{
+ zebra_vni_t *zvni = NULL;
+ struct zebra_if *zif = NULL;
+ struct zebra_l2info_vxlan zl2_info;
+ struct interface *vlan_if = NULL;
+ struct interface *ifp;
+
+ /* Add primary SVI MAC*/
+ zvni = (zebra_vni_t *)backet->data;
+ if (!zvni)
+ return;
+
+ ifp = zvni->vxlan_if;
+ if (!ifp)
+ return;
+ zif = ifp->info;
+
+ /* If down or not mapped to a bridge, we're done. */
+ if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
+ return;
+
+ zl2_info = zif->l2info.vxl;
+
+ vlan_if = zvni_map_to_svi(zl2_info.access_vlan,
+ zif->brslave_info.br_if);
+ if (!vlan_if)
+ return;
+
+ /* Del primary MAC-IP */
+ zvni_del_macip_for_intf(vlan_if, zvni);
return;
}
@@ -5329,6 +5421,8 @@ static void process_remote_macip_add(vni_t vni,
zvni_neigh_install(zvni, n);
}
+ zvni_probe_neigh_on_mac_add(zvni, mac);
+
/* Update seq number. */
n->rem_seq = seq;
}
@@ -6868,6 +6962,8 @@ void zebra_vxlan_print_evpn(struct vty *vty, bool uj)
vty_out(vty, "L3 VNIs: %u\n", num_l3vnis);
vty_out(vty, "Advertise gateway mac-ip: %s\n",
zvrf->advertise_gw_macip ? "Yes" : "No");
+ vty_out(vty, "Advertise svi mac-ip: %s\n",
+ zvrf->advertise_svi_macip ? "Yes" : "No");
vty_out(vty, "Duplicate address detection: %s\n",
zvrf->dup_addr_detect ? "Enable" : "Disable");
vty_out(vty, " Detection max-moves %u, time %d\n",
@@ -7029,6 +7125,7 @@ int zebra_vxlan_handle_kernel_neigh_del(struct interface *ifp,
zebra_vni_t *zvni = NULL;
zebra_mac_t *zmac = NULL;
zebra_l3vni_t *zl3vni = NULL;
+ struct zebra_vrf *zvrf;
/* check if this is a remote neigh entry corresponding to remote
* next-hop
@@ -7081,9 +7178,23 @@ int zebra_vxlan_handle_kernel_neigh_del(struct interface *ifp,
return 0;
}
+ zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id);
+ if (!zvrf) {
+ zlog_debug("%s: VNI %u vrf lookup failed.",
+ __PRETTY_FUNCTION__, zvni->vni);
+ return -1;
+ }
+
+ /* In case of feeze action, if local neigh is in duplicate state,
+ * Mark the Neigh as inactive before sending delete request to BGPd,
+ * If BGPd has remote entry, it will re-install
+ */
+ if (zvrf->dad_freeze &&
+ CHECK_FLAG(n->flags, ZEBRA_NEIGH_DUPLICATE))
+ ZEBRA_NEIGH_SET_INACTIVE(n);
+
/* Remove neighbor from BGP. */
- zvni_neigh_send_del_to_client(zvni->vni, &n->ip, &n->emac,
- 0, n->state);
+ zvni_neigh_send_del_to_client(zvni->vni, &n->ip, &n->emac, 0, n->state);
/* Delete this neighbor entry. */
zvni_neigh_del(zvni, n);
@@ -8656,6 +8767,102 @@ stream_failure:
}
/*
+ * Handle message from client to enable/disable advertisement of svi macip
+ * routes
+ */
+void zebra_vxlan_advertise_svi_macip(ZAPI_HANDLER_ARGS)
+{
+ struct stream *s;
+ int advertise;
+ vni_t vni = 0;
+ zebra_vni_t *zvni = NULL;
+ struct interface *ifp = NULL;
+
+ if (zvrf_id(zvrf) != VRF_DEFAULT) {
+ zlog_debug("EVPN GW-MACIP Adv for non-default VRF %u",
+ zvrf_id(zvrf));
+ return;
+ }
+
+ s = msg;
+ STREAM_GETC(s, advertise);
+ STREAM_GETL(s, vni);
+
+ if (!vni) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug("EVPN gateway macip Adv %s, currently %s",
+ advertise ? "enabled" : "disabled",
+ advertise_gw_macip_enabled(NULL)
+ ? "enabled"
+ : "disabled");
+
+ if (zvrf->advertise_svi_macip == advertise)
+ return;
+
+
+ if (advertise) {
+ zvrf->advertise_svi_macip = advertise;
+ hash_iterate(zvrf->vni_table,
+ zvni_gw_macip_add_for_vni_hash, NULL);
+ } else {
+ hash_iterate(zvrf->vni_table,
+ zvni_svi_macip_del_for_vni_hash, NULL);
+ zvrf->advertise_svi_macip = advertise;
+ }
+
+ } else {
+ struct zebra_if *zif = NULL;
+ struct zebra_l2info_vxlan zl2_info;
+ struct interface *vlan_if = NULL;
+
+ zvni = zvni_lookup(vni);
+ if (!zvni)
+ return;
+
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "EVPN SVI macip Adv %s on VNI %d , currently %s",
+ advertise ? "enabled" : "disabled", vni,
+ advertise_svi_macip_enabled(zvni)
+ ? "enabled"
+ : "disabled");
+
+ if (zvni->advertise_svi_macip == advertise)
+ return;
+
+ ifp = zvni->vxlan_if;
+ if (!ifp)
+ return;
+
+ zif = ifp->info;
+
+ /* If down or not mapped to a bridge, we're done. */
+ if (!if_is_operative(ifp) || !zif->brslave_info.br_if)
+ return;
+
+ zl2_info = zif->l2info.vxl;
+
+ vlan_if = zvni_map_to_svi(zl2_info.access_vlan,
+ zif->brslave_info.br_if);
+ if (!vlan_if)
+ return;
+
+ if (advertise) {
+ zvni->advertise_svi_macip = advertise;
+ /* Add primary SVI MAC-IP */
+ zvni_add_macip_for_intf(vlan_if, zvni);
+ } else {
+ /* Del primary MAC-IP */
+ zvni_del_macip_for_intf(vlan_if, zvni);
+ zvni->advertise_svi_macip = advertise;
+ }
+ }
+
+stream_failure:
+ return;
+}
+
+/*
* Handle message from client to enable/disable advertisement of g/w macip
* routes
*/
diff --git a/zebra/zebra_vxlan.h b/zebra/zebra_vxlan.h
index c25e7357ed..2cf21ff90b 100644
--- a/zebra/zebra_vxlan.h
+++ b/zebra/zebra_vxlan.h
@@ -68,6 +68,7 @@ extern void zebra_vxlan_remote_vtep_add(ZAPI_HANDLER_ARGS);
extern void zebra_vxlan_remote_vtep_del(ZAPI_HANDLER_ARGS);
extern void zebra_vxlan_flood_control(ZAPI_HANDLER_ARGS);
extern void zebra_vxlan_advertise_subnet(ZAPI_HANDLER_ARGS);
+extern void zebra_vxlan_advertise_svi_macip(ZAPI_HANDLER_ARGS);
extern void zebra_vxlan_advertise_gw_macip(ZAPI_HANDLER_ARGS);
extern void zebra_vxlan_advertise_all_vni(ZAPI_HANDLER_ARGS);
extern void zebra_vxlan_dup_addr_detection(ZAPI_HANDLER_ARGS);
diff --git a/zebra/zebra_vxlan_private.h b/zebra/zebra_vxlan_private.h
index cae0d62bb3..c36d156359 100644
--- a/zebra/zebra_vxlan_private.h
+++ b/zebra/zebra_vxlan_private.h
@@ -70,6 +70,9 @@ struct zebra_vni_t_ {
/* Flag for advertising gw macip */
uint8_t advertise_gw_macip;
+ /* Flag for advertising svi macip */
+ uint8_t advertise_svi_macip;
+
/* Flag for advertising gw macip */
uint8_t advertise_subnet;
diff --git a/zebra/zserv.c b/zebra/zserv.c
index 766dd54fb3..6532491cef 100644
--- a/zebra/zserv.c
+++ b/zebra/zserv.c
@@ -61,12 +61,16 @@
#include "zebra/zapi_msg.h" /* for zserv_handle_commands */
#include "zebra/zebra_vrf.h" /* for zebra_vrf_lookup_by_id, zvrf */
#include "zebra/zserv.h" /* for zserv */
+#include "zebra/zebra_router.h"
#include "zebra/zebra_errors.h" /* for error messages */
/* clang-format on */
/* privileges */
extern struct zebra_privs_t zserv_privs;
+/* The listener socket for clients connecting to us */
+static int zsock;
+
/*
* Client thread events.
*
@@ -312,7 +316,7 @@ static int zserv_read(struct thread *thread)
uint32_t p2p;
struct zmsghdr hdr;
- p2p_orig = atomic_load_explicit(&zebrad.packets_to_process,
+ p2p_orig = atomic_load_explicit(&zrouter.packets_to_process,
memory_order_relaxed);
cache = stream_fifo_new();
p2p = p2p_orig;
@@ -401,8 +405,10 @@ static int zserv_read(struct thread *thread)
}
/* Debug packet information. */
- if (IS_ZEBRA_DEBUG_EVENT)
- zlog_debug("zebra message comes from socket [%d]",
+ if (IS_ZEBRA_DEBUG_PACKET)
+ zlog_debug("zebra message[%s:%u:%u] comes from socket [%d]",
+ zserv_command_string(hdr.command),
+ hdr.vrf_id, hdr.length,
sock);
if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV)
@@ -438,7 +444,8 @@ static int zserv_read(struct thread *thread)
}
if (IS_ZEBRA_DEBUG_PACKET)
- zlog_debug("Read %d packets", p2p_orig - p2p);
+ zlog_debug("Read %d packets from client: %s", p2p_orig - p2p,
+ zebra_route_string(client->proto));
/* Reschedule ourselves */
zserv_client_event(client, ZSERV_CLIENT_READ);
@@ -481,9 +488,9 @@ static void zserv_client_event(struct zserv *client,
* with the message is executed. This proceeds until there are no more messages,
* an error occurs, or the processing limit is reached.
*
- * The client's I/O thread can push at most zebrad.packets_to_process messages
+ * The client's I/O thread can push at most zrouter.packets_to_process messages
* onto the input buffer before notifying us there are packets to read. As long
- * as we always process zebrad.packets_to_process messages here, then we can
+ * as we always process zrouter.packets_to_process messages here, then we can
* rely on the read thread to handle queuing this task enough times to process
* everything on the input queue.
*/
@@ -492,7 +499,7 @@ static int zserv_process_messages(struct thread *thread)
struct zserv *client = THREAD_ARG(thread);
struct stream *msg;
struct stream_fifo *cache = stream_fifo_new();
- uint32_t p2p = zebrad.packets_to_process;
+ uint32_t p2p = zrouter.packets_to_process;
bool need_resched = false;
pthread_mutex_lock(&client->ibuf_mtx);
@@ -622,7 +629,6 @@ static void zserv_client_free(struct zserv *client)
vrf_bitmap_free(client->redist_default[afi]);
}
- vrf_bitmap_free(client->ifinfo);
vrf_bitmap_free(client->ridinfo);
XFREE(MTYPE_TMP, client);
@@ -637,7 +643,7 @@ void zserv_close_client(struct zserv *client)
zlog_debug("Closing client '%s'",
zebra_route_string(client->proto));
- thread_cancel_event(zebrad.master, client);
+ thread_cancel_event(zrouter.master, client);
THREAD_OFF(client->t_cleanup);
THREAD_OFF(client->t_process);
@@ -646,7 +652,7 @@ void zserv_close_client(struct zserv *client)
client->pthread = NULL;
/* remove from client list */
- listnode_delete(zebrad.client_list, client);
+ listnode_delete(zrouter.client_list, client);
/* delete client */
zserv_client_free(client);
@@ -695,7 +701,7 @@ static struct zserv *zserv_client_create(int sock)
client->wb = buffer_new(0);
/* Set table number. */
- client->rtm_table = zebrad.rtm_table_default;
+ client->rtm_table = zrouter.rtm_table_default;
atomic_store_explicit(&client->connect_time, (uint32_t) monotime(NULL),
memory_order_relaxed);
@@ -706,14 +712,13 @@ static struct zserv *zserv_client_create(int sock)
client->redist[afi][i] = vrf_bitmap_init();
client->redist_default[afi] = vrf_bitmap_init();
}
- client->ifinfo = vrf_bitmap_init();
client->ridinfo = vrf_bitmap_init();
/* by default, it's not a synchronous client */
client->is_synchronous = 0;
/* Add this client to linked list. */
- listnode_add(zebrad.client_list, client);
+ listnode_add(zrouter.client_list, client);
struct frr_pthread_attr zclient_pthr_attrs = {
.start = frr_pthread_attr_default.start,
@@ -783,16 +788,16 @@ void zserv_start(char *path)
old_mask = umask(0077);
/* Make UNIX domain socket. */
- zebrad.sock = socket(sa.ss_family, SOCK_STREAM, 0);
- if (zebrad.sock < 0) {
+ zsock = socket(sa.ss_family, SOCK_STREAM, 0);
+ if (zsock < 0) {
flog_err_sys(EC_LIB_SOCKET, "Can't create zserv socket: %s",
safe_strerror(errno));
return;
}
if (sa.ss_family != AF_UNIX) {
- sockopt_reuseaddr(zebrad.sock);
- sockopt_reuseport(zebrad.sock);
+ sockopt_reuseaddr(zsock);
+ sockopt_reuseport(zsock);
} else {
struct sockaddr_un *suna = (struct sockaddr_un *)&sa;
if (suna->sun_path[0])
@@ -800,28 +805,28 @@ void zserv_start(char *path)
}
frr_elevate_privs(&zserv_privs) {
- setsockopt_so_recvbuf(zebrad.sock, 1048576);
- setsockopt_so_sendbuf(zebrad.sock, 1048576);
+ setsockopt_so_recvbuf(zsock, 1048576);
+ setsockopt_so_sendbuf(zsock, 1048576);
}
frr_elevate_privs((sa.ss_family != AF_UNIX) ? &zserv_privs : NULL) {
- ret = bind(zebrad.sock, (struct sockaddr *)&sa, sa_len);
+ ret = bind(zsock, (struct sockaddr *)&sa, sa_len);
}
if (ret < 0) {
flog_err_sys(EC_LIB_SOCKET, "Can't bind zserv socket on %s: %s",
path, safe_strerror(errno));
- close(zebrad.sock);
- zebrad.sock = -1;
+ close(zsock);
+ zsock = -1;
return;
}
- ret = listen(zebrad.sock, 5);
+ ret = listen(zsock, 5);
if (ret < 0) {
flog_err_sys(EC_LIB_SOCKET,
"Can't listen to zserv socket %s: %s", path,
safe_strerror(errno));
- close(zebrad.sock);
- zebrad.sock = -1;
+ close(zsock);
+ zsock = -1;
return;
}
@@ -834,15 +839,15 @@ void zserv_event(struct zserv *client, enum zserv_event event)
{
switch (event) {
case ZSERV_ACCEPT:
- thread_add_read(zebrad.master, zserv_accept, NULL, zebrad.sock,
+ thread_add_read(zrouter.master, zserv_accept, NULL, zsock,
NULL);
break;
case ZSERV_PROCESS_MESSAGES:
- thread_add_event(zebrad.master, zserv_process_messages, client,
+ thread_add_event(zrouter.master, zserv_process_messages, client,
0, &client->t_process);
break;
case ZSERV_HANDLE_CLIENT_FAIL:
- thread_add_event(zebrad.master, zserv_handle_client_fail,
+ thread_add_event(zrouter.master, zserv_handle_client_fail,
client, 0, &client->t_cleanup);
}
}
@@ -1002,7 +1007,7 @@ struct zserv *zserv_find_client(uint8_t proto, unsigned short instance)
struct listnode *node, *nnode;
struct zserv *client;
- for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) {
+ for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) {
if (client->proto == proto && client->instance == instance)
return client;
}
@@ -1021,7 +1026,7 @@ DEFUN (show_zebra_client,
struct listnode *node;
struct zserv *client;
- for (ALL_LIST_ELEMENTS_RO(zebrad.client_list, node, client))
+ for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client))
zebra_show_client_detail(vty, client);
return CMD_SUCCESS;
@@ -1044,7 +1049,7 @@ DEFUN (show_zebra_client_summary,
vty_out(vty,
"--------------------------------------------------------------------------------\n");
- for (ALL_LIST_ELEMENTS_RO(zebrad.client_list, node, client))
+ for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client))
zebra_show_client_brief(vty, client);
vty_out(vty, "Routes column shows (added+updated)/deleted\n");
@@ -1067,10 +1072,10 @@ void zserv_read_file(char *input)
void zserv_init(void)
{
/* Client list init. */
- zebrad.client_list = list_new();
+ zrouter.client_list = list_new();
/* Misc init. */
- zebrad.sock = -1;
+ zsock = -1;
install_element(ENABLE_NODE, &show_zebra_client_cmd);
install_element(ENABLE_NODE, &show_zebra_client_summary_cmd);
diff --git a/zebra/zserv.h b/zebra/zserv.h
index 041485cdc2..ac016e65f3 100644
--- a/zebra/zserv.h
+++ b/zebra/zserv.h
@@ -89,9 +89,6 @@ struct zserv {
/* Redistribute default route flag. */
vrf_bitmap_t redist_default[AFI_MAX];
- /* Interface information. */
- vrf_bitmap_t ifinfo;
-
/* Router-id information. */
vrf_bitmap_t ridinfo;
@@ -173,31 +170,6 @@ struct zserv {
DECLARE_HOOK(zserv_client_connect, (struct zserv *client), (client));
DECLARE_KOOH(zserv_client_close, (struct zserv *client), (client));
-/* Zebra instance */
-struct zebra_t {
- /* Thread master */
- struct thread_master *master;
- struct list *client_list;
-
- /* Socket */
- int sock;
-
- /* default table */
- uint32_t rtm_table_default;
-
-/* rib work queue */
-#define ZEBRA_RIB_PROCESS_HOLD_TIME 10
-#define ZEBRA_RIB_PROCESS_RETRY_TIME 1
- struct work_queue *ribq;
- struct meta_queue *mq;
-
- /* LSP work queue */
- struct work_queue *lsp_process_q;
-
-#define ZEBRA_ZAPI_PACKETS_TO_PROCESS 1000
- _Atomic uint32_t packets_to_process;
-};
-extern struct zebra_t zebrad;
extern unsigned int multipath_num;
/*