]> git.proxmox.com Git - mirror_frr.git/commitdiff
Merge pull request #8250 from idryzhov/fix-nb-running-get-entry
authorRenato Westphal <renato@opensourcerouting.org>
Wed, 24 Mar 2021 22:39:09 +0000 (19:39 -0300)
committerGitHub <noreply@github.com>
Wed, 24 Mar 2021 22:39:09 +0000 (19:39 -0300)
Fix aborts when using nb_running_get_entry during validation stage

598 files changed:
.git-blame-ignore-revs
.gitignore
Makefile.am
babeld/babel_interface.c
babeld/babel_main.c
babeld/babeld.c
babeld/babeld.h
babeld/util.h
bfdd/bfd.c
bfdd/bfd.h
bfdd/bfd_packet.c
bfdd/bfdctl.h
bfdd/bfdd.c
bfdd/bfdd_cli.c
bfdd/bfdd_nb.c
bfdd/bfdd_nb.h
bfdd/bfdd_nb_config.c
bfdd/bfdd_vty.c
bfdd/bfddp_packet.h
bfdd/config.c
bfdd/dplane.c
bgpd/bgp_advertise.h
bgpd/bgp_bfd.c
bgpd/bgp_bfd.h
bgpd/bgp_bmp.c
bgpd/bgp_bmp.h
bgpd/bgp_debug.c
bgpd/bgp_debug.h
bgpd/bgp_evpn.c
bgpd/bgp_evpn_mh.c
bgpd/bgp_evpn_mh.h
bgpd/bgp_evpn_private.h
bgpd/bgp_evpn_vty.c
bgpd/bgp_filter.c
bgpd/bgp_filter.h
bgpd/bgp_fsm.c
bgpd/bgp_fsm.h
bgpd/bgp_io.c
bgpd/bgp_labelpool.c
bgpd/bgp_labelpool.h
bgpd/bgp_main.c
bgpd/bgp_memory.c
bgpd/bgp_memory.h
bgpd/bgp_nb_config.c
bgpd/bgp_network.c
bgpd/bgp_nht.c
bgpd/bgp_packet.c
bgpd/bgp_packet.h
bgpd/bgp_pbr.c
bgpd/bgp_route.c
bgpd/bgp_route.h
bgpd/bgp_rpki.c
bgpd/bgp_snmp.c
bgpd/bgp_vty.c
bgpd/bgp_vty.h
bgpd/bgp_zebra.c
bgpd/bgpd.c
bgpd/bgpd.h
bgpd/rfapi/bgp_rfapi_cfg.c
bgpd/rfapi/bgp_rfapi_cfg.h
bgpd/rfapi/rfapi_private.h
bgpd/subdir.am
configure.ac
debian/frr.install
doc/developer/building-frr-for-ubuntu2004.rst
doc/developer/cross-compiling.rst
doc/developer/hooks.rst
doc/developer/images/PCEPlib_design.jpg [new file with mode: 0644]
doc/developer/images/PCEPlib_internal_deps.jpg [new file with mode: 0644]
doc/developer/images/PCEPlib_socket_comm.jpg [new file with mode: 0644]
doc/developer/images/PCEPlib_threading_model.jpg [new file with mode: 0644]
doc/developer/images/PCEPlib_threading_model_frr_infra.jpg [new file with mode: 0644]
doc/developer/images/PCEPlib_timers.jpg [new file with mode: 0644]
doc/developer/index.rst
doc/developer/lists.rst
doc/developer/memtypes.rst
doc/developer/modules.rst
doc/developer/pceplib.rst [new file with mode: 0644]
doc/developer/scripting.rst
doc/developer/subdir.am
doc/developer/topotests.rst
doc/user/bfd.rst
doc/user/bgp.rst
doc/user/ospf6d.rst
doc/user/ospfd.rst
eigrpd/eigrp_cli.c
eigrpd/eigrp_filter.c
eigrpd/eigrp_interface.c
eigrpd/eigrp_main.c
eigrpd/eigrp_memory.c [deleted file]
eigrpd/eigrp_memory.h [deleted file]
eigrpd/eigrp_neighbor.c
eigrpd/eigrp_packet.c
eigrpd/eigrp_query.c
eigrpd/eigrp_reply.c
eigrpd/eigrp_siaquery.c
eigrpd/eigrp_siareply.c
eigrpd/eigrp_structs.h
eigrpd/eigrp_topology.c
eigrpd/eigrp_topology.h
eigrpd/eigrp_update.c
eigrpd/eigrpd.c
eigrpd/eigrpd.h
eigrpd/subdir.am
isisd/fabricd.c
isisd/isis_adjacency.c
isisd/isis_adjacency.h
isisd/isis_bfd.c
isisd/isis_circuit.c
isisd/isis_circuit.h
isisd/isis_cli.c
isisd/isis_dynhn.c
isisd/isis_lfa.c
isisd/isis_lfa.h
isisd/isis_lsp.c
isisd/isis_lsp.h
isisd/isis_main.c
isisd/isis_memory.c [deleted file]
isisd/isis_memory.h [deleted file]
isisd/isis_mt.c
isisd/isis_nb_config.c
isisd/isis_redist.c
isisd/isis_route.c
isisd/isis_route.h
isisd/isis_snmp.c
isisd/isis_spf.c
isisd/isis_spf_private.h
isisd/isis_sr.c
isisd/isis_sr.h
isisd/isis_tlvs.c
isisd/isis_tlvs.h
isisd/isis_tx_queue.c
isisd/isisd.c
isisd/isisd.h
isisd/subdir.am
ldpd/ldp_snmp.c
ldpd/ldpd.c
ldpd/ldpd.h
ldpd/ldpe.h
ldpd/neighbor.c
ldpd/notification.c
ldpd/packet.c
ldpd/subdir.am
lib/agentx.c
lib/atomlist.h
lib/bfd.c
lib/bfd.h
lib/buffer.c
lib/command.c
lib/command.h
lib/command_graph.c
lib/command_graph.h
lib/command_match.c
lib/command_parse.y
lib/compiler.h
lib/debug.c
lib/debug.h
lib/defaults.h
lib/distribute.c
lib/elf_py.c
lib/ferr.c
lib/filter.c
lib/filter_nb.c
lib/frr_pthread.c
lib/frr_zmq.c
lib/frrcu.c
lib/frrcu.h
lib/grammar_sandbox.c
lib/graph.c
lib/hash.c
lib/hook.c
lib/hook.h
lib/id_alloc.c
lib/if.c
lib/if.h
lib/if_rmap.c
lib/keychain.c
lib/keychain.h
lib/ldp_sync.c
lib/libfrr.c
lib/libfrr.h
lib/link_state.c
lib/link_state.h
lib/linklist.c
lib/log_vty.c
lib/log_vty.h
lib/memory.c
lib/memory.h
lib/module.c
lib/module.h
lib/netns_linux.c
lib/netns_other.c
lib/nexthop.c
lib/nexthop_group.c
lib/nexthop_group.h
lib/northbound.c
lib/northbound.h
lib/northbound_confd.c
lib/northbound_grpc.cpp
lib/northbound_sysrepo.c
lib/plist.c
lib/prefix.c
lib/printfrr.h
lib/privs.c
lib/pullwr.c
lib/qobj.c
lib/qobj.h
lib/resolver.c
lib/ringbuf.c
lib/routemap.c
lib/routemap.h
lib/routing_nb.h
lib/routing_nb_config.c
lib/skiplist.c
lib/smux.h
lib/sockunion.c
lib/spf_backoff.c
lib/srcdest_table.c
lib/stream.c
lib/strlcat.c
lib/subdir.am
lib/table.c
lib/table.h
lib/termtable.c
lib/thread.c
lib/thread.h
lib/typerb.h
lib/typesafe.c
lib/typesafe.h
lib/vector.c
lib/vrf.c
lib/vrf.h
lib/vty.c
lib/wheel.c
lib/workqueue.c
lib/workqueue.h
lib/xref.c
lib/xref.h
lib/yang.c
lib/yang_translator.c
lib/zassert.h
lib/zclient.c
lib/zebra.h
lib/zlog.c
lib/zlog.h
lib/zlog_targets.c
m4/ax_pthread.m4
nhrpd/debug.h
nhrpd/nhrp_cache.c
nhrpd/nhrp_interface.c
nhrpd/nhrp_main.c
nhrpd/nhrp_nhs.c
nhrpd/nhrp_peer.c
nhrpd/nhrp_route.c
nhrpd/nhrp_shortcut.c
nhrpd/nhrp_vc.c
nhrpd/nhrpd.h
nhrpd/vici.c
nhrpd/zbuf.c
ospf6d/ospf6_area.c
ospf6d/ospf6_asbr.c
ospf6d/ospf6_interface.c
ospf6d/ospf6_interface.h
ospf6d/ospf6_lsa.c
ospf6d/ospf6_lsa.h
ospf6d/ospf6_lsdb.c
ospf6d/ospf6_main.c
ospf6d/ospf6_memory.c [deleted file]
ospf6d/ospf6_memory.h [deleted file]
ospf6d/ospf6_message.c
ospf6d/ospf6_neighbor.c
ospf6d/ospf6_neighbor.h
ospf6d/ospf6_route.c
ospf6d/ospf6_snmp.c
ospf6d/ospf6_spf.c
ospf6d/ospf6_spf.h
ospf6d/ospf6_top.c
ospf6d/ospf6_top.h
ospf6d/ospf6_zebra.c
ospf6d/ospf6d.c
ospf6d/ospf6d.h
ospf6d/subdir.am
ospfclient/ospf_apiclient.c
ospfd/ospf_bfd.c
ospfd/ospf_bfd.h
ospfd/ospf_dump.c
ospfd/ospf_dump.h
ospfd/ospf_interface.c
ospfd/ospf_interface.h
ospfd/ospf_ism.c
ospfd/ospf_ism.h
ospfd/ospf_main.c
ospfd/ospf_memory.c
ospfd/ospf_memory.h
ospfd/ospf_neighbor.c
ospfd/ospf_neighbor.h
ospfd/ospf_nsm.c
ospfd/ospf_nsm.h
ospfd/ospf_opaque.c
ospfd/ospf_snmp.c
ospfd/ospf_spf.c
ospfd/ospf_spf.h
ospfd/ospf_ti_lfa.c
ospfd/ospf_vty.c
ospfd/ospf_zebra.c
ospfd/ospfd.c
ospfd/ospfd.h
ospfd/subdir.am
pathd/path_cli.c
pathd/path_main.c
pathd/path_memory.c [deleted file]
pathd/path_memory.h [deleted file]
pathd/path_pcep.c
pathd/path_pcep.h
pathd/path_pcep_cli.c
pathd/path_pcep_config.c
pathd/path_pcep_config.h
pathd/path_pcep_controller.c
pathd/path_pcep_controller.h
pathd/path_pcep_debug.c
pathd/path_pcep_debug.h
pathd/path_pcep_lib.c
pathd/path_pcep_lib.h
pathd/path_pcep_memory.c [deleted file]
pathd/path_pcep_memory.h [deleted file]
pathd/path_pcep_pcc.c
pathd/path_pcep_pcc.h
pathd/pathd.c
pathd/pathd.h
pathd/subdir.am
pbrd/pbr_main.c
pbrd/pbr_map.c
pbrd/pbr_map.h
pbrd/pbr_memory.c
pbrd/pbr_memory.h
pbrd/pbr_nht.c
pbrd/pbr_vrf.c
pbrd/pbr_zebra.c
pceplib/.gitignore [new file with mode: 0644]
pceplib/pcep.h [new file with mode: 0644]
pceplib/pcep_msg_encoding.h [new file with mode: 0644]
pceplib/pcep_msg_messages.c [new file with mode: 0644]
pceplib/pcep_msg_messages.h [new file with mode: 0644]
pceplib/pcep_msg_messages_encoding.c [new file with mode: 0644]
pceplib/pcep_msg_object_error_types.c [new file with mode: 0644]
pceplib/pcep_msg_object_error_types.h [new file with mode: 0644]
pceplib/pcep_msg_objects.c [new file with mode: 0644]
pceplib/pcep_msg_objects.h [new file with mode: 0644]
pceplib/pcep_msg_objects_encoding.c [new file with mode: 0644]
pceplib/pcep_msg_tlvs.c [new file with mode: 0644]
pceplib/pcep_msg_tlvs.h [new file with mode: 0644]
pceplib/pcep_msg_tlvs_encoding.c [new file with mode: 0644]
pceplib/pcep_msg_tools.c [new file with mode: 0644]
pceplib/pcep_msg_tools.h [new file with mode: 0644]
pceplib/pcep_pcc.c [new file with mode: 0644]
pceplib/pcep_pcc_api.c [new file with mode: 0644]
pceplib/pcep_pcc_api.h [new file with mode: 0644]
pceplib/pcep_session_logic.c [new file with mode: 0644]
pceplib/pcep_session_logic.h [new file with mode: 0644]
pceplib/pcep_session_logic_counters.c [new file with mode: 0644]
pceplib/pcep_session_logic_internals.h [new file with mode: 0644]
pceplib/pcep_session_logic_loop.c [new file with mode: 0644]
pceplib/pcep_session_logic_states.c [new file with mode: 0644]
pceplib/pcep_socket_comm.c [new file with mode: 0644]
pceplib/pcep_socket_comm.h [new file with mode: 0644]
pceplib/pcep_socket_comm_internals.h [new file with mode: 0644]
pceplib/pcep_socket_comm_loop.c [new file with mode: 0644]
pceplib/pcep_socket_comm_loop.h [new file with mode: 0644]
pceplib/pcep_socket_comm_mock.c [new file with mode: 0644]
pceplib/pcep_socket_comm_mock.h [new file with mode: 0644]
pceplib/pcep_timer_internals.h [new file with mode: 0644]
pceplib/pcep_timers.c [new file with mode: 0644]
pceplib/pcep_timers.h [new file with mode: 0644]
pceplib/pcep_timers_event_loop.c [new file with mode: 0644]
pceplib/pcep_timers_event_loop.h [new file with mode: 0644]
pceplib/pcep_utils_counters.c [new file with mode: 0644]
pceplib/pcep_utils_counters.h [new file with mode: 0644]
pceplib/pcep_utils_double_linked_list.c [new file with mode: 0644]
pceplib/pcep_utils_double_linked_list.h [new file with mode: 0644]
pceplib/pcep_utils_logging.c [new file with mode: 0644]
pceplib/pcep_utils_logging.h [new file with mode: 0644]
pceplib/pcep_utils_memory.c [new file with mode: 0644]
pceplib/pcep_utils_memory.h [new file with mode: 0644]
pceplib/pcep_utils_ordered_list.c [new file with mode: 0644]
pceplib/pcep_utils_ordered_list.h [new file with mode: 0644]
pceplib/pcep_utils_queue.c [new file with mode: 0644]
pceplib/pcep_utils_queue.h [new file with mode: 0644]
pceplib/subdir.am [new file with mode: 0644]
pceplib/test/pcep_msg_messages_test.c [new file with mode: 0644]
pceplib/test/pcep_msg_messages_test.h [new file with mode: 0644]
pceplib/test/pcep_msg_messages_tests.c [new file with mode: 0644]
pceplib/test/pcep_msg_object_error_types_test.c [new file with mode: 0644]
pceplib/test/pcep_msg_object_error_types_test.h [new file with mode: 0644]
pceplib/test/pcep_msg_objects_test.c [new file with mode: 0644]
pceplib/test/pcep_msg_objects_test.h [new file with mode: 0644]
pceplib/test/pcep_msg_tests_valgrind.sh [new file with mode: 0755]
pceplib/test/pcep_msg_tlvs_test.c [new file with mode: 0644]
pceplib/test/pcep_msg_tlvs_test.h [new file with mode: 0644]
pceplib/test/pcep_msg_tools_test.c [new file with mode: 0644]
pceplib/test/pcep_msg_tools_test.h [new file with mode: 0644]
pceplib/test/pcep_pcc_api_test.c [new file with mode: 0644]
pceplib/test/pcep_pcc_api_test.h [new file with mode: 0644]
pceplib/test/pcep_pcc_api_tests.c [new file with mode: 0644]
pceplib/test/pcep_pcc_api_tests_valgrind.sh [new file with mode: 0755]
pceplib/test/pcep_session_logic_loop_test.c [new file with mode: 0644]
pceplib/test/pcep_session_logic_loop_test.h [new file with mode: 0644]
pceplib/test/pcep_session_logic_states_test.c [new file with mode: 0644]
pceplib/test/pcep_session_logic_states_test.h [new file with mode: 0644]
pceplib/test/pcep_session_logic_test.c [new file with mode: 0644]
pceplib/test/pcep_session_logic_test.h [new file with mode: 0644]
pceplib/test/pcep_session_logic_tests.c [new file with mode: 0644]
pceplib/test/pcep_session_logic_tests_valgrind.sh [new file with mode: 0755]
pceplib/test/pcep_socket_comm_loop_test.c [new file with mode: 0644]
pceplib/test/pcep_socket_comm_loop_test.h [new file with mode: 0644]
pceplib/test/pcep_socket_comm_test.c [new file with mode: 0644]
pceplib/test/pcep_socket_comm_test.h [new file with mode: 0644]
pceplib/test/pcep_socket_comm_tests.c [new file with mode: 0644]
pceplib/test/pcep_socket_comm_tests_valgrind.sh [new file with mode: 0755]
pceplib/test/pcep_tests_valgrind.sh [new file with mode: 0755]
pceplib/test/pcep_timers_event_loop_test.c [new file with mode: 0644]
pceplib/test/pcep_timers_event_loop_test.h [new file with mode: 0644]
pceplib/test/pcep_timers_test.c [new file with mode: 0644]
pceplib/test/pcep_timers_test.h [new file with mode: 0644]
pceplib/test/pcep_timers_tests.c [new file with mode: 0644]
pceplib/test/pcep_timers_tests_valgrind.sh [new file with mode: 0755]
pceplib/test/pcep_utils_counters_test.c [new file with mode: 0644]
pceplib/test/pcep_utils_counters_test.h [new file with mode: 0644]
pceplib/test/pcep_utils_double_linked_list_test.c [new file with mode: 0644]
pceplib/test/pcep_utils_double_linked_list_test.h [new file with mode: 0644]
pceplib/test/pcep_utils_memory_test.c [new file with mode: 0644]
pceplib/test/pcep_utils_memory_test.h [new file with mode: 0644]
pceplib/test/pcep_utils_ordered_list_test.c [new file with mode: 0644]
pceplib/test/pcep_utils_ordered_list_test.h [new file with mode: 0644]
pceplib/test/pcep_utils_queue_test.c [new file with mode: 0644]
pceplib/test/pcep_utils_queue_test.h [new file with mode: 0644]
pceplib/test/pcep_utils_tests.c [new file with mode: 0644]
pceplib/test/pcep_utils_tests_valgrind.sh [new file with mode: 0755]
pceplib/test/subdir.am [new file with mode: 0644]
pimd/pim_bsm.c
pimd/pim_main.c
pimd/pim_memory.c
pimd/pim_memory.h
pimd/pim_msdp_socket.c
pimd/pim_oil.h
pimd/pim_upstream.h
redhat/frr.spec.in
ripd/rip_interface.c
ripd/rip_interface.h
ripd/rip_main.c
ripd/rip_offset.c
ripd/rip_peer.c
ripd/rip_snmp.c
ripd/ripd.c
ripd/ripd.h
ripd/subdir.am
ripngd/ripng_interface.c
ripngd/ripng_main.c
ripngd/ripng_nexthop.c
ripngd/ripng_offset.c
ripngd/ripng_peer.c
ripngd/ripng_route.c
ripngd/ripngd.c
ripngd/ripngd.h
sharpd/sharp_globals.h
sharpd/sharp_main.c
sharpd/sharp_nht.c
sharpd/sharp_zebra.c
staticd/static_main.c
staticd/static_memory.c [deleted file]
staticd/static_memory.h [deleted file]
staticd/static_routes.c
staticd/static_routes.h
staticd/static_vrf.c
staticd/static_vty.c
staticd/subdir.am
tests/lib/cxxcompat.c
tests/lib/test_atomlist.c
tests/lib/test_heavy_wq.c
tests/lib/test_memory.c
tests/lib/test_typelist.h
tests/lib/test_xref.c
tests/lib/test_zmq.c
tests/ospfd/test_ospf_spf.c
tests/topotests/Dockerfile
tests/topotests/bfd-bgp-cbit-topo3/r1/peers.json
tests/topotests/bfd-bgp-cbit-topo3/r1/peers_down.json
tests/topotests/bfd-bgp-cbit-topo3/r3/peers.json
tests/topotests/bfd-bgp-cbit-topo3/r3/peers_down.json
tests/topotests/bfd-profiles-topo1/r1/bfd-peers-initial.json
tests/topotests/bfd-profiles-topo1/r1/bfdd.conf
tests/topotests/bfd-profiles-topo1/r1/ospfd.conf
tests/topotests/bfd-profiles-topo1/r2/bfd-peers-initial.json
tests/topotests/bfd-profiles-topo1/r2/bfdd.conf
tests/topotests/bfd-profiles-topo1/r3/bfd-peers-initial.json
tests/topotests/bfd-profiles-topo1/r4/bfd-peers-initial.json
tests/topotests/bfd-profiles-topo1/r6/bfd-peers-initial.json
tests/topotests/bfd-topo1/r2/peers.json
tests/topotests/bfd-topo2/r1/peers.json
tests/topotests/bfd-topo2/r2/peers.json
tests/topotests/bfd-topo2/r3/peers.json
tests/topotests/bfd-topo2/r4/peers.json
tests/topotests/bfd-topo3/r1/bfd-peers.json
tests/topotests/bfd-topo3/r2/bfd-peers.json
tests/topotests/bfd-topo3/r3/bfd-peers.json
tests/topotests/bfd-topo3/r4/bfd-peers.json
tests/topotests/bfd-vrf-topo1/r2/peers.json
tests/topotests/bgp-default-ipv4-ipv6-unicast/__init__.py [new file with mode: 0644]
tests/topotests/bgp-default-ipv4-ipv6-unicast/r1/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp-default-ipv4-ipv6-unicast/r1/zebra.conf [new file with mode: 0644]
tests/topotests/bgp-default-ipv4-ipv6-unicast/r2/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp-default-ipv4-ipv6-unicast/r2/zebra.conf [new file with mode: 0644]
tests/topotests/bgp-default-ipv4-ipv6-unicast/r3/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp-default-ipv4-ipv6-unicast/r3/zebra.conf [new file with mode: 0644]
tests/topotests/bgp-default-ipv4-ipv6-unicast/test_bgp-default-ipv4-ipv6-unicast.py [new file with mode: 0644]
tests/topotests/bgp-snmp-mplsl3vpn/test_bgp_snmp_mplsvpn.py
tests/topotests/bgp_multi_vrf_topo1/test_bgp_multi_vrf_topo1.py
tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py
tests/topotests/docker/frr-topotests.sh
tests/topotests/docker/inner/compile_frr.sh
tests/topotests/docker/inner/funcs.sh
tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py
tests/topotests/ldp-snmp/test_ldp_snmp_topo1.py
tests/topotests/lib/bgp.py
tests/topotests/lib/common_config.py
tests/topotests/lib/ospf.py
tests/topotests/lib/topotest.py
tools/etc/frr/support_bundle_commands.conf
vrrpd/vrrp.c
vrrpd/vrrp.h
vrrpd/vrrp_main.c
vrrpd/vrrp_packet.c
vtysh/extract.pl.in
vtysh/vtysh.c
vtysh/vtysh.h
vtysh/vtysh_config.c
watchfrr/watchfrr.c
watchfrr/watchfrr.h
yang/frr-bfdd.yang
yang/frr-filter.yang
zebra/connected.c
zebra/dplane_fpm_nl.c
zebra/if_ioctl.c
zebra/if_netlink.c
zebra/if_sysctl.c
zebra/interface.c
zebra/interface.h
zebra/irdp_interface.c
zebra/irdp_main.c
zebra/irdp_packet.c
zebra/kernel_netlink.c
zebra/kernel_socket.c
zebra/main.c
zebra/redistribute.c
zebra/rib.h
zebra/router-id.c
zebra/rt_netlink.c
zebra/rtadv.c
zebra/rtread_sysctl.c
zebra/sample_plugin.c
zebra/subdir.am
zebra/zapi_msg.c
zebra/zapi_msg.h
zebra/zebra_dplane.c
zebra/zebra_evpn.c
zebra/zebra_evpn_mac.c
zebra/zebra_evpn_mh.c
zebra/zebra_evpn_neigh.c
zebra/zebra_fpm.c
zebra/zebra_l2.c
zebra/zebra_memory.c [deleted file]
zebra/zebra_memory.h [deleted file]
zebra/zebra_mlag.c
zebra/zebra_mlag.h
zebra/zebra_mlag_private.c
zebra/zebra_mpls.c
zebra/zebra_nb.h
zebra/zebra_netns_notify.c
zebra/zebra_nhg.c
zebra/zebra_nhg.h
zebra/zebra_ns.c
zebra/zebra_opaque.c
zebra/zebra_pbr.c
zebra/zebra_pbr.h
zebra/zebra_ptm.c
zebra/zebra_ptm_redistribute.c
zebra/zebra_pw.c
zebra/zebra_pw.h
zebra/zebra_rib.c
zebra/zebra_rnh.c
zebra/zebra_routemap.c
zebra/zebra_router.c
zebra/zebra_snmp.c
zebra/zebra_srte.c
zebra/zebra_vrf.c
zebra/zebra_vrf.h
zebra/zebra_vty.c
zebra/zebra_vxlan.c
zebra/zebra_vxlan_private.h

index 103ac3a478adf31c55554dd046838ed650741b22..837ec75b8d71dc9fc77ba7f67f39a2f6d9254a2f 100644 (file)
@@ -12,3 +12,10 @@ ac4d0be5874fafd14212d6007fff7495edc9b152
 d62a17aedeb0eebdba98238874bb13d62c48dbf9
 c14777c6bfd0a446c85243d3a9835054a259c276
 996c93142d3abfab0f6d6c800474e22a8cfbdbc5
+# require semicolon after macro XYZ
+67b0f40c98aeb9bbc95370fe2be29e56a00a8748
+80413c2073a20774b264ab04f7a4ea4515699790
+960b9a53837d1aefa16bd531c7087f800dbe147b
+96244aca23adec551c29b78f26605f8af8eea53e
+8451921b70044a2c1075e7ba391f095fabee2550
+bf8d3d6aca3f20255a621ed1c148fd05b3a8ae5c
index 97349769adeb62e8c4e9c21d60224240d5a31d10..05ca0b114006324dfc7347b6feef96a43dba8e56 100644 (file)
@@ -29,6 +29,7 @@
 /libtool
 /libtool.orig
 /changelog-auto
+/test-driver
 
 /Makefile
 /Makefile.in
index bb8e97a115f4857bec08dc51414acef53c814e7c..0dff83e505a2a6f10341f5029310af831c6aa1a4 100644 (file)
@@ -158,6 +158,8 @@ include bfdd/subdir.am
 include yang/subdir.am
 include yang/libyang_plugins/subdir.am
 include vrrpd/subdir.am
+include pceplib/subdir.am
+include pceplib/test/subdir.am
 include pathd/subdir.am
 
 include vtysh/subdir.am
index 85d79bdc3bf0e6c5b79081ed4907c57adcb7716f..41391c51ac9b99e2017addec8e3c29f247558dbd 100644 (file)
@@ -42,7 +42,7 @@ THE SOFTWARE.
 #include "xroute.h"
 #include "babel_errors.h"
 
-DEFINE_MTYPE_STATIC(BABELD, BABEL_IF, "Babel Interface")
+DEFINE_MTYPE_STATIC(BABELD, BABEL_IF, "Babel Interface");
 
 #define IS_ENABLE(ifp) (babel_enable_if_lookup(ifp->name) >= 0)
 
index 14e583a35ce723d00ebb8ebf138eb06f88870b3f..71ac35658545654b3d9342cd5970ca49dfc238cf 100644 (file)
@@ -153,7 +153,7 @@ FRR_DAEMON_INFO(babeld, BABELD,
 
                .yang_modules = babeld_yang_modules,
                .n_yang_modules = array_size(babeld_yang_modules),
-               )
+);
 
 int
 main(int argc, char **argv)
index a907daf6c2ab6d06f95b882f16bbdca5c405a1f6..72080bd7eb48e52b4025155399a033eadaa6b0aa 100644 (file)
@@ -46,8 +46,8 @@ THE SOFTWARE.
 #include "babel_zebra.h"
 #include "babel_errors.h"
 
-DEFINE_MGROUP(BABELD, "babeld")
-DEFINE_MTYPE_STATIC(BABELD, BABEL, "Babel Structure")
+DEFINE_MGROUP(BABELD, "babeld");
+DEFINE_MTYPE_STATIC(BABELD, BABEL, "Babel Structure");
 
 static int babel_init_routing_process(struct thread *thread);
 static void babel_get_myid(void);
index 752cc8620a84708dc5189d5c53d9fca6907dacf6..4487aae99f4c74e23ff43a8c208e1d942ecc4aae 100644 (file)
@@ -41,20 +41,6 @@ THE SOFTWARE.
 #define MAX(x,y) ((x)<=(y)?(y):(x))
 #define MIN(x,y) ((x)<=(y)?(x):(y))
 
-#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
-/* nothing */
-#elif defined(__GNUC__)
-#define inline __inline
-#if  (__GNUC__ >= 3)
-#define restrict __restrict
-#else
-#define restrict /**/
-#endif
-#else
-#define inline /**/
-#define restrict /**/
-#endif
-
 #if defined(__GNUC__) && (__GNUC__ >= 3)
 #define ATTRIBUTE(x) __attribute__ (x)
 #define LIKELY(_x) __builtin_expect(!!(_x), 1)
index 93100405713466830534d5f6bb72953fe6793d1b..037ebe3666e8bbbeecfe94a7a476a11e50c78eab 100644 (file)
@@ -29,7 +29,7 @@ THE SOFTWARE.
 #include "log.h"
 #include "memory.h"
 
-DECLARE_MGROUP(BABELD)
+DECLARE_MGROUP(BABELD);
 
 #if defined(i386) || defined(__mc68020__) || defined(__x86_64__)
 #define DO_NTOHS(_d, _s) do{ _d = ntohs(*(const unsigned short*)(_s)); }while(0)
@@ -129,13 +129,7 @@ extern const unsigned char v4prefix[16];
    vararg macros are not portable. */
 #if defined NO_DEBUG
 
-#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
 #define debugf(...) do {} while(0)
-#elif defined __GNUC__
-#define debugf(_args...) do {} while(0)
-#else
-static inline void debugf(int level, const char *format, ...) { return; }
-#endif
 
 #else /* NO_DEBUG */
 
@@ -148,19 +142,10 @@ static inline void debugf(int level, const char *format, ...) { return; }
 #define BABEL_DEBUG_ROUTE       (1 << 5)
 #define BABEL_DEBUG_ALL         (0xFFFF)
 
-#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
 #define debugf(level, ...) \
 do { \
 if(UNLIKELY(debug & level)) zlog_debug(__VA_ARGS__);     \
 } while(0)
-#elif defined __GNUC__
-#define debugf(level, _args...) \
-do { \
-if(UNLIKELY(debug & level)) zlog_debug(_args);   \
-} while(0)
-#else
-static inline void debugf(int level, const char *format, ...) { return; }
-#endif
 
 #endif /* NO_DEBUG */
 
index 3cbb3691ec47f434b3d64bc653842fc3145c5421..234fc6d397c1509333718e67d535c50d33c55898 100644 (file)
 
 #include "bfd.h"
 
-DEFINE_MTYPE_STATIC(BFDD, BFDD_CONFIG, "long-lived configuration memory")
-DEFINE_MTYPE_STATIC(BFDD, BFDD_PROFILE, "long-lived profile memory")
-DEFINE_MTYPE_STATIC(BFDD, BFDD_SESSION_OBSERVER, "Session observer")
-DEFINE_MTYPE_STATIC(BFDD, BFDD_VRF, "BFD VRF")
+DEFINE_MTYPE_STATIC(BFDD, BFDD_CONFIG, "long-lived configuration memory");
+DEFINE_MTYPE_STATIC(BFDD, BFDD_PROFILE, "long-lived profile memory");
+DEFINE_MTYPE_STATIC(BFDD, BFDD_SESSION_OBSERVER, "Session observer");
+DEFINE_MTYPE_STATIC(BFDD, BFDD_VRF, "BFD VRF");
 
 /*
  * Prototypes
@@ -90,7 +90,8 @@ static void bfd_profile_set_default(struct bfd_profile *bp)
        bp->echo_mode = false;
        bp->passive = false;
        bp->minimum_ttl = BFD_DEF_MHOP_TTL;
-       bp->min_echo_rx = BFD_DEF_REQ_MIN_ECHO;
+       bp->min_echo_rx = BFD_DEF_REQ_MIN_ECHO_RX;
+       bp->min_echo_tx = BFD_DEF_DES_MIN_ECHO_TX;
        bp->min_rx = BFD_DEFREQUIREDMINRX;
        bp->min_tx = BFD_DEFDESIREDMINTX;
 }
@@ -179,13 +180,19 @@ void bfd_session_apply(struct bfd_session *bs)
 
        /* We can only apply echo options on single hop sessions. */
        if (!CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
-               /* Configure remote echo if it was default. */
-               if (bs->peer_profile.min_echo_rx == BFD_DEF_REQ_MIN_ECHO)
-                       bs->timers.required_min_echo = bp->min_echo_rx;
+               /* Configure echo timers if they were default. */
+               if (bs->peer_profile.min_echo_rx == BFD_DEF_REQ_MIN_ECHO_RX)
+                       bs->timers.required_min_echo_rx = bp->min_echo_rx;
                else
-                       bs->timers.required_min_echo =
+                       bs->timers.required_min_echo_rx =
                                bs->peer_profile.min_echo_rx;
 
+               if (bs->peer_profile.min_echo_tx == BFD_DEF_DES_MIN_ECHO_TX)
+                       bs->timers.desired_min_echo_tx = bp->min_echo_tx;
+               else
+                       bs->timers.desired_min_echo_tx =
+                               bs->peer_profile.min_echo_tx;
+
                /* Toggle echo if default value. */
                if (bs->peer_profile.echo_mode == false)
                        bfd_set_echo(bs, bp->echo_mode);
@@ -494,8 +501,10 @@ void ptm_bfd_echo_stop(struct bfd_session *bfd)
 void ptm_bfd_echo_start(struct bfd_session *bfd)
 {
        bfd->echo_detect_TO = (bfd->remote_detect_mult * bfd->echo_xmt_TO);
-       if (bfd->echo_detect_TO > 0)
+       if (bfd->echo_detect_TO > 0) {
+               bfd_echo_recvtimer_update(bfd);
                ptm_bfd_echo_xmt_TO(bfd);
+       }
 }
 
 void ptm_bfd_sess_up(struct bfd_session *bfd)
@@ -700,7 +709,8 @@ struct bfd_session *bfd_session_new(void)
 
        bs->timers.desired_min_tx = BFD_DEFDESIREDMINTX;
        bs->timers.required_min_rx = BFD_DEFREQUIREDMINRX;
-       bs->timers.required_min_echo = BFD_DEF_REQ_MIN_ECHO;
+       bs->timers.required_min_echo_rx = BFD_DEF_REQ_MIN_ECHO_RX;
+       bs->timers.desired_min_echo_tx = BFD_DEF_DES_MIN_ECHO_TX;
        bs->detect_mult = BFD_DEFDETECTMULT;
        bs->mh_ttl = BFD_DEF_MHOP_TTL;
        bs->ses_state = PTM_BFD_DOWN;
@@ -769,9 +779,14 @@ static void _bfd_session_update(struct bfd_session *bs,
                bs->peer_profile.detection_multiplier = bs->detect_mult;
        }
 
-       if (bpc->bpc_has_echointerval) {
-               bs->timers.required_min_echo = bpc->bpc_echointerval * 1000;
-               bs->peer_profile.min_echo_rx = bs->timers.required_min_echo;
+       if (bpc->bpc_has_echorecvinterval) {
+               bs->timers.required_min_echo_rx = bpc->bpc_echorecvinterval * 1000;
+               bs->peer_profile.min_echo_rx = bs->timers.required_min_echo_rx;
+       }
+
+       if (bpc->bpc_has_echotxinterval) {
+               bs->timers.desired_min_echo_tx = bpc->bpc_echotxinterval * 1000;
+               bs->peer_profile.min_echo_tx = bs->timers.desired_min_echo_tx;
        }
 
        if (bpc->bpc_has_label)
@@ -1189,10 +1204,10 @@ void bs_echo_timer_handler(struct bfd_session *bs)
         * RFC 5880, Section 6.8.9.
         */
        old_timer = bs->echo_xmt_TO;
-       if (bs->remote_timers.required_min_echo > bs->timers.required_min_echo)
+       if (bs->remote_timers.required_min_echo > bs->timers.desired_min_echo_tx)
                bs->echo_xmt_TO = bs->remote_timers.required_min_echo;
        else
-               bs->echo_xmt_TO = bs->timers.required_min_echo;
+               bs->echo_xmt_TO = bs->timers.desired_min_echo_tx;
 
        if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO_ACTIVE) == 0
            || old_timer != bs->echo_xmt_TO)
index 7c537b40d0467c9a27773f681a8f5316bcdb921e..a86c1bb9f316ecc28f24e696e6477eb94c1fa1e1 100644 (file)
@@ -41,9 +41,9 @@
 #define BFDD_JSON_CONV_OPTIONS (0)
 #endif
 
-DECLARE_MGROUP(BFDD)
-DECLARE_MTYPE(BFDD_CONTROL)
-DECLARE_MTYPE(BFDD_NOTIFICATION)
+DECLARE_MGROUP(BFDD);
+DECLARE_MTYPE(BFDD_CONTROL);
+DECLARE_MTYPE(BFDD_NOTIFICATION);
 
 struct bfd_timers {
        uint32_t desired_min_tx;
@@ -215,6 +215,8 @@ struct bfd_profile {
 
        /** Echo mode (only applies to single hop). */
        bool echo_mode;
+       /** Desired echo transmission interval (in microseconds). */
+       uint32_t min_echo_tx;
        /** Minimum required echo receive interval (in microseconds). */
        uint32_t min_echo_rx;
 
@@ -228,6 +230,13 @@ TAILQ_HEAD(bfdproflist, bfd_profile);
 /* bfd_session shortcut label forwarding. */
 struct peer_label;
 
+struct bfd_config_timers {
+       uint32_t desired_min_tx;
+       uint32_t required_min_rx;
+       uint32_t desired_min_echo_tx;
+       uint32_t required_min_echo_rx;
+};
+
 /*
  * Session state information
  */
@@ -251,7 +260,7 @@ struct bfd_session {
        struct bfd_profile peer_profile;
 
        /* Timers */
-       struct bfd_timers timers;
+       struct bfd_config_timers timers;
        struct bfd_timers cur_timers;
        uint64_t detect_TO;
        struct thread *echo_recvtimer_ev;
@@ -332,7 +341,8 @@ TAILQ_HEAD(obslist, bfd_session_observer);
 #define BFD_DEFDETECTMULT 3
 #define BFD_DEFDESIREDMINTX (300 * 1000) /* microseconds. */
 #define BFD_DEFREQUIREDMINRX (300 * 1000) /* microseconds. */
-#define BFD_DEF_REQ_MIN_ECHO (50 * 1000) /* microseconds. */
+#define BFD_DEF_DES_MIN_ECHO_TX (50 * 1000) /* microseconds. */
+#define BFD_DEF_REQ_MIN_ECHO_RX (50 * 1000) /* microseconds. */
 #define BFD_DEF_SLOWTX (1000 * 1000) /* microseconds. */
 /** Minimum multi hop TTL. */
 #define BFD_DEF_MHOP_TTL 254
index 12bb52cf67667812ea6a8cc331c48b6e899f1273..c871e2abe1e9aebcfe41dc86d0d43608afb1769a 100644 (file)
@@ -267,7 +267,7 @@ void ptm_bfd_snd(struct bfd_session *bfd, int fbit)
                cp.timers.required_min_rx =
                        htonl(bfd->cur_timers.required_min_rx);
        }
-       cp.timers.required_min_echo = htonl(bfd->timers.required_min_echo);
+       cp.timers.required_min_echo = htonl(bfd->timers.required_min_echo_rx);
 
        if (_ptm_bfd_send(bfd, NULL, &cp, BFD_PKT_LEN) != 0)
                return;
index e1cff9a31c5a2ea867f59f0e57a6f879d736f129..c4b2e803060d42d424db8f19486b7a1bf22beae7 100644 (file)
@@ -47,7 +47,8 @@ struct sockaddr_any {
 #define BPC_DEF_DETECTMULTIPLIER 3
 #define BPC_DEF_RECEIVEINTERVAL 300  /* milliseconds */
 #define BPC_DEF_TRANSMITINTERVAL 300 /* milliseconds */
-#define BPC_DEF_ECHOINTERVAL 50      /* milliseconds */
+#define BPC_DEF_ECHORECEIVEINTERVAL 50 /* milliseconds */
+#define BPC_DEF_ECHOTRANSMITINTERVAL 50 /* milliseconds */
 
 /* Peer status */
 enum bfd_peer_status {
@@ -81,8 +82,11 @@ struct bfd_peer_cfg {
        bool bpc_has_txinterval;
        uint64_t bpc_txinterval;
 
-       bool bpc_has_echointerval;
-       uint64_t bpc_echointerval;
+       bool bpc_has_echorecvinterval;
+       uint64_t bpc_echorecvinterval;
+
+       bool bpc_has_echotxinterval;
+       uint64_t bpc_echotxinterval;
 
        bool bpc_has_minimum_ttl;
        uint8_t bpc_minimum_ttl;
index 0cac990108475f535b546f908f200bdc85fbd9c4..7a2c3cc3aa1305899f3b7b323b3601ec1a381058 100644 (file)
@@ -41,9 +41,9 @@
 /*
  * FRR related code.
  */
-DEFINE_MGROUP(BFDD, "Bidirectional Forwarding Detection Daemon")
-DEFINE_MTYPE(BFDD, BFDD_CONTROL, "long-lived control socket memory")
-DEFINE_MTYPE(BFDD, BFDD_NOTIFICATION, "short-lived control notification data")
+DEFINE_MGROUP(BFDD, "Bidirectional Forwarding Detection Daemon");
+DEFINE_MTYPE(BFDD, BFDD_CONTROL, "long-lived control socket memory");
+DEFINE_MTYPE(BFDD, BFDD_NOTIFICATION, "short-lived control notification data");
 
 /* Master of threads. */
 struct thread_master *master;
@@ -134,7 +134,8 @@ FRR_DAEMON_INFO(bfdd, BFD, .vty_port = 2617,
                .signals = bfd_signals, .n_signals = array_size(bfd_signals),
                .privs = &bglobal.bfdd_privs,
                .yang_modules = bfdd_yang_modules,
-               .n_yang_modules = array_size(bfdd_yang_modules))
+               .n_yang_modules = array_size(bfdd_yang_modules),
+);
 
 #define OPTION_CTLSOCK 1001
 #define OPTION_DPLANEADDR 2000
index 206f6c7d0c1d64eb9f7dc4ed01b6c7e004816e46..ba80b2363f1bcd1a39a57b581737c1198081904b 100644 (file)
@@ -433,6 +433,10 @@ DEFPY_YANG(
                return CMD_WARNING_CONFIG_FAILED;
        }
 
+       if (!no && !bglobal.bg_use_dplane) {
+               vty_out(vty, "%% Current implementation of echo mode works only when the peer is also FRR.\n");
+       }
+
        nb_cli_enqueue_change(vty, "./echo-mode", NB_OP_MODIFY,
                              no ? "false" : "true");
        return nb_cli_apply_changes(vty, NULL);
@@ -451,8 +455,31 @@ void bfd_cli_show_echo(struct vty *vty, struct lyd_node *dnode,
 DEFPY_YANG(
        bfd_peer_echo_interval, bfd_peer_echo_interval_cmd,
        "echo-interval (10-60000)$interval",
-       "Configure peer echo interval\n"
-       "Configure peer echo interval value in milliseconds\n")
+       "Configure peer echo intervals\n"
+       "Configure peer echo rx/tx intervals value in milliseconds\n")
+{
+       char value[32];
+
+       if (!bfd_cli_is_profile(vty) && !bfd_cli_is_single_hop(vty)) {
+               vty_out(vty, "%% Echo mode is only available for single hop sessions.\n");
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       snprintf(value, sizeof(value), "%ld", interval * 1000);
+       nb_cli_enqueue_change(vty, "./desired-echo-transmission-interval",
+                             NB_OP_MODIFY, value);
+       nb_cli_enqueue_change(vty, "./required-echo-receive-interval",
+                             NB_OP_MODIFY, value);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY_YANG(
+       bfd_peer_echo_transmit_interval, bfd_peer_echo_transmit_interval_cmd,
+       "echo transmit-interval (10-60000)$interval",
+       "Configure peer echo intervals\n"
+       "Configure desired transmit interval\n"
+       "Configure interval value in milliseconds\n")
 {
        char value[32];
 
@@ -468,17 +495,61 @@ DEFPY_YANG(
        return nb_cli_apply_changes(vty, NULL);
 }
 
-void bfd_cli_show_echo_interval(struct vty *vty, struct lyd_node *dnode,
-                               bool show_defaults)
+void bfd_cli_show_desired_echo_transmission_interval(struct vty *vty,
+       struct lyd_node *dnode, bool show_defaults)
+{
+       uint32_t value;
+
+       if (show_defaults)
+               vty_out(vty, "  echo transmit-interval %d\n",
+                       BFD_DEF_DES_MIN_ECHO_TX);
+       else {
+               value = yang_dnode_get_uint32(dnode, NULL);
+               vty_out(vty, "  echo transmit-interval %u\n", value / 1000);
+       }
+}
+
+DEFPY_YANG(
+       bfd_peer_echo_receive_interval, bfd_peer_echo_receive_interval_cmd,
+       "echo receive-interval <disabled$disabled|(10-60000)$interval>",
+       "Configure peer echo intervals\n"
+       "Configure required receive interval\n"
+       "Disable echo packets receive\n"
+       "Configure interval value in milliseconds\n")
+{
+       char value[32];
+
+       if (!bfd_cli_is_profile(vty) && !bfd_cli_is_single_hop(vty)) {
+               vty_out(vty, "%% Echo mode is only available for single hop sessions.\n");
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       if (disabled)
+               snprintf(value, sizeof(value), "0");
+       else
+               snprintf(value, sizeof(value), "%ld", interval * 1000);
+       
+       nb_cli_enqueue_change(vty, "./required-echo-receive-interval",
+                             NB_OP_MODIFY, value);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+void bfd_cli_show_required_echo_receive_interval(struct vty *vty,
+       struct lyd_node *dnode, bool show_defaults)
 {
        uint32_t value;
 
        if (show_defaults)
-               vty_out(vty, "  echo-interval %d\n",
-                       BFD_DEF_REQ_MIN_ECHO);
+               vty_out(vty, "  echo receive-interval %d\n",
+                       BFD_DEF_REQ_MIN_ECHO_RX);
        else {
                value = yang_dnode_get_uint32(dnode, NULL);
-               vty_out(vty, "  echo-interval %u\n", value / 1000);
+               if (value)
+                       vty_out(vty, "  echo receive-interval %u\n",
+                               value / 1000);
+               else
+                       vty_out(vty, "  echo receive-interval disabled\n");
        }
 }
 
@@ -575,6 +646,21 @@ ALIAS_YANG(bfd_peer_echo_interval, bfd_profile_echo_interval_cmd,
       "Configure peer echo interval\n"
       "Configure peer echo interval value in milliseconds\n")
 
+ALIAS_YANG(
+       bfd_peer_echo_transmit_interval, bfd_profile_echo_transmit_interval_cmd,
+       "echo transmit-interval (10-60000)$interval",
+       "Configure peer echo intervals\n"
+       "Configure desired transmit interval\n"
+       "Configure interval value in milliseconds\n")
+
+ALIAS_YANG(
+       bfd_peer_echo_receive_interval, bfd_profile_echo_receive_interval_cmd,
+       "echo receive-interval <disabled$disabled|(10-60000)$interval>",
+       "Configure peer echo intervals\n"
+       "Configure required receive interval\n"
+       "Disable echo packets receive\n"
+       "Configure interval value in milliseconds\n")
+
 DEFPY_YANG(bfd_peer_profile, bfd_peer_profile_cmd,
       "[no] profile BFDPROF$pname",
       NO_STR
@@ -632,6 +718,8 @@ bfdd_cli_init(void)
        install_element(BFD_PEER_NODE, &bfd_peer_tx_cmd);
        install_element(BFD_PEER_NODE, &bfd_peer_echo_cmd);
        install_element(BFD_PEER_NODE, &bfd_peer_echo_interval_cmd);
+       install_element(BFD_PEER_NODE, &bfd_peer_echo_transmit_interval_cmd);
+       install_element(BFD_PEER_NODE, &bfd_peer_echo_receive_interval_cmd);
        install_element(BFD_PEER_NODE, &bfd_peer_profile_cmd);
        install_element(BFD_PEER_NODE, &bfd_peer_passive_cmd);
        install_element(BFD_PEER_NODE, &bfd_peer_minimum_ttl_cmd);
@@ -652,6 +740,8 @@ bfdd_cli_init(void)
        install_element(BFD_PROFILE_NODE, &bfd_profile_shutdown_cmd);
        install_element(BFD_PROFILE_NODE, &bfd_profile_echo_cmd);
        install_element(BFD_PROFILE_NODE, &bfd_profile_echo_interval_cmd);
+       install_element(BFD_PROFILE_NODE, &bfd_profile_echo_transmit_interval_cmd);
+       install_element(BFD_PROFILE_NODE, &bfd_profile_echo_receive_interval_cmd);
        install_element(BFD_PROFILE_NODE, &bfd_profile_passive_cmd);
        install_element(BFD_PROFILE_NODE, &bfd_profile_minimum_ttl_cmd);
        install_element(BFD_PROFILE_NODE, &no_bfd_profile_minimum_ttl_cmd);
index 64ba3cf81199c57d90e356184d3796bc12af8634..29a9b5f2d527028c2da07fded678e49ecc2ea21f 100644 (file)
@@ -103,8 +103,15 @@ const struct frr_yang_module_info frr_bfdd_info = {
                         .xpath = "/frr-bfdd:bfdd/bfd/profile/desired-echo-transmission-interval",
                         .cbs = {
                                 .modify = bfdd_bfd_profile_desired_echo_transmission_interval_modify,
-                               .cli_show = bfd_cli_show_echo_interval,
-                       }
+                               .cli_show = bfd_cli_show_desired_echo_transmission_interval,
+                        }
+                },
+                {
+                        .xpath = "/frr-bfdd:bfdd/bfd/profile/required-echo-receive-interval",
+                        .cbs = {
+                                .modify = bfdd_bfd_profile_required_echo_receive_interval_modify,
+                               .cli_show = bfd_cli_show_required_echo_receive_interval,
+                        }
                 },
                {
                        .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop",
@@ -179,7 +186,14 @@ const struct frr_yang_module_info frr_bfdd_info = {
                        .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/desired-echo-transmission-interval",
                        .cbs = {
                                .modify = bfdd_bfd_sessions_single_hop_desired_echo_transmission_interval_modify,
-                               .cli_show = bfd_cli_show_echo_interval,
+                               .cli_show = bfd_cli_show_desired_echo_transmission_interval,
+                       }
+               },
+               {
+                       .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/required-echo-receive-interval",
+                       .cbs = {
+                               .modify = bfdd_bfd_sessions_single_hop_required_echo_receive_interval_modify,
+                               .cli_show = bfd_cli_show_required_echo_receive_interval,
                        }
                },
                {
index fbd557b6b12e5068c6165d079d8adf3e10f3943b..874e98691fad90b5d2add75c9ce37c7074b0818a 100644 (file)
@@ -43,6 +43,8 @@ int bfdd_bfd_profile_minimum_ttl_destroy(struct nb_cb_destroy_args *args);
 int bfdd_bfd_profile_echo_mode_modify(struct nb_cb_modify_args *args);
 int bfdd_bfd_profile_desired_echo_transmission_interval_modify(
        struct nb_cb_modify_args *args);
+int bfdd_bfd_profile_required_echo_receive_interval_modify(
+       struct nb_cb_modify_args *args);
 int bfdd_bfd_sessions_single_hop_create(struct nb_cb_create_args *args);
 int bfdd_bfd_sessions_single_hop_destroy(struct nb_cb_destroy_args *args);
 const void *
@@ -71,6 +73,8 @@ int bfdd_bfd_sessions_single_hop_echo_mode_modify(
        struct nb_cb_modify_args *args);
 int bfdd_bfd_sessions_single_hop_desired_echo_transmission_interval_modify(
        struct nb_cb_modify_args *args);
+int bfdd_bfd_sessions_single_hop_required_echo_receive_interval_modify(
+       struct nb_cb_modify_args *args);
 struct yang_data *
 bfdd_bfd_sessions_single_hop_stats_local_discriminator_get_elem(
        struct nb_cb_get_elem_args *args);
@@ -209,8 +213,10 @@ void bfd_cli_show_shutdown(struct vty *vty, struct lyd_node *dnode,
                           bool show_defaults);
 void bfd_cli_show_echo(struct vty *vty, struct lyd_node *dnode,
                       bool show_defaults);
-void bfd_cli_show_echo_interval(struct vty *vty, struct lyd_node *dnode,
-                               bool show_defaults);
+void bfd_cli_show_desired_echo_transmission_interval(
+       struct vty *vty, struct lyd_node *dnode, bool show_defaults);
+void bfd_cli_show_required_echo_receive_interval(
+       struct vty *vty, struct lyd_node *dnode, bool show_defaults);
 void bfd_cli_show_profile(struct vty *vty, struct lyd_node *dnode,
                          bool show_defaults);
 void bfd_cli_peer_profile_show(struct vty *vty, struct lyd_node *dnode,
index c8dd5cc3f63653dc79b750ed42e09477e935ce08..26bce4f357f4748d21dfbeb2d5b43214d99cc110 100644 (file)
@@ -483,10 +483,48 @@ int bfdd_bfd_profile_echo_mode_modify(struct nb_cb_modify_args *args)
 }
 
 /*
- * XPath: /frr-bfdd:bfdd/bfd/profile/desired-echo-echo-transmission-interval
+ * XPath: /frr-bfdd:bfdd/bfd/profile/desired-echo-transmission-interval
  */
 int bfdd_bfd_profile_desired_echo_transmission_interval_modify(
        struct nb_cb_modify_args *args)
+{
+       struct bfd_profile *bp;
+       uint32_t min_tx;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+               min_tx = yang_dnode_get_uint32(args->dnode, NULL);
+               if (min_tx < 10000 || min_tx > 60000000)
+                       return NB_ERR_VALIDATION;
+               break;
+
+       case NB_EV_PREPARE:
+               /* NOTHING */
+               break;
+
+       case NB_EV_APPLY:
+               min_tx = yang_dnode_get_uint32(args->dnode, NULL);
+               bp = nb_running_get_entry(args->dnode, NULL, true);
+               if (bp->min_echo_tx == min_tx)
+                       return NB_OK;
+
+               bp->min_echo_tx = min_tx;
+               bfd_profile_update(bp);
+               break;
+
+       case NB_EV_ABORT:
+               /* NOTHING */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath: /frr-bfdd:bfdd/bfd/profile/required-echo-receive-interval
+ */
+int bfdd_bfd_profile_required_echo_receive_interval_modify(
+       struct nb_cb_modify_args *args)
 {
        struct bfd_profile *bp;
        uint32_t min_rx;
@@ -494,6 +532,8 @@ int bfdd_bfd_profile_desired_echo_transmission_interval_modify(
        switch (args->event) {
        case NB_EV_VALIDATE:
                min_rx = yang_dnode_get_uint32(args->dnode, NULL);
+               if (min_rx == 0)
+                       return NB_OK;
                if (min_rx < 10000 || min_rx > 60000000)
                        return NB_ERR_VALIDATION;
                break;
@@ -789,7 +829,46 @@ int bfdd_bfd_sessions_single_hop_desired_echo_transmission_interval_modify(
 
        case NB_EV_APPLY:
                bs = nb_running_get_entry(args->dnode, NULL, true);
-               if (echo_interval == bs->timers.required_min_echo)
+               if (echo_interval == bs->timers.desired_min_echo_tx)
+                       return NB_OK;
+
+               bs->peer_profile.min_echo_tx = echo_interval;
+               bfd_session_apply(bs);
+               break;
+
+       case NB_EV_ABORT:
+               /* NOTHING */
+               break;
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-bfdd:bfdd/bfd/sessions/single-hop/required-echo-receive-interval
+ */
+int bfdd_bfd_sessions_single_hop_required_echo_receive_interval_modify(
+       struct nb_cb_modify_args *args)
+{
+       uint32_t echo_interval = yang_dnode_get_uint32(args->dnode, NULL);
+       struct bfd_session *bs;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+               if (echo_interval == 0)
+                        return NB_OK;
+               if (echo_interval < 10000 || echo_interval > 60000000)
+                       return NB_ERR_VALIDATION;
+               break;
+
+       case NB_EV_PREPARE:
+               /* NOTHING */
+               break;
+
+       case NB_EV_APPLY:
+               bs = nb_running_get_entry(args->dnode, NULL, true);
+               if (echo_interval == bs->timers.required_min_echo_rx)
                        return NB_OK;
 
                bs->peer_profile.min_echo_rx = echo_interval;
index cb140f7b1833c781c719af5dadeb35ac7dd656b1..a03fb9f216534a32d13f91cadd133fbf15b07127 100644 (file)
@@ -158,8 +158,16 @@ static void _display_peer(struct vty *vty, struct bfd_session *bs)
                bs->timers.required_min_rx / 1000);
        vty_out(vty, "\t\t\tTransmission interval: %ums\n",
                bs->timers.desired_min_tx / 1000);
-       vty_out(vty, "\t\t\tEcho transmission interval: %ums\n",
-               bs->timers.required_min_echo / 1000);
+       if (bs->timers.required_min_echo_rx != 0)
+               vty_out(vty, "\t\t\tEcho receive interval: %ums\n",
+                       bs->timers.required_min_echo_rx / 1000);
+       else
+               vty_out(vty, "\t\t\tEcho receive interval: disabled\n");
+       if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO))
+               vty_out(vty, "\t\t\tEcho transmission interval: %ums\n",
+                       bs->timers.desired_min_echo_tx / 1000);
+       else
+               vty_out(vty, "\t\t\tEcho transmission interval: disabled\n");
 
        vty_out(vty, "\t\tRemote timers:\n");
        vty_out(vty, "\t\t\tDetect-multiplier: %u\n",
@@ -168,8 +176,11 @@ static void _display_peer(struct vty *vty, struct bfd_session *bs)
                bs->remote_timers.required_min_rx / 1000);
        vty_out(vty, "\t\t\tTransmission interval: %ums\n",
                bs->remote_timers.desired_min_tx / 1000);
-       vty_out(vty, "\t\t\tEcho transmission interval: %ums\n",
-               bs->remote_timers.required_min_echo / 1000);
+       if (bs->remote_timers.required_min_echo != 0)
+               vty_out(vty, "\t\t\tEcho receive interval: %ums\n",
+                       bs->remote_timers.required_min_echo / 1000);
+       else
+               vty_out(vty, "\t\t\tEcho receive interval: disabled\n");
 
        vty_out(vty, "\n");
 }
@@ -245,11 +256,13 @@ static struct json_object *__display_peer_json(struct bfd_session *bs)
                            bs->timers.required_min_rx / 1000);
        json_object_int_add(jo, "transmit-interval",
                            bs->timers.desired_min_tx / 1000);
+       json_object_int_add(jo, "echo-receive-interval",
+                           bs->timers.required_min_echo_rx / 1000);
        if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO))
-               json_object_int_add(jo, "echo-interval",
-                                   bs->timers.required_min_echo / 1000);
+               json_object_int_add(jo, "echo-transmit-interval",
+                                   bs->timers.desired_min_echo_tx / 1000);
        else
-               json_object_int_add(jo, "echo-interval", 0);
+               json_object_int_add(jo, "echo-transmit-interval", 0);
 
        json_object_int_add(jo, "detect-multiplier", bs->detect_mult);
 
@@ -257,7 +270,7 @@ static struct json_object *__display_peer_json(struct bfd_session *bs)
                            bs->remote_timers.required_min_rx / 1000);
        json_object_int_add(jo, "remote-transmit-interval",
                            bs->remote_timers.desired_min_tx / 1000);
-       json_object_int_add(jo, "remote-echo-interval",
+       json_object_int_add(jo, "remote-echo-receive-interval",
                            bs->remote_timers.required_min_echo / 1000);
        json_object_int_add(jo, "remote-detect-multiplier",
                            bs->remote_detect_mult);
@@ -844,7 +857,8 @@ static int bfd_configure_peer(struct bfd_peer_cfg *bpc, bool mhop,
        bpc->bpc_detectmultiplier = BPC_DEF_DETECTMULTIPLIER;
        bpc->bpc_recvinterval = BPC_DEF_RECEIVEINTERVAL;
        bpc->bpc_txinterval = BPC_DEF_TRANSMITINTERVAL;
-       bpc->bpc_echointerval = BPC_DEF_ECHOINTERVAL;
+       bpc->bpc_echorecvinterval = BPC_DEF_ECHORECEIVEINTERVAL;
+       bpc->bpc_echotxinterval = BPC_DEF_ECHOTRANSMITINTERVAL;
        bpc->bpc_lastevent = monotime(NULL);
 
        /* Safety check: when no error buf is provided len must be zero. */
index 8865baef6a0f9b364866d7de4e1af296d97368c4..4ece94f577716d4aa003d5e5abc85b64705f48ea 100644 (file)
@@ -162,6 +162,11 @@ struct bfddp_session {
         * jitter.
         */
        uint32_t min_rx;
+       /**
+        * Minimum desired echo transmission interval (in microseconds)
+        * without jitter.
+        */
+       uint32_t min_echo_tx;
        /**
         * Required minimum echo receive interval rate (in microseconds)
         * without jitter.
index b71670f012f09da795a59422d486bfe5b01e6c86..22ec91235941ffa25ea18bce3aa4bbf486ad0640 100644 (file)
@@ -30,7 +30,7 @@
 
 #include "bfd.h"
 
-DEFINE_MTYPE_STATIC(BFDD, BFDD_LABEL, "long-lived label memory")
+DEFINE_MTYPE_STATIC(BFDD, BFDD_LABEL, "long-lived label memory");
 
 /*
  * Definitions
@@ -135,7 +135,8 @@ static int parse_list(struct json_object *jo, enum peer_list_type plt,
                bpc.bpc_detectmultiplier = BFD_DEFDETECTMULT;
                bpc.bpc_recvinterval = BFD_DEFREQUIREDMINRX;
                bpc.bpc_txinterval = BFD_DEFDESIREDMINTX;
-               bpc.bpc_echointerval = BFD_DEF_REQ_MIN_ECHO;
+               bpc.bpc_echorecvinterval = BFD_DEF_REQ_MIN_ECHO_RX;
+               bpc.bpc_echotxinterval = BFD_DEF_DES_MIN_ECHO_TX;
 
                switch (plt) {
                case PLT_IPV4:
@@ -250,11 +251,16 @@ static int parse_peer_config(struct json_object *jo, struct bfd_peer_cfg *bpc)
                        bpc->bpc_has_txinterval = true;
                        zlog_debug("        transmit-interval: %" PRIu64,
                                   bpc->bpc_txinterval);
-               } else if (strcmp(key, "echo-interval") == 0) {
-                       bpc->bpc_echointerval = json_object_get_int64(jo_val);
-                       bpc->bpc_has_echointerval = true;
-                       zlog_debug("        echo-interval: %" PRIu64,
-                                  bpc->bpc_echointerval);
+               } else if (strcmp(key, "echo-receive-interval") == 0) {
+                       bpc->bpc_echorecvinterval = json_object_get_int64(jo_val);
+                       bpc->bpc_has_echorecvinterval = true;
+                       zlog_debug("        echo-receive-interval: %" PRIu64,
+                                  bpc->bpc_echorecvinterval);
+               } else if (strcmp(key, "echo-transmit-interval") == 0) {
+                       bpc->bpc_echotxinterval = json_object_get_int64(jo_val);
+                       bpc->bpc_has_echotxinterval = true;
+                       zlog_debug("        echo-transmit-interval: %" PRIu64,
+                                  bpc->bpc_echotxinterval);
                } else if (strcmp(key, "create-only") == 0) {
                        bpc->bpc_createonly = json_object_get_boolean(jo_val);
                        zlog_debug("        create-only: %s",
@@ -463,8 +469,10 @@ char *config_notify_config(const char *op, struct bfd_session *bs)
                            bs->timers.required_min_rx / 1000);
        json_object_int_add(resp, "transmit-interval",
                            bs->timers.desired_min_tx / 1000);
-       json_object_int_add(resp, "echo-interval",
-                           bs->timers.required_min_echo / 1000);
+       json_object_int_add(resp, "echo-receive-interval",
+                           bs->timers.required_min_echo_rx / 1000);
+       json_object_int_add(resp, "echo-transmit-interval",
+                           bs->timers.desired_min_echo_tx / 1000);
 
        json_object_int_add(resp, "remote-detect-multiplier",
                            bs->remote_detect_mult);
@@ -472,7 +480,7 @@ char *config_notify_config(const char *op, struct bfd_session *bs)
                            bs->remote_timers.required_min_rx / 1000);
        json_object_int_add(resp, "remote-transmit-interval",
                            bs->remote_timers.desired_min_tx / 1000);
-       json_object_int_add(resp, "remote-echo-interval",
+       json_object_int_add(resp, "remote-echo-receive-interval",
                            bs->remote_timers.required_min_echo / 1000);
 
        if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO))
index 66b79f3b13057640011cf949f8d7b205e9d78f82..6fb301d46a89a4a6be208f10057c7779b3ec4f8e 100644 (file)
@@ -46,7 +46,8 @@
 
 #include "lib/openbsd-queue.h"
 
-DEFINE_MTYPE_STATIC(BFDD, BFDD_DPLANE_CTX, "Data plane client allocated memory")
+DEFINE_MTYPE_STATIC(BFDD, BFDD_DPLANE_CTX,
+                   "Data plane client allocated memory");
 
 /** Data plane client socket buffer size. */
 #define BFD_DPLANE_CLIENT_BUF_SIZE 8192
@@ -765,7 +766,8 @@ static void _bfd_dplane_session_fill(const struct bfd_session *bs,
        msg->data.session.lid = htonl(bs->discrs.my_discr);
        msg->data.session.min_tx = htonl(bs->timers.desired_min_tx);
        msg->data.session.min_rx = htonl(bs->timers.required_min_rx);
-       msg->data.session.min_echo_rx = htonl(bs->timers.required_min_echo);
+       msg->data.session.min_echo_tx = htonl(bs->timers.desired_min_echo_tx);
+       msg->data.session.min_echo_rx = htonl(bs->timers.required_min_echo_rx);
 }
 
 static int _bfd_dplane_add_session(struct bfd_dplane_ctx *bdc,
index 745a0dffce2c1a9daf7868e7051ec04b315b4389..ef4f626111958fcde21b455904ddaa7741904a13 100644 (file)
@@ -23,7 +23,7 @@
 
 #include "lib/typesafe.h"
 
-PREDECL_DLIST(bgp_adv_fifo)
+PREDECL_DLIST(bgp_adv_fifo);
 
 struct update_subgroup;
 
@@ -60,7 +60,7 @@ struct bgp_advertise {
        struct bgp_path_info *pathi;
 };
 
-DECLARE_DLIST(bgp_adv_fifo, struct bgp_advertise, fifo)
+DECLARE_DLIST(bgp_adv_fifo, struct bgp_advertise, fifo);
 
 /* BGP adjacency out.  */
 struct bgp_adj_out {
index 11e9344d1cafafec0d912a27d1a337790fe2d83e..f1bdcc8bb47505fff582b94d328c15868905b97c 100644 (file)
@@ -29,6 +29,7 @@
 #include "thread.h"
 #include "buffer.h"
 #include "stream.h"
+#include "vrf.h"
 #include "zclient.h"
 #include "bfd.h"
 #include "lib/json.h"
 #include "bgpd/bgp_debug.h"
 #include "bgpd/bgp_vty.h"
 
+DEFINE_MTYPE_STATIC(BGPD, BFD_CONFIG, "BFD configuration data");
+
 extern struct zclient *zclient;
 
-/*
- * bgp_bfd_peer_group2peer_copy - Copy the BFD information from peer group
- * template
- *                                to peer.
- */
-void bgp_bfd_peer_group2peer_copy(struct peer *conf, struct peer *peer)
+static void bfd_session_status_update(struct bfd_session_params *bsp,
+                                     const struct bfd_session_status *bss,
+                                     void *arg)
 {
-       struct bfd_info *bfd_info;
-       struct bfd_info *conf_bfd_info;
-
-       if (!conf->bfd_info)
-               return;
-
-       conf_bfd_info = (struct bfd_info *)conf->bfd_info;
-       if (!peer->bfd_info)
-               peer->bfd_info = bfd_info_create();
-
-       bfd_info = (struct bfd_info *)peer->bfd_info;
+       struct peer *peer = arg;
+
+       if (BGP_DEBUG(bfd, BFD_LIB))
+               zlog_debug("%s: neighbor %s vrf %s(%u) bfd state %s -> %s",
+                          __func__, peer->conf_if ? peer->conf_if : peer->host,
+                          bfd_sess_vrf(bsp), bfd_sess_vrf_id(bsp),
+                          bfd_get_status_str(bss->previous_state),
+                          bfd_get_status_str(bss->state));
+
+       if (bss->state == BSS_DOWN && bss->previous_state == BSS_UP) {
+               if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_MODE)
+                   && bfd_sess_cbit(bsp) && !bss->remote_cbit) {
+                       if (BGP_DEBUG(bfd, BFD_LIB))
+                               zlog_info(
+                                       "%s BFD DOWN message ignored in the process of graceful restart when C bit is cleared",
+                                       peer->host);
+                       return;
+               }
+               peer->last_reset = PEER_DOWN_BFD_DOWN;
+               BGP_EVENT_ADD(peer, BGP_Stop);
+       }
 
-       /* Copy BFD parameter values */
-       bfd_info->required_min_rx = conf_bfd_info->required_min_rx;
-       bfd_info->desired_min_tx = conf_bfd_info->desired_min_tx;
-       bfd_info->detect_mult = conf_bfd_info->detect_mult;
-       bfd_info->type = conf_bfd_info->type;
+       if (bss->state == BSS_UP && bss->previous_state != BSS_UP
+           && peer->status != Established) {
+               if (!BGP_PEER_START_SUPPRESSED(peer)) {
+                       bgp_fsm_nht_update(peer, true);
+                       BGP_EVENT_ADD(peer, BGP_Start);
+               }
+       }
 }
 
-/*
- * bgp_bfd_is_peer_multihop - returns whether BFD peer is multi-hop or single
- * hop.
- */
-bool bgp_bfd_is_peer_multihop(struct peer *peer)
+void bgp_peer_config_apply(struct peer *p, struct peer_group *pg)
 {
-       struct bfd_info *bfd_info;
+       struct listnode *n;
+       struct peer *pn;
+       struct peer *gconfig;
+
+       /* When called on a group, apply to all peers. */
+       if (CHECK_FLAG(p->sflags, PEER_STATUS_GROUP)) {
+               for (ALL_LIST_ELEMENTS_RO(p->group->peer, n, pn))
+                       bgp_peer_config_apply(pn, pg);
+               return;
+       }
 
-       bfd_info = (struct bfd_info *)peer->bfd_info;
+       /* No group, just use current configuration. */
+       if (pg == NULL || pg->conf->bfd_config == NULL) {
+               bfd_sess_set_timers(p->bfd_config->session,
+                                   p->bfd_config->detection_multiplier,
+                                   p->bfd_config->min_rx,
+                                   p->bfd_config->min_tx);
+               bfd_sess_set_cbit(p->bfd_config->session, p->bfd_config->cbit);
+               bfd_sess_set_profile(p->bfd_config->session,
+                                    p->bfd_config->profile);
+               bfd_sess_install(p->bfd_config->session);
+               return;
+       }
 
-       if (!bfd_info)
-               return false;
+       /*
+        * Check if the group configuration was overwritten or apply group
+        * configuration.
+        */
+       gconfig = pg->conf;
+
+       /*
+        * If using default control plane independent configuration,
+        * then prefer group's (e.g. it means it wasn't manually configured).
+        */
+       if (!p->bfd_config->cbit)
+               bfd_sess_set_cbit(p->bfd_config->session,
+                                 gconfig->bfd_config->cbit);
+       else
+               bfd_sess_set_cbit(p->bfd_config->session, p->bfd_config->cbit);
 
-       if ((bfd_info->type == BFD_TYPE_MULTIHOP)
-           || ((peer->sort == BGP_PEER_IBGP) && !peer->shared_network)
-           || is_ebgp_multihop_configured(peer))
-               return true;
+       /* If no profile was specified in peer, then use the group profile. */
+       if (p->bfd_config->profile[0] == 0)
+               bfd_sess_set_profile(p->bfd_config->session,
+                                    gconfig->bfd_config->profile);
        else
-               return false;
+               bfd_sess_set_profile(p->bfd_config->session,
+                                    p->bfd_config->profile);
+
+       /* If no specific timers were configured, then use the group timers. */
+       if (p->bfd_config->detection_multiplier == BFD_DEF_DETECT_MULT
+           || p->bfd_config->min_rx == BFD_DEF_MIN_RX
+           || p->bfd_config->min_tx == BFD_DEF_MIN_TX)
+               bfd_sess_set_timers(p->bfd_config->session,
+                                   gconfig->bfd_config->detection_multiplier,
+                                   gconfig->bfd_config->min_rx,
+                                   gconfig->bfd_config->min_tx);
+       else
+               bfd_sess_set_timers(p->bfd_config->session,
+                                   p->bfd_config->detection_multiplier,
+                                   p->bfd_config->min_rx,
+                                   p->bfd_config->min_tx);
+
+       bfd_sess_install(p->bfd_config->session);
 }
 
-/*
- * bgp_bfd_peer_sendmsg - Format and send a Peer register/Unregister
- *                        command to Zebra to be forwarded to BFD
- */
-static void bgp_bfd_peer_sendmsg(struct peer *peer, int command)
+void bgp_peer_bfd_update_source(struct peer *p)
 {
-       struct bfd_session_arg arg = {};
-       struct bfd_info *bfd_info;
-       int multihop;
-       vrf_id_t vrf_id;
-       size_t addrlen;
-
-       /*
-        * XXX: some pointers are dangling during shutdown, so instead of
-        * trying to send a message during signal handlers lets just wait BGP
-        * to terminate zebra's connection and BFD will automatically find
-        * out that we are no longer expecting notifications.
-        *
-        * The pointer that is causing a crash here is `peer->nexthop.ifp`.
-        * That happens because at this point of the shutdown all interfaces are
-        * already `free()`d.
-        */
-       if (bm->terminating)
+       struct bfd_session_params *session = p->bfd_config->session;
+       bool changed = false;
+       int family;
+       union {
+               struct in_addr v4;
+               struct in6_addr v6;
+       } src, dst;
+
+       /* Nothing to do for groups. */
+       if (CHECK_FLAG(p->sflags, PEER_STATUS_GROUP))
                return;
 
-       bfd_info = (struct bfd_info *)peer->bfd_info;
+       /* Update peer's source/destination addresses. */
+       bfd_sess_addresses(session, &family, &src.v6, &dst.v6);
+       if (family == AF_INET) {
+               if ((p->su_local
+                    && p->su_local->sin.sin_addr.s_addr != src.v4.s_addr)
+                   || p->su.sin.sin_addr.s_addr != dst.v4.s_addr) {
+                       if (BGP_DEBUG(bfd, BFD_LIB))
+                               zlog_debug(
+                                       "%s: address [%pI4->%pI4] to [%pI4->%pI4]",
+                                       __func__, &src.v4, &dst.v4,
+                                       p->su_local ? &p->su_local->sin.sin_addr
+                                                   : &src.v4,
+                                       &p->su.sin.sin_addr);
+
+                       bfd_sess_set_ipv4_addrs(
+                               session,
+                               p->su_local ? &p->su_local->sin.sin_addr : NULL,
+                               &p->su.sin.sin_addr);
+                       changed = true;
+               }
+       } else {
+               if ((p->su_local
+                    && memcmp(&p->su_local->sin6, &src.v6, sizeof(src.v6)))
+                   || memcmp(&p->su.sin6, &dst.v6, sizeof(dst.v6))) {
+                       if (BGP_DEBUG(bfd, BFD_LIB))
+                               zlog_debug(
+                                       "%s: address [%pI6->%pI6] to [%pI6->%pI6]",
+                                       __func__, &src.v6, &dst.v6,
+                                       p->su_local
+                                               ? &p->su_local->sin6.sin6_addr
+                                               : &src.v6,
+                                       &p->su.sin6.sin6_addr);
+
+                       bfd_sess_set_ipv6_addrs(
+                               session,
+                               p->su_local ? &p->su_local->sin6.sin6_addr
+                                           : NULL,
+                               &p->su.sin6.sin6_addr);
+                       changed = true;
+               }
+       }
 
-       vrf_id = peer->bgp->vrf_id;
+       /* Update interface. */
+       if (p->nexthop.ifp && bfd_sess_interface(session) == NULL) {
+               if (BGP_DEBUG(bfd, BFD_LIB))
+                       zlog_debug("%s: interface none to %s", __func__,
+                                  p->nexthop.ifp->name);
 
-       if (command == ZEBRA_BFD_DEST_DEREGISTER) {
-               multihop =
-                       CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_TYPE_MULTIHOP);
-               UNSET_FLAG(bfd_info->flags, BFD_FLAG_BFD_TYPE_MULTIHOP);
-       } else {
-               multihop = bgp_bfd_is_peer_multihop(peer);
-               if ((command == ZEBRA_BFD_DEST_REGISTER) && multihop)
-                       SET_FLAG(bfd_info->flags, BFD_FLAG_BFD_TYPE_MULTIHOP);
+               bfd_sess_set_interface(session, p->nexthop.ifp->name);
+               changed = true;
        }
-       /* while graceful restart with fwd path preserved
-        * and bfd controlplane check not configured is not kept
-        * keep bfd independent controlplane bit set to 1
+
+       /*
+        * Update TTL.
+        *
+        * Two cases:
+        * - We detected that the peer is a hop away from us (remove multi hop).
+        *   (this happens when `p->shared_network` is set to `true`)
+        * - eBGP multi hop / TTL security changed.
         */
-       if (!CHECK_FLAG(peer->bgp->flags, BGP_FLAG_GRACEFUL_RESTART)
-           && !CHECK_FLAG(peer->bgp->flags, BGP_FLAG_GR_PRESERVE_FWD)
-           && !CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CHECK_CONTROLPLANE))
-               SET_FLAG(bfd_info->flags, BFD_FLAG_BFD_CBIT_ON);
-
-       /* Set all message arguments. */
-       arg.family = peer->su.sa.sa_family;
-       addrlen = arg.family == AF_INET ? sizeof(struct in_addr)
-                                       : sizeof(struct in6_addr);
-
-       if (arg.family == AF_INET)
-               memcpy(&arg.dst, &peer->su.sin.sin_addr, addrlen);
-       else
-               memcpy(&arg.dst, &peer->su.sin6.sin6_addr, addrlen);
+       if (!PEER_IS_MULTIHOP(p) && bfd_sess_hop_count(session) > 1) {
+               if (BGP_DEBUG(bfd, BFD_LIB))
+                       zlog_debug("%s: TTL %d to 1", __func__,
+                                  bfd_sess_hop_count(session));
 
-       if (peer->su_local) {
-               if (arg.family == AF_INET)
-                       memcpy(&arg.src, &peer->su_local->sin.sin_addr,
-                              addrlen);
-               else
-                       memcpy(&arg.src, &peer->su_local->sin6.sin6_addr,
-                              addrlen);
+               bfd_sess_set_hop_count(session, 1);
+               changed = true;
        }
+       if (PEER_IS_MULTIHOP(p) && p->ttl != bfd_sess_hop_count(session)) {
+               if (BGP_DEBUG(bfd, BFD_LIB))
+                       zlog_debug("%s: TTL %d to %d", __func__,
+                                  bfd_sess_hop_count(session), p->ttl);
 
-       if (peer->nexthop.ifp) {
-               arg.ifnamelen = strlen(peer->nexthop.ifp->name);
-               strlcpy(arg.ifname, peer->nexthop.ifp->name,
-                       sizeof(arg.ifname));
+               bfd_sess_set_hop_count(session, p->ttl);
+               changed = true;
        }
 
-       if (bfd_info->profile[0]) {
-               arg.profilelen = strlen(bfd_info->profile);
-               strlcpy(arg.profile, bfd_info->profile, sizeof(arg.profile));
+       /* Update VRF. */
+       if (bfd_sess_vrf_id(session) != p->bgp->vrf_id) {
+               if (BGP_DEBUG(bfd, BFD_LIB))
+                       zlog_debug(
+                               "%s: VRF %s(%d) to %s(%d)", __func__,
+                               bfd_sess_vrf(session), bfd_sess_vrf_id(session),
+                               vrf_id_to_name(p->bgp->vrf_id), p->bgp->vrf_id);
+
+               bfd_sess_set_vrf(session, p->bgp->vrf_id);
+               changed = true;
        }
 
-       arg.set_flag = 1;
-       arg.mhop = multihop;
-       arg.ttl = peer->ttl;
-       arg.vrf_id = vrf_id;
-       arg.command = command;
-       arg.bfd_info = bfd_info;
-       arg.min_tx = bfd_info->desired_min_tx;
-       arg.min_rx = bfd_info->required_min_rx;
-       arg.detection_multiplier = bfd_info->detect_mult;
-       arg.cbit = CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CBIT_ON);
-
-       /* Send message. */
-       zclient_bfd_command(zclient, &arg);
+       if (changed)
+               bfd_sess_install(session);
 }
 
-/*
- * bgp_bfd_register_peer - register a peer with BFD through zebra
- *                         for monitoring the peer rechahability.
+/**
+ * Reset BFD configuration data structure to its defaults settings.
  */
-void bgp_bfd_register_peer(struct peer *peer)
+static void bgp_peer_bfd_reset(struct peer *p)
 {
-       struct bfd_info *bfd_info;
-
-       if (!peer->bfd_info)
-               return;
-       bfd_info = (struct bfd_info *)peer->bfd_info;
-
-       /* Check if BFD is enabled and peer has already been registered with BFD
-        */
-       if (CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_REG))
-               return;
-
-       bgp_bfd_peer_sendmsg(peer, ZEBRA_BFD_DEST_REGISTER);
+       /* Set defaults. */
+       p->bfd_config->detection_multiplier = BFD_DEF_DETECT_MULT;
+       p->bfd_config->min_rx = BFD_DEF_MIN_RX;
+       p->bfd_config->min_tx = BFD_DEF_MIN_TX;
+       p->bfd_config->cbit = false;
+       p->bfd_config->profile[0] = 0;
 }
 
-/**
- * bgp_bfd_deregister_peer - deregister a peer with BFD through zebra
- *                           for stopping the monitoring of the peer
- *                           rechahability.
- */
-void bgp_bfd_deregister_peer(struct peer *peer)
+void bgp_peer_configure_bfd(struct peer *p, bool manual)
 {
-       struct bfd_info *bfd_info;
+       /* Groups should not call this. */
+       assert(!CHECK_FLAG(p->sflags, PEER_STATUS_GROUP));
 
-       if (!peer->bfd_info)
-               return;
-       bfd_info = (struct bfd_info *)peer->bfd_info;
+       /* Already configured, skip it. */
+       if (p->bfd_config) {
+               /* If manually active update flag. */
+               if (!p->bfd_config->manual)
+                       p->bfd_config->manual = manual;
 
-       /* Check if BFD is eanbled and peer has not been registered */
-       if (!CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_REG))
                return;
+       }
 
-       bfd_info->status = BFD_STATUS_DOWN;
-       bfd_info->last_update = bgp_clock();
-
-       bgp_bfd_peer_sendmsg(peer, ZEBRA_BFD_DEST_DEREGISTER);
-}
-
-/*
- * bgp_bfd_update_peer - update peer with BFD with new BFD paramters
- *                       through zebra.
- */
-static void bgp_bfd_update_peer(struct peer *peer)
-{
-       struct bfd_info *bfd_info;
+       /* Allocate memory for configuration overrides. */
+       p->bfd_config = XCALLOC(MTYPE_BFD_CONFIG, sizeof(*p->bfd_config));
+       p->bfd_config->manual = manual;
 
-       if (!peer->bfd_info)
-               return;
-       bfd_info = (struct bfd_info *)peer->bfd_info;
+       /* Create new session and assign callback. */
+       p->bfd_config->session = bfd_sess_new(bfd_session_status_update, p);
+       bgp_peer_bfd_reset(p);
 
-       /* Check if the peer has been registered with BFD*/
-       if (!CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_REG))
-               return;
+       /* Configure session with basic BGP peer data. */
+       if (p->su.sa.sa_family == AF_INET)
+               bfd_sess_set_ipv4_addrs(p->bfd_config->session,
+                                       p->su_local ? &p->su_local->sin.sin_addr
+                                                   : NULL,
+                                       &p->su.sin.sin_addr);
+       else
+               bfd_sess_set_ipv6_addrs(
+                       p->bfd_config->session,
+                       p->su_local ? &p->su_local->sin6.sin6_addr : NULL,
+                       &p->su.sin6.sin6_addr);
 
-       bgp_bfd_peer_sendmsg(peer, ZEBRA_BFD_DEST_UPDATE);
-}
+       bfd_sess_set_vrf(p->bfd_config->session, p->bgp->vrf_id);
+       bfd_sess_set_hop_count(p->bfd_config->session,
+                              PEER_IS_MULTIHOP(p) ? p->ttl : 1);
 
-/**
- * bgp_bfd_reset_peer - reinitialise bfd
- * ensures that bfd state machine is restarted
- * to be synced with remote bfd
- */
-void bgp_bfd_reset_peer(struct peer *peer)
-{
-       if (!peer->bfd_info)
-               return;
+       if (p->nexthop.ifp)
+               bfd_sess_set_interface(p->bfd_config->session,
+                                      p->nexthop.ifp->name);
 
-       bgp_bfd_peer_sendmsg(peer, ZEBRA_BFD_DEST_REGISTER);
+       bfd_sess_enable(p->bfd_config->session, true);
 }
 
-/*
- * bgp_bfd_update_type - update session type with BFD through zebra.
- */
-static void bgp_bfd_update_type(struct peer *peer)
+static void bgp_peer_remove_bfd(struct peer *p)
 {
-       struct bfd_info *bfd_info;
-       int multihop;
-
-       if (!peer->bfd_info)
-               return;
-       bfd_info = (struct bfd_info *)peer->bfd_info;
+       /* Groups should not call this. */
+       assert(!CHECK_FLAG(p->sflags, PEER_STATUS_GROUP));
 
-       /* Check if the peer has been registered with BFD*/
-       if (!CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_REG))
+       /*
+        * Peer configuration was removed, however we must check if there
+        * is still a group configuration to keep this running.
+        */
+       if (p->group && p->group->conf->bfd_config) {
+               p->bfd_config->manual = false;
+               bgp_peer_bfd_reset(p);
+               bgp_peer_config_apply(p, p->group);
                return;
-
-       if (bfd_info->type == BFD_TYPE_NOT_CONFIGURED) {
-               multihop = bgp_bfd_is_peer_multihop(peer);
-               if ((multihop
-                    && !CHECK_FLAG(bfd_info->flags,
-                                   BFD_FLAG_BFD_TYPE_MULTIHOP))
-                   || (!multihop && CHECK_FLAG(bfd_info->flags,
-                                               BFD_FLAG_BFD_TYPE_MULTIHOP))) {
-                       bgp_bfd_peer_sendmsg(peer, ZEBRA_BFD_DEST_DEREGISTER);
-                       bgp_bfd_peer_sendmsg(peer, ZEBRA_BFD_DEST_REGISTER);
-               }
-       } else {
-               if ((bfd_info->type == BFD_TYPE_MULTIHOP
-                    && !CHECK_FLAG(bfd_info->flags,
-                                   BFD_FLAG_BFD_TYPE_MULTIHOP))
-                   || (bfd_info->type == BFD_TYPE_SINGLEHOP
-                       && CHECK_FLAG(bfd_info->flags,
-                                     BFD_FLAG_BFD_TYPE_MULTIHOP))) {
-                       bgp_bfd_peer_sendmsg(peer, ZEBRA_BFD_DEST_DEREGISTER);
-                       bgp_bfd_peer_sendmsg(peer, ZEBRA_BFD_DEST_REGISTER);
-               }
        }
-}
-
-/*
- * bgp_bfd_dest_replay - Replay all the peers that have BFD enabled
- *                       to zebra
- */
-static int bgp_bfd_dest_replay(ZAPI_CALLBACK_ARGS)
-{
-       struct listnode *mnode, *node, *nnode;
-       struct bgp *bgp;
-       struct peer *peer;
-
-       if (BGP_DEBUG(zebra, ZEBRA))
-               zlog_debug("Zebra: BFD Dest replay request");
-
-       /* Send the client registration */
-       bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, vrf_id);
-
-       /* Replay the peer, if BFD is enabled in BGP */
 
-       for (ALL_LIST_ELEMENTS_RO(bm->bgp, mnode, bgp))
-               for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
-                       bgp_bfd_update_peer(peer);
-               }
-
-       return 0;
+       bfd_sess_free(&p->bfd_config->session);
+       XFREE(MTYPE_BFD_CONFIG, p->bfd_config);
 }
 
-/*
- * bgp_bfd_peer_status_update - Update the BFD status if it has changed. Bring
- *                              down the peer if the BFD session went down from
- * *                              up.
- */
-static void bgp_bfd_peer_status_update(struct peer *peer, int status,
-                                      int remote_cbit)
+static void bgp_group_configure_bfd(struct peer *p)
 {
-       struct bfd_info *bfd_info;
-       int old_status;
+       struct listnode *n;
+       struct peer *pn;
 
-       bfd_info = (struct bfd_info *)peer->bfd_info;
+       /* Peers should not call this. */
+       assert(CHECK_FLAG(p->sflags, PEER_STATUS_GROUP));
 
-       if (bfd_info->status == status)
+       /* Already allocated: do nothing. */
+       if (p->bfd_config)
                return;
 
-       old_status = bfd_info->status;
-       BFD_SET_CLIENT_STATUS(bfd_info->status, status);
+       p->bfd_config = XCALLOC(MTYPE_BFD_CONFIG, sizeof(*p->bfd_config));
 
-       bfd_info->last_update = bgp_clock();
+       /* Set defaults. */
+       p->bfd_config->detection_multiplier = BFD_DEF_DETECT_MULT;
+       p->bfd_config->min_rx = BFD_DEF_MIN_RX;
+       p->bfd_config->min_tx = BFD_DEF_MIN_TX;
 
-       if (status != old_status) {
-               if (BGP_DEBUG(neighbor_events, NEIGHBOR_EVENTS))
-                       zlog_debug("[%s]: BFD %s", peer->host,
-                                  bfd_get_status_str(status));
-       }
-       if ((status == BFD_STATUS_DOWN) && (old_status == BFD_STATUS_UP)) {
-               if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_MODE) &&
-                   CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CHECK_CONTROLPLANE) &&
-                   !remote_cbit) {
-                       zlog_info("%s BFD DOWN message ignored in the process of graceful restart when C bit is cleared",
-                                 peer->host);
-                       return;
-               }
-               peer->last_reset = PEER_DOWN_BFD_DOWN;
-               BGP_EVENT_ADD(peer, BGP_Stop);
-       }
-       if ((status == BFD_STATUS_UP) && (old_status == BFD_STATUS_DOWN)
-           && peer->status != Established) {
-               if (!BGP_PEER_START_SUPPRESSED(peer)) {
-                       bgp_fsm_nht_update(peer, true);
-                       BGP_EVENT_ADD(peer, BGP_Start);
-               }
-       }
+       for (ALL_LIST_ELEMENTS_RO(p->group->peer, n, pn))
+               bgp_peer_configure_bfd(pn, false);
 }
 
-/*
- * bgp_bfd_dest_update - Find the peer for which the BFD status
- *                       has changed and bring down the peer
- *                       connectivity if the BFD session went down.
- */
-static int bgp_bfd_dest_update(ZAPI_CALLBACK_ARGS)
+static void bgp_group_remove_bfd(struct peer *p)
 {
-       struct interface *ifp;
-       struct prefix dp;
-       struct prefix sp;
-       int status;
-       int remote_cbit;
+       struct listnode *n;
+       struct peer *pn;
 
-       ifp = bfd_get_peer_info(zclient->ibuf, &dp, &sp, &status,
-                               &remote_cbit, vrf_id);
+       /* Peers should not call this. */
+       assert(CHECK_FLAG(p->sflags, PEER_STATUS_GROUP));
 
-       if (BGP_DEBUG(zebra, ZEBRA)) {
-               struct vrf *vrf;
+       /* Already freed: do nothing. */
+       if (p->bfd_config == NULL)
+               return;
 
-               vrf = vrf_lookup_by_id(vrf_id);
+       /* Free configuration and point to `NULL`. */
+       XFREE(MTYPE_BFD_CONFIG, p->bfd_config);
 
-               if (ifp)
-                       zlog_debug(
-                               "Zebra: vrf %s(%u) interface %s bfd destination %pFX %s %s",
-                               VRF_LOGNAME(vrf), vrf_id, ifp->name, &dp,
-                               bfd_get_status_str(status),
-                               remote_cbit ? "(cbit on)" : "");
+       /* Now that it is `NULL` recalculate configuration for all peers. */
+       for (ALL_LIST_ELEMENTS_RO(p->group->peer, n, pn)) {
+               if (pn->bfd_config->manual)
+                       bgp_peer_config_apply(pn, NULL);
                else
-                       zlog_debug(
-                               "Zebra: vrf %s(%u) source %pFX bfd destination %pFX %s %s",
-                               VRF_LOGNAME(vrf), vrf_id, &sp, &dp,
-                               bfd_get_status_str(status),
-                               remote_cbit ? "(cbit on)" : "");
-       }
-
-       /* Bring the peer down if BFD is enabled in BGP */
-       {
-               struct listnode *mnode, *node, *nnode;
-               struct bgp *bgp;
-               struct peer *peer;
-
-               for (ALL_LIST_ELEMENTS_RO(bm->bgp, mnode, bgp))
-                       for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
-                               if (!peer->bfd_info)
-                                       continue;
-
-                               if ((dp.family == AF_INET)
-                                   && (peer->su.sa.sa_family == AF_INET)) {
-                                       if (dp.u.prefix4.s_addr
-                                           != peer->su.sin.sin_addr.s_addr)
-                                               continue;
-                               } else if ((dp.family == AF_INET6)
-                                          && (peer->su.sa.sa_family
-                                              == AF_INET6)) {
-                                       if (memcmp(&dp.u.prefix6,
-                                                  &peer->su.sin6.sin6_addr,
-                                                  sizeof(struct in6_addr)))
-                                               continue;
-                               } else
-                                       continue;
-
-                               if (ifp && (ifp == peer->nexthop.ifp)) {
-                                       bgp_bfd_peer_status_update(peer,
-                                                                  status,
-                                                                  remote_cbit);
-                               } else {
-                                       if (!peer->su_local)
-                                               continue;
-
-                                       if ((sp.family == AF_INET)
-                                           && (peer->su_local->sa.sa_family
-                                               == AF_INET)) {
-                                               if (sp.u.prefix4.s_addr
-                                                   != peer->su_local->sin
-                                                              .sin_addr.s_addr)
-                                                       continue;
-                                       } else if ((sp.family == AF_INET6)
-                                                  && (peer->su_local->sa
-                                                              .sa_family
-                                                      == AF_INET6)) {
-                                               if (memcmp(&sp.u.prefix6,
-                                                          &peer->su_local->sin6
-                                                                   .sin6_addr,
-                                                          sizeof(struct
-                                                                 in6_addr)))
-                                                       continue;
-                                       } else
-                                               continue;
-
-                                       if ((vrf_id != VRF_DEFAULT)
-                                           && (peer->bgp->vrf_id != vrf_id))
-                                               continue;
-
-                                       bgp_bfd_peer_status_update(peer,
-                                                                  status,
-                                                                  remote_cbit);
-                               }
-                       }
-       }
-
-       return 0;
-}
-
-/*
- * bgp_bfd_peer_param_set - Set the configured BFD paramter values for peer.
- */
-static int bgp_bfd_peer_param_set(struct peer *peer, uint32_t min_rx,
-                                 uint32_t min_tx, uint8_t detect_mult,
-                                 int defaults)
-{
-       struct bfd_info *bi;
-       struct peer_group *group;
-       struct listnode *node, *nnode;
-       int command = 0;
-
-       bfd_set_param((struct bfd_info **)&(peer->bfd_info), min_rx, min_tx,
-                     detect_mult, NULL, defaults, &command);
-
-       /* This command overrides profile if it was previously applied. */
-       bi = peer->bfd_info;
-       bi->profile[0] = 0;
-
-       if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
-               group = peer->group;
-               for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
-                       command = 0;
-                       bfd_set_param((struct bfd_info **)&(peer->bfd_info),
-                                     min_rx, min_tx, detect_mult, NULL,
-                                     defaults, &command);
-
-                       /*
-                        * This command overrides profile if it was previously
-                        * applied.
-                        */
-                       bi = peer->bfd_info;
-                       bi->profile[0] = 0;
-
-                       if ((peer->status == Established)
-                           && (command == ZEBRA_BFD_DEST_REGISTER))
-                               bgp_bfd_register_peer(peer);
-                       else if (command == ZEBRA_BFD_DEST_UPDATE)
-                               bgp_bfd_update_peer(peer);
-               }
-       } else {
-               if ((peer->status == Established)
-                   && (command == ZEBRA_BFD_DEST_REGISTER))
-                       bgp_bfd_register_peer(peer);
-               else if (command == ZEBRA_BFD_DEST_UPDATE)
-                       bgp_bfd_update_peer(peer);
-       }
-       return 0;
-}
-
-/*
- * bgp_bfd_peer_param_unset - Delete the configured BFD paramter values for
- * peer.
- */
-static int bgp_bfd_peer_param_unset(struct peer *peer)
-{
-       struct peer_group *group;
-       struct listnode *node, *nnode;
-
-       if (!peer->bfd_info)
-               return 0;
-
-       if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
-               bfd_info_free(&(peer->bfd_info));
-               group = peer->group;
-               for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
-                       bgp_bfd_deregister_peer(peer);
-                       bfd_info_free(&(peer->bfd_info));
-               }
-       } else {
-               bgp_bfd_deregister_peer(peer);
-               bfd_info_free(&(peer->bfd_info));
+                       bgp_peer_remove_bfd(pn);
        }
-       return 0;
 }
 
-/*
- * bgp_bfd_peer_param_type_set - set the BFD session type (multihop or
- * singlehop)
- */
-static int bgp_bfd_peer_param_type_set(struct peer *peer,
-                                      enum bfd_sess_type type)
+void bgp_peer_remove_bfd_config(struct peer *p)
 {
-       struct peer_group *group;
-       struct listnode *node, *nnode;
-       int command = 0;
-       struct bfd_info *bfd_info;
-
-       if (!peer->bfd_info)
-               bfd_set_param((struct bfd_info **)&(peer->bfd_info),
-                             BFD_DEF_MIN_RX, BFD_DEF_MIN_TX,
-                             BFD_DEF_DETECT_MULT, NULL, 1, &command);
-
-       bfd_info = (struct bfd_info *)peer->bfd_info;
-       bfd_info->type = type;
-
-       if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
-               group = peer->group;
-               for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
-                       command = 0;
-                       if (!peer->bfd_info)
-                               bfd_set_param(
-                                       (struct bfd_info **)&(peer->bfd_info),
-                                       BFD_DEF_MIN_RX, BFD_DEF_MIN_TX,
-                                       BFD_DEF_DETECT_MULT, NULL, 1, &command);
-
-                       bfd_info = (struct bfd_info *)peer->bfd_info;
-                       bfd_info->type = type;
-
-                       if (peer->status == Established) {
-                               if (command == ZEBRA_BFD_DEST_REGISTER)
-                                       bgp_bfd_register_peer(peer);
-                               else
-                                       bgp_bfd_update_type(peer);
-                       }
-               }
-       } else {
-               if (peer->status == Established) {
-                       if (command == ZEBRA_BFD_DEST_REGISTER)
-                               bgp_bfd_register_peer(peer);
-                       else
-                               bgp_bfd_update_type(peer);
-               }
-       }
-
-       return 0;
-}
-
-#if HAVE_BFDD > 0
-/**
- * Set peer BFD profile configuration.
- */
-static int bgp_bfd_peer_set_profile(struct peer *peer, const char *profile)
-{
-       struct peer_group *group;
-       struct listnode *node, *nnode;
-       int command = 0;
-       struct bfd_info *bfd_info;
-
-       bfd_set_param((struct bfd_info **)&(peer->bfd_info), BFD_DEF_MIN_RX,
-                     BFD_DEF_MIN_TX, BFD_DEF_DETECT_MULT, NULL, 1, &command);
-
-       bfd_info = (struct bfd_info *)peer->bfd_info;
-
-       /* If profile was specified, then copy string. */
-       if (profile)
-               strlcpy(bfd_info->profile, profile, sizeof(bfd_info->profile));
-       else /* Otherwise just initialize it empty. */
-               bfd_info->profile[0] = 0;
-
-       if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
-               group = peer->group;
-               for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
-                       command = 0;
-                       bfd_set_param((struct bfd_info **)&(peer->bfd_info),
-                                     BFD_DEF_MIN_RX, BFD_DEF_MIN_TX,
-                                     BFD_DEF_DETECT_MULT, NULL, 1, &command);
-
-                       bfd_info = (struct bfd_info *)peer->bfd_info;
-
-                       /* If profile was specified, then copy string. */
-                       if (profile)
-                               strlcpy(bfd_info->profile, profile,
-                                       sizeof(bfd_info->profile));
-                       else /* Otherwise just initialize it empty. */
-                               bfd_info->profile[0] = 0;
-
-                       if (peer->status == Established
-                           && command == ZEBRA_BFD_DEST_REGISTER)
-                               bgp_bfd_register_peer(peer);
-                       else if (command == ZEBRA_BFD_DEST_UPDATE)
-                               bgp_bfd_update_peer(peer);
-               }
-       } else {
-               if (peer->status == Established
-                   && command == ZEBRA_BFD_DEST_REGISTER)
-                       bgp_bfd_register_peer(peer);
-               else if (command == ZEBRA_BFD_DEST_UPDATE)
-                       bgp_bfd_update_peer(peer);
-       }
-
-       return 0;
+       if (CHECK_FLAG(p->sflags, PEER_STATUS_GROUP))
+               bgp_group_remove_bfd(p);
+       else
+               bgp_peer_remove_bfd(p);
 }
-#endif
 
 /*
  * bgp_bfd_peer_config_write - Write the peer BFD configuration.
  */
-void bgp_bfd_peer_config_write(struct vty *vty, struct peer *peer, char *addr)
+void bgp_bfd_peer_config_write(struct vty *vty, const struct peer *peer,
+                              const char *addr)
 {
-       struct bfd_info *bfd_info;
-
-       if (!peer->bfd_info)
-               return;
-
-       bfd_info = (struct bfd_info *)peer->bfd_info;
-
-       if (CHECK_FLAG(bfd_info->flags, BFD_FLAG_PARAM_CFG))
+       /*
+        * Always show group BFD configuration, but peer only when explicitly
+        * configured.
+        */
+       if ((!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)
+            && peer->bfd_config->manual)
+           || CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
 #if HAVE_BFDD > 0
                vty_out(vty, " neighbor %s bfd\n", addr);
 #else
                vty_out(vty, " neighbor %s bfd %d %d %d\n", addr,
-                       bfd_info->detect_mult, bfd_info->required_min_rx,
-                       bfd_info->desired_min_tx);
+                       peer->bfd_config->detection_multiplier,
+                       peer->bfd_config->min_rx, peer->bfd_config->min_tx);
 #endif /* HAVE_BFDD */
-
-       if (bfd_info->type != BFD_TYPE_NOT_CONFIGURED)
-               vty_out(vty, " neighbor %s bfd %s\n", addr,
-                       (bfd_info->type == BFD_TYPE_MULTIHOP) ? "multihop"
-                                                             : "singlehop");
-
-       if (!CHECK_FLAG(bfd_info->flags, BFD_FLAG_PARAM_CFG)
-           && (bfd_info->type == BFD_TYPE_NOT_CONFIGURED)) {
-               vty_out(vty, " neighbor %s bfd", addr);
-               if (bfd_info->profile[0])
-                       vty_out(vty, " profile %s", bfd_info->profile);
-               vty_out(vty, "\n");
        }
 
-       if (CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CHECK_CONTROLPLANE))
-               vty_out(vty, " neighbor %s bfd check-control-plane-failure\n", addr);
+       if (peer->bfd_config->profile[0])
+               vty_out(vty, " neighbor %s bfd profile %s\n", addr,
+                       peer->bfd_config->profile);
+
+       if (peer->bfd_config->cbit)
+               vty_out(vty, " neighbor %s bfd check-control-plane-failure\n",
+                       addr);
 }
 
 /*
  * bgp_bfd_show_info - Show the peer BFD information.
  */
-void bgp_bfd_show_info(struct vty *vty, struct peer *peer, bool use_json,
+void bgp_bfd_show_info(struct vty *vty, const struct peer *peer,
                       json_object *json_neigh)
 {
-       bfd_show_info(vty, (struct bfd_info *)peer->bfd_info,
-                     bgp_bfd_is_peer_multihop(peer), 0, use_json, json_neigh);
+       if (peer->bfd_config->session)
+               bfd_sess_show(vty, json_neigh, peer->bfd_config->session);
 }
 
 DEFUN (neighbor_bfd,
@@ -712,16 +437,17 @@ DEFUN (neighbor_bfd,
 {
        int idx_peer = 1;
        struct peer *peer;
-       int ret;
 
        peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
        if (!peer)
                return CMD_WARNING_CONFIG_FAILED;
 
-       ret = bgp_bfd_peer_param_set(peer, BFD_DEF_MIN_RX, BFD_DEF_MIN_TX,
-                                    BFD_DEF_DETECT_MULT, 1);
-       if (ret != 0)
-               return bgp_vty_return(vty, ret);
+       if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
+               bgp_group_configure_bfd(peer);
+       else
+               bgp_peer_configure_bfd(peer, true);
+
+       bgp_peer_config_apply(peer, peer->group);
 
        return CMD_SUCCESS;
 }
@@ -745,89 +471,30 @@ DEFUN(
        int idx_number_1 = 3;
        int idx_number_2 = 4;
        int idx_number_3 = 5;
+       long detection_multiplier, min_rx, min_tx;
        struct peer *peer;
-       uint32_t rx_val;
-       uint32_t tx_val;
-       uint8_t dm_val;
-       int ret;
 
        peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
        if (!peer)
                return CMD_WARNING_CONFIG_FAILED;
 
-       if ((ret = bfd_validate_param(
-                    vty, argv[idx_number_1]->arg, argv[idx_number_2]->arg,
-                    argv[idx_number_3]->arg, &dm_val, &rx_val, &tx_val))
-           != CMD_SUCCESS)
-               return ret;
-
-       ret = bgp_bfd_peer_param_set(peer, rx_val, tx_val, dm_val, 0);
-       if (ret != 0)
-               return bgp_vty_return(vty, ret);
-
-       return CMD_SUCCESS;
-}
-
-DEFUN_HIDDEN (neighbor_bfd_type,
-       neighbor_bfd_type_cmd,
-       "neighbor <A.B.C.D|X:X::X:X|WORD> bfd <multihop|singlehop>",
-       NEIGHBOR_STR
-       NEIGHBOR_ADDR_STR2
-       "Enables BFD support\n"
-       "Multihop session\n"
-       "Single hop session\n")
-{
-       int idx_peer = 1;
-       int idx_hop = 3;
-       struct peer *peer;
-       enum bfd_sess_type type;
-       int ret;
-
-       peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
-       if (!peer)
-               return CMD_WARNING_CONFIG_FAILED;
+       detection_multiplier = strtol(argv[idx_number_1]->arg, NULL, 10);
+       min_rx = strtol(argv[idx_number_2]->arg, NULL, 10);
+       min_tx = strtol(argv[idx_number_3]->arg, NULL, 10);
 
-       if (strmatch(argv[idx_hop]->text, "singlehop"))
-               type = BFD_TYPE_SINGLEHOP;
-       else if (strmatch(argv[idx_hop]->text, "multihop"))
-               type = BFD_TYPE_MULTIHOP;
+       if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
+               bgp_group_configure_bfd(peer);
        else
-               return CMD_WARNING_CONFIG_FAILED;
-
-       ret = bgp_bfd_peer_param_type_set(peer, type);
-       if (ret != 0)
-               return bgp_vty_return(vty, ret);
+               bgp_peer_configure_bfd(peer, true);
 
-       return CMD_SUCCESS;
-}
-
-static int bgp_bfd_set_check_controlplane_failure_peer(struct vty *vty, struct peer *peer,
-                                                      const char *no)
-{
-       struct bfd_info *bfd_info;
+       peer->bfd_config->detection_multiplier = detection_multiplier;
+       peer->bfd_config->min_rx = min_rx;
+       peer->bfd_config->min_tx = min_tx;
+       bgp_peer_config_apply(peer, peer->group);
 
-       if (!peer->bfd_info) {
-               if (no)
-                       return CMD_SUCCESS;
-               vty_out(vty, "%% Specify bfd command first\n");
-               return CMD_WARNING_CONFIG_FAILED;
-       }
-       bfd_info = (struct bfd_info *)peer->bfd_info;
-       if (!no) {
-               if (!CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CHECK_CONTROLPLANE)) {
-                       SET_FLAG(bfd_info->flags,  BFD_FLAG_BFD_CHECK_CONTROLPLANE);
-                       bgp_bfd_update_peer(peer);
-               }
-       } else {
-               if (CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CHECK_CONTROLPLANE)) {
-                       UNSET_FLAG(bfd_info->flags,  BFD_FLAG_BFD_CHECK_CONTROLPLANE);
-                       bgp_bfd_update_peer(peer);
-               }
-       }
        return CMD_SUCCESS;
 }
 
-
 DEFUN (neighbor_bfd_check_controlplane_failure,
        neighbor_bfd_check_controlplane_failure_cmd,
        "[no] neighbor <A.B.C.D|X:X::X:X|WORD> bfd check-control-plane-failure",
@@ -840,9 +507,6 @@ DEFUN (neighbor_bfd_check_controlplane_failure,
        const char *no = strmatch(argv[0]->text, "no") ? "no" : NULL;
        int idx_peer = 0;
        struct peer *peer;
-       struct peer_group *group;
-       struct listnode *node, *nnode;
-       int ret = CMD_SUCCESS;
 
        if (no)
                idx_peer = 2;
@@ -853,19 +517,16 @@ DEFUN (neighbor_bfd_check_controlplane_failure,
                vty_out(vty, "%% Specify remote-as or peer-group commands first\n");
                return CMD_WARNING_CONFIG_FAILED;
        }
-       if (!peer->bfd_info) {
-               if (no)
-                       return CMD_SUCCESS;
-               vty_out(vty, "%% Specify bfd command first\n");
-               return CMD_WARNING_CONFIG_FAILED;
-       }
-       if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
-               group = peer->group;
-               for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer))
-                       ret = bgp_bfd_set_check_controlplane_failure_peer(vty, peer, no);
-       } else
-               ret = bgp_bfd_set_check_controlplane_failure_peer(vty, peer, no);
-       return ret;
+
+       if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
+               bgp_group_configure_bfd(peer);
+       else
+               bgp_peer_configure_bfd(peer, true);
+
+       peer->bfd_config->cbit = no == NULL;
+       bgp_peer_config_apply(peer, peer->group);
+
+       return CMD_SUCCESS;
  }
 
 DEFUN (no_neighbor_bfd,
@@ -888,44 +549,15 @@ DEFUN (no_neighbor_bfd,
 {
        int idx_peer = 2;
        struct peer *peer;
-       int ret;
 
        peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
        if (!peer)
                return CMD_WARNING_CONFIG_FAILED;
 
-       ret = bgp_bfd_peer_param_unset(peer);
-       if (ret != 0)
-               return bgp_vty_return(vty, ret);
-
-       return CMD_SUCCESS;
-}
-
-
-DEFUN_HIDDEN (no_neighbor_bfd_type,
-       no_neighbor_bfd_type_cmd,
-       "no neighbor <A.B.C.D|X:X::X:X|WORD> bfd <multihop|singlehop>",
-       NO_STR
-       NEIGHBOR_STR
-       NEIGHBOR_ADDR_STR2
-       "Disables BFD support\n"
-       "Multihop session\n"
-       "Singlehop session\n")
-{
-       int idx_peer = 2;
-       struct peer *peer;
-       int ret;
-
-       peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
-       if (!peer)
-               return CMD_WARNING_CONFIG_FAILED;
-
-       if (!peer->bfd_info)
-               return 0;
-
-       ret = bgp_bfd_peer_param_type_set(peer, BFD_TYPE_NOT_CONFIGURED);
-       if (ret != 0)
-               return bgp_vty_return(vty, ret);
+       if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
+               bgp_group_remove_bfd(peer);
+       else
+               bgp_peer_remove_bfd(peer);
 
        return CMD_SUCCESS;
 }
@@ -941,15 +573,19 @@ DEFUN(neighbor_bfd_profile, neighbor_bfd_profile_cmd,
 {
        int idx_peer = 1, idx_prof = 4;
        struct peer *peer;
-       int ret;
 
        peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
        if (!peer)
                return CMD_WARNING_CONFIG_FAILED;
 
-       ret = bgp_bfd_peer_set_profile(peer, argv[idx_prof]->arg);
-       if (ret != 0)
-               return bgp_vty_return(vty, ret);
+       if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
+               bgp_group_configure_bfd(peer);
+       else
+               bgp_peer_configure_bfd(peer, true);
+
+       strlcpy(peer->bfd_config->profile, argv[idx_prof]->arg,
+               sizeof(peer->bfd_config->profile));
+       bgp_peer_config_apply(peer, peer->group);
 
        return CMD_SUCCESS;
 }
@@ -965,38 +601,33 @@ DEFUN(no_neighbor_bfd_profile, no_neighbor_bfd_profile_cmd,
 {
        int idx_peer = 2;
        struct peer *peer;
-       int ret;
 
        peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
        if (!peer)
                return CMD_WARNING_CONFIG_FAILED;
 
-       if (!peer->bfd_info)
-               return 0;
+       if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
+               bgp_group_configure_bfd(peer);
+       else
+               bgp_peer_configure_bfd(peer, true);
 
-       ret = bgp_bfd_peer_set_profile(peer, NULL);
-       if (ret != 0)
-               return bgp_vty_return(vty, ret);
+       peer->bfd_config->profile[0] = 0;
+       bgp_peer_config_apply(peer, peer->group);
 
        return CMD_SUCCESS;
 }
 #endif /* HAVE_BFDD */
 
-void bgp_bfd_init(void)
+void bgp_bfd_init(struct thread_master *tm)
 {
-       bfd_gbl_init();
-
        /* Initialize BFD client functions */
-       zclient->interface_bfd_dest_update = bgp_bfd_dest_update;
-       zclient->bfd_dest_replay = bgp_bfd_dest_replay;
+       bfd_protocol_integration_init(zclient, tm);
 
        /* "neighbor bfd" commands. */
        install_element(BGP_NODE, &neighbor_bfd_cmd);
        install_element(BGP_NODE, &neighbor_bfd_param_cmd);
-       install_element(BGP_NODE, &neighbor_bfd_type_cmd);
        install_element(BGP_NODE, &neighbor_bfd_check_controlplane_failure_cmd);
        install_element(BGP_NODE, &no_neighbor_bfd_cmd);
-       install_element(BGP_NODE, &no_neighbor_bfd_type_cmd);
 
 #if HAVE_BFDD > 0
        install_element(BGP_NODE, &neighbor_bfd_profile_cmd);
index f2fa959b4587502fd0d52cb3bbd5b2e62bfb87d4..9dca48a437bb402f8ee6d6cb03176090d47d2492 100644 (file)
 #ifndef _QUAGGA_BGP_BFD_H
 #define _QUAGGA_BGP_BFD_H
 
-extern void bgp_bfd_init(void);
+#define PEER_IS_MULTIHOP(peer)                                                 \
+       ((((peer)->sort == BGP_PEER_IBGP) && !(peer)->shared_network)          \
+        || is_ebgp_multihop_configured((peer)))
 
-extern void bgp_bfd_peer_group2peer_copy(struct peer *conf, struct peer *peer);
+extern void bgp_bfd_init(struct thread_master *tm);
 
-extern void bgp_bfd_register_peer(struct peer *peer);
+extern void bgp_bfd_peer_config_write(struct vty *vty, const struct peer *peer,
+                                     const char *addr);
 
-extern void bgp_bfd_deregister_peer(struct peer *peer);
+/**
+ * Show BFD information helper.
+ *
+ * \param vty the VTY pointer.
+ * \param peer the BGP configuration pointer.
+ * \param use_json unused.
+ * \param json_neigh JSON object when called as JSON command.
+ */
+extern void bgp_bfd_show_info(struct vty *vty, const struct peer *peer,
+                             json_object *json_neigh);
 
-extern void bgp_bfd_reset_peer(struct peer *peer);
+/**
+ * When called on a group it applies configuration to all peers in that group,
+ * otherwise just applies the configuration to a single peer.
+ *
+ * This function should be called when configuration changes either on group
+ * or peer.
+ *
+ * \param p the BGP peer pointer.
+ * \param pg the BGP group to copy configuration from (it is usually
+ *           `p->group` exception when copying new group configuration
+ *           see `peer_group2peer_config_copy` function case).
+ */
+extern void bgp_peer_config_apply(struct peer *p, struct peer_group *pg);
 
-extern void bgp_bfd_peer_config_write(struct vty *vty, struct peer *peer,
-                                     char *addr);
+/**
+ * Allocates and configure BFD session for peer. If it is already configured,
+ * then it does nothing.
+ *
+ * Always call `bgp_peer_config_apply` afterwards if you need the changes
+ * immediately applied.
+ */
+extern void bgp_peer_configure_bfd(struct peer *p, bool manual);
 
-extern void bgp_bfd_show_info(struct vty *vty, struct peer *peer, bool use_json,
-                             json_object *json_neigh);
+/**
+ * Removes BFD configuration from either peer or peer group.
+ */
+extern void bgp_peer_remove_bfd_config(struct peer *p);
 
-extern bool bgp_bfd_is_peer_multihop(struct peer *peer);
+/**
+ * Special function to handle the case of changing source address. This
+ * happens when the peer/group is configured with `neigbor X update-source Y`.
+ */
+extern void bgp_peer_bfd_update_source(struct peer *p);
 
 #endif /* _QUAGGA_BGP_BFD_H */
index 4102d102e6275f6f65ca7e7732fa7bc52a3a45a1..0e5f506b3aef1b0dafb295ca2c34aa93df2b4469 100644 (file)
@@ -59,21 +59,21 @@ static struct bmp_bgp_peer *bmp_bgp_peer_get(struct peer *peer);
 static void bmp_active_disconnected(struct bmp_active *ba);
 static void bmp_active_put(struct bmp_active *ba);
 
-DEFINE_MGROUP(BMP, "BMP (BGP Monitoring Protocol)")
-
-DEFINE_MTYPE_STATIC(BMP, BMP_CONN,     "BMP connection state")
-DEFINE_MTYPE_STATIC(BMP, BMP_TARGETS,  "BMP targets")
-DEFINE_MTYPE_STATIC(BMP, BMP_TARGETSNAME, "BMP targets name")
-DEFINE_MTYPE_STATIC(BMP, BMP_LISTENER, "BMP listener")
-DEFINE_MTYPE_STATIC(BMP, BMP_ACTIVE,   "BMP active connection config")
-DEFINE_MTYPE_STATIC(BMP, BMP_ACLNAME,  "BMP access-list name")
-DEFINE_MTYPE_STATIC(BMP, BMP_QUEUE,    "BMP update queue item")
-DEFINE_MTYPE_STATIC(BMP, BMP,          "BMP instance state")
-DEFINE_MTYPE_STATIC(BMP, BMP_MIRRORQ,  "BMP route mirroring buffer")
-DEFINE_MTYPE_STATIC(BMP, BMP_PEER,     "BMP per BGP peer data")
-DEFINE_MTYPE_STATIC(BMP, BMP_OPEN,     "BMP stored BGP OPEN message")
-
-DEFINE_QOBJ_TYPE(bmp_targets)
+DEFINE_MGROUP(BMP, "BMP (BGP Monitoring Protocol)");
+
+DEFINE_MTYPE_STATIC(BMP, BMP_CONN,     "BMP connection state");
+DEFINE_MTYPE_STATIC(BMP, BMP_TARGETS,  "BMP targets");
+DEFINE_MTYPE_STATIC(BMP, BMP_TARGETSNAME, "BMP targets name");
+DEFINE_MTYPE_STATIC(BMP, BMP_LISTENER, "BMP listener");
+DEFINE_MTYPE_STATIC(BMP, BMP_ACTIVE,   "BMP active connection config");
+DEFINE_MTYPE_STATIC(BMP, BMP_ACLNAME,  "BMP access-list name");
+DEFINE_MTYPE_STATIC(BMP, BMP_QUEUE,    "BMP update queue item");
+DEFINE_MTYPE_STATIC(BMP, BMP,          "BMP instance state");
+DEFINE_MTYPE_STATIC(BMP, BMP_MIRRORQ,  "BMP route mirroring buffer");
+DEFINE_MTYPE_STATIC(BMP, BMP_PEER,     "BMP per BGP peer data");
+DEFINE_MTYPE_STATIC(BMP, BMP_OPEN,     "BMP stored BGP OPEN message");
+
+DEFINE_QOBJ_TYPE(bmp_targets);
 
 static int bmp_bgp_cmp(const struct bmp_bgp *a, const struct bmp_bgp *b)
 {
@@ -89,7 +89,7 @@ static uint32_t bmp_bgp_hash(const struct bmp_bgp *e)
        return jhash(&e->bgp, sizeof(e->bgp), 0x55aa5a5a);
 }
 
-DECLARE_HASH(bmp_bgph, struct bmp_bgp, bbi, bmp_bgp_cmp, bmp_bgp_hash)
+DECLARE_HASH(bmp_bgph, struct bmp_bgp, bbi, bmp_bgp_cmp, bmp_bgp_hash);
 
 struct bmp_bgph_head bmp_bgph;
 
@@ -109,11 +109,11 @@ static uint32_t bmp_bgp_peer_hash(const struct bmp_bgp_peer *e)
 }
 
 DECLARE_HASH(bmp_peerh, struct bmp_bgp_peer, bpi,
-               bmp_bgp_peer_cmp, bmp_bgp_peer_hash)
+               bmp_bgp_peer_cmp, bmp_bgp_peer_hash);
 
 struct bmp_peerh_head bmp_peerh;
 
-DECLARE_LIST(bmp_mirrorq, struct bmp_mirrorq, bmi)
+DECLARE_LIST(bmp_mirrorq, struct bmp_mirrorq, bmi);
 
 /* listener management */
 
@@ -132,7 +132,8 @@ static int bmp_listener_cmp(const struct bmp_listener *a,
        return 0;
 }
 
-DECLARE_SORTLIST_UNIQ(bmp_listeners, struct bmp_listener, bli, bmp_listener_cmp)
+DECLARE_SORTLIST_UNIQ(bmp_listeners, struct bmp_listener, bli,
+                     bmp_listener_cmp);
 
 static int bmp_targets_cmp(const struct bmp_targets *a,
                           const struct bmp_targets *b)
@@ -140,11 +141,11 @@ static int bmp_targets_cmp(const struct bmp_targets *a,
        return strcmp(a->name, b->name);
 }
 
-DECLARE_SORTLIST_UNIQ(bmp_targets, struct bmp_targets, bti, bmp_targets_cmp)
+DECLARE_SORTLIST_UNIQ(bmp_targets, struct bmp_targets, bti, bmp_targets_cmp);
 
-DECLARE_LIST(bmp_session, struct bmp, bsi)
+DECLARE_LIST(bmp_session, struct bmp, bsi);
 
-DECLARE_DLIST(bmp_qlist, struct bmp_queue_entry, bli)
+DECLARE_DLIST(bmp_qlist, struct bmp_queue_entry, bli);
 
 static int bmp_qhash_cmp(const struct bmp_queue_entry *a,
                const struct bmp_queue_entry *b)
@@ -189,7 +190,7 @@ static uint32_t bmp_qhash_hkey(const struct bmp_queue_entry *e)
 }
 
 DECLARE_HASH(bmp_qhash, struct bmp_queue_entry, bhi,
-               bmp_qhash_cmp, bmp_qhash_hkey)
+               bmp_qhash_cmp, bmp_qhash_hkey);
 
 static int bmp_active_cmp(const struct bmp_active *a,
                const struct bmp_active *b)
@@ -206,7 +207,7 @@ static int bmp_active_cmp(const struct bmp_active *a,
        return 0;
 }
 
-DECLARE_SORTLIST_UNIQ(bmp_actives, struct bmp_active, bai, bmp_active_cmp)
+DECLARE_SORTLIST_UNIQ(bmp_actives, struct bmp_active, bai, bmp_active_cmp);
 
 static struct bmp *bmp_new(struct bmp_targets *bt, int bmp_sock)
 {
@@ -2443,4 +2444,5 @@ static int bgp_bmp_module_init(void)
 
 FRR_MODULE_SETUP(.name = "bgpd_bmp", .version = FRR_VERSION,
                 .description = "bgpd BMP module",
-                .init = bgp_bmp_module_init)
+                .init = bgp_bmp_module_init,
+);
index 2c3ba570ee24f30132930bab63e5b9d7ddc0ff6b..899840e582de2e1cd2158ec24bf563a01049956d 100644 (file)
@@ -66,8 +66,8 @@
  * always happens from the front of the queue.)
  */
 
-PREDECL_DLIST(bmp_qlist)
-PREDECL_HASH(bmp_qhash)
+PREDECL_DLIST(bmp_qlist);
+PREDECL_HASH(bmp_qhash);
 
 struct bmp_queue_entry {
        struct bmp_qlist_item bli;
@@ -92,7 +92,7 @@ struct bmp_queue_entry {
  * with a size limit.  Refcount works the same as for monitoring above.
  */
 
-PREDECL_LIST(bmp_mirrorq)
+PREDECL_LIST(bmp_mirrorq);
 
 struct bmp_mirrorq {
        struct bmp_mirrorq_item bmi;
@@ -112,7 +112,7 @@ enum {
        BMP_AFI_LIVE,
 };
 
-PREDECL_LIST(bmp_session)
+PREDECL_LIST(bmp_session);
 
 struct bmp_active;
 struct bmp_targets;
@@ -166,7 +166,7 @@ struct bmp {
  * succeeds, "bmp" is set up.
  */
 
-PREDECL_SORTLIST_UNIQ(bmp_actives)
+PREDECL_SORTLIST_UNIQ(bmp_actives);
 
 #define BMP_DFLT_MINRETRY      30000
 #define BMP_DFLT_MAXRETRY      720000
@@ -191,7 +191,7 @@ struct bmp_active {
 };
 
 /* config & state for passive / listening sockets */
-PREDECL_SORTLIST_UNIQ(bmp_listeners)
+PREDECL_SORTLIST_UNIQ(bmp_listeners);
 
 struct bmp_listener {
        struct bmp_listeners_item bli;
@@ -209,7 +209,7 @@ struct bmp_listener {
  * bmp_active items.  If they have the same config, BMP session should be
  * put in the same targets since that's a bit more effective.
  */
-PREDECL_SORTLIST_UNIQ(bmp_targets)
+PREDECL_SORTLIST_UNIQ(bmp_targets);
 
 struct bmp_targets {
        struct bmp_targets_item bti;
@@ -245,13 +245,13 @@ struct bmp_targets {
 
        uint64_t cnt_accept, cnt_aclrefused;
 
-       QOBJ_FIELDS
+       QOBJ_FIELDS;
 };
-DECLARE_QOBJ_TYPE(bmp_targets)
+DECLARE_QOBJ_TYPE(bmp_targets);
 
 /* per struct peer * data.  Lookup by peer->qobj_node.nid, created on demand,
  * deleted in peer_backward hook. */
-PREDECL_HASH(bmp_peerh)
+PREDECL_HASH(bmp_peerh);
 
 struct bmp_bgp_peer {
        struct bmp_peerh_item bpi;
@@ -267,7 +267,7 @@ struct bmp_bgp_peer {
 };
 
 /* per struct bgp * data */
-PREDECL_HASH(bmp_bgph)
+PREDECL_HASH(bmp_bgph);
 
 #define BMP_PEER_DOWN_NO_RELEVANT_EVENT_CODE 0x00
 
@@ -309,6 +309,6 @@ enum {
        BMP_STATS_FRR_NH_INVALID        = 65531,
 };
 
-DECLARE_MGROUP(BMP)
+DECLARE_MGROUP(BMP);
 
 #endif /*_BGP_BMP_H_*/
index 3afa6eaf09ee7a6bad0174bb243baf614531d579..ce1b7b552b598754cdb5fdaaa9796a6672aadb6c 100644 (file)
@@ -21,6 +21,7 @@
 #include <zebra.h>
 
 #include <lib/version.h>
+#include "lib/bfd.h"
 #include "lib/printfrr.h"
 #include "prefix.h"
 #include "linklist.h"
@@ -67,6 +68,7 @@ unsigned long conf_bgp_debug_labelpool;
 unsigned long conf_bgp_debug_pbr;
 unsigned long conf_bgp_debug_graceful_restart;
 unsigned long conf_bgp_debug_evpn_mh;
+unsigned long conf_bgp_debug_bfd;
 
 unsigned long term_bgp_debug_as4;
 unsigned long term_bgp_debug_neighbor_events;
@@ -86,6 +88,7 @@ unsigned long term_bgp_debug_labelpool;
 unsigned long term_bgp_debug_pbr;
 unsigned long term_bgp_debug_graceful_restart;
 unsigned long term_bgp_debug_evpn_mh;
+unsigned long term_bgp_debug_bfd;
 
 struct list *bgp_debug_neighbor_events_peers = NULL;
 struct list *bgp_debug_keepalive_peers = NULL;
@@ -2093,6 +2096,31 @@ DEFUN (no_debug_bgp_labelpool,
        return CMD_SUCCESS;
 }
 
+DEFPY(debug_bgp_bfd, debug_bgp_bfd_cmd,
+      "[no] debug bgp bfd",
+      NO_STR
+      DEBUG_STR
+      BGP_STR
+      "Bidirection Forwarding Detection\n")
+{
+       if (vty->node == CONFIG_NODE) {
+               if (no) {
+                       DEBUG_OFF(bfd, BFD_LIB);
+                       bfd_protocol_integration_set_debug(false);
+               } else {
+                       DEBUG_ON(bfd, BFD_LIB);
+                       bfd_protocol_integration_set_debug(true);
+               }
+       } else {
+               if (no)
+                       TERM_DEBUG_OFF(bfd, BFD_LIB);
+               else
+                       TERM_DEBUG_ON(bfd, BFD_LIB);
+       }
+
+       return CMD_SUCCESS;
+}
+
 DEFUN (no_debug_bgp,
        no_debug_bgp_cmd,
        "no debug bgp",
@@ -2136,6 +2164,7 @@ DEFUN (no_debug_bgp,
        TERM_DEBUG_OFF(graceful_restart, GRACEFUL_RESTART);
        TERM_DEBUG_OFF(evpn_mh, EVPN_MH_ES);
        TERM_DEBUG_OFF(evpn_mh, EVPN_MH_RT);
+       TERM_DEBUG_OFF(bfd, BFD_LIB);
 
        vty_out(vty, "All possible debugging has been turned off\n");
 
@@ -2225,6 +2254,9 @@ DEFUN_NOSH (show_debugging_bgp,
        if (BGP_DEBUG(evpn_mh, EVPN_MH_RT))
                vty_out(vty, "  BGP EVPN-MH route debugging is on\n");
 
+       if (BGP_DEBUG(bfd, BFD_LIB))
+               vty_out(vty, "  BGP BFD library debugging is on\n");
+
        vty_out(vty, "\n");
        return CMD_SUCCESS;
 }
@@ -2350,6 +2382,11 @@ static int bgp_config_write_debug(struct vty *vty)
                write++;
        }
 
+       if (CONF_BGP_DEBUG(bfd, BFD_LIB)) {
+               vty_out(vty, "debug bgp bfd\n");
+               write++;
+       }
+
        return write;
 }
 
@@ -2478,6 +2515,10 @@ void bgp_debug_init(void)
 
        install_element(ENABLE_NODE, &debug_bgp_evpn_mh_cmd);
        install_element(CONFIG_NODE, &debug_bgp_evpn_mh_cmd);
+
+       /* debug bgp bfd */
+       install_element(ENABLE_NODE, &debug_bgp_bfd_cmd);
+       install_element(CONFIG_NODE, &debug_bgp_bfd_cmd);
 }
 
 /* Return true if this prefix is on the per_prefix_list of prefixes to debug
index f16cfee4f228e75bed53048b643b53094a97809b..fa8da1c345b66cf367482da920865ccd938fc89d 100644 (file)
@@ -78,6 +78,7 @@ extern unsigned long conf_bgp_debug_labelpool;
 extern unsigned long conf_bgp_debug_pbr;
 extern unsigned long conf_bgp_debug_graceful_restart;
 extern unsigned long conf_bgp_debug_evpn_mh;
+extern unsigned long conf_bgp_debug_bfd;
 
 extern unsigned long term_bgp_debug_as4;
 extern unsigned long term_bgp_debug_neighbor_events;
@@ -95,6 +96,7 @@ extern unsigned long term_bgp_debug_labelpool;
 extern unsigned long term_bgp_debug_pbr;
 extern unsigned long term_bgp_debug_graceful_restart;
 extern unsigned long term_bgp_debug_evpn_mh;
+extern unsigned long term_bgp_debug_bfd;
 
 extern struct list *bgp_debug_neighbor_events_peers;
 extern struct list *bgp_debug_keepalive_peers;
@@ -139,6 +141,8 @@ struct bgp_debug_filter {
 
 #define BGP_DEBUG_GRACEFUL_RESTART     0x01
 
+#define BGP_DEBUG_BFD_LIB             0x01
+
 #define CONF_DEBUG_ON(a, b)    (conf_bgp_debug_ ## a |= (BGP_DEBUG_ ## b))
 #define CONF_DEBUG_OFF(a, b)   (conf_bgp_debug_ ## a &= ~(BGP_DEBUG_ ## b))
 
index 7b29f1e4c9281ca21fc0335a4b2169acb43180eb..cebc1c4d22ac94dceb2958ed78a059e0b097a391 100644 (file)
@@ -57,8 +57,8 @@
 /*
  * Definitions and external declarations.
  */
-DEFINE_QOBJ_TYPE(bgpevpn)
-DEFINE_QOBJ_TYPE(bgp_evpn_es)
+DEFINE_QOBJ_TYPE(bgpevpn);
+DEFINE_QOBJ_TYPE(bgp_evpn_es);
 
 
 /*
@@ -2235,6 +2235,8 @@ int update_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn)
        int ret;
        struct prefix_evpn p;
 
+       update_type1_routes_for_evi(bgp, vpn);
+
        /* Update and advertise the type-3 route (only one) followed by the
         * locally learnt type-2 routes (MACIP) - for this VNI.
         *
@@ -3136,7 +3138,7 @@ static int uninstall_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn)
                return ret;
 
        ret = install_uninstall_routes_for_vni(bgp, vpn, BGP_EVPN_AD_ROUTE,
-                                              1);
+                                              0);
        if (ret)
                return ret;
 
index 175514f6395e8d672f735cc1ddd333b990a29c25..826de21b9db966b90342e37c8497f9b09697bf8d 100644 (file)
@@ -970,6 +970,48 @@ static int bgp_evpn_type1_route_update(struct bgp *bgp,
        return 0;
 }
 
+/*
+ * This function is called when the export RT for a VNI changes.
+ * Update all type-1 local routes for this VNI from VNI/ES tables and the global
+ * table and advertise these routes to peers.
+ */
+
+void update_type1_routes_for_evi(struct bgp *bgp, struct bgpevpn *vpn)
+{
+       struct prefix_evpn p;
+       struct bgp_evpn_es *es;
+       struct bgp_evpn_es_evi *es_evi;
+       struct bgp_evpn_es_evi *es_evi_next;
+
+       RB_FOREACH_SAFE(es_evi, bgp_es_evi_rb_head,
+                       &vpn->es_evi_rb_tree, es_evi_next) {
+               es = es_evi->es;
+
+               /* Update EAD-ES */
+               if (CHECK_FLAG(es->flags, BGP_EVPNES_OPER_UP)) {
+                       build_evpn_type1_prefix(&p, BGP_EVPN_AD_ES_ETH_TAG,
+                                               &es->esi, es->originator_ip);
+                       if (bgp_evpn_type1_route_update(bgp, es, NULL, &p))
+                               flog_err(EC_BGP_EVPN_ROUTE_CREATE,
+                                       "%u: EAD-ES route update failure for ESI %s VNI %u",
+                                       bgp->vrf_id, es->esi_str,
+                                       es_evi->vpn->vni);
+               }
+
+               /* Update EAD-EVI */
+               if (CHECK_FLAG(es->flags, BGP_EVPNES_ADV_EVI)) {
+                       build_evpn_type1_prefix(&p, BGP_EVPN_AD_EVI_ETH_TAG,
+                                               &es->esi, es->originator_ip);
+                       if (bgp_evpn_type1_route_update(bgp, es, es_evi->vpn,
+                                                       &p))
+                               flog_err(EC_BGP_EVPN_ROUTE_DELETE,
+                                       "%u: EAD-EVI route update failure for ESI %s VNI %u",
+                                       bgp->vrf_id, es->esi_str,
+                                       es_evi->vpn->vni);
+               }
+       }
+}
+
 /* Delete local Type-1 route */
 static int bgp_evpn_type1_es_route_delete(struct bgp *bgp,
                struct bgp_evpn_es *es, struct prefix_evpn *p)
@@ -3847,3 +3889,39 @@ void bgp_evpn_mh_finish(void)
 
        XFREE(MTYPE_BGP_EVPN_MH_INFO, bgp_mh_info);
 }
+
+/* This function is called when disable-ead-evi-rx knob flaps */
+void bgp_evpn_switch_ead_evi_rx(void)
+{
+       struct bgp *bgp;
+       struct bgp_evpn_es *es;
+       struct bgp_evpn_es_evi *es_evi;
+       struct listnode *evi_node = NULL;
+       struct listnode *evi_next = NULL;
+       struct bgp_evpn_es_evi_vtep *vtep;
+       struct listnode *vtep_node = NULL;
+       struct listnode *vtep_next = NULL;
+
+       bgp = bgp_get_evpn();
+       if (!bgp)
+               return;
+
+       /*
+        * Process all the remote es_evi_vteps and reevaluate if the es_evi_vtep
+        * is active.
+        */
+       RB_FOREACH(es, bgp_es_rb_head, &bgp_mh_info->es_rb_tree) {
+               if (!CHECK_FLAG(es->flags, BGP_EVPNES_REMOTE))
+                       continue;
+
+               for (ALL_LIST_ELEMENTS(es->es_evi_list, evi_node, evi_next,
+                                      es_evi)) {
+                       if (!CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_REMOTE))
+                               continue;
+
+                       for (ALL_LIST_ELEMENTS(es_evi->es_evi_vtep_list,
+                                              vtep_node, vtep_next, vtep))
+                               bgp_evpn_es_evi_vtep_re_eval_active(bgp, vtep);
+               }
+       }
+}
index 818fad2eb6f9fbefe070b689ab6c189102f4b8c4..8c66e391b689aeef5a087fc323db7f3c53867e6c 100644 (file)
@@ -125,9 +125,9 @@ struct bgp_evpn_es {
        /* preference config for BUM-DF election. advertised via the ESR. */
        uint16_t df_pref;
 
-       QOBJ_FIELDS
+       QOBJ_FIELDS;
 };
-DECLARE_QOBJ_TYPE(bgp_evpn_es)
+DECLARE_QOBJ_TYPE(bgp_evpn_es);
 RB_HEAD(bgp_es_rb_head, bgp_evpn_es);
 RB_PROTOTYPE(bgp_es_rb_head, bgp_evpn_es, rb_node, bgp_es_rb_cmp);
 
@@ -335,6 +335,7 @@ extern int bgp_evpn_es_route_install_uninstall(struct bgp *bgp,
                struct bgp_evpn_es *es, afi_t afi, safi_t safi,
                struct prefix_evpn *evp, struct bgp_path_info *pi,
                int install);
+extern void update_type1_routes_for_evi(struct bgp *bgp, struct bgpevpn *vpn);
 int bgp_evpn_type1_route_process(struct peer *peer, afi_t afi, safi_t safi,
                struct attr *attr, uint8_t *pfx, int psize,
                uint32_t addpath_id);
@@ -376,5 +377,6 @@ extern bool bgp_evpn_path_es_use_nhg(struct bgp *bgp_vrf,
 extern void bgp_evpn_es_vrf_show(struct vty *vty, bool uj,
                                 struct bgp_evpn_es *es);
 extern void bgp_evpn_es_vrf_show_esi(struct vty *vty, esi_t *esi, bool uj);
+extern void bgp_evpn_switch_ead_evi_rx(void);
 
 #endif /* _FRR_BGP_EVPN_MH_H */
index 77b37463447b034a15ccd54556d522dfc1509528..ff4970af41a5c57621cdfe6292327f04bf945034 100644 (file)
@@ -112,10 +112,10 @@ struct bgpevpn {
        /* List of local ESs */
        struct list *local_es_evi_list;
 
-       QOBJ_FIELDS
+       QOBJ_FIELDS;
 };
 
-DECLARE_QOBJ_TYPE(bgpevpn)
+DECLARE_QOBJ_TYPE(bgpevpn);
 
 /* Mapping of Import RT to VNIs.
  * The Import RTs of all VNIs are maintained in a hash table with each
index 73bce5df9ad41ecf82c2e6e9ff5d4926f4b4533e..b101589a79a32f9e609ba4257760731b54efe9e5 100644 (file)
@@ -3767,7 +3767,12 @@ DEFPY (bgp_evpn_ead_evi_rx_disable,
        NO_STR
        "Activate PE on EAD-ES even if EAD-EVI is not received\n")
 {
-       bgp_mh_info->ead_evi_rx = no? true :false;
+       bool ead_evi_rx = no? true :false;
+
+       if (ead_evi_rx != bgp_mh_info->ead_evi_rx) {
+               bgp_mh_info->ead_evi_rx = ead_evi_rx;
+               bgp_evpn_switch_ead_evi_rx();
+       }
        return CMD_SUCCESS;
 }
 
index 3162579688db9e64ff9ac49aa17cfff065454839..5d1a7a98d7c9853963450e8c6944e21dfc7e3424 100644 (file)
@@ -62,6 +62,9 @@ struct as_filter {
 
        regex_t *reg;
        char *reg_str;
+
+       /* Sequence number. */
+       int64_t seq;
 };
 
 /* AS path filter list. */
@@ -77,6 +80,38 @@ struct as_list {
        struct as_filter *tail;
 };
 
+
+/* Calculate new sequential number. */
+static int64_t bgp_alist_new_seq_get(struct as_list *list)
+{
+       int64_t maxseq;
+       int64_t newseq;
+       struct as_filter *entry;
+
+       maxseq = 0;
+
+       for (entry = list->head; entry; entry = entry->next) {
+               if (maxseq < entry->seq)
+                       maxseq = entry->seq;
+       }
+
+       newseq = ((maxseq / 5) * 5) + 5;
+
+       return (newseq > UINT_MAX) ? UINT_MAX : newseq;
+}
+
+/* Return as-list entry which has same seq number. */
+static struct as_filter *bgp_aslist_seq_check(struct as_list *list, int64_t seq)
+{
+       struct as_filter *entry;
+
+       for (entry = list->head; entry; entry = entry->next)
+               if (entry->seq == seq)
+                       return entry;
+
+       return NULL;
+}
+
 /* as-path access-list 10 permit AS1. */
 
 static struct as_list_master as_list_master = {{NULL, NULL},
@@ -125,17 +160,69 @@ static struct as_filter *as_filter_lookup(struct as_list *aslist,
        return NULL;
 }
 
+static void as_filter_entry_replace(struct as_list *list,
+                                   struct as_filter *replace,
+                                   struct as_filter *entry)
+{
+       if (replace->next) {
+               entry->next = replace->next;
+               replace->next->prev = entry;
+       } else {
+               entry->next = NULL;
+               list->tail = entry;
+       }
+
+       if (replace->prev) {
+               entry->prev = replace->prev;
+               replace->prev->next = entry;
+       } else {
+               entry->prev = NULL;
+               list->head = entry;
+       }
+
+       as_filter_free(replace);
+}
+
 static void as_list_filter_add(struct as_list *aslist,
                               struct as_filter *asfilter)
 {
-       asfilter->next = NULL;
-       asfilter->prev = aslist->tail;
+       struct as_filter *point;
+       struct as_filter *replace;
 
-       if (aslist->tail)
-               aslist->tail->next = asfilter;
-       else
-               aslist->head = asfilter;
-       aslist->tail = asfilter;
+       if (aslist->tail && asfilter->seq > aslist->tail->seq)
+               point = NULL;
+       else {
+               replace = bgp_aslist_seq_check(aslist, asfilter->seq);
+               if (replace) {
+                       as_filter_entry_replace(aslist, replace, asfilter);
+                       return;
+               }
+
+               /* Check insert point. */
+               for (point = aslist->head; point; point = point->next)
+                       if (point->seq >= asfilter->seq)
+                               break;
+       }
+
+       asfilter->next = point;
+
+       if (point) {
+               if (point->prev)
+                       point->prev->next = asfilter;
+               else
+                       aslist->head = asfilter;
+
+               asfilter->prev = point->prev;
+               point->prev = asfilter;
+       } else {
+               if (aslist->tail)
+                       aslist->tail->next = asfilter;
+               else
+                       aslist->head = asfilter;
+
+               asfilter->prev = aslist->tail;
+               aslist->tail = asfilter;
+       }
 
        /* Run hook function. */
        if (as_list_master.add_hook)
@@ -391,11 +478,13 @@ bool config_bgp_aspath_validate(const char *regstr)
 }
 
 DEFUN(as_path, bgp_as_path_cmd,
-      "bgp as-path access-list WORD <deny|permit> LINE...",
+      "bgp as-path access-list WORD [seq (0-4294967295)] <deny|permit> LINE...",
       BGP_STR
       "BGP autonomous system path filter\n"
       "Specify an access list name\n"
       "Regular expression access list name\n"
+      "Sequence number of an entry\n"
+      "Sequence number\n"
       "Specify packets to reject\n"
       "Specify packets to forward\n"
       "A regular-expression (1234567890_^|[,{}() ]$*+.?-\\) to match the BGP AS paths\n")
@@ -406,11 +495,15 @@ DEFUN(as_path, bgp_as_path_cmd,
        struct as_list *aslist;
        regex_t *regex;
        char *regstr;
+       int64_t seqnum = ASPATH_SEQ_NUMBER_AUTO;
 
        /* Retrieve access list name */
        argv_find(argv, argc, "WORD", &idx);
        char *alname = argv[idx]->arg;
 
+       if (argv_find(argv, argc, "(0-4294967295)", &idx))
+               seqnum = (int64_t)atol(argv[idx]->arg);
+
        /* Check the filter type. */
        type = argv_find(argv, argc, "deny", &idx) ? AS_FILTER_DENY
                                                   : AS_FILTER_PERMIT;
@@ -439,6 +532,11 @@ DEFUN(as_path, bgp_as_path_cmd,
        /* Install new filter to the access_list. */
        aslist = as_list_get(alname);
 
+       if (seqnum == ASPATH_SEQ_NUMBER_AUTO)
+               seqnum = bgp_alist_new_seq_get(aslist);
+
+       asfilter->seq = seqnum;
+
        /* Duplicate insertion check. */;
        if (as_list_dup_check(aslist, asfilter))
                as_filter_free(asfilter);
@@ -449,12 +547,14 @@ DEFUN(as_path, bgp_as_path_cmd,
 }
 
 DEFUN(no_as_path, no_bgp_as_path_cmd,
-      "no bgp as-path access-list WORD <deny|permit> LINE...",
+      "no bgp as-path access-list WORD [seq (0-4294967295)] <deny|permit> LINE...",
       NO_STR
       BGP_STR
       "BGP autonomous system path filter\n"
       "Specify an access list name\n"
       "Regular expression access list name\n"
+      "Sequence number of an entry\n"
+      "Sequence number\n"
       "Specify packets to reject\n"
       "Specify packets to forward\n"
       "A regular-expression (1234567890_^|[,{}() ]$*+.?-\\) to match the BGP AS paths\n")
@@ -643,8 +743,11 @@ static int config_write_as_list(struct vty *vty)
        for (aslist = as_list_master.num.head; aslist; aslist = aslist->next)
                for (asfilter = aslist->head; asfilter;
                     asfilter = asfilter->next) {
-                       vty_out(vty, "bgp as-path access-list %s %s %s\n",
-                               aslist->name, filter_type_str(asfilter->type),
+                       vty_out(vty,
+                               "bgp as-path access-list %s seq %" PRId64
+                               " %s %s\n",
+                               aslist->name, asfilter->seq,
+                               filter_type_str(asfilter->type),
                                asfilter->reg_str);
                        write++;
                }
@@ -652,8 +755,11 @@ static int config_write_as_list(struct vty *vty)
        for (aslist = as_list_master.str.head; aslist; aslist = aslist->next)
                for (asfilter = aslist->head; asfilter;
                     asfilter = asfilter->next) {
-                       vty_out(vty, "bgp as-path access-list %s %s %s\n",
-                               aslist->name, filter_type_str(asfilter->type),
+                       vty_out(vty,
+                               "bgp as-path access-list %s seq %" PRId64
+                               " %s %s\n",
+                               aslist->name, asfilter->seq,
+                               filter_type_str(asfilter->type),
                                asfilter->reg_str);
                        write++;
                }
index 9357a2d3820f954a5dc2223401e1b5e4f448a274..66c83d97e9e26da8276ea62d79a996afccee1bee 100644 (file)
@@ -21,6 +21,8 @@
 #ifndef _QUAGGA_BGP_FILTER_H
 #define _QUAGGA_BGP_FILTER_H
 
+#define ASPATH_SEQ_NUMBER_AUTO -1
+
 enum as_filter_type { AS_FILTER_DENY, AS_FILTER_PERMIT };
 
 extern void bgp_filter_init(void);
index 757d76f69e0da0a480cfe97f941ab915c0f3e915..45a856a4591fc5f0f7a834fe88acd7eaf7a73c2b 100644 (file)
@@ -57,8 +57,8 @@
 #include "bgpd/bgp_zebra.h"
 #include "bgpd/bgp_vty.h"
 
-DEFINE_HOOK(peer_backward_transition, (struct peer * peer), (peer))
-DEFINE_HOOK(peer_status_changed, (struct peer * peer), (peer))
+DEFINE_HOOK(peer_backward_transition, (struct peer * peer), (peer));
+DEFINE_HOOK(peer_status_changed, (struct peer * peer), (peer));
 
 /* Definition of display strings corresponding to FSM events. This should be
  * kept consistent with the events defined in bgpd.h
@@ -343,8 +343,8 @@ static struct peer *peer_xfer_conn(struct peer *from_peer)
 
        bgp_reads_on(peer);
        bgp_writes_on(peer);
-       thread_add_timer_msec(bm->master, bgp_process_packet, peer, 0,
-                             &peer->t_process_packet);
+       thread_add_event(bm->master, bgp_process_packet, peer, 0,
+                        &peer->t_process_packet);
 
        return (peer);
 }
@@ -1215,8 +1215,9 @@ int bgp_stop(struct peer *peer)
        peer->nsf_af_count = 0;
 
        /* deregister peer */
-       if (peer->last_reset == PEER_DOWN_UPDATE_SOURCE_CHANGE)
-               bgp_bfd_deregister_peer(peer);
+       if (peer->bfd_config
+           && peer->last_reset == PEER_DOWN_UPDATE_SOURCE_CHANGE)
+               bfd_sess_uninstall(peer->bfd_config->session);
 
        if (peer_dynamic_neighbor(peer)
            && !(CHECK_FLAG(peer->flags, PEER_FLAG_DELETE))) {
@@ -2122,7 +2123,10 @@ static int bgp_establish(struct peer *peer)
        hash_release(peer->bgp->peerhash, peer);
        hash_get(peer->bgp->peerhash, peer, hash_alloc_intern);
 
-       bgp_bfd_reset_peer(peer);
+       /* Start BFD peer if not already running. */
+       if (peer->bfd_config)
+               bgp_peer_bfd_update_source(peer);
+
        return ret;
 }
 
index bf4966c839760e20c5ba91755b11294595d9acf9..bcf697e153fb4275d3d777d4c4c54c6b820fc555 100644 (file)
@@ -155,8 +155,8 @@ extern void bgp_start_routeadv(struct bgp *);
 extern void bgp_adjust_routeadv(struct peer *);
 
 #include "hook.h"
-DECLARE_HOOK(peer_backward_transition, (struct peer *peer), (peer))
-DECLARE_HOOK(peer_established, (struct peer *peer), (peer))
+DECLARE_HOOK(peer_backward_transition, (struct peer *peer), (peer));
+DECLARE_HOOK(peer_established, (struct peer *peer), (peer));
 
 int bgp_gr_update_all(struct bgp *bgp, int global_gr_cmd);
 int bgp_neighbor_graceful_restart(struct peer *peer, int peer_gr_cmd);
index 7aa489e9324129777d6bf92b2fab86b5628ea617..a696d956977aba5b4fc05bd52c5af5d9e88d668f 100644 (file)
@@ -268,8 +268,8 @@ static int bgp_process_reads(struct thread *thread)
                thread_add_read(fpt->master, bgp_process_reads, peer, peer->fd,
                                &peer->t_read);
                if (added_pkt)
-                       thread_add_timer_msec(bm->master, bgp_process_packet,
-                                             peer, 0, &peer->t_process_packet);
+                       thread_add_event(bm->master, bgp_process_packet,
+                                        peer, 0, &peer->t_process_packet);
        }
 
        return 0;
index 001340be3506b8b06ffbeb9ca18977bb023bdfb1..fcb2df9d6f8f071b9d8ea71cf9ec797b5c95e33a 100644 (file)
@@ -50,10 +50,10 @@ static struct labelpool *lp;
 /* request this many labels at a time from zebra */
 #define LP_CHUNK_SIZE  50
 
-DEFINE_MTYPE_STATIC(BGPD, BGP_LABEL_CHUNK, "BGP Label Chunk")
-DEFINE_MTYPE_STATIC(BGPD, BGP_LABEL_FIFO, "BGP Label FIFO item")
-DEFINE_MTYPE_STATIC(BGPD, BGP_LABEL_CB, "BGP Dynamic Label Assignment")
-DEFINE_MTYPE_STATIC(BGPD, BGP_LABEL_CBQ, "BGP Dynamic Label Callback")
+DEFINE_MTYPE_STATIC(BGPD, BGP_LABEL_CHUNK, "BGP Label Chunk");
+DEFINE_MTYPE_STATIC(BGPD, BGP_LABEL_FIFO, "BGP Label FIFO item");
+DEFINE_MTYPE_STATIC(BGPD, BGP_LABEL_CB, "BGP Dynamic Label Assignment");
+DEFINE_MTYPE_STATIC(BGPD, BGP_LABEL_CBQ, "BGP Dynamic Label Callback");
 
 struct lp_chunk {
        uint32_t        first;
@@ -80,7 +80,7 @@ struct lp_fifo {
        struct lp_lcb   lcb;
 };
 
-DECLARE_LIST(lp_fifo, struct lp_fifo, fifo)
+DECLARE_LIST(lp_fifo, struct lp_fifo, fifo);
 
 struct lp_cbq_item {
        int             (*cbfunc)(mpls_label_t label, void *lblid, bool alloc);
index d9f64acfe40002f25d4e87492c151cf83f8c8ce0..d6a8eec84d8d364b548c1552d38edf1600da5a4f 100644 (file)
@@ -31,7 +31,7 @@
 #define LP_TYPE_VRF    0x00000001
 #define LP_TYPE_BGP_LU 0x00000002
 
-PREDECL_LIST(lp_fifo)
+PREDECL_LIST(lp_fifo);
 
 struct labelpool {
        struct skiplist         *ledger;        /* all requests */
index 3cb3d06217a3884288688b6f175532c16d4639ed..2ddafd9a0c2dafca41900eb2986cb208f61d4a7d 100644 (file)
@@ -162,6 +162,9 @@ __attribute__((__noreturn__)) void sigint(void)
        assert(bm->terminating == false);
        bm->terminating = true; /* global flag that shutting down */
 
+       /* Disable BFD events to avoid wasting processing. */
+       bfd_protocol_integration_set_shutdown(true);
+
        bgp_terminate();
 
        bgp_exit(0);
@@ -394,7 +397,8 @@ FRR_DAEMON_INFO(bgpd, BGP, .vty_port = BGP_VTY_PORT,
                .signals = bgp_signals, .n_signals = array_size(bgp_signals),
 
                .privs = &bgpd_privs, .yang_modules = bgpd_yang_modules,
-               .n_yang_modules = array_size(bgpd_yang_modules), )
+               .n_yang_modules = array_size(bgpd_yang_modules),
+);
 
 #define DEPRECATED_OPTIONS ""
 
index 0013eb2df2a575239799c407513e8f956d3f1bd2..9a4eb5d3bdc0f9448150f7c00c2834d0b9fbd479 100644 (file)
 /* this file is temporary in nature;  definitions should be moved to the
  * files they're used in */
 
-DEFINE_MGROUP(BGPD, "bgpd")
-DEFINE_MTYPE(BGPD, BGP, "BGP instance")
-DEFINE_MTYPE(BGPD, BGP_LISTENER, "BGP listen socket details")
-DEFINE_MTYPE(BGPD, BGP_PEER, "BGP peer")
-DEFINE_MTYPE(BGPD, BGP_PEER_HOST, "BGP peer hostname")
-DEFINE_MTYPE(BGPD, BGP_PEER_IFNAME, "BGP peer ifname")
-DEFINE_MTYPE(BGPD, PEER_GROUP, "Peer group")
-DEFINE_MTYPE(BGPD, PEER_GROUP_HOST, "BGP Peer group hostname")
-DEFINE_MTYPE(BGPD, PEER_DESC, "Peer description")
-DEFINE_MTYPE(BGPD, PEER_PASSWORD, "Peer password string")
-DEFINE_MTYPE(BGPD, BGP_PEER_AF, "BGP peer af")
-DEFINE_MTYPE(BGPD, BGP_UPDGRP, "BGP update group")
-DEFINE_MTYPE(BGPD, BGP_UPD_SUBGRP, "BGP update subgroup")
-DEFINE_MTYPE(BGPD, BGP_PACKET, "BGP packet")
-DEFINE_MTYPE(BGPD, ATTR, "BGP attribute")
-DEFINE_MTYPE(BGPD, AS_PATH, "BGP aspath")
-DEFINE_MTYPE(BGPD, AS_SEG, "BGP aspath seg")
-DEFINE_MTYPE(BGPD, AS_SEG_DATA, "BGP aspath segment data")
-DEFINE_MTYPE(BGPD, AS_STR, "BGP aspath str")
-
-DEFINE_MTYPE(BGPD, BGP_TABLE, "BGP table")
-DEFINE_MTYPE(BGPD, BGP_NODE, "BGP node")
-DEFINE_MTYPE(BGPD, BGP_ROUTE, "BGP route")
-DEFINE_MTYPE(BGPD, BGP_ROUTE_EXTRA, "BGP ancillary route info")
-DEFINE_MTYPE(BGPD, BGP_CONN, "BGP connected")
-DEFINE_MTYPE(BGPD, BGP_STATIC, "BGP static")
-DEFINE_MTYPE(BGPD, BGP_ADVERTISE_ATTR, "BGP adv attr")
-DEFINE_MTYPE(BGPD, BGP_ADVERTISE, "BGP adv")
-DEFINE_MTYPE(BGPD, BGP_SYNCHRONISE, "BGP synchronise")
-DEFINE_MTYPE(BGPD, BGP_ADJ_IN, "BGP adj in")
-DEFINE_MTYPE(BGPD, BGP_ADJ_OUT, "BGP adj out")
-DEFINE_MTYPE(BGPD, BGP_MPATH_INFO, "BGP multipath info")
-
-DEFINE_MTYPE(BGPD, AS_LIST, "BGP AS list")
-DEFINE_MTYPE(BGPD, AS_FILTER, "BGP AS filter")
-DEFINE_MTYPE(BGPD, AS_FILTER_STR, "BGP AS filter str")
-
-DEFINE_MTYPE(BGPD, COMMUNITY, "community")
-DEFINE_MTYPE(BGPD, COMMUNITY_VAL, "community val")
-DEFINE_MTYPE(BGPD, COMMUNITY_STR, "community str")
-
-DEFINE_MTYPE(BGPD, ECOMMUNITY, "extcommunity")
-DEFINE_MTYPE(BGPD, ECOMMUNITY_VAL, "extcommunity val")
-DEFINE_MTYPE(BGPD, ECOMMUNITY_STR, "extcommunity str")
-
-DEFINE_MTYPE(BGPD, COMMUNITY_LIST, "community-list")
-DEFINE_MTYPE(BGPD, COMMUNITY_LIST_NAME, "community-list name")
-DEFINE_MTYPE(BGPD, COMMUNITY_LIST_ENTRY, "community-list entry")
-DEFINE_MTYPE(BGPD, COMMUNITY_LIST_CONFIG, "community-list config")
-DEFINE_MTYPE(BGPD, COMMUNITY_LIST_HANDLER, "community-list handler")
-
-DEFINE_MTYPE(BGPD, CLUSTER, "Cluster list")
-DEFINE_MTYPE(BGPD, CLUSTER_VAL, "Cluster list val")
-
-DEFINE_MTYPE(BGPD, BGP_PROCESS_QUEUE, "BGP Process queue")
-DEFINE_MTYPE(BGPD, BGP_CLEAR_NODE_QUEUE, "BGP node clear queue")
-
-DEFINE_MTYPE(BGPD, TRANSIT, "BGP transit attr")
-DEFINE_MTYPE(BGPD, TRANSIT_VAL, "BGP transit val")
-
-DEFINE_MTYPE(BGPD, BGP_DEBUG_FILTER, "BGP debug filter")
-DEFINE_MTYPE(BGPD, BGP_DEBUG_STR, "BGP debug filter string")
-
-DEFINE_MTYPE(BGPD, BGP_DISTANCE, "BGP distance")
-DEFINE_MTYPE(BGPD, BGP_NEXTHOP_CACHE, "BGP nexthop")
-DEFINE_MTYPE(BGPD, BGP_CONFED_LIST, "BGP confed list")
-DEFINE_MTYPE(BGPD, PEER_UPDATE_SOURCE, "BGP peer update interface")
-DEFINE_MTYPE(BGPD, PEER_CONF_IF, "BGP peer config interface")
-DEFINE_MTYPE(BGPD, BGP_DAMP_INFO, "Dampening info")
-DEFINE_MTYPE(BGPD, BGP_DAMP_ARRAY, "BGP Dampening array")
-DEFINE_MTYPE(BGPD, BGP_DAMP_REUSELIST, "BGP Dampening reuse list")
-DEFINE_MTYPE(BGPD, BGP_REGEXP, "BGP regexp")
-DEFINE_MTYPE(BGPD, BGP_AGGREGATE, "BGP aggregate")
-DEFINE_MTYPE(BGPD, BGP_ADDR, "BGP own address")
-DEFINE_MTYPE(BGPD, TIP_ADDR, "BGP own tunnel-ip address")
-
-DEFINE_MTYPE(BGPD, BGP_REDIST, "BGP redistribution")
-DEFINE_MTYPE(BGPD, BGP_FILTER_NAME, "BGP Filter Information")
-DEFINE_MTYPE(BGPD, BGP_DUMP_STR, "BGP Dump String Information")
-DEFINE_MTYPE(BGPD, ENCAP_TLV, "ENCAP TLV")
-
-DEFINE_MTYPE(BGPD, BGP_TEA_OPTIONS, "BGP TEA Options")
-DEFINE_MTYPE(BGPD, BGP_TEA_OPTIONS_VALUE, "BGP TEA Options Value")
-
-DEFINE_MTYPE(BGPD, LCOMMUNITY, "Large Community")
-DEFINE_MTYPE(BGPD, LCOMMUNITY_STR, "Large Community display string")
-DEFINE_MTYPE(BGPD, LCOMMUNITY_VAL, "Large Community value")
-
-DEFINE_MTYPE(BGPD, BGP_EVPN, "BGP EVPN Information")
-DEFINE_MTYPE(BGPD, BGP_EVPN_MH_INFO, "BGP EVPN MH Information")
-DEFINE_MTYPE(BGPD, BGP_EVPN_ES_VTEP, "BGP EVPN ES VTEP")
-DEFINE_MTYPE(BGPD, BGP_EVPN_PATH_ES_INFO, "BGP EVPN PATH ES Information")
-DEFINE_MTYPE(BGPD, BGP_EVPN_ES_EVI_VTEP, "BGP EVPN ES-EVI VTEP")
-DEFINE_MTYPE(BGPD, BGP_EVPN_ES, "BGP EVPN ESI Information")
-DEFINE_MTYPE(BGPD, BGP_EVPN_ES_EVI, "BGP EVPN ES-per-EVI Information")
-DEFINE_MTYPE(BGPD, BGP_EVPN_ES_VRF, "BGP EVPN ES-per-VRF Information")
-DEFINE_MTYPE(BGPD, BGP_EVPN_IMPORT_RT, "BGP EVPN Import RT")
-DEFINE_MTYPE(BGPD, BGP_EVPN_VRF_IMPORT_RT, "BGP EVPN VRF Import RT")
-DEFINE_MTYPE(BGPD, BGP_EVPN_MACIP, "BGP EVPN MAC IP")
-
-DEFINE_MTYPE(BGPD, BGP_FLOWSPEC, "BGP flowspec")
-DEFINE_MTYPE(BGPD, BGP_FLOWSPEC_RULE, "BGP flowspec rule")
-DEFINE_MTYPE(BGPD, BGP_FLOWSPEC_RULE_STR, "BGP flowspec rule str")
-DEFINE_MTYPE(BGPD, BGP_FLOWSPEC_COMPILED, "BGP flowspec compiled")
-DEFINE_MTYPE(BGPD, BGP_FLOWSPEC_NAME, "BGP flowspec name")
-DEFINE_MTYPE(BGPD, BGP_FLOWSPEC_INDEX, "BGP flowspec index")
-
-DEFINE_MTYPE(BGPD, BGP_SRV6_L3VPN, "BGP prefix-sid srv6 l3vpn servcie")
-DEFINE_MTYPE(BGPD, BGP_SRV6_VPN, "BGP prefix-sid srv6 vpn service")
+DEFINE_MGROUP(BGPD, "bgpd");
+DEFINE_MTYPE(BGPD, BGP, "BGP instance");
+DEFINE_MTYPE(BGPD, BGP_LISTENER, "BGP listen socket details");
+DEFINE_MTYPE(BGPD, BGP_PEER, "BGP peer");
+DEFINE_MTYPE(BGPD, BGP_PEER_HOST, "BGP peer hostname");
+DEFINE_MTYPE(BGPD, BGP_PEER_IFNAME, "BGP peer ifname");
+DEFINE_MTYPE(BGPD, PEER_GROUP, "Peer group");
+DEFINE_MTYPE(BGPD, PEER_GROUP_HOST, "BGP Peer group hostname");
+DEFINE_MTYPE(BGPD, PEER_DESC, "Peer description");
+DEFINE_MTYPE(BGPD, PEER_PASSWORD, "Peer password string");
+DEFINE_MTYPE(BGPD, BGP_PEER_AF, "BGP peer af");
+DEFINE_MTYPE(BGPD, BGP_UPDGRP, "BGP update group");
+DEFINE_MTYPE(BGPD, BGP_UPD_SUBGRP, "BGP update subgroup");
+DEFINE_MTYPE(BGPD, BGP_PACKET, "BGP packet");
+DEFINE_MTYPE(BGPD, ATTR, "BGP attribute");
+DEFINE_MTYPE(BGPD, AS_PATH, "BGP aspath");
+DEFINE_MTYPE(BGPD, AS_SEG, "BGP aspath seg");
+DEFINE_MTYPE(BGPD, AS_SEG_DATA, "BGP aspath segment data");
+DEFINE_MTYPE(BGPD, AS_STR, "BGP aspath str");
+
+DEFINE_MTYPE(BGPD, BGP_TABLE, "BGP table");
+DEFINE_MTYPE(BGPD, BGP_NODE, "BGP node");
+DEFINE_MTYPE(BGPD, BGP_ROUTE, "BGP route");
+DEFINE_MTYPE(BGPD, BGP_ROUTE_EXTRA, "BGP ancillary route info");
+DEFINE_MTYPE(BGPD, BGP_CONN, "BGP connected");
+DEFINE_MTYPE(BGPD, BGP_STATIC, "BGP static");
+DEFINE_MTYPE(BGPD, BGP_ADVERTISE_ATTR, "BGP adv attr");
+DEFINE_MTYPE(BGPD, BGP_ADVERTISE, "BGP adv");
+DEFINE_MTYPE(BGPD, BGP_SYNCHRONISE, "BGP synchronise");
+DEFINE_MTYPE(BGPD, BGP_ADJ_IN, "BGP adj in");
+DEFINE_MTYPE(BGPD, BGP_ADJ_OUT, "BGP adj out");
+DEFINE_MTYPE(BGPD, BGP_MPATH_INFO, "BGP multipath info");
+
+DEFINE_MTYPE(BGPD, AS_LIST, "BGP AS list");
+DEFINE_MTYPE(BGPD, AS_FILTER, "BGP AS filter");
+DEFINE_MTYPE(BGPD, AS_FILTER_STR, "BGP AS filter str");
+
+DEFINE_MTYPE(BGPD, COMMUNITY, "community");
+DEFINE_MTYPE(BGPD, COMMUNITY_VAL, "community val");
+DEFINE_MTYPE(BGPD, COMMUNITY_STR, "community str");
+
+DEFINE_MTYPE(BGPD, ECOMMUNITY, "extcommunity");
+DEFINE_MTYPE(BGPD, ECOMMUNITY_VAL, "extcommunity val");
+DEFINE_MTYPE(BGPD, ECOMMUNITY_STR, "extcommunity str");
+
+DEFINE_MTYPE(BGPD, COMMUNITY_LIST, "community-list");
+DEFINE_MTYPE(BGPD, COMMUNITY_LIST_NAME, "community-list name");
+DEFINE_MTYPE(BGPD, COMMUNITY_LIST_ENTRY, "community-list entry");
+DEFINE_MTYPE(BGPD, COMMUNITY_LIST_CONFIG, "community-list config");
+DEFINE_MTYPE(BGPD, COMMUNITY_LIST_HANDLER, "community-list handler");
+
+DEFINE_MTYPE(BGPD, CLUSTER, "Cluster list");
+DEFINE_MTYPE(BGPD, CLUSTER_VAL, "Cluster list val");
+
+DEFINE_MTYPE(BGPD, BGP_PROCESS_QUEUE, "BGP Process queue");
+DEFINE_MTYPE(BGPD, BGP_CLEAR_NODE_QUEUE, "BGP node clear queue");
+
+DEFINE_MTYPE(BGPD, TRANSIT, "BGP transit attr");
+DEFINE_MTYPE(BGPD, TRANSIT_VAL, "BGP transit val");
+
+DEFINE_MTYPE(BGPD, BGP_DEBUG_FILTER, "BGP debug filter");
+DEFINE_MTYPE(BGPD, BGP_DEBUG_STR, "BGP debug filter string");
+
+DEFINE_MTYPE(BGPD, BGP_DISTANCE, "BGP distance");
+DEFINE_MTYPE(BGPD, BGP_NEXTHOP_CACHE, "BGP nexthop");
+DEFINE_MTYPE(BGPD, BGP_CONFED_LIST, "BGP confed list");
+DEFINE_MTYPE(BGPD, PEER_UPDATE_SOURCE, "BGP peer update interface");
+DEFINE_MTYPE(BGPD, PEER_CONF_IF, "BGP peer config interface");
+DEFINE_MTYPE(BGPD, BGP_DAMP_INFO, "Dampening info");
+DEFINE_MTYPE(BGPD, BGP_DAMP_ARRAY, "BGP Dampening array");
+DEFINE_MTYPE(BGPD, BGP_DAMP_REUSELIST, "BGP Dampening reuse list");
+DEFINE_MTYPE(BGPD, BGP_REGEXP, "BGP regexp");
+DEFINE_MTYPE(BGPD, BGP_AGGREGATE, "BGP aggregate");
+DEFINE_MTYPE(BGPD, BGP_ADDR, "BGP own address");
+DEFINE_MTYPE(BGPD, TIP_ADDR, "BGP own tunnel-ip address");
+
+DEFINE_MTYPE(BGPD, BGP_REDIST, "BGP redistribution");
+DEFINE_MTYPE(BGPD, BGP_FILTER_NAME, "BGP Filter Information");
+DEFINE_MTYPE(BGPD, BGP_DUMP_STR, "BGP Dump String Information");
+DEFINE_MTYPE(BGPD, ENCAP_TLV, "ENCAP TLV");
+
+DEFINE_MTYPE(BGPD, BGP_TEA_OPTIONS, "BGP TEA Options");
+DEFINE_MTYPE(BGPD, BGP_TEA_OPTIONS_VALUE, "BGP TEA Options Value");
+
+DEFINE_MTYPE(BGPD, LCOMMUNITY, "Large Community");
+DEFINE_MTYPE(BGPD, LCOMMUNITY_STR, "Large Community display string");
+DEFINE_MTYPE(BGPD, LCOMMUNITY_VAL, "Large Community value");
+
+DEFINE_MTYPE(BGPD, BGP_EVPN, "BGP EVPN Information");
+DEFINE_MTYPE(BGPD, BGP_EVPN_MH_INFO, "BGP EVPN MH Information");
+DEFINE_MTYPE(BGPD, BGP_EVPN_ES_VTEP, "BGP EVPN ES VTEP");
+DEFINE_MTYPE(BGPD, BGP_EVPN_PATH_ES_INFO, "BGP EVPN PATH ES Information");
+DEFINE_MTYPE(BGPD, BGP_EVPN_ES_EVI_VTEP, "BGP EVPN ES-EVI VTEP");
+DEFINE_MTYPE(BGPD, BGP_EVPN_ES, "BGP EVPN ESI Information");
+DEFINE_MTYPE(BGPD, BGP_EVPN_ES_EVI, "BGP EVPN ES-per-EVI Information");
+DEFINE_MTYPE(BGPD, BGP_EVPN_ES_VRF, "BGP EVPN ES-per-VRF Information");
+DEFINE_MTYPE(BGPD, BGP_EVPN_IMPORT_RT, "BGP EVPN Import RT");
+DEFINE_MTYPE(BGPD, BGP_EVPN_VRF_IMPORT_RT, "BGP EVPN VRF Import RT");
+DEFINE_MTYPE(BGPD, BGP_EVPN_MACIP, "BGP EVPN MAC IP");
+
+DEFINE_MTYPE(BGPD, BGP_FLOWSPEC, "BGP flowspec");
+DEFINE_MTYPE(BGPD, BGP_FLOWSPEC_RULE, "BGP flowspec rule");
+DEFINE_MTYPE(BGPD, BGP_FLOWSPEC_RULE_STR, "BGP flowspec rule str");
+DEFINE_MTYPE(BGPD, BGP_FLOWSPEC_COMPILED, "BGP flowspec compiled");
+DEFINE_MTYPE(BGPD, BGP_FLOWSPEC_NAME, "BGP flowspec name");
+DEFINE_MTYPE(BGPD, BGP_FLOWSPEC_INDEX, "BGP flowspec index");
+
+DEFINE_MTYPE(BGPD, BGP_SRV6_L3VPN, "BGP prefix-sid srv6 l3vpn servcie");
+DEFINE_MTYPE(BGPD, BGP_SRV6_VPN, "BGP prefix-sid srv6 vpn service");
index 63998e95acb5e7d469154d45ba139b750063874f..7b839f1d4cc0d69c65c01f2458793afbf7c47c14 100644 (file)
 
 #include "memory.h"
 
-DECLARE_MGROUP(BGPD)
-DECLARE_MTYPE(BGP)
-DECLARE_MTYPE(BGP_LISTENER)
-DECLARE_MTYPE(BGP_PEER)
-DECLARE_MTYPE(BGP_PEER_HOST)
-DECLARE_MTYPE(BGP_PEER_IFNAME)
-DECLARE_MTYPE(PEER_GROUP)
-DECLARE_MTYPE(PEER_GROUP_HOST)
-DECLARE_MTYPE(PEER_DESC)
-DECLARE_MTYPE(PEER_PASSWORD)
-DECLARE_MTYPE(BGP_PEER_AF)
-DECLARE_MTYPE(BGP_UPDGRP)
-DECLARE_MTYPE(BGP_UPD_SUBGRP)
-DECLARE_MTYPE(BGP_PACKET)
-DECLARE_MTYPE(ATTR)
-DECLARE_MTYPE(AS_PATH)
-DECLARE_MTYPE(AS_SEG)
-DECLARE_MTYPE(AS_SEG_DATA)
-DECLARE_MTYPE(AS_STR)
-
-DECLARE_MTYPE(BGP_TABLE)
-DECLARE_MTYPE(BGP_NODE)
-DECLARE_MTYPE(BGP_ROUTE)
-DECLARE_MTYPE(BGP_ROUTE_EXTRA)
-DECLARE_MTYPE(BGP_CONN)
-DECLARE_MTYPE(BGP_STATIC)
-DECLARE_MTYPE(BGP_ADVERTISE_ATTR)
-DECLARE_MTYPE(BGP_ADVERTISE)
-DECLARE_MTYPE(BGP_SYNCHRONISE)
-DECLARE_MTYPE(BGP_ADJ_IN)
-DECLARE_MTYPE(BGP_ADJ_OUT)
-DECLARE_MTYPE(BGP_MPATH_INFO)
-
-DECLARE_MTYPE(AS_LIST)
-DECLARE_MTYPE(AS_FILTER)
-DECLARE_MTYPE(AS_FILTER_STR)
-
-DECLARE_MTYPE(COMMUNITY)
-DECLARE_MTYPE(COMMUNITY_VAL)
-DECLARE_MTYPE(COMMUNITY_STR)
-
-DECLARE_MTYPE(ECOMMUNITY)
-DECLARE_MTYPE(ECOMMUNITY_VAL)
-DECLARE_MTYPE(ECOMMUNITY_STR)
-
-DECLARE_MTYPE(COMMUNITY_LIST)
-DECLARE_MTYPE(COMMUNITY_LIST_NAME)
-DECLARE_MTYPE(COMMUNITY_LIST_ENTRY)
-DECLARE_MTYPE(COMMUNITY_LIST_CONFIG)
-DECLARE_MTYPE(COMMUNITY_LIST_HANDLER)
-
-DECLARE_MTYPE(CLUSTER)
-DECLARE_MTYPE(CLUSTER_VAL)
-
-DECLARE_MTYPE(BGP_PROCESS_QUEUE)
-DECLARE_MTYPE(BGP_CLEAR_NODE_QUEUE)
-
-DECLARE_MTYPE(TRANSIT)
-DECLARE_MTYPE(TRANSIT_VAL)
-
-DECLARE_MTYPE(BGP_DEBUG_FILTER)
-DECLARE_MTYPE(BGP_DEBUG_STR)
-
-DECLARE_MTYPE(BGP_DISTANCE)
-DECLARE_MTYPE(BGP_NEXTHOP_CACHE)
-DECLARE_MTYPE(BGP_CONFED_LIST)
-DECLARE_MTYPE(PEER_UPDATE_SOURCE)
-DECLARE_MTYPE(PEER_CONF_IF)
-DECLARE_MTYPE(BGP_DAMP_INFO)
-DECLARE_MTYPE(BGP_DAMP_ARRAY)
-DECLARE_MTYPE(BGP_DAMP_REUSELIST)
-DECLARE_MTYPE(BGP_REGEXP)
-DECLARE_MTYPE(BGP_AGGREGATE)
-DECLARE_MTYPE(BGP_ADDR)
-DECLARE_MTYPE(TIP_ADDR)
-
-DECLARE_MTYPE(BGP_REDIST)
-DECLARE_MTYPE(BGP_FILTER_NAME)
-DECLARE_MTYPE(BGP_DUMP_STR)
-DECLARE_MTYPE(ENCAP_TLV)
-
-DECLARE_MTYPE(BGP_TEA_OPTIONS)
-DECLARE_MTYPE(BGP_TEA_OPTIONS_VALUE)
-
-DECLARE_MTYPE(LCOMMUNITY)
-DECLARE_MTYPE(LCOMMUNITY_STR)
-DECLARE_MTYPE(LCOMMUNITY_VAL)
-
-DECLARE_MTYPE(BGP_EVPN_MH_INFO)
-DECLARE_MTYPE(BGP_EVPN_ES)
-DECLARE_MTYPE(BGP_EVPN_ES_EVI)
-DECLARE_MTYPE(BGP_EVPN_ES_VRF)
-DECLARE_MTYPE(BGP_EVPN_ES_VTEP)
-DECLARE_MTYPE(BGP_EVPN_PATH_ES_INFO)
-DECLARE_MTYPE(BGP_EVPN_ES_EVI_VTEP)
-
-DECLARE_MTYPE(BGP_EVPN)
-DECLARE_MTYPE(BGP_EVPN_IMPORT_RT)
-DECLARE_MTYPE(BGP_EVPN_VRF_IMPORT_RT)
-DECLARE_MTYPE(BGP_EVPN_MACIP)
-
-DECLARE_MTYPE(BGP_FLOWSPEC)
-DECLARE_MTYPE(BGP_FLOWSPEC_RULE)
-DECLARE_MTYPE(BGP_FLOWSPEC_RULE_STR)
-DECLARE_MTYPE(BGP_FLOWSPEC_COMPILED)
-DECLARE_MTYPE(BGP_FLOWSPEC_NAME)
-DECLARE_MTYPE(BGP_FLOWSPEC_INDEX)
-
-DECLARE_MTYPE(BGP_SRV6_L3VPN)
-DECLARE_MTYPE(BGP_SRV6_VPN)
+DECLARE_MGROUP(BGPD);
+DECLARE_MTYPE(BGP);
+DECLARE_MTYPE(BGP_LISTENER);
+DECLARE_MTYPE(BGP_PEER);
+DECLARE_MTYPE(BGP_PEER_HOST);
+DECLARE_MTYPE(BGP_PEER_IFNAME);
+DECLARE_MTYPE(PEER_GROUP);
+DECLARE_MTYPE(PEER_GROUP_HOST);
+DECLARE_MTYPE(PEER_DESC);
+DECLARE_MTYPE(PEER_PASSWORD);
+DECLARE_MTYPE(BGP_PEER_AF);
+DECLARE_MTYPE(BGP_UPDGRP);
+DECLARE_MTYPE(BGP_UPD_SUBGRP);
+DECLARE_MTYPE(BGP_PACKET);
+DECLARE_MTYPE(ATTR);
+DECLARE_MTYPE(AS_PATH);
+DECLARE_MTYPE(AS_SEG);
+DECLARE_MTYPE(AS_SEG_DATA);
+DECLARE_MTYPE(AS_STR);
+
+DECLARE_MTYPE(BGP_TABLE);
+DECLARE_MTYPE(BGP_NODE);
+DECLARE_MTYPE(BGP_ROUTE);
+DECLARE_MTYPE(BGP_ROUTE_EXTRA);
+DECLARE_MTYPE(BGP_CONN);
+DECLARE_MTYPE(BGP_STATIC);
+DECLARE_MTYPE(BGP_ADVERTISE_ATTR);
+DECLARE_MTYPE(BGP_ADVERTISE);
+DECLARE_MTYPE(BGP_SYNCHRONISE);
+DECLARE_MTYPE(BGP_ADJ_IN);
+DECLARE_MTYPE(BGP_ADJ_OUT);
+DECLARE_MTYPE(BGP_MPATH_INFO);
+
+DECLARE_MTYPE(AS_LIST);
+DECLARE_MTYPE(AS_FILTER);
+DECLARE_MTYPE(AS_FILTER_STR);
+
+DECLARE_MTYPE(COMMUNITY);
+DECLARE_MTYPE(COMMUNITY_VAL);
+DECLARE_MTYPE(COMMUNITY_STR);
+
+DECLARE_MTYPE(ECOMMUNITY);
+DECLARE_MTYPE(ECOMMUNITY_VAL);
+DECLARE_MTYPE(ECOMMUNITY_STR);
+
+DECLARE_MTYPE(COMMUNITY_LIST);
+DECLARE_MTYPE(COMMUNITY_LIST_NAME);
+DECLARE_MTYPE(COMMUNITY_LIST_ENTRY);
+DECLARE_MTYPE(COMMUNITY_LIST_CONFIG);
+DECLARE_MTYPE(COMMUNITY_LIST_HANDLER);
+
+DECLARE_MTYPE(CLUSTER);
+DECLARE_MTYPE(CLUSTER_VAL);
+
+DECLARE_MTYPE(BGP_PROCESS_QUEUE);
+DECLARE_MTYPE(BGP_CLEAR_NODE_QUEUE);
+
+DECLARE_MTYPE(TRANSIT);
+DECLARE_MTYPE(TRANSIT_VAL);
+
+DECLARE_MTYPE(BGP_DEBUG_FILTER);
+DECLARE_MTYPE(BGP_DEBUG_STR);
+
+DECLARE_MTYPE(BGP_DISTANCE);
+DECLARE_MTYPE(BGP_NEXTHOP_CACHE);
+DECLARE_MTYPE(BGP_CONFED_LIST);
+DECLARE_MTYPE(PEER_UPDATE_SOURCE);
+DECLARE_MTYPE(PEER_CONF_IF);
+DECLARE_MTYPE(BGP_DAMP_INFO);
+DECLARE_MTYPE(BGP_DAMP_ARRAY);
+DECLARE_MTYPE(BGP_DAMP_REUSELIST);
+DECLARE_MTYPE(BGP_REGEXP);
+DECLARE_MTYPE(BGP_AGGREGATE);
+DECLARE_MTYPE(BGP_ADDR);
+DECLARE_MTYPE(TIP_ADDR);
+
+DECLARE_MTYPE(BGP_REDIST);
+DECLARE_MTYPE(BGP_FILTER_NAME);
+DECLARE_MTYPE(BGP_DUMP_STR);
+DECLARE_MTYPE(ENCAP_TLV);
+
+DECLARE_MTYPE(BGP_TEA_OPTIONS);
+DECLARE_MTYPE(BGP_TEA_OPTIONS_VALUE);
+
+DECLARE_MTYPE(LCOMMUNITY);
+DECLARE_MTYPE(LCOMMUNITY_STR);
+DECLARE_MTYPE(LCOMMUNITY_VAL);
+
+DECLARE_MTYPE(BGP_EVPN_MH_INFO);
+DECLARE_MTYPE(BGP_EVPN_ES);
+DECLARE_MTYPE(BGP_EVPN_ES_EVI);
+DECLARE_MTYPE(BGP_EVPN_ES_VRF);
+DECLARE_MTYPE(BGP_EVPN_ES_VTEP);
+DECLARE_MTYPE(BGP_EVPN_PATH_ES_INFO);
+DECLARE_MTYPE(BGP_EVPN_ES_EVI_VTEP);
+
+DECLARE_MTYPE(BGP_EVPN);
+DECLARE_MTYPE(BGP_EVPN_IMPORT_RT);
+DECLARE_MTYPE(BGP_EVPN_VRF_IMPORT_RT);
+DECLARE_MTYPE(BGP_EVPN_MACIP);
+
+DECLARE_MTYPE(BGP_FLOWSPEC);
+DECLARE_MTYPE(BGP_FLOWSPEC_RULE);
+DECLARE_MTYPE(BGP_FLOWSPEC_RULE_STR);
+DECLARE_MTYPE(BGP_FLOWSPEC_COMPILED);
+DECLARE_MTYPE(BGP_FLOWSPEC_NAME);
+DECLARE_MTYPE(BGP_FLOWSPEC_INDEX);
+
+DECLARE_MTYPE(BGP_SRV6_L3VPN);
+DECLARE_MTYPE(BGP_SRV6_VPN);
 
 #endif /* _QUAGGA_BGP_MEMORY_H */
index 721ce5b5c6c4190e28c31d2e0692f5c96f884c1f..0d2f84bfc42ed1f12af622a4a8dfe2c3f3f7a332 100644 (file)
 #include "bgpd/bgp_io.h"
 #include "bgpd/bgp_damp.h"
 
-DEFINE_HOOK(bgp_snmp_init_stats, (struct bgp *bgp), (bgp))
+DEFINE_HOOK(bgp_snmp_init_stats, (struct bgp *bgp), (bgp));
 
 FRR_CFG_DEFAULT_ULONG(BGP_CONNECT_RETRY,
         { .val_ulong = 10, .match_profile = "datacenter", },
         { .val_ulong = 120 },
-)
+);
 FRR_CFG_DEFAULT_ULONG(BGP_HOLDTIME,
         { .val_ulong = 9, .match_profile = "datacenter", },
         { .val_ulong = 180 },
-)
+);
 FRR_CFG_DEFAULT_ULONG(BGP_KEEPALIVE,
         { .val_ulong = 3, .match_profile = "datacenter", },
         { .val_ulong = 60 },
-)
+);
 
 int routing_control_plane_protocols_name_validate(
        struct nb_cb_create_args *args)
@@ -3146,8 +3146,7 @@ int bgp_neighbors_neighbor_neighbor_remote_as_remote_as_type_modify(
                        return NB_OK;
 
                str2sockunion(peer_str, &su);
-               ret = peer_remote_as(bgp, &su, NULL, &as, as_type, AFI_IP,
-                                    SAFI_UNICAST);
+               ret = peer_remote_as(bgp, &su, NULL, &as, as_type);
                if (bgp_nb_errmsg_return(args->errmsg, args->errmsg_len, ret)
                    < 0)
                        return NB_ERR_INCONSISTENCY;
@@ -3202,8 +3201,7 @@ int bgp_neighbors_neighbor_neighbor_remote_as_remote_as_modify(
                as = yang_dnode_get_uint32(args->dnode, NULL);
 
                str2sockunion(peer_str, &su);
-               ret = peer_remote_as(bgp, &su, NULL, &as, as_type, AFI_IP,
-                                    SAFI_UNICAST);
+               ret = peer_remote_as(bgp, &su, NULL, &as, as_type);
                if (bgp_nb_errmsg_return(args->errmsg, args->errmsg_len, ret)
                    < 0)
                        return NB_ERR_INCONSISTENCY;
@@ -4370,8 +4368,7 @@ int bgp_neighbors_unnumbered_neighbor_create(struct nb_cb_create_args *args)
                                        "./neighbor-remote-as/remote-as");
                }
 
-               if (peer_conf_interface_create(bgp, peer_str, AFI_IP,
-                                              SAFI_UNICAST, v6_only,
+               if (peer_conf_interface_create(bgp, peer_str, v6_only,
                                               peer_grp_str, as_type, as,
                                               args->errmsg, args->errmsg_len))
                        return NB_ERR_INCONSISTENCY;
@@ -4440,9 +4437,9 @@ int bgp_neighbors_unnumbered_neighbor_v6only_modify(
 
                v6_only = yang_dnode_get_bool(args->dnode, NULL);
 
-               if (peer_conf_interface_create(
-                           bgp, peer_str, AFI_IP, SAFI_UNICAST, v6_only, NULL,
-                           AS_UNSPECIFIED, 0, args->errmsg, args->errmsg_len))
+               if (peer_conf_interface_create(bgp, peer_str, v6_only, NULL,
+                                              AS_UNSPECIFIED, 0, args->errmsg,
+                                              args->errmsg_len))
                        return NB_ERR_INCONSISTENCY;
 
                break;
@@ -5174,8 +5171,6 @@ void bgp_neighbors_unnumbered_neighbor_neighbor_remote_as_apply_finish(
        int ret;
        as_t as = 0;
        struct peer *peer = NULL;
-       afi_t afi = AFI_IP;
-       safi_t safi = SAFI_UNICAST;
 
        bgp = nb_running_get_entry(args->dnode, NULL, true);
        peer_str = yang_dnode_get_string(args->dnode, "../interface");
@@ -5185,7 +5180,7 @@ void bgp_neighbors_unnumbered_neighbor_neighbor_remote_as_apply_finish(
 
        peer = peer_lookup_by_conf_if(bgp, peer_str);
 
-       ret = peer_remote_as(bgp, NULL, peer_str, &as, as_type, afi, safi);
+       ret = peer_remote_as(bgp, NULL, peer_str, &as, as_type);
 
        if (ret < 0 && !peer) {
                snprintf(args->errmsg, args->errmsg_len,
index 03ff27c7ca55b8b0fe2a100b5c3a38453c2ffa4b..4821ce8ddbf4000fe04bebba50a86c152e683a5a 100644 (file)
@@ -544,7 +544,7 @@ static int bgp_accept(struct thread *thread)
                                peer1->host);
 
        peer = peer_create(&su, peer1->conf_if, peer1->bgp, peer1->local_as,
-                          peer1->as, peer1->as_type, 0, 0, NULL);
+                          peer1->as, peer1->as_type, NULL);
        hash_release(peer->bgp->peerhash, peer);
        hash_get(peer->bgp->peerhash, peer, hash_alloc_intern);
 
index c6fa37fa8da0440d2e3a52325b2497b10ad35f9f..9c8d7878c513ac2bca0105b44f0672873d13a7c4 100644 (file)
@@ -194,6 +194,16 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop,
                                   bnc->srte_color, bnc->bgp->name_pretty,
                                   peer);
                }
+       } else {
+               if (BGP_DEBUG(nht, NHT)) {
+                       char buf[PREFIX2STR_BUFFER];
+
+                       zlog_debug(
+                               "Found existing bnc %s(%s) flags 0x%x ifindex %d #paths %d peer %p",
+                               bnc_str(bnc, buf, PREFIX2STR_BUFFER),
+                               bnc->bgp->name_pretty, bnc->flags, bnc->ifindex,
+                               bnc->path_count, bnc->nht_info);
+               }
        }
 
        if (is_bgp_static_route) {
@@ -237,6 +247,11 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop,
                UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
                UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
        }
+       if (peer && (bnc->ifindex != ifindex)) {
+               UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
+               UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
+               bnc->ifindex = ifindex;
+       }
        if (bgp_route->inst_type == BGP_INSTANCE_TYPE_VIEW) {
                SET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
                SET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
@@ -454,17 +469,21 @@ static void bgp_nht_ifp_table_handle(struct bgp *bgp,
                bnc->last_update = bgp_clock();
                bnc->change_flags = 0;
 
+               /*
+                * For interface based routes ( ala the v6 LL routes
+                * that this was written for ) the metric received
+                * for the connected route is 0 not 1.
+                */
+               bnc->metric = 0;
                if (up) {
                        SET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
                        SET_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED);
-                       bnc->metric = 1;
                        bnc->nexthop_num = 1;
                } else {
                        UNSET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED);
                        UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
                        SET_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED);
                        bnc->nexthop_num = 0;
-                       bnc->metric = 0;
                }
 
                evaluate_paths(bnc);
@@ -502,6 +521,11 @@ static int bgp_nht_ifp_initial(struct thread *thread)
        if (!ifp)
                return 0;
 
+       if (BGP_DEBUG(nht, NHT))
+               zlog_debug(
+                       "Handle NHT initial update for Intf %s(%d) status %s",
+                       ifp->name, ifp->ifindex, if_is_up(ifp) ? "up" : "down");
+
        if (if_is_up(ifp))
                bgp_nht_ifp_up(ifp);
        else
index f04b89594ee97848659b6755531fdd692bbfd244..24df324633854ec2e9a32575fee5029f35c1e0db 100644 (file)
 DEFINE_HOOK(bgp_packet_dump,
                (struct peer *peer, uint8_t type, bgp_size_t size,
                        struct stream *s),
-               (peer, type, size, s))
+               (peer, type, size, s));
 
 DEFINE_HOOK(bgp_packet_send,
                (struct peer *peer, uint8_t type, bgp_size_t size,
                        struct stream *s),
-               (peer, type, size, s))
+               (peer, type, size, s));
 
 /**
  * Sets marker and type fields for a BGP message.
@@ -2680,7 +2680,7 @@ int bgp_process_packet(struct thread *thread)
                frr_with_mutex(&peer->io_mtx) {
                        // more work to do, come back later
                        if (peer->ibuf->count > 0)
-                               thread_add_timer_msec(
+                               thread_add_event(
                                        bm->master, bgp_process_packet, peer, 0,
                                        &peer->t_process_packet);
                }
index d32f091d0c87ea0e3eeaccfa39e964a6f0baa94e..d69c86230439fc038675614981319ac9525e9791 100644 (file)
 DECLARE_HOOK(bgp_packet_dump,
                (struct peer *peer, uint8_t type, bgp_size_t size,
                        struct stream *s),
-               (peer, type, size, s))
+               (peer, type, size, s));
 
 DECLARE_HOOK(bgp_packet_send,
                (struct peer *peer, uint8_t type, bgp_size_t size,
                        struct stream *s),
-               (peer, type, size, s))
+               (peer, type, size, s));
 
 #define BGP_NLRI_LENGTH       1U
 #define BGP_TOTAL_ATTR_LEN    2U
index 171522f8ae114a914b1f709e53390d6d12ee3c13..2c6c2c3861fadeff0642d676acd67803d619d4f3 100644 (file)
 #include "bgpd/bgp_flowspec_private.h"
 #include "bgpd/bgp_errors.h"
 
-DEFINE_MTYPE_STATIC(BGPD, PBR_MATCH_ENTRY, "PBR match entry")
-DEFINE_MTYPE_STATIC(BGPD, PBR_MATCH, "PBR match")
-DEFINE_MTYPE_STATIC(BGPD, PBR_ACTION, "PBR action")
-DEFINE_MTYPE_STATIC(BGPD, PBR_RULE, "PBR rule")
-DEFINE_MTYPE_STATIC(BGPD, PBR, "BGP PBR Context")
-DEFINE_MTYPE_STATIC(BGPD, PBR_VALMASK, "BGP PBR Val Mask Value")
+DEFINE_MTYPE_STATIC(BGPD, PBR_MATCH_ENTRY, "PBR match entry");
+DEFINE_MTYPE_STATIC(BGPD, PBR_MATCH, "PBR match");
+DEFINE_MTYPE_STATIC(BGPD, PBR_ACTION, "PBR action");
+DEFINE_MTYPE_STATIC(BGPD, PBR_RULE, "PBR rule");
+DEFINE_MTYPE_STATIC(BGPD, PBR, "BGP PBR Context");
+DEFINE_MTYPE_STATIC(BGPD, PBR_VALMASK, "BGP PBR Val Mask Value");
 
 /* chain strings too long to fit in one line */
 #define FSPEC_ACTION_EXCEED_LIMIT "flowspec actions exceeds limit"
index 87fd5f28ca5296fcd9d12b106d067d19488ab93e..124a477248ea233c068b9e6c10a4cf556de22194 100644 (file)
 
 DEFINE_HOOK(bgp_snmp_update_stats,
            (struct bgp_node *rn, struct bgp_path_info *pi, bool added),
-           (rn, pi, added))
+           (rn, pi, added));
 
 DEFINE_HOOK(bgp_rpki_prefix_status,
            (struct peer *peer, struct attr *attr,
             const struct prefix *prefix),
-           (peer, attr, prefix))
+           (peer, attr, prefix));
 
 /* Extern from bgp_dump.c */
 extern const char *bgp_origin_str[];
@@ -126,7 +126,7 @@ static const struct message bgp_pmsi_tnltype_str[] = {
 DEFINE_HOOK(bgp_process,
            (struct bgp * bgp, afi_t afi, safi_t safi, struct bgp_dest *bn,
             struct peer *peer, bool withdraw),
-           (bgp, afi, safi, bn, peer, withdraw))
+           (bgp, afi, safi, bn, peer, withdraw));
 
 /** Test if path is suppressed. */
 static bool bgp_path_suppressed(struct bgp_path_info *pi)
index 766e5ade92f23ba47d40d193de2f11fbfb7ea10f..1dec99f08572b977d7921707e6e7239d05f49428 100644 (file)
@@ -550,7 +550,7 @@ static inline bool bgp_check_advertise(struct bgp *bgp, struct bgp_dest *dest)
 DECLARE_HOOK(bgp_process,
             (struct bgp * bgp, afi_t afi, safi_t safi, struct bgp_dest *bn,
              struct peer *peer, bool withdraw),
-            (bgp, afi, safi, bn, peer, withdraw))
+            (bgp, afi, safi, bn, peer, withdraw));
 
 /* BGP show options */
 #define BGP_SHOW_OPT_JSON (1 << 0)
index 42951efb0164e23464d428c16c3395d4e08821bc..9344384956ab7f65f308b91c54e19122e3b681e4 100644 (file)
@@ -60,8 +60,8 @@
 #include "bgpd/bgp_rpki_clippy.c"
 #endif
 
-DEFINE_MTYPE_STATIC(BGPD, BGP_RPKI_CACHE, "BGP RPKI Cache server")
-DEFINE_MTYPE_STATIC(BGPD, BGP_RPKI_CACHE_GROUP, "BGP RPKI Cache server group")
+DEFINE_MTYPE_STATIC(BGPD, BGP_RPKI_CACHE, "BGP RPKI Cache server");
+DEFINE_MTYPE_STATIC(BGPD, BGP_RPKI_CACHE_GROUP, "BGP RPKI Cache server group");
 
 #define RPKI_VALID      1
 #define RPKI_NOTFOUND   2
@@ -1471,4 +1471,5 @@ static void install_cli_commands(void)
 
 FRR_MODULE_SETUP(.name = "bgpd_rpki", .version = "0.3.6",
                 .description = "Enable RPKI support for FRR.",
-                .init = bgp_rpki_module_init)
+                .init = bgp_rpki_module_init,
+);
index 71868abc5f667bb946200c6803f2bbc8519cc36d..bc26314b50cb72a2e77363210c90b89b181f3853 100644 (file)
@@ -914,4 +914,5 @@ static int bgp_snmp_module_init(void)
 
 FRR_MODULE_SETUP(.name = "bgpd_snmp", .version = FRR_VERSION,
                 .description = "bgpd AgentX SNMP module",
-                .init = bgp_snmp_module_init)
+                .init = bgp_snmp_module_init,
+);
index a4e56c95c8fc7150bf9533e936f61b8da75b9007..a016265d6e2ea21bbe3464f15751b1f2f0d1f1a7 100644 (file)
@@ -24,6 +24,7 @@
 #include "lib/json.h"
 #include "lib_errors.h"
 #include "lib/zclient.h"
+#include "lib/printfrr.h"
 #include "prefix.h"
 #include "plist.h"
 #include "buffer.h"
@@ -85,49 +86,49 @@ FRR_CFG_DEFAULT_BOOL(BGP_IMPORT_CHECK,
                        .match_version = "< 7.4",
        },
        { .val_bool = true },
-)
+);
 FRR_CFG_DEFAULT_BOOL(BGP_SHOW_HOSTNAME,
        { .val_bool = true, .match_profile = "datacenter", },
        { .val_bool = false },
-)
+);
 FRR_CFG_DEFAULT_BOOL(BGP_SHOW_NEXTHOP_HOSTNAME,
        { .val_bool = true, .match_profile = "datacenter", },
        { .val_bool = false },
-)
+);
 FRR_CFG_DEFAULT_BOOL(BGP_LOG_NEIGHBOR_CHANGES,
        { .val_bool = true, .match_profile = "datacenter", },
        { .val_bool = false },
-)
+);
 FRR_CFG_DEFAULT_BOOL(BGP_DETERMINISTIC_MED,
        { .val_bool = true, .match_profile = "datacenter", },
        { .val_bool = false },
-)
+);
 FRR_CFG_DEFAULT_ULONG(BGP_CONNECT_RETRY,
        { .val_ulong = 10, .match_profile = "datacenter", },
        { .val_ulong = 120 },
-)
+);
 FRR_CFG_DEFAULT_ULONG(BGP_HOLDTIME,
        { .val_ulong = 9, .match_profile = "datacenter", },
        { .val_ulong = 180 },
-)
+);
 FRR_CFG_DEFAULT_ULONG(BGP_KEEPALIVE,
        { .val_ulong = 3, .match_profile = "datacenter", },
        { .val_ulong = 60 },
-)
+);
 FRR_CFG_DEFAULT_BOOL(BGP_EBGP_REQUIRES_POLICY,
        { .val_bool = false, .match_profile = "datacenter", },
        { .val_bool = false, .match_version = "< 7.4", },
        { .val_bool = true },
-)
+);
 FRR_CFG_DEFAULT_BOOL(BGP_SUPPRESS_DUPLICATES,
        { .val_bool = false, .match_version = "< 7.6", },
        { .val_bool = true },
-)
+);
 
 DEFINE_HOOK(bgp_inst_config_write,
                (struct bgp *bgp, struct vty *vty),
-               (bgp, vty))
-DEFINE_HOOK(bgp_snmp_update_last_changed, (struct bgp *bgp), (bgp))
+               (bgp, vty));
+DEFINE_HOOK(bgp_snmp_update_last_changed, (struct bgp *bgp), (bgp));
 
 #define GR_NO_OPER                                                             \
        "The Graceful Restart No Operation was executed as cmd same as previous one."
@@ -739,7 +740,7 @@ int bgp_nb_errmsg_return(char *errmsg, size_t errmsg_len, int ret)
                str = "Operation not allowed on a directly connected neighbor";
                break;
        case BGP_ERR_PEER_SAFI_CONFLICT:
-               str = GR_INVALID;
+               str = "Cannot activate peer for both 'ipv4 unicast' and 'ipv4 labeled-unicast'";
                break;
        case BGP_ERR_GR_INVALID_CMD:
                str = "The Graceful Restart command used is not valid at this moment.";
@@ -831,7 +832,7 @@ int bgp_vty_return(struct vty *vty, int ret)
                str = "Operation not allowed on a directly connected neighbor";
                break;
        case BGP_ERR_PEER_SAFI_CONFLICT:
-               str = GR_INVALID;
+               str = "Cannot activate peer for both 'ipv4 unicast' and 'ipv4 labeled-unicast'";
                break;
        case BGP_ERR_GR_INVALID_CMD:
                str = "The Graceful Restart command used is not valid at this moment.";
@@ -3726,6 +3727,29 @@ DEFPY (no_bgp_bestpath_bw,
        return CMD_SUCCESS;
 }
 
+/* "no bgp default ipv6-unicast". */
+DEFUN(no_bgp_default_ipv6_unicast, no_bgp_default_ipv6_unicast_cmd,
+      "no bgp default ipv6-unicast", NO_STR
+      "BGP specific commands\n"
+      "Configure BGP defaults\n"
+      "Activate ipv6-unicast for a peer by default\n")
+{
+       VTY_DECLVAR_CONTEXT(bgp, bgp);
+       UNSET_FLAG(bgp->flags, BGP_FLAG_DEFAULT_IPV6);
+       return CMD_SUCCESS;
+}
+
+DEFUN(bgp_default_ipv6_unicast, bgp_default_ipv6_unicast_cmd,
+      "bgp default ipv6-unicast",
+      "BGP specific commands\n"
+      "Configure BGP defaults\n"
+      "Activate ipv6-unicast for a peer by default\n")
+{
+       VTY_DECLVAR_CONTEXT(bgp, bgp);
+       SET_FLAG(bgp->flags, BGP_FLAG_DEFAULT_IPV6);
+       return CMD_SUCCESS;
+}
+
 /* "no bgp default ipv4-unicast". */
 DEFUN (no_bgp_default_ipv4_unicast,
        no_bgp_default_ipv4_unicast_cmd,
@@ -4367,10 +4391,10 @@ DEFUN_YANG(neighbor_remote_as,
        return nb_cli_apply_changes(vty, base_xpath);
 }
 
-int peer_conf_interface_create(struct bgp *bgp, const char *conf_if, afi_t afi,
-                              safi_t safi, bool v6only,
-                              const char *peer_group_name, int as_type,
-                              as_t as, char *errmsg, size_t errmsg_len)
+int peer_conf_interface_create(struct bgp *bgp, const char *conf_if,
+                              bool v6only, const char *peer_group_name,
+                              int as_type, as_t as, char *errmsg,
+                              size_t errmsg_len)
 {
        struct peer *peer;
        struct peer_group *group;
@@ -4387,16 +4411,10 @@ int peer_conf_interface_create(struct bgp *bgp, const char *conf_if, afi_t afi,
        peer = peer_lookup_by_conf_if(bgp, conf_if);
        if (peer) {
                if (as_type != AS_UNSPECIFIED)
-                       ret = peer_remote_as(bgp, NULL, conf_if, &as, as_type,
-                                            afi, safi);
+                       ret = peer_remote_as(bgp, NULL, conf_if, &as, as_type);
        } else {
-               if (CHECK_FLAG(bgp->flags, BGP_FLAG_NO_DEFAULT_IPV4)
-                   && afi == AFI_IP && safi == SAFI_UNICAST)
-                       peer = peer_create(NULL, conf_if, bgp, bgp->as, as,
-                                          as_type, 0, 0, NULL);
-               else
-                       peer = peer_create(NULL, conf_if, bgp, bgp->as, as,
-                                          as_type, afi, safi, NULL);
+               peer = peer_create(NULL, conf_if, bgp, bgp->as, as, as_type,
+                                  NULL);
 
                if (!peer) {
                        snprintf(errmsg, errmsg_len,
@@ -6138,10 +6156,28 @@ DEFUN_YANG (neighbor_send_community,
            "Send Community attribute to this neighbor\n")
 {
        int idx_peer = 1;
+       char *peer_str = argv[idx_peer]->arg;
+       char base_xpath[XPATH_MAXLEN];
+       char af_xpath[XPATH_MAXLEN];
+       char std_xpath[XPATH_MAXLEN];
+       afi_t afi = bgp_node_afi(vty);
+       safi_t safi = bgp_node_safi(vty);
 
-       return peer_af_flag_set_vty(vty, argv[idx_peer]->arg, bgp_node_afi(vty),
-                                   bgp_node_safi(vty),
-                                   PEER_FLAG_SEND_COMMUNITY);
+       snprintf(af_xpath, sizeof(af_xpath), FRR_BGP_AF_XPATH,
+                yang_afi_safi_value2identity(afi, safi));
+
+       if (peer_and_group_lookup_nb(vty, peer_str, base_xpath,
+                                    sizeof(base_xpath), af_xpath)
+           < 0)
+               return CMD_WARNING_CONFIG_FAILED;
+
+       snprintf(std_xpath, sizeof(std_xpath),
+                "./%s/send-community/send-community",
+                bgp_afi_safi_get_container_str(afi, safi));
+
+       nb_cli_enqueue_change(vty, std_xpath, NB_OP_MODIFY, "true");
+
+       return nb_cli_apply_changes(vty, base_xpath);
 }
 
 ALIAS_HIDDEN(neighbor_send_community, neighbor_send_community_hidden_cmd,
@@ -6158,10 +6194,28 @@ DEFUN_YANG (no_neighbor_send_community,
            "Send Community attribute to this neighbor\n")
 {
        int idx_peer = 2;
+       char *peer_str = argv[idx_peer]->arg;
+       char base_xpath[XPATH_MAXLEN];
+       char af_xpath[XPATH_MAXLEN];
+       char std_xpath[XPATH_MAXLEN];
+       afi_t afi = bgp_node_afi(vty);
+       safi_t safi = bgp_node_safi(vty);
 
-       return peer_af_flag_unset_vty(vty, argv[idx_peer]->arg,
-                                     bgp_node_afi(vty), bgp_node_safi(vty),
-                                     PEER_FLAG_SEND_COMMUNITY);
+       snprintf(af_xpath, sizeof(af_xpath), FRR_BGP_AF_XPATH,
+                yang_afi_safi_value2identity(afi, safi));
+
+       if (peer_and_group_lookup_nb(vty, peer_str, base_xpath,
+                                    sizeof(base_xpath), af_xpath)
+           < 0)
+               return CMD_WARNING_CONFIG_FAILED;
+
+       snprintf(std_xpath, sizeof(std_xpath),
+                "./%s/send-community/send-community",
+                bgp_afi_safi_get_container_str(afi, safi));
+
+       nb_cli_enqueue_change(vty, std_xpath, NB_OP_MODIFY, "false");
+
+       return nb_cli_apply_changes(vty, base_xpath);
 }
 
 ALIAS_HIDDEN(no_neighbor_send_community, no_neighbor_send_community_hidden_cmd,
@@ -14357,7 +14411,8 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
                vty_out(vty, "\n");
 
        /* BFD information. */
-       bgp_bfd_show_info(vty, p, use_json, json_neigh);
+       if (p->bfd_config)
+               bgp_bfd_show_info(vty, p, json_neigh);
 
        if (use_json) {
                if (p->conf_if) /* Configured interface name. */
@@ -15464,7 +15519,8 @@ DEFPY(show_ip_bgp_instance_updgrps_adj_s,
        return CMD_SUCCESS;
 }
 
-static int bgp_show_one_peer_group(struct vty *vty, struct peer_group *group)
+static int bgp_show_one_peer_group(struct vty *vty, struct peer_group *group,
+                                  json_object *json)
 {
        struct listnode *node, *nnode;
        struct prefix *range;
@@ -15473,64 +15529,143 @@ static int bgp_show_one_peer_group(struct vty *vty, struct peer_group *group)
        afi_t afi;
        safi_t safi;
        const char *peer_status;
-       const char *af_str;
        int lr_count;
        int dynamic;
-       int af_cfgd;
+       bool af_cfgd;
+       json_object *json_peer_group = NULL;
+       json_object *json_peer_group_afc = NULL;
+       json_object *json_peer_group_members = NULL;
+       json_object *json_peer_group_dynamic = NULL;
+       json_object *json_peer_group_dynamic_af = NULL;
+       json_object *json_peer_group_ranges = NULL;
 
        conf = group->conf;
 
+       if (json) {
+               json_peer_group = json_object_new_object();
+               json_peer_group_afc = json_object_new_array();
+       }
+
        if (conf->as_type == AS_SPECIFIED || conf->as_type == AS_EXTERNAL) {
-               vty_out(vty, "\nBGP peer-group %s, remote AS %u\n",
-                       group->name, conf->as);
+               if (json)
+                       json_object_int_add(json_peer_group, "remoteAs",
+                                           conf->as);
+               else
+                       vty_out(vty, "\nBGP peer-group %s, remote AS %u\n",
+                               group->name, conf->as);
        } else if (conf->as_type == AS_INTERNAL) {
-               vty_out(vty, "\nBGP peer-group %s, remote AS %u\n",
-                       group->name, group->bgp->as);
+               if (json)
+                       json_object_int_add(json_peer_group, "remoteAs",
+                                           group->bgp->as);
+               else
+                       vty_out(vty, "\nBGP peer-group %s, remote AS %u\n",
+                               group->name, group->bgp->as);
        } else {
-               vty_out(vty, "\nBGP peer-group %s\n", group->name);
+               if (!json)
+                       vty_out(vty, "\nBGP peer-group %s\n", group->name);
        }
 
-       if ((group->bgp->as == conf->as) || (conf->as_type == AS_INTERNAL))
-               vty_out(vty, "  Peer-group type is internal\n");
-       else
-               vty_out(vty, "  Peer-group type is external\n");
+       if ((group->bgp->as == conf->as) || (conf->as_type == AS_INTERNAL)) {
+               if (json)
+                       json_object_string_add(json_peer_group, "type",
+                                              "internal");
+               else
+                       vty_out(vty, "  Peer-group type is internal\n");
+       } else {
+               if (json)
+                       json_object_string_add(json_peer_group, "type",
+                                              "external");
+               else
+                       vty_out(vty, "  Peer-group type is external\n");
+       }
 
        /* Display AFs configured. */
-       vty_out(vty, "  Configured address-families:");
+       if (!json)
+               vty_out(vty, "  Configured address-families:");
+
        FOREACH_AFI_SAFI (afi, safi) {
                if (conf->afc[afi][safi]) {
-                       af_cfgd = 1;
-                       vty_out(vty, " %s;", get_afi_safi_str(afi, safi, false));
+                       af_cfgd = true;
+                       if (json)
+                               json_object_array_add(
+                                       json_peer_group_afc,
+                                       json_object_new_string(get_afi_safi_str(
+                                               afi, safi, false)));
+                       else
+                               vty_out(vty, " %s;",
+                                       get_afi_safi_str(afi, safi, false));
                }
        }
-       if (!af_cfgd)
-               vty_out(vty, " none\n");
-       else
-               vty_out(vty, "\n");
+
+       if (json) {
+               json_object_object_add(json_peer_group,
+                                      "addressFamiliesConfigured",
+                                      json_peer_group_afc);
+       } else {
+               if (!af_cfgd)
+                       vty_out(vty, " none\n");
+               else
+                       vty_out(vty, "\n");
+       }
 
        /* Display listen ranges (for dynamic neighbors), if any */
        for (afi = AFI_IP; afi < AFI_MAX; afi++) {
-               if (afi == AFI_IP)
-                       af_str = "IPv4";
-               else if (afi == AFI_IP6)
-                       af_str = "IPv6";
-               else
-                       af_str = "???";
                lr_count = listcount(group->listen_range[afi]);
                if (lr_count) {
-                       vty_out(vty, "  %d %s listen range(s)\n", lr_count,
-                               af_str);
-
+                       if (json) {
+                               if (!json_peer_group_dynamic)
+                                       json_peer_group_dynamic =
+                                               json_object_new_object();
+
+                               json_peer_group_dynamic_af =
+                                       json_object_new_object();
+                               json_peer_group_ranges =
+                                       json_object_new_array();
+                               json_object_int_add(json_peer_group_dynamic_af,
+                                                   "count", lr_count);
+                       } else {
+                               vty_out(vty, "  %d %s listen range(s)\n",
+                                       lr_count, afi2str(afi));
+                       }
 
                        for (ALL_LIST_ELEMENTS(group->listen_range[afi], node,
-                                              nnode, range))
-                               vty_out(vty, "    %pFX\n", range);
+                                              nnode, range)) {
+                               if (json) {
+                                       char buf[BUFSIZ];
+
+                                       snprintfrr(buf, sizeof(buf), "%pFX",
+                                                  range);
+
+                                       json_object_array_add(
+                                               json_peer_group_ranges,
+                                               json_object_new_string(buf));
+                               } else {
+                                       vty_out(vty, "    %pFX\n", range);
+                               }
+                       }
+
+                       if (json) {
+                               json_object_object_add(
+                                       json_peer_group_dynamic_af, "ranges",
+                                       json_peer_group_ranges);
+
+                               json_object_object_add(
+                                       json_peer_group_dynamic, afi2str(afi),
+                                       json_peer_group_dynamic_af);
+                       }
                }
        }
 
+       if (json_peer_group_dynamic)
+               json_object_object_add(json_peer_group, "dynamicRanges",
+                                      json_peer_group_dynamic);
+
        /* Display group members and their status */
        if (listcount(group->peer)) {
-               vty_out(vty, "  Peer-group members:\n");
+               if (json)
+                       json_peer_group_members = json_object_new_object();
+               else
+                       vty_out(vty, "  Peer-group members:\n");
                for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
                        if (CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN)
                            || CHECK_FLAG(peer->bgp->flags, BGP_FLAG_SHUTDOWN))
@@ -15543,65 +15678,106 @@ static int bgp_show_one_peer_group(struct vty *vty, struct peer_group *group)
                                                         peer->status, NULL);
 
                        dynamic = peer_dynamic_neighbor(peer);
-                       vty_out(vty, "    %s %s %s \n", peer->host,
-                               dynamic ? "(dynamic)" : "", peer_status);
+
+                       if (json) {
+                               json_object *json_peer_group_member =
+                                       json_object_new_object();
+
+                               json_object_string_add(json_peer_group_member,
+                                                      "status", peer_status);
+
+                               if (dynamic)
+                                       json_object_boolean_true_add(
+                                               json_peer_group_member,
+                                               "dynamic");
+
+                               json_object_object_add(json_peer_group_members,
+                                                      peer->host,
+                                                      json_peer_group_member);
+                       } else {
+                               vty_out(vty, "    %s %s %s \n", peer->host,
+                                       dynamic ? "(dynamic)" : "",
+                                       peer_status);
+                       }
                }
+               if (json)
+                       json_object_object_add(json_peer_group, "members",
+                                              json_peer_group_members);
        }
 
+       if (json)
+               json_object_object_add(json, group->name, json_peer_group);
+
        return CMD_SUCCESS;
 }
 
 static int bgp_show_peer_group_vty(struct vty *vty, const char *name,
-                                  const char *group_name)
+                                  const char *group_name, bool uj)
 {
        struct bgp *bgp;
        struct listnode *node, *nnode;
        struct peer_group *group;
        bool found = false;
+       json_object *json = NULL;
+
+       if (uj)
+               json = json_object_new_object();
 
        bgp = name ? bgp_lookup_by_name(name) : bgp_get_default();
 
        if (!bgp) {
-               vty_out(vty, "%% BGP instance not found\n");
+               if (uj) {
+                       vty_out(vty, "%s\n",
+                               json_object_to_json_string_ext(
+                                       json, JSON_C_TO_STRING_PRETTY));
+                       json_object_free(json);
+               } else {
+                       vty_out(vty, "%% BGP instance not found\n");
+               }
+
                return CMD_WARNING;
        }
 
        for (ALL_LIST_ELEMENTS(bgp->group, node, nnode, group)) {
                if (group_name) {
                        if (strmatch(group->name, group_name)) {
-                               bgp_show_one_peer_group(vty, group);
+                               bgp_show_one_peer_group(vty, group, json);
                                found = true;
                                break;
                        }
                } else {
-                       bgp_show_one_peer_group(vty, group);
+                       bgp_show_one_peer_group(vty, group, json);
                }
        }
 
-       if (group_name && !found)
+       if (group_name && !found && !uj)
                vty_out(vty, "%% No such peer-group\n");
 
+       if (uj) {
+               vty_out(vty, "%s\n",
+                       json_object_to_json_string_ext(
+                               json, JSON_C_TO_STRING_PRETTY));
+               json_object_free(json);
+       }
+
        return CMD_SUCCESS;
 }
 
-DEFUN (show_ip_bgp_peer_groups,
-       show_ip_bgp_peer_groups_cmd,
-       "show [ip] bgp [<view|vrf> VIEWVRFNAME] peer-group [PGNAME]",
-       SHOW_STR
-       IP_STR
-       BGP_STR
-       BGP_INSTANCE_HELP_STR
-       "Detailed information on BGP peer groups\n"
-       "Peer group name\n")
+DEFUN(show_ip_bgp_peer_groups, show_ip_bgp_peer_groups_cmd,
+      "show [ip] bgp [<view|vrf> VIEWVRFNAME] peer-group [PGNAME] [json]",
+      SHOW_STR IP_STR BGP_STR BGP_INSTANCE_HELP_STR
+      "Detailed information on BGP peer groups\n"
+      "Peer group name\n" JSON_STR)
 {
        char *vrf, *pg;
        int idx = 0;
+       bool uj = use_json(argc, argv);
 
        vrf = argv_find(argv, argc, "VIEWVRFNAME", &idx) ? argv[idx]->arg
                                                         : NULL;
        pg = argv_find(argv, argc, "PGNAME", &idx) ? argv[idx]->arg : NULL;
 
-       return bgp_show_peer_group_vty(vty, vrf, pg);
+       return bgp_show_peer_group_vty(vty, vrf, pg, uj);
 }
 
 
@@ -16643,11 +16819,8 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp,
                        peer->rtt_expected, peer->rtt_keepalive_conf);
 
        /* bfd */
-       if (peer->bfd_info) {
-               if (!peer_group_active(peer) || !g_peer->bfd_info) {
-                       bgp_bfd_peer_config_write(vty, peer, addr);
-               }
-       }
+       if (peer->bfd_config)
+               bgp_bfd_peer_config_write(vty, peer, addr);
 
        /* password */
        if (peergroup_flag_check(peer, PEER_FLAG_PASSWORD))
@@ -16844,18 +17017,36 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp,
                }
        } else {
                if (peer->afc[afi][safi]) {
-                       if ((afi == AFI_IP) && (safi == SAFI_UNICAST)) {
-                               if (CHECK_FLAG(bgp->flags,
-                                              BGP_FLAG_NO_DEFAULT_IPV4)) {
+                       if ((afi == AFI_IP || afi == AFI_IP6)
+                           && safi == SAFI_UNICAST) {
+                               if (afi == AFI_IP
+                                   && CHECK_FLAG(bgp->flags,
+                                                 BGP_FLAG_NO_DEFAULT_IPV4)) {
+                                       vty_out(vty, "  neighbor %s activate\n",
+                                               addr);
+                               } else if (afi == AFI_IP6
+                                          && !CHECK_FLAG(
+                                                     bgp->flags,
+                                                     BGP_FLAG_DEFAULT_IPV6)) {
                                        vty_out(vty, "  neighbor %s activate\n",
                                                addr);
                                }
-                       } else
+                       } else {
                                vty_out(vty, "  neighbor %s activate\n", addr);
+                       }
                } else {
-                       if ((afi == AFI_IP) && (safi == SAFI_UNICAST)) {
-                               if (!CHECK_FLAG(bgp->flags,
-                                               BGP_FLAG_NO_DEFAULT_IPV4)) {
+                       if ((afi == AFI_IP || afi == AFI_IP6)
+                           && safi == SAFI_UNICAST) {
+                               if (afi == AFI_IP
+                                   && !CHECK_FLAG(bgp->flags,
+                                                 BGP_FLAG_NO_DEFAULT_IPV4)) {
+                                       vty_out(vty,
+                                               "  no neighbor %s activate\n",
+                                               addr);
+                               } else if (afi == AFI_IP6
+                                          && CHECK_FLAG(
+                                                     bgp->flags,
+                                                     BGP_FLAG_DEFAULT_IPV6)) {
                                        vty_out(vty,
                                                "  no neighbor %s activate\n",
                                                addr);
@@ -17289,6 +17480,10 @@ int bgp_config_write(struct vty *vty)
                if (CHECK_FLAG(bgp->flags, BGP_FLAG_NO_DEFAULT_IPV4))
                        vty_out(vty, " no bgp default ipv4-unicast\n");
 
+               /* BGP default ipv6-unicast. */
+               if (CHECK_FLAG(bgp->flags, BGP_FLAG_DEFAULT_IPV6))
+                       vty_out(vty, " bgp default ipv6-unicast\n");
+
                /* BGP default local-preference. */
                if (bgp->default_local_pref != BGP_DEFAULT_LOCAL_PREF)
                        vty_out(vty, " bgp default local-preference %u\n",
@@ -17959,6 +18154,10 @@ void bgp_vty_init(void)
        install_element(BGP_NODE, &no_bgp_default_ipv4_unicast_cmd);
        install_element(BGP_NODE, &bgp_default_ipv4_unicast_cmd);
 
+       /* "no bgp default ipv6-unicast" commands. */
+       install_element(BGP_NODE, &no_bgp_default_ipv6_unicast_cmd);
+       install_element(BGP_NODE, &bgp_default_ipv6_unicast_cmd);
+
        /* "bgp network import-check" commands. */
        install_element(BGP_NODE, &bgp_network_import_check_cmd);
        install_element(BGP_NODE, &bgp_network_import_check_exact_cmd);
index 85619dd074dbac774476aadfaae7b0e547bdd6df..251bdc3fe3a2e11375608833db23fed16a438eda 100644 (file)
@@ -205,9 +205,9 @@ extern int peer_local_interface_cfg(struct bgp *bgp, const char *ip_str,
                                    const char *str, char *errmsg,
                                    size_t errmsg_len);
 extern int peer_conf_interface_create(struct bgp *bgp, const char *conf_if,
-                                     afi_t afi, safi_t safi, bool v6only,
-                                     const char *peer_group_name, int as_type,
-                                     as_t as, char *errmsg, size_t errmsg_len);
+                                     bool v6only, const char *peer_group_name,
+                                     int as_type, as_t as, char *errmsg,
+                                     size_t errmsg_len);
 extern int peer_flag_modify_nb(struct bgp *bgp, const char *ip_str,
                               struct peer *peer, uint32_t flag, bool set,
                               char *errmsg, size_t errmsg_len);
index c554332255df9f588b05b50db1d1cb5d02b988b9..0a12e719ced0c2e0ffca1fd198d9a8ed7b8256ad 100644 (file)
@@ -69,7 +69,7 @@ struct zclient *zclient = NULL;
 
 /* hook to indicate vrf status change for SNMP */
 DEFINE_HOOK(bgp_vrf_status_changed, (struct bgp *bgp, struct interface *ifp),
-           (bgp, ifp))
+           (bgp, ifp));
 
 /* Can we install into zebra? */
 static inline bool bgp_install_info_to_zebra(struct bgp *bgp)
@@ -283,20 +283,9 @@ static int bgp_ifp_down(struct interface *ifp)
        if (!CHECK_FLAG(bgp->flags, BGP_FLAG_NO_FAST_EXT_FAILOVER)) {
 
                for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
-#if defined(HAVE_CUMULUS)
-                       /* Take down directly connected EBGP peers as well as
-                        * 1-hop BFD
-                        * tracked (directly connected) IBGP peers.
-                        */
-                       if ((peer->ttl != BGP_DEFAULT_TTL)
-                           && (peer->gtsm_hops != BGP_GTSM_HOPS_CONNECTED)
-                           && (!peer->bfd_info
-                               || bgp_bfd_is_peer_multihop(peer)))
-#else
-                       /* Take down directly connected EBGP peers */
+                       /* Take down directly connected peers. */
                        if ((peer->ttl != BGP_DEFAULT_TTL)
                            && (peer->gtsm_hops != BGP_GTSM_HOPS_CONNECTED))
-#endif
                                continue;
 
                        if (ifp == peer->nexthop.ifp) {
index 33c8f3c1f097bdb2ffed30f089272d3e778ba7bd..d37b9fa48c04782f7d6a9f04dd49d696965f6705 100644 (file)
 
 DEFINE_MTYPE_STATIC(BGPD, PEER_TX_SHUTDOWN_MSG, "Peer shutdown message (TX)");
 DEFINE_MTYPE_STATIC(BGPD, BGP_EVPN_INFO, "BGP EVPN instance information");
-DEFINE_QOBJ_TYPE(bgp_master)
-DEFINE_QOBJ_TYPE(bgp)
-DEFINE_QOBJ_TYPE(peer)
-DEFINE_HOOK(bgp_inst_delete, (struct bgp *bgp), (bgp))
+DEFINE_QOBJ_TYPE(bgp_master);
+DEFINE_QOBJ_TYPE(bgp);
+DEFINE_QOBJ_TYPE(peer);
+DEFINE_HOOK(bgp_inst_delete, (struct bgp *bgp), (bgp));
 
 /* BGP process wide configuration.  */
 static struct bgp_master bgp_master;
@@ -1161,7 +1161,9 @@ static void peer_free(struct peer *peer)
 
        XFREE(MTYPE_PEER_CONF_IF, peer->conf_if);
 
-       bfd_info_free(&(peer->bfd_info));
+       /* Remove BFD configuration. */
+       if (peer->bfd_config)
+               bgp_peer_remove_bfd_config(peer);
 
        FOREACH_AFI_SAFI (afi, safi)
                bgp_addpath_set_peer_type(peer, afi, safi, BGP_ADDPATH_NONE);
@@ -1468,8 +1470,10 @@ void peer_xfer_config(struct peer *peer_dst, struct peer *peer_src)
 
        for (afidx = BGP_AF_START; afidx < BGP_AF_MAX; afidx++) {
                paf = peer_src->peer_af_array[afidx];
-               if (paf != NULL)
-                       peer_af_create(peer_dst, paf->afi, paf->safi);
+               if (paf != NULL) {
+                       if (!peer_af_find(peer_dst, paf->afi, paf->safi))
+                               peer_af_create(peer_dst, paf->afi, paf->safi);
+               }
        }
 
        /* update-source apply */
@@ -1683,12 +1687,13 @@ void bgp_recalculate_all_bestpaths(struct bgp *bgp)
  */
 struct peer *peer_create(union sockunion *su, const char *conf_if,
                         struct bgp *bgp, as_t local_as, as_t remote_as,
-                        int as_type, afi_t afi, safi_t safi,
-                        struct peer_group *group)
+                        int as_type, struct peer_group *group)
 {
        int active;
        struct peer *peer;
        char buf[SU_ADDRSTRLEN];
+       afi_t afi;
+       safi_t safi;
 
        peer = peer_new(bgp);
        if (conf_if) {
@@ -1747,9 +1752,23 @@ struct peer *peer_create(union sockunion *su, const char *conf_if,
 
        SET_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE);
 
-       if (afi && safi) {
-               peer->afc[afi][safi] = 1;
-               peer_af_create(peer, afi, safi);
+       /* If address family is IPv4 and `bgp default ipv4-unicast` (default),
+        * then activate the neighbor for this AF.
+        * If address family is IPv6 and `bgp default ipv6-unicast`
+        * (non-default), then activate the neighbor for this AF.
+        */
+       FOREACH_AFI_SAFI (afi, safi) {
+               if ((afi == AFI_IP || afi == AFI_IP6) && safi == SAFI_UNICAST) {
+                       if ((afi == AFI_IP
+                            && !CHECK_FLAG(bgp->flags,
+                                           BGP_FLAG_NO_DEFAULT_IPV4))
+                           || (afi == AFI_IP6
+                               && CHECK_FLAG(bgp->flags,
+                                             BGP_FLAG_DEFAULT_IPV6))) {
+                               peer->afc[afi][safi] = 1;
+                               peer_af_create(peer, afi, safi);
+                       }
+               }
        }
 
        /* auto shutdown if configured */
@@ -1878,7 +1897,7 @@ void peer_as_change(struct peer *peer, as_t as, int as_specified)
 /* If peer does not exist, create new one.  If peer already exists,
    set AS number to the peer.  */
 int peer_remote_as(struct bgp *bgp, union sockunion *su, const char *conf_if,
-                  as_t *as, int as_type, afi_t afi, safi_t safi)
+                  as_t *as, int as_type)
 {
        struct peer *peer;
        as_t local_as;
@@ -1946,16 +1965,7 @@ int peer_remote_as(struct bgp *bgp, union sockunion *su, const char *conf_if,
                else
                        local_as = bgp->as;
 
-               /* If this is IPv4 unicast configuration and "no bgp default
-                  ipv4-unicast" is specified. */
-
-               if (CHECK_FLAG(bgp->flags, BGP_FLAG_NO_DEFAULT_IPV4)
-                   && afi == AFI_IP && safi == SAFI_UNICAST)
-                       peer_create(su, conf_if, bgp, local_as, *as, as_type, 0,
-                                   0, NULL);
-               else
-                       peer_create(su, conf_if, bgp, local_as, *as, as_type,
-                                   afi, safi, NULL);
+               peer_create(su, conf_if, bgp, local_as, *as, as_type, NULL);
        }
 
        return 0;
@@ -2203,7 +2213,7 @@ int peer_activate(struct peer *peer, afi_t afi, safi_t safi)
 
        /* If this is the first peer to be activated for this
         * afi/labeled-unicast recalc bestpaths to trigger label allocation */
-       if (safi == SAFI_LABELED_UNICAST
+       if (ret != BGP_ERR_PEER_SAFI_CONFLICT && safi == SAFI_LABELED_UNICAST
            && !bgp->allocate_mpls_labels[afi][SAFI_UNICAST]) {
 
                if (BGP_DEBUG(zebra, ZEBRA))
@@ -2386,7 +2396,9 @@ int peer_delete(struct peer *peer)
 
        SET_FLAG(peer->flags, PEER_FLAG_DELETE);
 
-       bgp_bfd_deregister_peer(peer);
+       /* Remove BFD settings. */
+       if (peer->bfd_config)
+               bgp_peer_remove_bfd_config(peer);
 
        /* Delete peer route flap dampening configuration. This needs to happen
         * before removing the peer from peer groups.
@@ -2562,6 +2574,8 @@ struct peer_group *peer_group_get(struct bgp *bgp, const char *name)
        group->conf = peer_new(bgp);
        if (!CHECK_FLAG(bgp->flags, BGP_FLAG_NO_DEFAULT_IPV4))
                group->conf->afc[AFI_IP][SAFI_UNICAST] = 1;
+       if (CHECK_FLAG(bgp->flags, BGP_FLAG_DEFAULT_IPV6))
+               group->conf->afc[AFI_IP6][SAFI_UNICAST] = 1;
        XFREE(MTYPE_BGP_PEER_HOST, group->conf->host);
        group->conf->host = XSTRDUP(MTYPE_BGP_PEER_HOST, name);
        group->conf->group = group;
@@ -2668,7 +2682,11 @@ static void peer_group2peer_config_copy(struct peer_group *group,
        /* Update GR flags for the peer. */
        bgp_peer_gr_flags_update(peer);
 
-       bgp_bfd_peer_group2peer_copy(conf, peer);
+       /* Apply BFD settings from group to peer if it exists. */
+       if (conf->bfd_config) {
+               bgp_peer_configure_bfd(peer, false);
+               bgp_peer_config_apply(peer, group);
+       }
 }
 
 /* Peer group's remote AS configuration.  */
@@ -2758,7 +2776,8 @@ int peer_group_delete(struct peer_group *group)
        XFREE(MTYPE_PEER_GROUP_HOST, group->name);
        group->name = NULL;
 
-       bfd_info_free(&(group->conf->bfd_info));
+       if (group->conf->bfd_config)
+               bgp_peer_remove_bfd_config(group->conf);
 
        group->conf->group = NULL;
        peer_delete(group->conf);
@@ -2996,7 +3015,7 @@ int peer_group_bind(struct bgp *bgp, union sockunion *su, struct peer *peer,
                }
 
                peer = peer_create(su, NULL, bgp, bgp->as, group->conf->as,
-                                  group->conf->as_type, 0, 0, group);
+                                  group->conf->as_type, group);
 
                peer = peer_lock(peer); /* group->peer list reference */
                listnode_add(group->peer, peer);
@@ -3008,7 +3027,10 @@ int peer_group_bind(struct bgp *bgp, union sockunion *su, struct peer *peer,
                FOREACH_AFI_SAFI (afi, safi) {
                        if (group->conf->afc[afi][safi]) {
                                peer->afc[afi][safi] = 1;
-                               peer_af_create(peer, afi, safi);
+
+                               if (!peer_af_find(peer, afi, safi))
+                                       peer_af_create(peer, afi, safi);
+
                                peer_group2peer_config_copy_af(group, peer, afi,
                                                               safi);
                        } else if (peer->afc[afi][safi])
@@ -3807,7 +3829,7 @@ struct peer *peer_create_bind_dynamic_neighbor(struct bgp *bgp,
 
        /* Create peer first; we've already checked group config is valid. */
        peer = peer_create(su, NULL, bgp, bgp->as, group->conf->as,
-                          group->conf->as_type, 0, 0, group);
+                          group->conf->as_type, group);
        if (!peer)
                return NULL;
 
@@ -7687,7 +7709,7 @@ void bgp_init(unsigned short instance)
        bgp_clist = community_list_init();
 
        /* BFD init */
-       bgp_bfd_init();
+       bgp_bfd_init(bm->master);
 
        bgp_lp_vty_init();
 
index 3f5ec0779676f6d2c809d9f841c057ed61888d10..6270542178cafa7ab9025997ddadbf3afa9a9811 100644 (file)
@@ -45,6 +45,8 @@
 #include "bgp_nexthop.h"
 #include "bgp_damp.h"
 
+#include "lib/bfd.h"
+
 #define BGP_MAX_HOSTNAME 64    /* Linux max, is larger than most other sys */
 #define BGP_PEER_MAX_HASH_SIZE 16384
 
@@ -175,9 +177,9 @@ struct bgp_master {
 #define BM_FLAG_SEND_EXTRA_DATA_TO_ZEBRA (1 << 1)
 
        bool terminating;       /* global flag that sigint terminate seen */
-       QOBJ_FIELDS
+       QOBJ_FIELDS;
 };
-DECLARE_QOBJ_TYPE(bgp_master)
+DECLARE_QOBJ_TYPE(bgp_master);
 
 /* BGP route-map structure.  */
 struct bgp_rmap {
@@ -477,6 +479,7 @@ struct bgp {
 #define BGP_FLAG_SHUTDOWN                 (1 << 27)
 #define BGP_FLAG_SUPPRESS_FIB_PENDING     (1 << 28)
 #define BGP_FLAG_SUPPRESS_DUPLICATES      (1 << 29)
+#define BGP_FLAG_DEFAULT_IPV6             (1 << 30)
 
        enum global_mode GLOBAL_GR_FSM[BGP_GLOBAL_GR_MODE]
                                      [BGP_GLOBAL_GR_EVENT_CMD];
@@ -710,14 +713,14 @@ struct bgp {
        /* BGP route flap dampening configuration */
        struct bgp_damp_config damp[AFI_MAX][SAFI_MAX];
 
-       QOBJ_FIELDS
+       QOBJ_FIELDS;
 };
-DECLARE_QOBJ_TYPE(bgp)
+DECLARE_QOBJ_TYPE(bgp);
 
-DECLARE_HOOK(bgp_inst_delete, (struct bgp *bgp), (bgp))
+DECLARE_HOOK(bgp_inst_delete, (struct bgp *bgp), (bgp));
 DECLARE_HOOK(bgp_inst_config_write,
                (struct bgp *bgp, struct vty *vty),
-               (bgp, vty))
+               (bgp, vty));
 
 /* Thread callback information */
 struct afi_safi_info {
@@ -1557,8 +1560,29 @@ struct peer {
 #define PEER_RMAP_TYPE_EXPORT         (1U << 7) /* neighbor route-map export */
 #define PEER_RMAP_TYPE_AGGREGATE      (1U << 8) /* aggregate-address route-map */
 
-       /* peer specific BFD information */
-       struct bfd_info *bfd_info;
+       /** Peer overwrite configuration. */
+       struct bfd_session_config {
+               /**
+                * Manual configuration bit.
+                *
+                * This flag only makes sense for real peers (and not groups),
+                * it keeps track if the user explicitly configured BFD for a
+                * peer.
+                */
+               bool manual;
+               /** Control Plane Independent. */
+               bool cbit;
+               /** Detection multiplier. */
+               uint8_t detection_multiplier;
+               /** Minimum required RX interval. */
+               uint32_t min_rx;
+               /** Minimum required TX interval. */
+               uint32_t min_tx;
+               /** Profile name. */
+               char profile[BFD_PROFILE_NAME_LEN];
+               /** Peer BFD session */
+               struct bfd_session_params *session;
+       } * bfd_config;
 
        /* hostname and domainname advertised by host */
        char *hostname;
@@ -1574,9 +1598,9 @@ struct peer {
        bool advmap_config_change[AFI_MAX][SAFI_MAX];
        bool advmap_table_change;
 
-       QOBJ_FIELDS
+       QOBJ_FIELDS;
 };
-DECLARE_QOBJ_TYPE(peer)
+DECLARE_QOBJ_TYPE(peer);
 
 /* Inherit peer attribute from peer-group. */
 #define PEER_ATTR_INHERIT(peer, group, attr)                                   \
@@ -1922,8 +1946,7 @@ extern bool peer_active(struct peer *);
 extern bool peer_active_nego(struct peer *);
 extern void bgp_recalculate_all_bestpaths(struct bgp *bgp);
 extern struct peer *peer_create(union sockunion *, const char *, struct bgp *,
-                               as_t, as_t, int, afi_t, safi_t,
-                               struct peer_group *);
+                               as_t, as_t, int, struct peer_group *);
 extern struct peer *peer_create_accept(struct bgp *);
 extern void peer_xfer_config(struct peer *dst, struct peer *src);
 extern char *peer_uptime(time_t uptime2, char *buf, size_t len, bool use_json,
@@ -1991,7 +2014,7 @@ extern bool bgp_update_delay_configured(struct bgp *);
 extern int bgp_afi_safi_peer_exists(struct bgp *bgp, afi_t afi, safi_t safi);
 extern void peer_as_change(struct peer *, as_t, int);
 extern int peer_remote_as(struct bgp *, union sockunion *, const char *, as_t *,
-                         int, afi_t, safi_t);
+                         int);
 extern int peer_group_remote_as(struct bgp *, const char *, as_t *, int);
 extern int peer_delete(struct peer *peer);
 extern void peer_notify_unconfig(struct peer *peer);
@@ -2364,17 +2387,17 @@ extern int bgp_lookup_by_as_name_type(struct bgp **bgp_val, as_t *as,
 
 /* Hooks */
 DECLARE_HOOK(bgp_vrf_status_changed, (struct bgp *bgp, struct interface *ifp),
-            (bgp, ifp))
-DECLARE_HOOK(peer_status_changed, (struct peer *peer), (peer))
-DECLARE_HOOK(bgp_snmp_init_stats, (struct bgp *bgp), (bgp))
-DECLARE_HOOK(bgp_snmp_update_last_changed, (struct bgp *bgp), (bgp))
+            (bgp, ifp));
+DECLARE_HOOK(peer_status_changed, (struct peer *peer), (peer));
+DECLARE_HOOK(bgp_snmp_init_stats, (struct bgp *bgp), (bgp));
+DECLARE_HOOK(bgp_snmp_update_last_changed, (struct bgp *bgp), (bgp));
 DECLARE_HOOK(bgp_snmp_update_stats,
             (struct bgp_node *rn, struct bgp_path_info *pi, bool added),
-            (rn, pi, added))
+            (rn, pi, added));
 DECLARE_HOOK(bgp_rpki_prefix_status,
             (struct peer * peer, struct attr *attr,
              const struct prefix *prefix),
-            (peer, attr, prefix))
+            (peer, attr, prefix));
 
 void peer_nsf_stop(struct peer *peer);
 
index 88c92f7954ad89319f11ef1d0828419952478ee5..cc64261388c6f09bbdf9f89785636a27663b0890 100644 (file)
 #undef BGP_VNC_DEBUG_MATCH_GROUP
 
 
-DEFINE_MGROUP(RFAPI, "rfapi")
-DEFINE_MTYPE(RFAPI, RFAPI_CFG, "NVE Configuration")
-DEFINE_MTYPE(RFAPI, RFAPI_GROUP_CFG, "NVE Group Configuration")
-DEFINE_MTYPE(RFAPI, RFAPI_L2_CFG, "RFAPI L2 Group Configuration")
-DEFINE_MTYPE(RFAPI, RFAPI_RFP_GROUP_CFG, "RFAPI RFP Group Configuration")
-DEFINE_MTYPE(RFAPI, RFAPI, "RFAPI Generic")
-DEFINE_MTYPE(RFAPI, RFAPI_DESC, "RFAPI Descriptor")
-DEFINE_MTYPE(RFAPI, RFAPI_IMPORTTABLE, "RFAPI Import Table")
-DEFINE_MTYPE(RFAPI, RFAPI_MONITOR, "RFAPI Monitor VPN")
-DEFINE_MTYPE(RFAPI, RFAPI_MONITOR_ENCAP, "RFAPI Monitor Encap")
-DEFINE_MTYPE(RFAPI, RFAPI_NEXTHOP, "RFAPI Next Hop")
-DEFINE_MTYPE(RFAPI, RFAPI_VN_OPTION, "RFAPI VN Option")
-DEFINE_MTYPE(RFAPI, RFAPI_UN_OPTION, "RFAPI UN Option")
-DEFINE_MTYPE(RFAPI, RFAPI_WITHDRAW, "RFAPI Withdraw")
-DEFINE_MTYPE(RFAPI, RFAPI_RFG_NAME, "RFAPI RFGName")
-DEFINE_MTYPE(RFAPI, RFAPI_ADB, "RFAPI Advertisement Data")
-DEFINE_MTYPE(RFAPI, RFAPI_ETI, "RFAPI Export Table Info")
-DEFINE_MTYPE(RFAPI, RFAPI_NVE_ADDR, "RFAPI NVE Address")
-DEFINE_MTYPE(RFAPI, RFAPI_PREFIX_BAG, "RFAPI Prefix Bag")
-DEFINE_MTYPE(RFAPI, RFAPI_IT_EXTRA, "RFAPI IT Extra")
-DEFINE_MTYPE(RFAPI, RFAPI_INFO, "RFAPI Info")
-DEFINE_MTYPE(RFAPI, RFAPI_ADDR, "RFAPI Addr")
-DEFINE_MTYPE(RFAPI, RFAPI_UPDATED_RESPONSE_QUEUE, "RFAPI Updated Rsp Queue")
-DEFINE_MTYPE(RFAPI, RFAPI_RECENT_DELETE, "RFAPI Recently Deleted Route")
-DEFINE_MTYPE(RFAPI, RFAPI_L2ADDR_OPT, "RFAPI L2 Address Option")
-DEFINE_MTYPE(RFAPI, RFAPI_AP, "RFAPI Advertised Prefix")
-DEFINE_MTYPE(RFAPI, RFAPI_MONITOR_ETH, "RFAPI Monitor Ethernet")
-
-DEFINE_QOBJ_TYPE(rfapi_nve_group_cfg)
-DEFINE_QOBJ_TYPE(rfapi_l2_group_cfg)
+DEFINE_MGROUP(RFAPI, "rfapi");
+DEFINE_MTYPE(RFAPI, RFAPI_CFG, "NVE Configuration");
+DEFINE_MTYPE(RFAPI, RFAPI_GROUP_CFG, "NVE Group Configuration");
+DEFINE_MTYPE(RFAPI, RFAPI_L2_CFG, "RFAPI L2 Group Configuration");
+DEFINE_MTYPE(RFAPI, RFAPI_RFP_GROUP_CFG, "RFAPI RFP Group Configuration");
+DEFINE_MTYPE(RFAPI, RFAPI, "RFAPI Generic");
+DEFINE_MTYPE(RFAPI, RFAPI_DESC, "RFAPI Descriptor");
+DEFINE_MTYPE(RFAPI, RFAPI_IMPORTTABLE, "RFAPI Import Table");
+DEFINE_MTYPE(RFAPI, RFAPI_MONITOR, "RFAPI Monitor VPN");
+DEFINE_MTYPE(RFAPI, RFAPI_MONITOR_ENCAP, "RFAPI Monitor Encap");
+DEFINE_MTYPE(RFAPI, RFAPI_NEXTHOP, "RFAPI Next Hop");
+DEFINE_MTYPE(RFAPI, RFAPI_VN_OPTION, "RFAPI VN Option");
+DEFINE_MTYPE(RFAPI, RFAPI_UN_OPTION, "RFAPI UN Option");
+DEFINE_MTYPE(RFAPI, RFAPI_WITHDRAW, "RFAPI Withdraw");
+DEFINE_MTYPE(RFAPI, RFAPI_RFG_NAME, "RFAPI RFGName");
+DEFINE_MTYPE(RFAPI, RFAPI_ADB, "RFAPI Advertisement Data");
+DEFINE_MTYPE(RFAPI, RFAPI_ETI, "RFAPI Export Table Info");
+DEFINE_MTYPE(RFAPI, RFAPI_NVE_ADDR, "RFAPI NVE Address");
+DEFINE_MTYPE(RFAPI, RFAPI_PREFIX_BAG, "RFAPI Prefix Bag");
+DEFINE_MTYPE(RFAPI, RFAPI_IT_EXTRA, "RFAPI IT Extra");
+DEFINE_MTYPE(RFAPI, RFAPI_INFO, "RFAPI Info");
+DEFINE_MTYPE(RFAPI, RFAPI_ADDR, "RFAPI Addr");
+DEFINE_MTYPE(RFAPI, RFAPI_UPDATED_RESPONSE_QUEUE, "RFAPI Updated Rsp Queue");
+DEFINE_MTYPE(RFAPI, RFAPI_RECENT_DELETE, "RFAPI Recently Deleted Route");
+DEFINE_MTYPE(RFAPI, RFAPI_L2ADDR_OPT, "RFAPI L2 Address Option");
+DEFINE_MTYPE(RFAPI, RFAPI_AP, "RFAPI Advertised Prefix");
+DEFINE_MTYPE(RFAPI, RFAPI_MONITOR_ETH, "RFAPI Monitor Ethernet");
+
+DEFINE_QOBJ_TYPE(rfapi_nve_group_cfg);
+DEFINE_QOBJ_TYPE(rfapi_l2_group_cfg);
 /***********************************************************************
  *                     RFAPI Support
  ***********************************************************************/
index f1548a6173cb13d09769d75e7aad52c7b32c4dfe..ef97419c4d01bb8c52ed432d33e83572fbce3ba8 100644 (file)
@@ -35,9 +35,9 @@ struct rfapi_l2_group_cfg {
        struct ecommunity *rt_export_list;
        void *rfp_cfg; /* rfp owned group config */
 
-       QOBJ_FIELDS
+       QOBJ_FIELDS;
 };
-DECLARE_QOBJ_TYPE(rfapi_l2_group_cfg)
+DECLARE_QOBJ_TYPE(rfapi_l2_group_cfg);
 
 typedef enum {
        RFAPI_GROUP_CFG_NVE = 1,
@@ -108,9 +108,9 @@ struct rfapi_nve_group_cfg {
        /* for VRF type groups */
        uint32_t label;
        struct rfapi_descriptor *rfd;
-       QOBJ_FIELDS
+       QOBJ_FIELDS;
 };
-DECLARE_QOBJ_TYPE(rfapi_nve_group_cfg)
+DECLARE_QOBJ_TYPE(rfapi_nve_group_cfg);
 
 struct rfapi_rfg_name {
        struct rfapi_nve_group_cfg *rfg;
index af563679552dc81ee685b70c12f2b1158dfcc242..e7825e8bfcbc93fbce8e94bfdbace7a24bccabae 100644 (file)
@@ -367,33 +367,33 @@ extern int rfapi_extract_l2o(
  */
 extern time_t rfapi_time(time_t *t);
 
-DECLARE_MGROUP(RFAPI)
-DECLARE_MTYPE(RFAPI_CFG)
-DECLARE_MTYPE(RFAPI_GROUP_CFG)
-DECLARE_MTYPE(RFAPI_L2_CFG)
-DECLARE_MTYPE(RFAPI_RFP_GROUP_CFG)
-DECLARE_MTYPE(RFAPI)
-DECLARE_MTYPE(RFAPI_DESC)
-DECLARE_MTYPE(RFAPI_IMPORTTABLE)
-DECLARE_MTYPE(RFAPI_MONITOR)
-DECLARE_MTYPE(RFAPI_MONITOR_ENCAP)
-DECLARE_MTYPE(RFAPI_NEXTHOP)
-DECLARE_MTYPE(RFAPI_VN_OPTION)
-DECLARE_MTYPE(RFAPI_UN_OPTION)
-DECLARE_MTYPE(RFAPI_WITHDRAW)
-DECLARE_MTYPE(RFAPI_RFG_NAME)
-DECLARE_MTYPE(RFAPI_ADB)
-DECLARE_MTYPE(RFAPI_ETI)
-DECLARE_MTYPE(RFAPI_NVE_ADDR)
-DECLARE_MTYPE(RFAPI_PREFIX_BAG)
-DECLARE_MTYPE(RFAPI_IT_EXTRA)
-DECLARE_MTYPE(RFAPI_INFO)
-DECLARE_MTYPE(RFAPI_ADDR)
-DECLARE_MTYPE(RFAPI_UPDATED_RESPONSE_QUEUE)
-DECLARE_MTYPE(RFAPI_RECENT_DELETE)
-DECLARE_MTYPE(RFAPI_L2ADDR_OPT)
-DECLARE_MTYPE(RFAPI_AP)
-DECLARE_MTYPE(RFAPI_MONITOR_ETH)
+DECLARE_MGROUP(RFAPI);
+DECLARE_MTYPE(RFAPI_CFG);
+DECLARE_MTYPE(RFAPI_GROUP_CFG);
+DECLARE_MTYPE(RFAPI_L2_CFG);
+DECLARE_MTYPE(RFAPI_RFP_GROUP_CFG);
+DECLARE_MTYPE(RFAPI);
+DECLARE_MTYPE(RFAPI_DESC);
+DECLARE_MTYPE(RFAPI_IMPORTTABLE);
+DECLARE_MTYPE(RFAPI_MONITOR);
+DECLARE_MTYPE(RFAPI_MONITOR_ENCAP);
+DECLARE_MTYPE(RFAPI_NEXTHOP);
+DECLARE_MTYPE(RFAPI_VN_OPTION);
+DECLARE_MTYPE(RFAPI_UN_OPTION);
+DECLARE_MTYPE(RFAPI_WITHDRAW);
+DECLARE_MTYPE(RFAPI_RFG_NAME);
+DECLARE_MTYPE(RFAPI_ADB);
+DECLARE_MTYPE(RFAPI_ETI);
+DECLARE_MTYPE(RFAPI_NVE_ADDR);
+DECLARE_MTYPE(RFAPI_PREFIX_BAG);
+DECLARE_MTYPE(RFAPI_IT_EXTRA);
+DECLARE_MTYPE(RFAPI_INFO);
+DECLARE_MTYPE(RFAPI_ADDR);
+DECLARE_MTYPE(RFAPI_UPDATED_RESPONSE_QUEUE);
+DECLARE_MTYPE(RFAPI_RECENT_DELETE);
+DECLARE_MTYPE(RFAPI_L2ADDR_OPT);
+DECLARE_MTYPE(RFAPI_AP);
+DECLARE_MTYPE(RFAPI_MONITOR_ETH);
 
 
 /*
index 4614363bf01431bcf890f15fe151d9e9b0506620..3991f7d1ed8420bcc6d40fd079006f6142f21d7b 100644 (file)
@@ -220,7 +220,7 @@ bgpd_bgpd_LDADD = bgpd/libbgp.a $(RFPLDADD) lib/libfrr.la $(LIBCAP) $(LIBM) $(US
 bgpd_bgp_btoa_LDADD = bgpd/libbgp.a $(RFPLDADD) lib/libfrr.la $(LIBCAP) $(LIBM) $(UST_LIBS)
 
 bgpd_bgpd_snmp_la_SOURCES = bgpd/bgp_snmp.c  bgpd/bgp_mplsvpn_snmp.c
-bgpd_bgpd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu99
+bgpd_bgpd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu11
 bgpd_bgpd_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
 bgpd_bgpd_snmp_la_LIBADD = lib/libfrrsnmp.la
 
index 139fca7c42280691a57100edd96539ef8a9d1ebf..f9516e559f645be078d2e9836c3e24d619f7d64a 100755 (executable)
@@ -288,11 +288,17 @@ if test "$enable_clang_coverage" = "yes"; then
 fi
 
 if test "$enable_scripting" = "yes"; then
-   AX_PROG_LUA([5.3])
-   AX_LUA_HEADERS
+   AX_PROG_LUA([5.3], [5.4], [], [
+     AC_MSG_ERROR([Lua 5.3 is required to build with Lua support. No other version is supported.])
+   ])
+   AX_LUA_HEADERS([], [
+     AC_MSG_ERROR([Lua 5.3 headers are required to build with Lua support. No other version is supported.])
+   ])
    AX_LUA_LIBS([
-      AC_DEFINE([HAVE_SCRIPTING], [1], [Have support for scripting])
-      LIBS="$LIBS $LUA_LIB"
+     AC_DEFINE([HAVE_SCRIPTING], [1], [Have support for scripting])
+     LIBS="$LIBS $LUA_LIB"
+   ], [
+     AC_MSG_ERROR([Lua 5.3 libraries are required to build with Lua support. No other version is supported.])
    ])
 fi
 
@@ -301,6 +307,7 @@ if test "$enable_dev_build" = "yes"; then
    if test "$orig_cflags" = ""; then
       AC_C_FLAG([-g3])
       AC_C_FLAG([-O0])
+      AC_C_FLAG([-ggdb3])
    fi
 else
    if test "$orig_cflags" = ""; then
@@ -308,6 +315,7 @@ else
       AC_C_FLAG([-O2])
    fi
 fi
+
 AM_CONDITIONAL([DEV_BUILD], [test "$enable_dev_build" = "yes"])
 
 dnl always want these CFLAGS
@@ -1723,12 +1731,10 @@ fi
 
 AS_IF([test "$enable_pathd" != "no"], [
   AC_DEFINE([HAVE_PATHD], [1], [pathd])
-])
-
-AS_IF([test "$enable_pcep" != "no"], [
   AC_DEFINE([HAVE_PATHD_PCEP], [1], [pathd-pcep])
 ])
 
+
 if test "$ac_cv_lib_json_c_json_object_get" = "no" -a "$BFDD" = "bfdd"; then
   AC_MSG_ERROR(["you must use json-c library to use bfdd"])
 fi
@@ -2550,15 +2556,14 @@ AM_CONDITIONAL([HAVE_PROTOBUF], [test "$enable_protobuf" = "yes"])
 AM_CONDITIONAL([HAVE_PROTOBUF3], [$PROTO3])
 
 dnl PCEP plugin
-AM_CONDITIONAL([HAVE_PATHD_PCEP], [test "$enable_pcep" = "yes"])
-AS_IF([test "$enable_pcep" = "yes"], [
-  AC_CHECK_LIB([pcep_pcc], [initialize_pcc], [
-    PATHD_PCEP_LIBS="-lpcep_pcc"
-  ],[
-    AC_MSG_ERROR([PCEP library libpcep_pcc not found])
-  ])
-  AC_SUBST([PATHD_PCEP_LIBS])
-])
+AS_IF([test "$enable_pathd" != "no"], [
+       AC_SUBST([PATHD_PCEP_LIBS], ["pceplib/libpcep_pcc.la"])
+       AC_SUBST([PATHD_PCEP_INCL], ["-I./pceplib "])
+       ])
+AC_CHECK_LIB([cunit], [CU_initialize_registry], [pcep_cunit=yes],[pcep_cunit=no])
+AM_CONDITIONAL([PATHD_PCEP_TEST], [test "x${pcep_cunit}" = xyes])
+AC_CHECK_PROG(VALGRIND_CHECK, valgrind, yes)
+AM_CONDITIONAL([HAVE_VALGRIND_PCEP], [test "$VALGRIND_CHECK" = "yes"])
 
 dnl daemons
 AM_CONDITIONAL([VTYSH], [test "$VTYSH" = "vtysh"])
@@ -2583,6 +2588,7 @@ AM_CONDITIONAL([STATICD], [test "$enable_staticd" != "no"])
 AM_CONDITIONAL([FABRICD], [test "$enable_fabricd" != "no"])
 AM_CONDITIONAL([VRRPD], [test "$enable_vrrpd" != "no"])
 AM_CONDITIONAL([PATHD], [test "$enable_pathd" != "no"])
+AM_CONDITIONAL([PATHD_PCEP], [test "$enable_pathd" != "no"])
 
 AC_CONFIG_FILES([Makefile],[
        test "$enable_dev_build" = "yes" && makefile_devbuild="--dev-build"
index cefc3135b2e5d1f82c30a381b90f24f59fc3c779..9972b579f0f4152f576a7c07e62a232c4ae160a6 100644 (file)
@@ -11,6 +11,7 @@ usr/lib/*/frr/modules/dplane_fpm_nl.so
 usr/lib/*/frr/modules/zebra_cumulus_mlag.so
 usr/lib/*/frr/modules/zebra_fpm.so
 usr/lib/*/frr/modules/zebra_irdp.so
+usr/lib/*/frr/modules/pathd_pcep.so
 usr/lib/frr/*.sh
 usr/lib/frr/*d
 usr/lib/frr/watchfrr
index ffc05a6841ff455e5670eae9fd9b629a500325aa..58d72e2891c670896806fecc3188fb04e0c6ae85 100644 (file)
@@ -27,7 +27,7 @@ ubuntu apt repositories; in order to install it:
 
 .. code-block:: shell
 
-   curl https://bootstrap.pypa.io/2.7/get-pip.py --output get-pip.py
+   curl https://bootstrap.pypa.io/pip/2.7/get-pip.py --output get-pip.py
    sudo python2 ./get-pip.py
 
    # And verify the installation
index 339e00c9216def2db88812fc09b28f7ec2065fde..3bf78f7633fc98ef3b5a427154857174f1d397a1 100644 (file)
@@ -189,7 +189,7 @@ later on to FRR. One may get burned when compiling gRPC if the ``protoc``
 version on the build machine differs from the version of ``protoc`` being linked
 to during a gRPC build. The error messages from this defect look like:
 
-.. code-block:: terminal
+.. code-block:: shell
 
    gens/src/proto/grpc/channelz/channelz.pb.h: In member function â€˜void grpc::channelz::v1::ServerRef::set_name(const char*, size_t)’:
    gens/src/proto/grpc/channelz/channelz.pb.h:9127:64: error: â€˜EmptyDefault’ is not a member of â€˜google::protobuf::internal::ArenaStringPtr’
index 10fe6b9c43605b656e94978a6df37455128eec61..b37a4aeea7aa01018afe62617206de8db4e43a74 100644 (file)
@@ -15,13 +15,13 @@ Example:
    :caption: mydaemon.h
 
    #include "hook.h"
-   DECLARE_HOOK(some_update_event, (struct eventinfo *info), (info))
+   DECLARE_HOOK(some_update_event, (struct eventinfo *info), (info));
 
 .. code-block:: c
    :caption: mydaemon.c
 
    #include "mydaemon.h"
-   DEFINE_HOOK(some_update_event, (struct eventinfo *info), (info))
+   DEFINE_HOOK(some_update_event, (struct eventinfo *info), (info));
    ...
    hook_call(some_update_event, info);
 
@@ -110,9 +110,9 @@ Definition
 
    .. code-block:: c
 
-      DECLARE_HOOK(foo, (), ())
-      DECLARE_HOOK(bar, (int arg), (arg))
-      DECLARE_HOOK(baz, (const void *x, in_addr_t y), (x, y))
+      DECLARE_HOOK(foo, (), ());
+      DECLARE_HOOK(bar, (int arg), (arg));
+      DECLARE_HOOK(baz, (const void *x, in_addr_t y), (x, y));
 
 .. c:macro:: DEFINE_HOOK(name, arglist, passlist)
 
diff --git a/doc/developer/images/PCEPlib_design.jpg b/doc/developer/images/PCEPlib_design.jpg
new file mode 100644 (file)
index 0000000..41aada3
Binary files /dev/null and b/doc/developer/images/PCEPlib_design.jpg differ
diff --git a/doc/developer/images/PCEPlib_internal_deps.jpg b/doc/developer/images/PCEPlib_internal_deps.jpg
new file mode 100644 (file)
index 0000000..8380021
Binary files /dev/null and b/doc/developer/images/PCEPlib_internal_deps.jpg differ
diff --git a/doc/developer/images/PCEPlib_socket_comm.jpg b/doc/developer/images/PCEPlib_socket_comm.jpg
new file mode 100644 (file)
index 0000000..3d62a46
Binary files /dev/null and b/doc/developer/images/PCEPlib_socket_comm.jpg differ
diff --git a/doc/developer/images/PCEPlib_threading_model.jpg b/doc/developer/images/PCEPlib_threading_model.jpg
new file mode 100644 (file)
index 0000000..afe91c2
Binary files /dev/null and b/doc/developer/images/PCEPlib_threading_model.jpg differ
diff --git a/doc/developer/images/PCEPlib_threading_model_frr_infra.jpg b/doc/developer/images/PCEPlib_threading_model_frr_infra.jpg
new file mode 100644 (file)
index 0000000..5648a9d
Binary files /dev/null and b/doc/developer/images/PCEPlib_threading_model_frr_infra.jpg differ
diff --git a/doc/developer/images/PCEPlib_timers.jpg b/doc/developer/images/PCEPlib_timers.jpg
new file mode 100644 (file)
index 0000000..a178ee9
Binary files /dev/null and b/doc/developer/images/PCEPlib_timers.jpg differ
index 8e7913419f2d982c77b1d7cfbe149da69fe58777..46fd8f612e891f2e284097e82df58e7c134f46f9 100644 (file)
@@ -19,4 +19,5 @@ FRRouting Developer's Guide
    zebra
    vtysh
    path
+   pceplib
    link-state
index 28b21533c0450f66f326b6a721720875a743d360..86db788c0e47766da8f90df8e50cb1702f8c9651 100644 (file)
@@ -140,7 +140,7 @@ The common setup pattern will look like this:
 
    #include <typesafe.h>
 
-   PREDECL_XXX(Z)
+   PREDECL_XXX(Z);
    struct item {
        int otherdata;
        struct Z_item mylistitem;
@@ -149,20 +149,20 @@ The common setup pattern will look like this:
    struct Z_head mylisthead;
 
    /* unsorted: */
-   DECLARE_XXX(Z, struct item, mylistitem)
+   DECLARE_XXX(Z, struct item, mylistitem);
 
    /* sorted, items that compare as equal cannot be added to list */
    int compare_func(const struct item *a, const struct item *b);
-   DECLARE_XXX_UNIQ(Z, struct item, mylistitem, compare_func)
+   DECLARE_XXX_UNIQ(Z, struct item, mylistitem, compare_func);
 
    /* sorted, items that compare as equal can be added to list */
    int compare_func(const struct item *a, const struct item *b);
-   DECLARE_XXX_NONUNIQ(Z, struct item, mylistitem, compare_func)
+   DECLARE_XXX_NONUNIQ(Z, struct item, mylistitem, compare_func);
 
    /* hash tables: */
    int compare_func(const struct item *a, const struct item *b);
    uint32_t hash_func(const struct item *a);
-   DECLARE_XXX(Z, struct item, mylistitem, compare_func, hash_func)
+   DECLARE_XXX(Z, struct item, mylistitem, compare_func, hash_func);
 
 ``XXX`` is replaced with the name of the data structure, e.g. ``SKIPLIST``
 or ``ATOMLIST``.  The ``DECLARE_XXX`` invocation can either occur in a `.h`
index 952b316ea0b208392207b8db1aec6cf7050363bd..08dad7fb6804cfac57edf55e1cd8ca1c4267dfd3 100644 (file)
@@ -15,15 +15,15 @@ Example:
 .. code-block:: c
    :caption: mydaemon.h
 
-   DECLARE_MGROUP(MYDAEMON)
-   DECLARE_MTYPE(MYNEIGHBOR)
+   DECLARE_MGROUP(MYDAEMON);
+   DECLARE_MTYPE(MYNEIGHBOR);
 
 .. code-block:: c
    :caption: mydaemon.c
 
-   DEFINE_MGROUP(      MYDAEMON, "My daemon's memory")
-   DEFINE_MTYPE(       MYDAEMON, MYNEIGHBOR,     "Neighbor entry")
-   DEFINE_MTYPE_STATIC(MYDAEMON, MYNEIGHBORNAME, "Neighbor name")
+   DEFINE_MGROUP(      MYDAEMON, "My daemon's memory");
+   DEFINE_MTYPE(       MYDAEMON, MYNEIGHBOR,     "Neighbor entry");
+   DEFINE_MTYPE_STATIC(MYDAEMON, MYNEIGHBORNAME, "Neighbor name");
 
    struct neigh *neighbor_new(const char *name)
    {
index 02330ddfe4503538e10bc13cf5fef5e34bf4fb84..e95f8a1b4a72eebd2f63c95b30f5e801056bd2bd 100644 (file)
@@ -76,7 +76,7 @@ Basic boilerplate:
         .version = "0.0",
         .description = "my module",
         .init = module_init,
-    )
+    );
 
 The ``frr_late_init`` hook will be called after the daemon has finished
 its other startup and is about to enter the main event loop; this is the
diff --git a/doc/developer/pceplib.rst b/doc/developer/pceplib.rst
new file mode 100644 (file)
index 0000000..774617d
--- /dev/null
@@ -0,0 +1,781 @@
+.. _pceplib:
+
+*******
+PCEPlib
+*******
+
+Overview
+========
+
+The PCEPlib is a PCEP implementation library that can be used by either a PCE
+or PCC.
+
+Currently, only the FRR pathd has been implemented as a PCC with the PCEPlib.
+The PCEPlib is able to simultaneously connect to multiple PCEP peers and can
+maintain persistent PCEP connections.
+
+
+PCEPlib compliance
+==================
+
+The PCEPlib implements version 1 of the PCEP protocol, according to `RFC 5440 <https://tools.ietf.org/html/rfc5440>`_.
+
+Additionally, the PCEPlib implements the following PCEP extensions:
+
+- `RFC 8281 <https://tools.ietf.org/html/rfc8281>`_ PCE initiated for PCE-Initiated LSP Setup
+- `RFC 8231 <https://tools.ietf.org/html/rfc8231>`_ Extensions for Stateful PCE
+- `RFC 8232 <https://tools.ietf.org/html/rfc8232>`_ Optimizations of Label Switched Path State Synchronization Procedures for a Stateful PCE
+- `RFC 8282 <https://tools.ietf.org/html/rfc8282>`_ Extensions to PCEP for Inter-Layer MPLS and GMPLS Traffic Engineering
+- `RFC 8408 <https://tools.ietf.org/html/rfc8408>`_ Conveying Path Setup Type in PCE Communication Protocol (PCEP) Messages
+- `draft-ietf-pce-segment-routing-07 <https://tools.ietf.org/html/draft-ietf-pce-segment-routing-07>`_,
+  `draft-ietf-pce-segment-routing-16 <https://tools.ietf.org/html/draft-ietf-pce-segment-routing-16>`_,
+  `RFC 8664 <https://tools.ietf.org/html/rfc8664>`_ Segment routing protocol extensions
+- `RFC 7470 <https://tools.ietf.org/html/rfc7470>`_ Conveying Vendor-Specific Constraints
+- `Draft-ietf-pce-association-group-10 <https://tools.ietf.org/html/draft-ietf-pce-association-group-10>`_
+  Establishing Relationships Between Sets of Label Switched Paths
+- `Draft-barth-pce-segment-routing-policy-cp-04 <https://tools.ietf.org/html/draft-barth-pce-segment-routing-policy-cp-04>`_
+  Segment Routing Policy Candidate Paths
+
+
+PCEPlib Architecture
+====================
+
+The PCEPlib is comprised of the following modules, each of which will be
+detailed in the following sections.
+
+- **pcep_messages**
+    - PCEP messages, objects, and TLVs implementations
+    
+- **pcep_pcc**
+    - PCEPlib public PCC API with a sample PCC binary
+
+- **pcep_session_logic**
+    - PCEP Session handling
+
+- **pcep_socket_comm**
+    - Socket communications
+
+- **pcep_timers**
+    - PCEP timers
+
+- **pcep_utils**
+    - Internal utilities used by the PCEPlib modules.
+
+The interaction of these modules can be seen in the following diagram.
+
+PCEPlib Architecture:
+
+.. image:: images/PCEPlib_design.jpg
+
+
+PCEP Session Logic library
+--------------------------
+
+The PCEP Session Logic library orchestrates calls to the rest of the PCC libraries.
+
+PCEP Session Logic library responsibilities:
+
+- Handle messages received from "PCEP Socket Comm"
+- Create and manage "PCEP Session" objects
+- Set timers and react to timer expirations
+- Manage counters
+
+The PCEP Session Logic library will have 2 main triggers controlled by a
+pthread condition variable:
+
+- Timer expirations - ``on_timer_expire()`` callback
+- Messages received from PCEP SocketComm - ``message_received()`` callback
+
+The counters are created and managed using the ``pcep_utils/pcep_utils_counters.h``
+counters library. The following are the different counter groups managed:
+
+- **COUNTER_SUBGROUP_ID_RX_MSG**
+- **COUNTER_SUBGROUP_ID_TX_MSG**
+- **COUNTER_SUBGROUP_ID_RX_OBJ**
+- **COUNTER_SUBGROUP_ID_TX_OBJ**
+- **COUNTER_SUBGROUP_ID_RX_SUBOBJ**
+- **COUNTER_SUBGROUP_ID_TX_SUBOBJ**
+- **COUNTER_SUBGROUP_ID_RX_RO_SR_SUBOBJ**
+- **COUNTER_SUBGROUP_ID_TX_RO_SR_SUBOBJ**
+- **COUNTER_SUBGROUP_ID_RX_TLV**
+- **COUNTER_SUBGROUP_ID_TX_TLV**
+- **COUNTER_SUBGROUP_ID_EVENT**
+
+The counters can be obtained and reset as explained later in the PCEPlib PCC API.
+
+PCEP Socket Comm library
+------------------------
+
+PCEP communication can be configured to be handled internally in this simple
+library. When this library is instantiated by the PCEP Session Logic, callbacks
+are provided to handle received messages and error conditions. 
+
+The following diagram illustrates how the library works.
+
+PCEPlib Socket Comm:
+
+.. image:: images/PCEPlib_socket_comm.jpg
+
+
+PCEP Timers library
+-------------------
+
+Timers can be configured to be handled internally by this library. When this
+library is instantiated by the PCEP Session Logic, callbacks are provided to
+ha:0
+ndle timer expirations. The following timers are implemented and handled,
+according to `RFC 5440 <https://tools.ietf.org/html/rfc5440>`_.
+
+- Open KeepWait (fixed at 60 seconds)
+    - Set once the PCC sends an Open, and if it expires before receiving a KeepAlive or PCErr, then the PCC should send a PCErr and close the TCP connection
+
+- Keepalive timer
+    - How often the PCC should send Keepalive messages to the PCE (and vice-versa)
+    - The timer will be reset after any message is sent: any message serves as a Keepalive
+
+- DeadTimer
+    - If no messages are received before expiration, the session is declared as down
+    - Reset everytime any message is received
+
+- PCReq request timer
+    - How long the PCC waits for the PCE to reply to PCReq messages.
+
+PCEPlib Timers:
+
+.. image:: images/PCEPlib_timers.jpg
+
+
+PCEP Messages library
+---------------------
+
+The PCEP Messages library has all of the implemented PCEP messages, objects,
+TLVs, and related functionality.
+
+The following header files can be used for creating and handling received PCEP
+entities.
+
+- pcep-messages.h
+- pcep-objects.h
+- pcep-tlvs.h
+
+
+PCEP Messages
++++++++++++++
+
+The following PCEP messages can be created and received:
+
+- ``struct pcep_message*  pcep_msg_create_open(...);``
+- ``struct pcep_message*  pcep_msg_create_open_with_tlvs(...);``
+- ``struct pcep_message*  pcep_msg_create_request(...);``
+- ``struct pcep_message*  pcep_msg_create_request_ipv6(...);``
+- ``struct pcep_message*  pcep_msg_create_reply(...);``
+- ``struct pcep_message*  pcep_msg_create_close(...);``
+- ``struct pcep_message*  pcep_msg_create_error(...);``
+- ``struct pcep_message*  pcep_msg_create_error_with_objects(...);``
+- ``struct pcep_message*  pcep_msg_create_keepalive(...);``
+- ``struct pcep_message*  pcep_msg_create_report(...);``
+- ``struct pcep_message*  pcep_msg_create_update(...);``
+- ``struct pcep_message*  pcep_msg_create_initiate(...);``
+
+Refer to ``pcep_messages/include/pcep-messages.h`` and the API section
+below for more details.
+
+
+PCEP Objects
+++++++++++++
+
+The following PCEP objects can be created and received:
+
+- ``struct pcep_object_open*             pcep_obj_create_open(...);``
+- ``struct pcep_object_rp*               pcep_obj_create_rp(...);``
+- ``struct pcep_object_notify*           pcep_obj_create_notify(...);``
+- ``struct pcep_object_nopath*           pcep_obj_create_nopath(...);``
+- ``struct pcep_object_association_ipv4* pcep_obj_create_association_ipv4(...);``
+- ``struct pcep_object_association_ipv6* pcep_obj_create_association_ipv6(...);``
+- ``struct pcep_object_endpoints_ipv4*   pcep_obj_create_endpoint_ipv4(...);``
+- ``struct pcep_object_endpoints_ipv6*   pcep_obj_create_endpoint_ipv6(...);``
+- ``struct pcep_object_bandwidth*        pcep_obj_create_bandwidth(...);``
+- ``struct pcep_object_metric*           pcep_obj_create_metric(...);``
+- ``struct pcep_object_lspa*             pcep_obj_create_lspa(...);``
+- ``struct pcep_object_svec*             pcep_obj_create_svec(...);``
+- ``struct pcep_object_error*            pcep_obj_create_error(...);``
+- ``struct pcep_object_close*            pcep_obj_create_close(...);``
+- ``struct pcep_object_srp*              pcep_obj_create_srp(...);``
+- ``struct pcep_object_lsp*              pcep_obj_create_lsp(...);``
+- ``struct pcep_object_vendor_info*      pcep_obj_create_vendor_info(...);``
+- ``struct pcep_object_ro*               pcep_obj_create_ero(...);``
+- ``struct pcep_object_ro*               pcep_obj_create_rro(...);``
+- ``struct pcep_object_ro*               pcep_obj_create_iro(...);``
+- ``struct pcep_ro_subobj_ipv4*          pcep_obj_create_ro_subobj_ipv4(...);``
+- ``struct pcep_ro_subobj_ipv6*          pcep_obj_create_ro_subobj_ipv6(...);``
+- ``struct pcep_ro_subobj_unnum*         pcep_obj_create_ro_subobj_unnum(...);``
+- ``struct pcep_ro_subobj_32label*       pcep_obj_create_ro_subobj_32label(...);``
+- ``struct pcep_ro_subobj_asn*           pcep_obj_create_ro_subobj_asn(...);``
+- ``struct pcep_ro_subobj_sr*            pcep_obj_create_ro_subobj_sr_nonai(...);``
+- ``struct pcep_ro_subobj_sr*            pcep_obj_create_ro_subobj_sr_ipv4_node(...);``
+- ``struct pcep_ro_subobj_sr*            pcep_obj_create_ro_subobj_sr_ipv6_node(...);``
+- ``struct pcep_ro_subobj_sr*            pcep_obj_create_ro_subobj_sr_ipv4_adj(...);``
+- ``struct pcep_ro_subobj_sr*            pcep_obj_create_ro_subobj_sr_ipv6_adj(...);``
+- ``struct pcep_ro_subobj_sr*            pcep_obj_create_ro_subobj_sr_unnumbered_ipv4_adj(...);``
+- ``struct pcep_ro_subobj_sr*            pcep_obj_create_ro_subobj_sr_linklocal_ipv6_adj(...);``
+
+Refer to ``pcep_messages/include/pcep-objects.h`` and the API section
+below for more details.
+
+
+PCEP TLVs
++++++++++
+
+The following PCEP TLVs (Tag, Length, Value) can be created and received:
+
+- Open Object TLVs
+    - ``struct pcep_object_tlv_stateful_pce_capability*    pcep_tlv_create_stateful_pce_capability(...);``
+    - ``struct pcep_object_tlv_lsp_db_version*             pcep_tlv_create_lsp_db_version(...);``
+    - ``struct pcep_object_tlv_speaker_entity_identifier*  pcep_tlv_create_speaker_entity_id(...);``
+    - ``struct pcep_object_tlv_path_setup_type*            pcep_tlv_create_path_setup_type(...);``
+    - ``struct pcep_object_tlv_path_setup_type_capability* pcep_tlv_create_path_setup_type_capability(...);``
+    - ``struct pcep_object_tlv_sr_pce_capability*          pcep_tlv_create_sr_pce_capability(...);``
+
+- LSP Object TLVs
+    - ``struct pcep_object_tlv_ipv4_lsp_identifier*        pcep_tlv_create_ipv4_lsp_identifiers(...);``
+    - ``struct pcep_object_tlv_ipv6_lsp_identifier*        pcep_tlv_create_ipv6_lsp_identifiers(...);``
+    - ``struct pcep_object_tlv_symbolic_path_name*         pcep_tlv_create_symbolic_path_name(...);``
+    - ``struct pcep_object_tlv_lsp_error_code*             pcep_tlv_create_lsp_error_code(...);``
+    - ``struct pcep_object_tlv_rsvp_error_spec*            pcep_tlv_create_rsvp_ipv4_error_spec(...);``
+    - ``struct pcep_object_tlv_rsvp_error_spec*            pcep_tlv_create_rsvp_ipv6_error_spec(...);``
+    - ``struct pcep_object_tlv_nopath_vector*              pcep_tlv_create_nopath_vector(...);``
+    - ``struct pcep_object_tlv_vendor_info*                pcep_tlv_create_vendor_info(...);``
+    - ``struct pcep_object_tlv_arbitrary*                  pcep_tlv_create_tlv_arbitrary(...);``
+
+- SRPAG (SR Association Group) TLVs
+    - ``struct pcep_object_tlv_srpag_pol_id *pcep_tlv_create_srpag_pol_id_ipv4(...);``
+    - ``struct pcep_object_tlv_srpag_pol_id *pcep_tlv_create_srpag_pol_id_ipv6(...);``
+    - ``struct pcep_object_tlv_srpag_pol_name *pcep_tlv_create_srpag_pol_name(...);``
+    - ``struct pcep_object_tlv_srpag_cp_id *pcep_tlv_create_srpag_cp_id(...);``
+    - ``struct pcep_object_tlv_srpag_cp_pref *pcep_tlv_create_srpag_cp_pref(...);``
+
+Refer to ``pcep_messages/include/pcep-tlvs.h`` and the API section
+below for more details.
+
+
+PCEP PCC
+--------
+
+This module has a Public PCC API library (explained in detail later) and a
+sample PCC binary.  The APIs in this library encapsulate other PCEPlib libraries
+for simplicity. With this API, the PCEPlib PCC can be started and stopped, and
+the PCEPlib event queue can be accessed. The PCEP Messages library is not
+encapsulated, and should be used directly.
+
+
+Internal Dependencies
+---------------------
+
+The following diagram illustrates the internal PCEPlib library dependencies.
+
+PCEPlib internal dependencies:
+
+.. image:: images/PCEPlib_internal_deps.jpg
+
+
+External Dependencies
+---------------------
+
+Originally the PCEPlib was based on the open source `libpcep project <https://www.acreo.se/open-software-libpcep>`_,
+but that dependency has been reduced to just one source file (pcep-tools.[ch]).
+
+
+PCEPlib Threading model
+-----------------------
+
+The PCEPlib can be run in stand-alone mode whereby a thread is launched for 
+timers and socket comm, as is illustrated in the following diagram.
+
+PCEPlib Threading model:
+
+.. image:: images/PCEPlib_threading_model.jpg
+
+The PCEPlib can also be configured to use an external timers and socket
+infrastructure like the FRR threads and tasks. In this case, no internal
+threads are launched for timers and socket comm, as is illustrated in the
+following diagram.
+
+PCEPlib Threading model with external infra:
+
+.. image:: images/PCEPlib_threading_model_frr_infra.jpg
+
+
+Building
+--------
+
+The autotools build system is used and integrated with the frr build system.
+
+Testing
+-------
+
+The Unit Tests for an individual library are executed with the ``make check``
+command. The Unit Test binary will be written to the project ``build`` directory.
+All Unit Tests are executed with Valgrind, and any memory issues reported by
+Valgrind will cause the Unit Test to fail.
+
+
+PCEPlib PCC API
+===============
+
+The following sections describe the PCEPlib PCC API.
+
+
+PCEPlib PCC Initialization and Destruction
+------------------------------------------
+
+The PCEPlib can be initialized to handle memory, timers, and socket comm
+internally in what is called stand-alone mode, or with an external
+infrastructure, like FRR.
+
+PCEPlib PCC Initialization and Destruction in stand-alone mode
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+PCEPlib PCC initialization and destruction functions:
+
+- ``bool initialize_pcc();``
+- ``bool initialize_pcc_wait_for_completion();``
+- ``bool destroy_pcc();``
+
+The PCC can be initialized with either ``initialize_pcc()`` or
+``initialize_pcc_wait_for_completion()``.
+
+- ``initialize_pcc_wait_for_completion()`` blocks until ``destroy_pcc()``
+   is called from a separate pthread.
+- ``initialize_pcc()`` is non-blocking and will be stopped when
+  ``destroy_pcc()`` is called.
+
+Both initialize functions will launch 3 pthreads:
+
+- 1 Timer pthread
+- 1 SocketComm pthread
+- 1 SessionLogic pthread
+
+When ``destroy_pcc()`` is called, all pthreads will be stopped and all
+resources will be released.
+
+All 3 functions return true upon success, and false otherwise.
+
+PCEPlib PCC Initialization and Destruction with FRR infrastructure
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+PCEPlib PCC initialization and destruction functions:
+
+- ``bool initialize_pcc_infra(struct pceplib_infra_config *infra_config);``
+- ``bool destroy_pcc();``
+
+The ``pceplib_infra_config`` struct has the following fields:
+
+- **void *pceplib_infra_mt**
+    - FRR Memory type pointer for infra related memory management
+
+- **void *pceplib_messages_mt**
+    - FRR Memory type pointer for PCEP messages related memory management
+
+- **pceplib_malloc_func mfunc**
+    - FRR malloc function pointer
+
+- **pceplib_calloc_func cfunc**
+    - FRR calloc function pointer
+
+- **pceplib_realloc_func rfunc**
+    - FRR realloc function pointer
+
+- **pceplib_strdup_func sfunc**
+    - FRR strdup function pointer
+
+- **pceplib_free_func ffunc**
+    - FRR free function pointer
+
+- **void *external_infra_data**
+    - FRR data used by FRR timers and sockets infrastructure
+
+- **ext_timer_create timer_create_func**
+    - FRR timer create function pointer
+
+- **ext_timer_cancel timer_cancel_func**
+    - FRR timer cancel function pointer
+
+- **ext_socket_write socket_write_func**
+    - FRR socket write function pointer, indicating fd is ready to be written to
+
+- **ext_socket_read socket_read_func**
+    - FRR socket write function pointer, indicating fd is ready to be read from
+
+
+PCEPlib PCC configuration
+-------------------------
+
+PCEPlib PCC configuratoin functions:
+
+- ``pcep_configuration *create_default_pcep_configuration();``
+- ``void destroy_pcep_configuration(pcep_configuration *config);``
+
+A ``pcep_configuration`` object with default values is created with
+``create_default_pcep_configuration()``. These values can be tailored to
+specific use cases.
+
+Created ``pcep_configuration`` objects are destroyed with
+``destroy_pcep_configuration()``.
+
+
+PCEPlib PCC configuration paramaters
+++++++++++++++++++++++++++++++++++++
+
+The ``pcep_configuration`` object is defined in ``pcep_session_logic/include/pcep_session_logic.h``
+The attributes in the ``pcep_configuration`` object are detailed as follows.
+
+PCEP Connection parameters:
+
+- **dst_pcep_port**
+    - Defaults to 0, in which case the default PCEP TCP destination port
+      4189 will be used.
+    - Set to use a specific PCEP TCP destination port.
+
+- **src_pcep_port**
+    - Defaults to 0, in which case the default PCEP TCP source port
+      4189 will be used.
+    - Set to use a specific PCEP TCP source port.
+
+- **Source IP**
+    - Defaults to IPv4 INADDR_ANY
+    - Set **src_ip.src_ipv4** and **is_src_ipv6=false** to set the source IPv4.
+    - Set **src_ip.src_ipv6** and **is_src_ipv6=true** to set the source IPv6.
+
+- **socket_connect_timeout_millis**
+    - Maximum amount of time to wait to connect to the PCE TCP socket
+      before failing, in milliseconds.
+
+PCEP Versioning:
+
+- **pcep_msg_versioning->draft_ietf_pce_segment_routing_07**
+    - Defaults to false, in which case draft 16 versioning will be used.
+    - Set to true to use draft 07 versioning.
+
+PCEP Open Message Parameters:
+
+- **keep_alive_seconds**
+    - Sent to PCE in PCEP Open Msg
+    - Recommended value = 30, Minimum value = 1
+    - Disabled by setting value = 0
+
+- **dead_timer_seconds**
+    - Sent to PCE in PCEP Open Msg
+    - Recommended value = 4 * keepalive timer value
+
+- Supported value ranges for PCEP Open Message received from the PCE
+    - **min_keep_alive_seconds**, **max_keep_alive_seconds**
+    - **min_dead_timer_seconds**, **max_dead_timer_seconds**
+
+- **request_time_seconds**
+    - When a PCC sends a PcReq to a PCE, the amount of time a PCC will
+      wait for a PcRep reply from the PCE.
+
+- **max_unknown_requests**
+    - If a PCC/PCE receives PCRep/PCReq messages with unknown requests
+      at a rate equal or greater than MAX-UNKNOWN-REQUESTS per minute,
+      the PCC/PCE MUST send a PCEP CLOSE message.
+    - Recommended value = 5
+
+- **max_unknown_messages**
+    - If a PCC/PCE receives unrecognized messages at a rate equal or
+      greater than MAX-UNKNOWN-MESSAGES per minute, the PCC/PCE MUST
+      send a PCEP CLOSE message
+    - Recommended value = 5
+
+Stateful PCE Capability TLV configuration parameters (RFC 8231, 8232, 8281, and
+draft-ietf-pce-segment-routing-16):
+
+- **support_stateful_pce_lsp_update**
+    - If this flag is true, then a Stateful PCE Capability TLV will
+      be added to the PCEP Open object, with the LSP Update Capability
+      U-flag set true.
+    - The rest of these parameters are used to configure the Stateful
+      PCE Capability TLV
+
+- **support_pce_lsp_instantiation**
+    - Sets the I-flag true, indicating the PCC allows instantiation
+      of an LSP by a PCE.
+
+- **support_include_db_version**
+    - Sets the S-bit true, indicating the PCC will include the
+      LSP-DB-VERSION TLV in each LSP object. See lsp_db_version below.
+
+- **support_lsp_triggered_resync**
+    - Sets the T-bit true, indicating the PCE can trigger resynchronization
+      of LSPs at any point in the life of the session.
+
+- **support_lsp_delta_sync**
+    - Sets the D-bit true, indicating the PCEP speaker allows incremental
+      (delta) State Synchronization.
+
+- **support_pce_triggered_initial_sync**
+    - Sets the F-bit true, indicating the PCE SHOULD trigger initial (first)
+      State Synchronization
+
+LSP DB Version TLV configuration parameters:
+
+- **lsp_db_version**
+    - If this parameter has a value other than 0, and the above
+      support_include_db_version flag is true, then an LSP DB
+      Version TLV will be added to the PCEP Open object.
+    - This parameter should only be set if LSP-DB survived a restart
+      and is available.
+    - This value will be copied over to the pcep_session upon initialization.
+
+SR PCE Capability sub-TLV configuration parameters (draft-ietf-pce-segment-routing-16):
+
+- **support_sr_te_pst**
+    - If this flag is true, then an SR PCE Capability sub-TLV will be
+      added to a Path Setup type Capability TLV, which will be added
+      to the PCEP Open object.
+    - The PST used in the Path Setup type Capability will be 1,
+      indicating the Path is setup using Segment Routing Traffic Engineering.
+
+Only set the following fields if the **support_sr_te_pst** flag is true.
+
+- **pcc_can_resolve_nai_to_sid**
+    - Sets the N-flag true, indicating that the PCC is capable of resolving
+      a Node or Adjacency Identifier to a SID
+
+- **max_sid_depth**
+    - If set other than 0, then the PCC imposes a limit on the Maximum
+      SID depth.
+    - If this parameter is other than 0, then the X bit will be true,
+      and the parameter value will be set in the MSD field.
+
+
+PCEPlib PCC connections
+-----------------------
+
+PCEPlib PCC connect and disconnect functions:
+
+- ``pcep_session *connect_pce(pcep_configuration *config, struct in_addr *pce_ip);``
+- ``pcep_session *connect_pce_ipv6(pcep_configuration *config, struct in6_addr *pce_ip);``
+- ``void disconnect_pce(pcep_session *session);``
+
+When connecting to a PCE, a ``pcep_session`` will be returned on success, NULL
+otherwise.
+
+Refer to the above PCC configuration parameters section for setting the source
+and destination PCEP TCP ports, and the source IP address and version.
+
+
+PCEP Messages, Objects, and TLVs
+--------------------------------
+
+The PCEP messages, objects, and TLVs created in the PCEPlib are high-level API
+structures, meaning they need to be encoded before being sent on-the-wire, and
+the raw data received needs to be decoded into these structures. This makes
+using these objects much easier for the library consumer, since they do not
+need to know the detailed raw format of the PCEP entities.
+
+
+PCEP Messages
++++++++++++++
+
+Received messages (in the ``pcep_event`` explained below) are of type
+``pcep_message``, which have the following fields:
+
+- ``struct pcep_message_header *msg_header;``
+    - Defines the PCEP version and message type
+
+- ``double_linked_list *obj_list;``
+    - A double linked list of the message objects
+    - Each entry is a pointer to a ``struct pcep_object_header``, and
+      using the ``object_class`` and ``object_type`` fields, the pointer
+      can be cast to the appropriate object structure to access the
+      rest of the object fields
+
+- ``uint8_t *encoded_message;``
+    - This field is only populated for received messages or once the
+      ``pcep_encode_message()`` function has been called on the message.
+    - This field is a pointer to the raw PCEP data for the entire
+      message, including all objects and TLVs.
+
+- ``uint16_t encoded_message_length;``
+    - This field is only populated for received messages or once the
+      ``pcep_encode_message()`` function has been called on the message.
+    - This field is the length of the entire raw message, including
+      all objects and TLVs.
+    - This field is in host byte order.
+
+
+PCEP Objects
+++++++++++++
+
+A PCEP message has a double linked list of pointers to ``struct pcep_object_header``
+structures, which have the following fields:
+
+- ``enum pcep_object_classes object_class;``
+- ``enum pcep_object_types object_type;``
+- ``bool flag_p;``
+    - PCC Processing rule bit: When set, the object MUST be taken into
+      account, when cleared the object is optional
+
+- ``bool flag_i;``
+    - PCE Ignore bit: indicates to a PCC whether or not an optional
+      object was processed 
+
+- ``double_linked_list *tlv_list;``
+    - A double linked list of the object TLVs
+    - Each entry is a pointer to a ``struct pcep_object_tlv_header``, and
+      using the TLV type field, the pointer can be cast to the
+      appropriate TLV structure to access the rest of the TLV fields
+
+- ``uint8_t *encoded_object;``
+    - This field is only populated for received objects or once the
+      ``pcep_encode_object()`` (called by ``pcep_encode_message()``)
+      function has been called on the object.
+    - Pointer into the encoded_message field (from the pcep_message)
+      where the raw object PCEP data starts.
+
+- ``uint16_t encoded_object_length;``
+    - This field is only populated for received objects or once the
+      ``pcep_encode_object()`` (called by ``pcep_encode_message()``)
+      function has been called on the object.
+    - This field is the length of the entire raw TLV
+    - This field is in host byte order.
+
+The object class and type can be used to cast the ``struct pcep_object_header``
+pointer to the appropriate object structure so the specific object fields can
+be accessed.
+
+
+PCEP TLVs
++++++++++
+
+A PCEP object has a double linked list of pointers to ``struct pcep_object_tlv_header``
+structures, which have the following fields:
+
+- ``enum pcep_object_tlv_types type;``
+- ``uint8_t *encoded_tlv;``
+    - This field is only populated for received TLVs or once the
+      ``pcep_encode_tlv()`` (called by ``pcep_encode_message()``)
+      function has been called on the TLV.
+    - Pointer into the encoded_message field (from the pcep_message)
+      where the raw TLV PCEP data starts.
+
+- ``uint16_t encoded_tlv_length;``
+    - This field is only populated for received TLVs or once the
+      ``pcep_encode_tlv()`` (called by ``pcep_encode_message()``)
+      function has been called on the TLV.
+    - This field is the length of the entire raw TLV
+    - This field is in host byte order.
+
+
+Memory management
++++++++++++++++++
+
+Any of the PCEPlib Message Library functions that receive a pointer to a
+``double_linked_list``, ``pcep_object_header``, or ``pcep_object_tlv_header``,
+transfer the ownership of the entity to the PCEPlib. The memory will be freed
+internally when the encapsulating structure is freed. If the memory for any of
+these is freed by the caller, then there will be a double memory free error
+when the memory is freed internally in the PCEPlib.
+
+Any of the PCEPlib Message Library functions that receive either a pointer to a
+``struct in_addr`` or ``struct in6_addr`` will allocate memory for the IP
+address internally and copy the IP address. It is the responsibility of the
+caller to manage the memory for the IP address passed into the PCEPlib Message
+Library functions.
+
+For messages received via the event queue (explained below), the message will
+be freed when the event is freed by calling ``destroy_pcep_event()``.
+
+When sending messages, the message will be freed internally in the PCEPlib when
+the ``send_message()`` ``pcep_pcc`` API function when the ``free_after_send`` flag
+is set true.
+
+To manually delete a message, call the ``pcep_msg_free_message()`` function.
+Internally, this will call ``pcep_obj_free_object()`` and ``pcep_obj_free_tlv()``
+appropriately.
+
+
+Sending a PCEP Report message
+-----------------------------
+
+This section shows how to send a PCEP Report messages from the PCC to the PCE,
+and serves as an example of how to send other messages. Refer to the sample
+PCC binary located in ``pcep_pcc/src/pcep_pcc.c`` for code examples os sending
+a PCEP Report message.
+
+The Report message must have at least an SRP, LSP, and ERO object.
+
+The PCEP Report message objects are created with the following APIs:
+
+- ``struct pcep_object_srp *pcep_obj_create_srp(...);``
+- ``struct pcep_object_lsp *pcep_obj_create_lsp(...);``
+- ``struct pcep_object_ro *pcep_obj_create_ero(...);``
+    - Create ero subobjects with the ``pcep_obj_create_ro_subobj_*(...);`` functions
+
+PCEP Report message is created with the following API:
+
+- ``struct pcep_header *pcep_msg_create_report(double_linked_list *report_object_list);``
+
+A PCEP report messages is sent with the following API:
+
+- ``void send_message(pcep_session *session, pcep_message *message, bool free_after_send);``
+
+
+PCEPlib Received event queue
+----------------------------
+
+PCEP events and messages of interest to the PCEPlib consumer will be stored
+internally in a message queue for retrieval.
+
+The following are the event types:
+
+- **MESSAGE_RECEIVED**
+- **PCE_CLOSED_SOCKET**
+- **PCE_SENT_PCEP_CLOSE**
+- **PCE_DEAD_TIMER_EXPIRED**
+- **PCE_OPEN_KEEP_WAIT_TIMER_EXPIRED**
+- **PCC_CONNECTED_TO_PCE**
+- **PCC_CONNECTION_FAILURE**
+- **PCC_PCEP_SESSION_CLOSED**
+- **PCC_RCVD_INVALID_OPEN**
+- **PCC_SENT_INVALID_OPEN**
+- **PCC_RCVD_MAX_INVALID_MSGS**
+- **PCC_RCVD_MAX_UNKOWN_MSGS**
+
+The following PCEP messages will not be posted on the message queue, as they
+are handled internally in the library:
+
+- **Open**
+- **Keep Alive**
+- **Close**
+
+Received event queue API:
+
+- ``bool event_queue_is_empty();``
+    - Returns true if the queue is empty, false otherwise
+
+- ``uint32_t event_queue_num_events_available();``
+    - Return the number of events on the queue, 0 if empty
+
+- ``struct pcep_event *event_queue_get_event();``
+    - Return the next event on the queue, NULL if empty
+    - The ``message`` pointer will only be non-NULL if ``event_type``
+      is ``MESSAGE_RECEIVED``
+
+- ``void destroy_pcep_event(struct pcep_event *event);``
+    - Free the PCEP Event resources, including the PCEP message if present
+
+
+PCEPlib Counters
+----------------
+
+The PCEPlib counters are managed in the ``pcep_session_logic`` library, and can
+be accessed in the ``pcep_session_counters`` field of the ``pcep_session`` structure.
+There are 2 API functions to manage the counters:
+
+- ``void dump_pcep_session_counters(pcep_session *session);``
+    - Dump all of the counters to the logs
+
+- ``void reset_pcep_session_counters(pcep_session *session);``
+
index b0413619ab6300483064fa8c3d91be876242d3bc..708f65ff7d081e22d16e56640e6921922e83a205 100644 (file)
@@ -271,7 +271,7 @@ has). For example, here is the encoder function for ``struct prefix``:
 
 This function pushes a single value onto the Lua stack. It is a table whose equivalent in Lua is:
 
-.. code-block::
+.. code-block:: c
 
    { ["network"] = "1.2.3.4/24", ["prefixlen"] = 24, ["family"] = 2 }
 
index f7e4486ef07449febf088ac6ab8a400e3dd1733d..d16420c7e72c644b37a5d08a1bc324fa26ccb05e 100644 (file)
@@ -57,6 +57,7 @@ dev_RSTFILES = \
        doc/developer/tracing.rst \
        doc/developer/testing.rst \
        doc/developer/topotests-snippets.rst \
+       doc/developer/topotests-markers.rst \
        doc/developer/topotests.rst \
        doc/developer/workflow.rst \
        doc/developer/xrefs.rst \
index 93d81548b23986d167e4fb67f349660477b3d5c1..4f58ee335bffc35b0c5d20ce8e32fdd029278b3e 100644 (file)
@@ -60,6 +60,7 @@ following steps will get you there on Ubuntu 20.04.
 
 .. code:: shell
          
+   apt install libsnmp-dev
    apt install snmpd snmp
    apt install snmp-mibs-downloader
    download-mibs
@@ -388,11 +389,19 @@ This is the recommended test writing routine:
 - Format the new code using `black <https://github.com/psf/black>`_
 - Create a Pull Request
 
-.. Note::
+Some things to keep in mind:
+
+- BGP tests MUST use generous convergence timeouts - you must ensure
+  that any test involving BGP uses a convergence timeout of at least
+  130 seconds.
+- Topotests are run on a range of Linux versions: if your test
+  requires some OS-specific capability (like mpls support, or vrf
+  support), there are test functions available in the libraries that
+  will help you determine whether your test should run or be skipped.
+- Avoid including unstable data in your test: don't rely on link-local
+  addresses or ifindex values, for example, because these can change
+  from run to run.
 
-   BGP tests MUST use generous convergence timeouts - you must ensure
-   that any test involving BGP uses a convergence timeout of at least
-   130 seconds.
 
 Topotest File Hierarchy
 """""""""""""""""""""""
@@ -795,7 +804,7 @@ Requirements:
 - Use `black <https://github.com/psf/black>`_ code formatter before creating
   a pull request. This ensures we have a unified code style.
 - Mark test modules with pytest markers depending on the daemons used during the
-  tests (s. Markers)
+  tests (see :ref:`topotests-markers`)
 
 Tips:
 
index b8f749b740e7b564906c90b37e09d21bc67e266b..6f797f7cc1841c7779ae96b2896e6af800b5a77e 100644 (file)
@@ -166,15 +166,22 @@ BFD peers and profiles share the same BFD session configuration commands.
    The minimum transmission interval (less jitter) that this system
    wants to use to send BFD control packets. Defaults to 300ms.
 
-.. clicmd:: echo-interval (10-60000)
+.. clicmd:: echo receive-interval <disabled|(10-60000)>
 
-   Configures the minimal echo receive transmission interval that this
-   system is capable of handling.
+   Configures the minimum interval that this system is capable of
+   receiving echo packets. Disabled means that this system doesn't want
+   to receive echo packets. The default value is 50 milliseconds.
+
+.. clicmd:: echo transmit-interval (10-60000)
+
+   The minimum transmission interval (less jitter) that this system
+   wants to use to send BFD echo packets. Defaults to 50ms.
 
 .. clicmd:: echo-mode
 
    Enables or disables the echo transmission mode. This mode is disabled
-   by default.
+   by default. If you are not using distributed BFD then echo mode works
+   only when the peer is also FRR.
 
    It is recommended that the transmission interval of control packets
    to be increased after enabling echo-mode to reduce bandwidth usage.
@@ -306,6 +313,11 @@ The following commands are available inside the interface configuration node.
    a new neighbor is found a BFD peer is created to monitor the link
    status for fast convergence.
 
+.. clicmd:: ip ospf bfd profile BFDPROF
+
+   Same as command ``ip ospf bfd``, but applies the BFD profile to the sessions
+   it creates or that already exist.
+
 
 .. _bfd-ospf6-peer-config:
 
@@ -445,12 +457,13 @@ You can inspect the current BFD peer status with the following commands:
                            Detect-multiplier: 3
                            Receive interval: 300ms
                            Transmission interval: 300ms
+                           Echo receive interval: 50ms
                            Echo transmission interval: disabled
                    Remote timers:
                            Detect-multiplier: 3
                            Receive interval: 300ms
                            Transmission interval: 300ms
-                           Echo transmission interval: 50ms
+                           Echo receive interval: 50ms
 
            peer 192.168.1.1
                    label: router3-peer
@@ -465,12 +478,13 @@ You can inspect the current BFD peer status with the following commands:
                            Detect-multiplier: 3
                            Receive interval: 300ms
                            Transmission interval: 300ms
+                           Echo receive interval: 50ms
                            Echo transmission interval: disabled
                    Remote timers:
                            Detect-multiplier: 3
                            Receive interval: 300ms
                            Transmission interval: 300ms
-                           Echo transmission interval: 50ms
+                           Echo receive interval: 50ms
 
    frr# show bfd peer 192.168.1.1
    BFD Peer:
@@ -487,15 +501,16 @@ You can inspect the current BFD peer status with the following commands:
                            Detect-multiplier: 3
                            Receive interval: 300ms
                            Transmission interval: 300ms
+                           Echo receive interval: 50ms
                            Echo transmission interval: disabled
                    Remote timers:
                            Detect-multiplier: 3
                            Receive interval: 300ms
                            Transmission interval: 300ms
-                           Echo transmission interval: 50ms
+                           Echo receive interval: 50ms
 
    frr# show bfd peer 192.168.0.1 json
-   {"multihop":false,"peer":"192.168.0.1","id":1,"remote-id":1,"status":"up","uptime":161,"diagnostic":"ok","remote-diagnostic":"ok","receive-interval":300,"transmit-interval":300,"echo-interval":50,"detect-multiplier":3,"remote-receive-interval":300,"remote-transmit-interval":300,"remote-echo-interval":50,"remote-detect-multiplier":3,"peer-type":"dynamic"}
+   {"multihop":false,"peer":"192.168.0.1","id":1,"remote-id":1,"status":"up","uptime":161,"diagnostic":"ok","remote-diagnostic":"ok","receive-interval":300,"transmit-interval":300,"echo-receive-interval":50,"echo-transmit-interval":0,"detect-multiplier":3,"remote-receive-interval":300,"remote-transmit-interval":300,"remote-echo-receive-interval":50,"remote-detect-multiplier":3,"peer-type":"dynamic"}
 
 
 You can inspect the current BFD peer status in brief with the following commands:
index da6c0d9824ab652b09d749904162bc537b8f054e..4433dc9e2173cf2f2be16be696a511d00c96191b 100644 (file)
@@ -1087,6 +1087,9 @@ IPv6 Support
    be used in a setup with two upstreams where each of the upstreams should only
    receive either IPv4 or IPv6 annocuments.
 
+   Using the ``bgp default ipv6-unicast`` configuration, IPv6 unicast
+   address family is enabled by default for all new neighbors.
+
 
 .. _bgp-route-aggregation:
 
@@ -1576,6 +1579,12 @@ Configuring Peers
    on by default or not.  This command defaults to on and is not displayed.
    The `no bgp default ipv4-unicast` form of the command is displayed.
 
+.. clicmd:: bgp default ipv6-unicast
+
+   This command allows the user to specify that v6 peering is turned
+   on by default or not.  This command defaults to off and is not displayed.
+   The `bgp default ipv6-unicast` form of the command is displayed.
+
 .. clicmd:: bgp default show-hostname
 
    This command shows the hostname of the peer in certain BGP commands
@@ -1667,6 +1676,74 @@ and will share updates.
    should not be reflected back to the peer.  This command only is only
    meaningful when there is a single peer defined in the peer-group.
 
+.. clicmd:: show [ip] bgp peer-group [json]
+
+   This command displays configured BGP peer-groups.
+
+      .. code-block:: frr
+
+         exit1-debian-9# show bgp peer-group
+
+         BGP peer-group test1, remote AS 65001
+         Peer-group type is external
+         Configured address-families: IPv4 Unicast; IPv6 Unicast;
+         1 IPv4 listen range(s)
+            192.168.100.0/24
+         2 IPv6 listen range(s)
+            2001:db8:1::/64
+            2001:db8:2::/64
+         Peer-group members:
+            192.168.200.1  Active
+            2001:db8::1  Active
+
+         BGP peer-group test2
+         Peer-group type is external
+         Configured address-families: IPv4 Unicast;
+
+   Optional ``json`` parameter is used to display JSON output.
+
+      .. code-block:: frr
+
+         {
+           "test1":{
+             "remoteAs":65001,
+             "type":"external",
+             "addressFamiliesConfigured":[
+               "IPv4 Unicast",
+               "IPv6 Unicast"
+             ],
+             "dynamicRanges":{
+               "IPv4":{
+                 "count":1,
+                 "ranges":[
+                   "192.168.100.0\/24"
+                 ]
+               },
+               "IPv6":{
+                 "count":2,
+                 "ranges":[
+                   "2001:db8:1::\/64",
+                   "2001:db8:2::\/64"
+                 ]
+               }
+             },
+             "members":{
+               "192.168.200.1":{
+                 "status":"Active"
+               },
+               "2001:db8::1":{
+                 "status":"Active"
+               }
+             }
+           },
+           "test2":{
+              "type":"external",
+              "addressFamiliesConfigured":[
+                "IPv4 Unicast"
+              ]
+           }
+         }
+
 Capability Negotiation
 ^^^^^^^^^^^^^^^^^^^^^^
 
@@ -1715,7 +1792,7 @@ AS Path Access Lists
 
 AS path access list is user defined AS path.
 
-.. clicmd:: bgp as-path access-list WORD permit|deny LINE
+.. clicmd:: bgp as-path access-list WORD [seq (0-4294967295)] permit|deny LINE
 
    This command defines a new AS path access list.
 
@@ -1731,6 +1808,7 @@ Bogon ASN filter policy configuration example
    bgp as-path access-list 99 permit _0_
    bgp as-path access-list 99 permit _23456_
    bgp as-path access-list 99 permit _1310[0-6][0-9]_|_13107[0-1]_
+   bgp as-path access-list 99 seq 20 permit ^65
 
 .. _bgp-using-as-path-in-route-map:
 
@@ -2838,6 +2916,12 @@ Debugging
    Display Listen sockets and the vrf that created them.  Useful for debugging of when
    listen is not working and this is considered a developer debug statement.
 
+.. clicmd:: debug bgp bfd
+
+   Enable or disable debugging for BFD events. This will show BFD integration
+   library messages and BGP BFD integration messages that are mostly state
+   transitions and validation problems.
+
 .. clicmd:: debug bgp neighbor-events
 
    Enable or disable debugging for neighbor events. This provides general
@@ -3529,8 +3613,8 @@ certainly contains silly mistakes, if not serious flaws.
    ip prefix-list pl-peer2-network permit 192.168.2.0/24
    ip prefix-list pl-peer2-network permit 172.16.1/24
    !
-   bgp as-path access-list asp-own-as permit ^$
-   bgp as-path access-list asp-own-as permit _64512_
+   bgp as-path access-list seq 5 asp-own-as permit ^$
+   bgp as-path access-list seq 10 asp-own-as permit _64512_
    !
    ! #################################################################
    ! Match communities we provide actions for, on routes receives from
index 00571487d7825a88d6258e0f4f190d79bbbd547a..607acd37061e2d78553bf1c7f271235ca9f502ac 100644 (file)
@@ -229,7 +229,6 @@ Showing OSPF6 information
    Interface name can also be given. JSON output can be obtained by appending
    'json' to the end of command.
 
-.. index:: show ipv6 ospf6 spf tree [json]
 .. clicmd:: show ipv6 ospf6 spf tree [json]
 
    This commands shows the spf tree from the recent spf calculation with the
@@ -237,7 +236,7 @@ Showing OSPF6 information
    tree in JSON format. Each area that the router belongs to has it's own
    JSON object, with each router having "cost", "isLeafNode" and "children" as
    arguments.
-   
+
 OSPF6 Configuration Examples
 ============================
 
index 8689bc4ccb33730f024b9f0333e4c96652b00a33..64ce85503ed01575aa4f8996c18d09a6a4937578 100644 (file)
@@ -733,23 +733,25 @@ Showing Information
    Json o/p of this command covers base route information
    i.e all LSAs except opaque lsa info.
 
-.. clicmd:: show ip ospf database [json]
+.. clicmd:: show ip ospf [vrf <NAME|all>] database [json]
 
-.. clicmd:: show ip ospf database (asbr-summary|external|network|router|summary) [json]
+.. clicmd:: show ip ospf [vrf <NAME|all>] database (asbr-summary|external|network|router|summary) [json]
 
-.. clicmd:: show ip ospf database (asbr-summary|external|network|router|summary) LINK-STATE-ID [json]
+.. clicmd:: show ip ospf [vrf <NAME|all>] database (asbr-summary|external|network|router|summary) LINK-STATE-ID [json]
 
-.. clicmd:: show ip ospf database (asbr-summary|external|network|router|summary) LINK-STATE-ID adv-router ADV-ROUTER [json]
+.. clicmd:: show ip ospf [vrf <NAME|all>] database (asbr-summary|external|network|router|summary) LINK-STATE-ID adv-router ADV-ROUTER [json]
 
-.. clicmd:: show ip ospf database (asbr-summary|external|network|router|summary) adv-router ADV-ROUTER [json]
+.. clicmd:: show ip ospf [vrf <NAME|all>] database (asbr-summary|external|network|router|summary) adv-router ADV-ROUTER [json]
 
-.. clicmd:: show ip ospf database (asbr-summary|external|network|router|summary) LINK-STATE-ID self-originate [json]
+.. clicmd:: show ip ospf [vrf <NAME|all>] database (asbr-summary|external|network|router|summary) LINK-STATE-ID self-originate [json]
 
-.. clicmd:: show ip ospf database (asbr-summary|external|network|router|summary) self-originate [json]
+.. clicmd:: show ip ospf [vrf <NAME|all>] database (asbr-summary|external|network|router|summary) self-originate [json]
 
-.. clicmd:: show ip ospf database max-age [json]
+.. clicmd:: show ip ospf [vrf <NAME|all>] database max-age [json]
 
-.. clicmd:: show ip ospf database self-originate [json]
+.. clicmd:: show ip ospf [vrf <NAME|all>] database self-originate [json]
+
+   Show the OSPF database summary.
 
 .. clicmd:: show ip ospf route [json]
 
@@ -780,17 +782,17 @@ Opaque LSA
    extensions that are used with MPLS-TE; it does not support a
    complete RSVP-TE solution.
 
-.. clicmd:: show ip ospf database (opaque-link|opaque-area|opaque-external)
+.. clicmd:: show ip ospf [vrf <NAME|all>] database (opaque-link|opaque-area|opaque-external)
 
-.. clicmd:: show ip ospf database (opaque-link|opaque-area|opaque-external) LINK-STATE-ID
+.. clicmd:: show ip ospf [vrf <NAME|all>] database (opaque-link|opaque-area|opaque-external) LINK-STATE-ID
 
-.. clicmd:: show ip ospf database (opaque-link|opaque-area|opaque-external) LINK-STATE-ID adv-router ADV-ROUTER
+.. clicmd:: show ip ospf [vrf <NAME|all>] database (opaque-link|opaque-area|opaque-external) LINK-STATE-ID adv-router ADV-ROUTER
 
-.. clicmd:: show ip ospf database (opaque-link|opaque-area|opaque-external) adv-router ADV-ROUTER
+.. clicmd:: show ip ospf [vrf <NAME|all>] database (opaque-link|opaque-area|opaque-external) adv-router ADV-ROUTER
 
-.. clicmd:: show ip ospf database (opaque-link|opaque-area|opaque-external) LINK-STATE-ID self-originate
+.. clicmd:: show ip ospf [vrf <NAME|all>] database (opaque-link|opaque-area|opaque-external) LINK-STATE-ID self-originate
 
-.. clicmd:: show ip ospf database (opaque-link|opaque-area|opaque-external) self-originate
+.. clicmd:: show ip ospf [vrf <NAME|all>] database (opaque-link|opaque-area|opaque-external) self-originate
 
    Show Opaque LSA from the database.
 
@@ -966,6 +968,12 @@ TI-LFA requires a proper Segment Routing configuration.
 Debugging OSPF
 ==============
 
+.. clicmd:: debug ospf bfd
+
+   Enable or disable debugging for BFD events. This will show BFD integration
+   library messages and OSPF BFD integration messages that are mostly state
+   transitions and validation problems.
+
 .. clicmd:: debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) [detail]
 
 
index 00d8ea8867284b2161c7bb618557e32fd2dff7ce..ae15e97d4ab45a889f86a60658f8702c78982050 100644 (file)
@@ -671,7 +671,7 @@ DEFPY_YANG(
                 as_str);
        nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
 
-       snprintf(xpath_auth, sizeof(xpath_auth), "%s/summarize-address", xpath);
+       snprintf(xpath_auth, sizeof(xpath_auth), "%s/summarize-addresses", xpath);
        nb_cli_enqueue_change(vty, xpath_auth, NB_OP_CREATE, prefix_str);
 
        return nb_cli_apply_changes(vty, NULL);
@@ -694,7 +694,7 @@ DEFPY_YANG(
                 as_str);
        nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
 
-       snprintf(xpath_auth, sizeof(xpath_auth), "%s/summarize-address", xpath);
+       snprintf(xpath_auth, sizeof(xpath_auth), "%s/summarize-addresses", xpath);
        nb_cli_enqueue_change(vty, xpath_auth, NB_OP_DESTROY, prefix_str);
 
        return nb_cli_apply_changes(vty, NULL);
@@ -703,12 +703,12 @@ DEFPY_YANG(
 void eigrp_cli_show_summarize_address(struct vty *vty, struct lyd_node *dnode,
                                      bool show_defaults)
 {
-       const struct eigrp_interface *eif = nb_running_get_entry(dnode, NULL,
-                                                                true);
+       const struct lyd_node *instance = yang_dnode_get_parent(dnode, "instance");
+       uint16_t asn = yang_dnode_get_uint16(instance, "./asn");
        const char *summarize_address = yang_dnode_get_string(dnode, NULL);
 
-       vty_out(vty, " ip summary-address eigrp %d %s\n",
-               eif->eigrp->AS, summarize_address);
+       vty_out(vty, " ip summary-address eigrp %d %s\n", asn,
+               summarize_address);
 }
 
 /*
@@ -767,12 +767,11 @@ DEFPY_YANG(
 void eigrp_cli_show_authentication(struct vty *vty, struct lyd_node *dnode,
                                   bool show_defaults)
 {
-       const struct eigrp_interface *eif = nb_running_get_entry(dnode, NULL,
-                                                                true);
+       const struct lyd_node *instance = yang_dnode_get_parent(dnode, "instance");
+       uint16_t asn = yang_dnode_get_uint16(instance, "./asn");
        const char *crypt = yang_dnode_get_string(dnode, NULL);
 
-       vty_out(vty, " ip authentication mode eigrp %d %s\n",
-               eif->eigrp->AS, crypt);
+       vty_out(vty, " ip authentication mode eigrp %d %s\n", asn, crypt);
 }
 
 /*
@@ -827,12 +826,12 @@ DEFPY_YANG(
 void eigrp_cli_show_keychain(struct vty *vty, struct lyd_node *dnode,
                             bool show_defaults)
 {
-       const struct eigrp_interface *eif = nb_running_get_entry(dnode, NULL,
-                                                                true);
+       const struct lyd_node *instance = yang_dnode_get_parent(dnode, "instance");
+       uint16_t asn = yang_dnode_get_uint16(instance, "./asn");
        const char *keychain = yang_dnode_get_string(dnode, NULL);
 
-       vty_out(vty, " ip authentication key-chain eigrp %d %s\n",
-               eif->eigrp->AS, keychain);
+       vty_out(vty, " ip authentication key-chain eigrp %d %s\n", asn,
+               keychain);
 }
 
 
index c77a6fc1b1d21c78e2c655814df664b7375faaac..8f80b78d200ffb0975c3e7a27324b1ac7a97e34a 100644 (file)
@@ -57,7 +57,6 @@
 #include "eigrpd/eigrp_const.h"
 #include "eigrpd/eigrp_filter.h"
 #include "eigrpd/eigrp_packet.h"
-#include "eigrpd/eigrp_memory.h"
 
 /*
  * Distribute-list update functions.
index bb7a930e6d928055565a756c132b653cf309d354..02e943043f19e028825ba7867a3b55678e4702f0 100644 (file)
 #include "eigrpd/eigrp_vty.h"
 #include "eigrpd/eigrp_network.h"
 #include "eigrpd/eigrp_topology.h"
-#include "eigrpd/eigrp_memory.h"
 #include "eigrpd/eigrp_fsm.h"
 #include "eigrpd/eigrp_dump.h"
 #include "eigrpd/eigrp_types.h"
 #include "eigrpd/eigrp_metric.h"
 
+DEFINE_MTYPE_STATIC(EIGRPD, EIGRP_IF,      "EIGRP interface");
+DEFINE_MTYPE_STATIC(EIGRPD, EIGRP_IF_INFO, "EIGRP Interface Information");
+
 struct eigrp_interface *eigrp_if_new(struct eigrp *eigrp, struct interface *ifp,
                                     struct prefix *p)
 {
index b1a6498cbcb189dc43ddf8e7b47e250e07b3d188..0ed7e94968f7f3ff768a5f5b3d02cccdf2aab152 100644 (file)
@@ -155,7 +155,8 @@ FRR_DAEMON_INFO(eigrpd, EIGRP, .vty_port = EIGRP_VTY_PORT,
                .n_signals = array_size(eigrp_signals),
 
                .privs = &eigrpd_privs, .yang_modules = eigrpd_yang_modules,
-               .n_yang_modules = array_size(eigrpd_yang_modules), )
+               .n_yang_modules = array_size(eigrpd_yang_modules),
+);
 
 /* EIGRPd main routine. */
 int main(int argc, char **argv, char **envp)
diff --git a/eigrpd/eigrp_memory.c b/eigrpd/eigrp_memory.c
deleted file mode 100644 (file)
index 57ca785..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-/* eigrpd memory type definitions
- *
- * Copyright (C) 2017  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
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "eigrp_memory.h"
-
-DEFINE_MGROUP(EIGRPD, "eigrpd")
-DEFINE_MTYPE(EIGRPD, EIGRP_TOP, "EIGRP structure")
-DEFINE_MTYPE(EIGRPD, EIGRP_IF, "EIGRP interface")
-DEFINE_MTYPE(EIGRPD, EIGRP_NEIGHBOR, "EIGRP neighbor")
-DEFINE_MTYPE(EIGRPD, EIGRP_IF_PARAMS, "EIGRP Interface Parameters")
-DEFINE_MTYPE(EIGRPD, EIGRP_IF_INFO, "EIGRP Interface Information")
-DEFINE_MTYPE(EIGRPD, EIGRP_FIFO, "EIGRP FIFO")
-DEFINE_MTYPE(EIGRPD, EIGRP_PACKET, "EIGRP Packet")
-DEFINE_MTYPE(EIGRPD, EIGRP_IPV4_INT_TLV, "EIGRP IPv4 TLV")
-DEFINE_MTYPE(EIGRPD, EIGRP_SEQ_TLV, "EIGRP SEQ TLV")
-DEFINE_MTYPE(EIGRPD, EIGRP_AUTH_TLV, "EIGRP AUTH TLV")
-DEFINE_MTYPE(EIGRPD, EIGRP_AUTH_SHA256_TLV, "EIGRP SHA TLV")
-DEFINE_MTYPE(EIGRPD, EIGRP_PREFIX_DESCRIPTOR, "EIGRP Prefix")
-DEFINE_MTYPE(EIGRPD, EIGRP_ROUTE_DESCRIPTOR, "EIGRP Nexthop Entry")
-DEFINE_MTYPE(EIGRPD, EIGRP_FSM_MSG, "EIGRP FSM Message")
diff --git a/eigrpd/eigrp_memory.h b/eigrpd/eigrp_memory.h
deleted file mode 100644 (file)
index 21ecba2..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/* eigrpd memory type declarations
- *
- * Copyright (C) 2017  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 _FRR_EIGRP_MEMORY_H
-#define _FRR_EIGRP_MEMORY_H
-
-#include "memory.h"
-
-DECLARE_MGROUP(EIGRPD)
-DECLARE_MTYPE(EIGRP_TOP)
-DECLARE_MTYPE(EIGRP_IF)
-DECLARE_MTYPE(EIGRP_NEIGHBOR)
-DECLARE_MTYPE(EIGRP_IF_PARAMS)
-DECLARE_MTYPE(EIGRP_IF_INFO)
-DECLARE_MTYPE(EIGRP_FIFO)
-DECLARE_MTYPE(EIGRP_PACKET)
-DECLARE_MTYPE(EIGRP_IPV4_INT_TLV)
-DECLARE_MTYPE(EIGRP_SEQ_TLV)
-DECLARE_MTYPE(EIGRP_AUTH_TLV)
-DECLARE_MTYPE(EIGRP_AUTH_SHA256_TLV)
-DECLARE_MTYPE(EIGRP_PREFIX_DESCRIPTOR)
-DECLARE_MTYPE(EIGRP_ROUTE_DESCRIPTOR)
-DECLARE_MTYPE(EIGRP_FSM_MSG)
-
-#endif /* _FRR_EIGRP_MEMORY_H */
index 1da2f7a10826df43036ec544552d852ce1591ee2..f2d5217eb0d68cedbfaf80bd6a289fc883e473ae 100644 (file)
 #include "eigrpd/eigrp_vty.h"
 #include "eigrpd/eigrp_network.h"
 #include "eigrpd/eigrp_topology.h"
-#include "eigrpd/eigrp_memory.h"
 #include "eigrpd/eigrp_errors.h"
 
+DEFINE_MTYPE_STATIC(EIGRPD, EIGRP_NEIGHBOR, "EIGRP neighbor");
+
 struct eigrp_neighbor *eigrp_nbr_new(struct eigrp_interface *ei)
 {
        struct eigrp_neighbor *nbr;
index 7eee2546270c282a36bd53a5b3245b55757fc33d..0b37733990ebaa401a94764f4098e08d4c493cdf 100644 (file)
 #include "eigrpd/eigrp_network.h"
 #include "eigrpd/eigrp_topology.h"
 #include "eigrpd/eigrp_fsm.h"
-#include "eigrpd/eigrp_memory.h"
 #include "eigrpd/eigrp_errors.h"
 
+DEFINE_MTYPE_STATIC(EIGRPD, EIGRP_FIFO,            "EIGRP FIFO");
+DEFINE_MTYPE_STATIC(EIGRPD, EIGRP_PACKET,          "EIGRP Packet");
+DEFINE_MTYPE_STATIC(EIGRPD, EIGRP_IPV4_INT_TLV,    "EIGRP IPv4 TLV");
+DEFINE_MTYPE_STATIC(EIGRPD, EIGRP_SEQ_TLV,         "EIGRP SEQ TLV");
+DEFINE_MTYPE_STATIC(EIGRPD, EIGRP_AUTH_TLV,        "EIGRP AUTH TLV");
+DEFINE_MTYPE_STATIC(EIGRPD, EIGRP_AUTH_SHA256_TLV, "EIGRP SHA TLV");
+
 /* Packet Type String. */
 const struct message eigrp_packet_type_str[] = {
        {EIGRP_OPC_UPDATE, "Update"},
index 0ab7b59dbb323c777d973aff0e40497c7f3f496b..c8769fb11f784066e1813c22b07194e2f47e4540 100644 (file)
@@ -52,7 +52,6 @@
 #include "eigrpd/eigrp_macros.h"
 #include "eigrpd/eigrp_topology.h"
 #include "eigrpd/eigrp_fsm.h"
-#include "eigrpd/eigrp_memory.h"
 
 uint32_t eigrp_query_send_all(struct eigrp *eigrp)
 {
index d16482173c009da82a418e2b6e472a065e5c7b2f..015daa768f4961f8024aff89f0711ea886ca27d3 100644 (file)
@@ -58,7 +58,6 @@
 #include "eigrpd/eigrp_macros.h"
 #include "eigrpd/eigrp_topology.h"
 #include "eigrpd/eigrp_fsm.h"
-#include "eigrpd/eigrp_memory.h"
 #include "eigrpd/eigrp_errors.h"
 
 void eigrp_send_reply(struct eigrp_neighbor *nbr,
index 027700fe11a95322fefcd2d920c303b629bbb6b0..9c2a8c9d849f624af9f315509d34a0bce9192ccb 100644 (file)
@@ -52,7 +52,6 @@
 #include "eigrpd/eigrp_macros.h"
 #include "eigrpd/eigrp_topology.h"
 #include "eigrpd/eigrp_fsm.h"
-#include "eigrpd/eigrp_memory.h"
 
 /*EIGRP SIA-QUERY read function*/
 void eigrp_siaquery_receive(struct eigrp *eigrp, struct ip *iph,
index 590b224d68ec2c8e5ae2f39e020de05f530eccde..2d298c20bfe985293db6ae4c3cdd3cc4b7d9e98c 100644 (file)
@@ -51,7 +51,6 @@
 #include "eigrpd/eigrp_macros.h"
 #include "eigrpd/eigrp_topology.h"
 #include "eigrpd/eigrp_fsm.h"
-#include "eigrpd/eigrp_memory.h"
 
 /*EIGRP SIA-REPLY read function*/
 void eigrp_siareply_receive(struct eigrp *eigrp, struct ip *iph,
index 0d8bb2996416ed0efb651960dfcd2b6a4e59b9f2..eb4a91cb64e4d1993a155533cb3841295bd65388 100644 (file)
@@ -126,9 +126,9 @@ struct eigrp {
        /* distribute_ctx */
        struct distribute_ctx *distribute_ctx;
 
-       QOBJ_FIELDS
+       QOBJ_FIELDS;
 };
-DECLARE_QOBJ_TYPE(eigrp)
+DECLARE_QOBJ_TYPE(eigrp);
 
 struct eigrp_if_params {
        uint8_t passive_interface;
index 6da7756f84bf5f23d20d430eb55275f248578ad9..846e21162237614a8e1cf8cd9f6bb02831a29dd0 100644 (file)
 #include "eigrpd/eigrp_dump.h"
 #include "eigrpd/eigrp_topology.h"
 #include "eigrpd/eigrp_fsm.h"
-#include "eigrpd/eigrp_memory.h"
 #include "eigrpd/eigrp_metric.h"
 
+DEFINE_MTYPE_STATIC(EIGRPD, EIGRP_ROUTE_DESCRIPTOR, "EIGRP Nexthop Entry");
+DEFINE_MTYPE(EIGRPD, EIGRP_PREFIX_DESCRIPTOR,       "EIGRP Prefix");
+
 static int eigrp_route_descriptor_cmp(struct eigrp_route_descriptor *rd1,
                                      struct eigrp_route_descriptor *rd2);
 
index 26fa1a11b0be1ed54317c8068bb3dc4a707368a5..d7f79057aba468c12e332d094a11c21d80caf95c 100644 (file)
 #ifndef _ZEBRA_EIGRP_TOPOLOGY_H
 #define _ZEBRA_EIGRP_TOPOLOGY_H
 
+#include "memory.h"
+
+DECLARE_MTYPE(EIGRP_PREFIX_DESCRIPTOR);
+
 /* EIGRP Topology table related functions. */
 extern struct route_table *eigrp_topology_new(void);
 extern void eigrp_topology_init(struct route_table *table);
index 91f3b3218bca44063789d308990488b111a3a345..0dc509706c91e0af15dd8f5ee3f59945ed10fb5d 100644 (file)
@@ -62,7 +62,6 @@
 #include "eigrpd/eigrp_topology.h"
 #include "eigrpd/eigrp_fsm.h"
 #include "eigrpd/eigrp_network.h"
-#include "eigrpd/eigrp_memory.h"
 #include "eigrpd/eigrp_metric.h"
 
 bool eigrp_update_prefix_apply(struct eigrp *eigrp, struct eigrp_interface *ei,
index 5002630796c9feec76b3761467f45fa5e135e00d..103015490783a2fd548e0e20485f59681888f467 100644 (file)
 #include "eigrpd/eigrp_packet.h"
 #include "eigrpd/eigrp_network.h"
 #include "eigrpd/eigrp_topology.h"
-#include "eigrpd/eigrp_memory.h"
 #include "eigrpd/eigrp_filter.h"
 
-DEFINE_QOBJ_TYPE(eigrp)
+DEFINE_MGROUP(EIGRPD, "eigrpd");
+
+DEFINE_MTYPE_STATIC(EIGRPD, EIGRP_TOP, "EIGRP structure");
+
+DEFINE_QOBJ_TYPE(eigrp);
 
 static struct eigrp_master eigrp_master;
 
index 01173768ba99c865f05dc1ce450c3d83499126e9..949fe682c70d5327136400c2b27735e028b6f0f5 100644 (file)
@@ -32,6 +32,9 @@
 
 #include "filter.h"
 #include "log.h"
+#include "memory.h"
+
+DECLARE_MGROUP(EIGRPD);
 
 /* Set EIGRP version is "classic" - wide metrics comes next */
 #define EIGRP_MAJOR_VERSION     1
index 13c9f7f8aeb072d261bfa779584490432acad41b..ba9445acb9958f981b4c931104d214d48b6232c2 100644 (file)
@@ -24,7 +24,6 @@ eigrpd_libeigrp_a_SOURCES = \
        eigrpd/eigrp_fsm.c \
        eigrpd/eigrp_hello.c \
        eigrpd/eigrp_interface.c \
-       eigrpd/eigrp_memory.c \
        eigrpd/eigrp_metric.c \
        eigrpd/eigrp_neighbor.c \
        eigrpd/eigrp_network.c \
@@ -63,7 +62,6 @@ noinst_HEADERS += \
        eigrpd/eigrp_fsm.h \
        eigrpd/eigrp_interface.h \
        eigrpd/eigrp_macros.h \
-       eigrpd/eigrp_memory.h \
        eigrpd/eigrp_metric.h \
        eigrpd/eigrp_neighbor.h \
        eigrpd/eigrp_network.h \
index 57e9e91c1510c1fa8eb44299ae3dbea9db22e346..20651706d394931f33fd6ef9b40d122f750721a4 100644 (file)
@@ -22,7 +22,6 @@
 #include <zebra.h>
 #include "isisd/fabricd.h"
 #include "isisd/isisd.h"
-#include "isisd/isis_memory.h"
 #include "isisd/isis_circuit.h"
 #include "isisd/isis_misc.h"
 #include "isisd/isis_adjacency.h"
@@ -33,9 +32,9 @@
 #include "isisd/isis_tx_queue.h"
 #include "isisd/isis_csm.h"
 
-DEFINE_MTYPE_STATIC(ISISD, FABRICD_STATE, "ISIS OpenFabric")
-DEFINE_MTYPE_STATIC(ISISD, FABRICD_NEIGHBOR, "ISIS OpenFabric Neighbor Entry")
-DEFINE_MTYPE_STATIC(ISISD, FABRICD_FLOODING_INFO, "ISIS OpenFabric Flooding Log")
+DEFINE_MTYPE_STATIC(ISISD, FABRICD_STATE, "ISIS OpenFabric");
+DEFINE_MTYPE_STATIC(ISISD, FABRICD_NEIGHBOR, "ISIS OpenFabric Neighbor Entry");
+DEFINE_MTYPE_STATIC(ISISD, FABRICD_FLOODING_INFO, "ISIS OpenFabric Flooding Log");
 
 /* Tracks initial synchronization as per section 2.4
  *
index 3c3a68764e3c4ca480e49d9e6dd44a13ab0ad830..c1f5e49ecaf0296a2b3385b38853b8f2dd482ebd 100644 (file)
@@ -49,6 +49,9 @@
 #include "isisd/fabricd.h"
 #include "isisd/isis_nb.h"
 
+DEFINE_MTYPE_STATIC(ISISD, ISIS_ADJACENCY, "ISIS adjacency");
+DEFINE_MTYPE(ISISD, ISIS_ADJACENCY_INFO, "ISIS adjacency info");
+
 static struct isis_adjacency *adj_alloc(struct isis_circuit *circuit,
                                        const uint8_t *id)
 {
@@ -146,7 +149,7 @@ struct isis_adjacency *isis_adj_find(const struct isis_area *area, int level,
        return NULL;
 }
 
-DEFINE_HOOK(isis_adj_state_change_hook, (struct isis_adjacency *adj), (adj))
+DEFINE_HOOK(isis_adj_state_change_hook, (struct isis_adjacency *adj), (adj));
 
 void isis_delete_adj(void *arg)
 {
@@ -260,22 +263,26 @@ void isis_adj_process_threeway(struct isis_adjacency *adj,
 
        adj->threeway_state = next_tw_state;
 }
-void isis_log_adj_change(struct isis_adjacency *adj,
-                        enum isis_adj_state old_state,
-                        enum isis_adj_state new_state, const char *reason)
+const char *isis_adj_name(const struct isis_adjacency *adj)
 {
-       const char *adj_name;
+       if (!adj)
+               return "NONE";
+
        struct isis_dynhn *dyn;
 
        dyn = dynhn_find_by_id(adj->sysid);
        if (dyn)
-               adj_name = dyn->hostname;
+               return dyn->hostname;
        else
-               adj_name = sysid_print(adj->sysid);
-
+               return sysid_print(adj->sysid);
+}
+void isis_log_adj_change(struct isis_adjacency *adj,
+                        enum isis_adj_state old_state,
+                        enum isis_adj_state new_state, const char *reason)
+{
        zlog_info(
                "%%ADJCHANGE: Adjacency to %s (%s) for %s changed from %s to %s, %s",
-               adj_name, adj->circuit->interface->name,
+               isis_adj_name(adj), adj->circuit->interface->name,
                adj_level2string(adj->level), adj_state2string(old_state),
                adj_state2string(new_state), reason ? reason : "unspecified");
 }
@@ -462,11 +469,7 @@ void isis_adj_print_vty(struct isis_adjacency *adj, struct vty *vty,
        struct isis_dynhn *dyn;
        int level;
 
-       dyn = dynhn_find_by_id(adj->sysid);
-       if (dyn)
-               vty_out(vty, "  %-20s", dyn->hostname);
-       else
-               vty_out(vty, "  %-20s", sysid_print(adj->sysid));
+       vty_out(vty, " %-20s", isis_adj_name(adj));
 
        if (detail == ISIS_UI_LEVEL_BRIEF) {
                if (adj->circuit)
index 3afb7209f3db24b15e5dba0e5c3c4cdf4a0b2641..754345c0085c46f39e33f81abcd2dae1733766ba 100644 (file)
@@ -27,6 +27,8 @@
 
 #include "isisd/isis_tlvs.h"
 
+DECLARE_MTYPE(ISIS_ADJACENCY_INFO);
+
 enum isis_adj_usage {
        ISIS_ADJ_NONE,
        ISIS_ADJ_LEVEL1,
@@ -123,11 +125,11 @@ void isis_delete_adj(void *adj);
 void isis_adj_process_threeway(struct isis_adjacency *adj,
                               struct isis_threeway_adj *tw_adj,
                               enum isis_adj_usage adj_usage);
-DECLARE_HOOK(isis_adj_state_change_hook, (struct isis_adjacency *adj), (adj))
+DECLARE_HOOK(isis_adj_state_change_hook, (struct isis_adjacency *adj), (adj));
 DECLARE_HOOK(isis_adj_ip_enabled_hook,
-            (struct isis_adjacency *adj, int family), (adj, family))
+            (struct isis_adjacency *adj, int family), (adj, family));
 DECLARE_HOOK(isis_adj_ip_disabled_hook,
-            (struct isis_adjacency *adj, int family), (adj, family))
+            (struct isis_adjacency *adj, int family), (adj, family));
 void isis_log_adj_change(struct isis_adjacency *adj,
                         enum isis_adj_state old_state,
                         enum isis_adj_state new_state, const char *reason);
@@ -142,5 +144,6 @@ void isis_adj_build_neigh_list(struct list *adjdb, struct list *list);
 void isis_adj_build_up_list(struct list *adjdb, struct list *list);
 int isis_adj_usage2levels(enum isis_adj_usage usage);
 int isis_bfd_startup_timer(struct thread *thread);
+const char *isis_adj_name(const struct isis_adjacency *adj);
 
 #endif /* ISIS_ADJACENCY_H */
index 4fac73511b0227447558abb502fbf2bb17595113..89f1ed0ba38833d5ad62b50e046789582f2347bd 100644 (file)
@@ -32,7 +32,7 @@
 #include "isisd/isisd.h"
 #include "isisd/fabricd.h"
 
-DEFINE_MTYPE_STATIC(ISISD, BFD_SESSION, "ISIS BFD Session")
+DEFINE_MTYPE_STATIC(ISISD, BFD_SESSION, "ISIS BFD Session");
 
 struct bfd_session {
        int family;
@@ -92,22 +92,42 @@ static bool bfd_session_same(const struct bfd_session *session, int family,
 static void bfd_adj_event(struct isis_adjacency *adj, struct prefix *dst,
                          int new_status)
 {
-       if (!adj->bfd_session)
+       if (!adj->bfd_session) {
+               if (IS_DEBUG_BFD)
+                       zlog_debug(
+                               "ISIS-BFD: Ignoring update for adjacency with %s, could not find bfd session on the adjacency",
+                               isis_adj_name(adj));
                return;
+       }
 
-       if (adj->bfd_session->family != dst->family)
+       if (adj->bfd_session->family != dst->family) {
+               if (IS_DEBUG_BFD)
+                       zlog_debug(
+                               "ISIS-BFD: Ignoring update for adjacency with %s, address family does not match the family on the adjacency",
+                               isis_adj_name(adj));
                return;
+       }
 
        switch (adj->bfd_session->family) {
        case AF_INET:
                if (!IPV4_ADDR_SAME(&adj->bfd_session->dst_ip.ipv4,
-                                   &dst->u.prefix4))
+                                   &dst->u.prefix4)) {
+                       if (IS_DEBUG_BFD)
+                               zlog_debug(
+                                       "ISIS-BFD: Ignoring update for adjacency with %s, IPv4 address does not match",
+                                       isis_adj_name(adj));
                        return;
+               }
                break;
        case AF_INET6:
                if (!IPV6_ADDR_SAME(&adj->bfd_session->dst_ip.ipv6,
-                                   &dst->u.prefix6))
+                                   &dst->u.prefix6)) {
+                       if (IS_DEBUG_BFD)
+                               zlog_debug(
+                                       "ISIS-BFD: Ignoring update for adjacency with %s, IPv6 address does not match",
+                                       isis_adj_name(adj));
                        return;
+               }
                break;
        default:
                flog_err(EC_LIB_DEVELOPMENT, "%s: unknown address-family: %u",
@@ -119,8 +139,13 @@ static void bfd_adj_event(struct isis_adjacency *adj, struct prefix *dst,
 
        BFD_SET_CLIENT_STATUS(adj->bfd_session->status, new_status);
 
-       if (old_status == new_status)
+       if (old_status == new_status) {
+               if (IS_DEBUG_BFD)
+                       zlog_debug(
+                               "ISIS-BFD: Ignoring update for adjacency with %s, new status matches current known status",
+                               isis_adj_name(adj));
                return;
+       }
 
        if (IS_DEBUG_BFD) {
                char dst_str[INET6_ADDRSTRLEN];
@@ -166,8 +191,12 @@ static int isis_bfd_interface_dest_update(ZAPI_CALLBACK_ARGS)
 
        struct isis_circuit *circuit = circuit_scan_by_ifp(ifp);
 
-       if (!circuit)
+       if (!circuit) {
+               if (IS_DEBUG_BFD)
+                       zlog_debug(
+                               "ISIS-BFD: Ignoring update, could not find circuit");
                return 0;
+       }
 
        if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
                for (int level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) {
@@ -326,15 +355,26 @@ static void bfd_handle_adj_up(struct isis_adjacency *adj, int command)
        struct list *local_ips;
        struct prefix *local_ip;
 
-       if (!circuit->bfd_info)
+       if (!circuit->bfd_info) {
+               if (IS_DEBUG_BFD)
+                       zlog_debug(
+                               "ISIS-BFD: skipping BFD initialization on adjacency with %s because there is no bfd_info in the circuit",
+                               isis_adj_name(adj));
                goto out;
+       }
 
        /* If IS-IS IPv6 is configured wait for IPv6 address to be programmed
         * before starting up BFD
         */
-       if ((circuit->ipv6_router && listcount(circuit->ipv6_link) == 0)
-           || adj->ipv6_address_count == 0)
+       if (circuit->ipv6_router
+           && (listcount(circuit->ipv6_link) == 0
+               || adj->ipv6_address_count == 0)) {
+               if (IS_DEBUG_BFD)
+                       zlog_debug(
+                               "ISIS-BFD: skipping BFD initialization on adjacency with %s because IPv6 is enabled but not ready",
+                               isis_adj_name(adj));
                return;
+       }
 
        /*
         * If IS-IS is enabled for both IPv4 and IPv6 on the circuit, prefer
@@ -344,16 +384,24 @@ static void bfd_handle_adj_up(struct isis_adjacency *adj, int command)
                family = AF_INET6;
                dst_ip.ipv6 = adj->ipv6_addresses[0];
                local_ips = circuit->ipv6_link;
-               if (!local_ips || list_isempty(local_ips))
+               if (!local_ips || list_isempty(local_ips)) {
+                       if (IS_DEBUG_BFD)
+                               zlog_debug(
+                                       "ISIS-BFD: skipping BFD initialization: IPv6 enabled and no local IPv6 addresses");
                        goto out;
+               }
                local_ip = listgetdata(listhead(local_ips));
                src_ip.ipv6 = local_ip->u.prefix6;
        } else if (circuit->ip_router && adj->ipv4_address_count) {
                family = AF_INET;
                dst_ip.ipv4 = adj->ipv4_addresses[0];
                local_ips = fabricd_ip_addrs(adj->circuit);
-               if (!local_ips || list_isempty(local_ips))
+               if (!local_ips || list_isempty(local_ips)) {
+                       if (IS_DEBUG_BFD)
+                               zlog_debug(
+                                       "ISIS-BFD: skipping BFD initialization: IPv4 enabled and no local IPv4 addresses");
                        goto out;
+               }
                local_ip = listgetdata(listhead(local_ips));
                src_ip.ipv4 = local_ip->u.prefix4;
        } else
@@ -365,8 +413,13 @@ static void bfd_handle_adj_up(struct isis_adjacency *adj, int command)
                        bfd_handle_adj_down(adj);
        }
 
-       if (!adj->bfd_session)
+       if (!adj->bfd_session) {
+               if (IS_DEBUG_BFD)
+                       zlog_debug(
+                               "ISIS-BFD: creating BFD session for adjacency with %s",
+                               isis_adj_name(adj));
                adj->bfd_session = bfd_session_new(family, &dst_ip, &src_ip);
+       }
 
        bfd_debug(adj->bfd_session->family, &adj->bfd_session->dst_ip,
                  &adj->bfd_session->src_ip, circuit->interface->name, command);
index 62822cbf89f96f95bc2ab7060c54afb201b6b37a..a637429e848b51844df7e669f3011cda74ebe05d 100644 (file)
 #include "isisd/isis_nb.h"
 #include "isisd/isis_ldp_sync.h"
 
-DEFINE_QOBJ_TYPE(isis_circuit)
+DEFINE_MTYPE_STATIC(ISISD, ISIS_CIRCUIT, "ISIS circuit");
 
-DEFINE_HOOK(isis_if_new_hook, (struct interface *ifp), (ifp))
+DEFINE_QOBJ_TYPE(isis_circuit);
+
+DEFINE_HOOK(isis_if_new_hook, (struct interface *ifp), (ifp));
 
 /*
  * Prototypes.
@@ -308,7 +310,7 @@ struct isis_circuit *circuit_scan_by_ifp(struct interface *ifp)
 }
 
 DEFINE_HOOK(isis_circuit_add_addr_hook, (struct isis_circuit *circuit),
-           (circuit))
+           (circuit));
 
 void isis_circuit_add_addr(struct isis_circuit *circuit,
                           struct connected *connected)
@@ -1085,7 +1087,7 @@ void isis_circuit_print_vty(struct isis_circuit *circuit, struct vty *vty,
 #ifdef FABRICD
 DEFINE_HOOK(isis_circuit_config_write,
            (struct isis_circuit *circuit, struct vty *vty),
-           (circuit, vty))
+           (circuit, vty));
 
 static int isis_interface_config_write(struct vty *vty)
 {
index 15d58bd7369b0dcc26f08573f7741f1d143c9fbb..cbe4040b64d6cbaa66dd4822af9f7e2cc119aeb2 100644 (file)
@@ -174,9 +174,9 @@ struct isis_circuit {
                                    */
        struct list *snmp_adj_list; /* List in id order */
 
-       QOBJ_FIELDS
+       QOBJ_FIELDS;
 };
-DECLARE_QOBJ_TYPE(isis_circuit)
+DECLARE_QOBJ_TYPE(isis_circuit);
 
 void isis_circuit_init(void);
 struct isis_circuit *isis_circuit_new(struct isis *isis);
@@ -231,10 +231,10 @@ int isis_circuit_mt_enabled_set(struct isis_circuit *circuit, uint16_t mtid,
 #ifdef FABRICD
 DECLARE_HOOK(isis_circuit_config_write,
            (struct isis_circuit *circuit, struct vty *vty),
-           (circuit, vty))
+           (circuit, vty));
 #endif
 
 DECLARE_HOOK(isis_circuit_add_addr_hook, (struct isis_circuit *circuit),
-            (circuit))
+            (circuit));
 
 #endif /* _ZEBRA_ISIS_CIRCUIT_H */
index fb9721e8b3a0a504c81a6c1747d5261efd0978d9..b108210686486617594d512209d7b648db0e261c 100644 (file)
@@ -136,10 +136,10 @@ void cli_show_router_isis(struct vty *vty, struct lyd_node *dnode,
        vrf = yang_dnode_get_string(dnode, "./vrf");
 
        vty_out(vty, "!\n");
-       vty_out(vty, "router isis %s ",
+       vty_out(vty, "router isis %s",
                yang_dnode_get_string(dnode, "./area-tag"));
        if (!strmatch(vrf, VRF_DEFAULT_NAME))
-               vty_out(vty, "vrf %s", yang_dnode_get_string(dnode, "./vrf"));
+               vty_out(vty, " vrf %s", yang_dnode_get_string(dnode, "./vrf"));
        vty_out(vty, "\n");
 }
 
@@ -392,10 +392,10 @@ void cli_show_ip_isis_ipv4(struct vty *vty, struct lyd_node *dnode,
 
        if (!yang_dnode_get_bool(dnode, NULL))
                vty_out(vty, " no");
-       vty_out(vty, " ip router isis %s ",
+       vty_out(vty, " ip router isis %s",
                yang_dnode_get_string(dnode, "../area-tag"));
        if (!strmatch(vrf, VRF_DEFAULT_NAME))
-               vty_out(vty, "vrf %s", vrf);
+               vty_out(vty, " vrf %s", vrf);
        vty_out(vty, "\n");
 }
 
@@ -408,10 +408,10 @@ void cli_show_ip_isis_ipv6(struct vty *vty, struct lyd_node *dnode,
 
        if (!yang_dnode_get_bool(dnode, NULL))
                vty_out(vty, " no");
-       vty_out(vty, " ipv6 router isis %s ",
+       vty_out(vty, " ipv6 router isis %s",
                yang_dnode_get_string(dnode, "../area-tag"));
        if (!strmatch(vrf, VRF_DEFAULT_NAME))
-               vty_out(vty, "vrf %s", vrf);
+               vty_out(vty, " vrf %s", vrf);
        vty_out(vty, "\n");
 }
 
index d2c5d93e255aa7f97ffcfdcc328d5128bab62248..decd3e8922810f3947ff92d86575a094b9ed36c5 100644 (file)
@@ -40,6 +40,8 @@
 #include "isisd/isis_misc.h"
 #include "isisd/isis_constants.h"
 
+DEFINE_MTYPE_STATIC(ISISD, ISIS_DYNHN, "ISIS dyn hostname");
+
 extern struct host host;
 
 struct list *dyn_cache = NULL;
index 3ebac8aaa91b31447f37dc0e756766daa727ccc7..085177b94352ca1bfaaab884f7a1c28665360343 100644 (file)
@@ -46,6 +46,7 @@ DEFINE_MTYPE_STATIC(ISISD, ISIS_SPF_NODE, "ISIS SPF Node");
 DEFINE_MTYPE_STATIC(ISISD, ISIS_LFA_TIEBREAKER, "ISIS LFA Tiebreaker");
 DEFINE_MTYPE_STATIC(ISISD, ISIS_LFA_EXCL_IFACE, "ISIS LFA Excluded Interface");
 DEFINE_MTYPE_STATIC(ISISD, ISIS_RLFA, "ISIS Remote LFA");
+DEFINE_MTYPE(ISISD, ISIS_NEXTHOP_LABELS, "ISIS nexthop MPLS labels");
 
 static inline int isis_spf_node_compare(const struct isis_spf_node *a,
                                        const struct isis_spf_node *b)
index 65891cae44313e81ed0f56fe1651facb6ca62d55..9db03a3a19c4a140c5003afc60b45518cc5a1e10 100644 (file)
 
 #include "lib/typesafe.h"
 #include "lib/zclient.h"
+#include "lib/memory.h"
 
-PREDECL_RBTREE_UNIQ(lfa_tiebreaker_tree)
-PREDECL_RBTREE_UNIQ(rlfa_tree)
+DECLARE_MTYPE(ISIS_NEXTHOP_LABELS);
+
+PREDECL_RBTREE_UNIQ(lfa_tiebreaker_tree);
+PREDECL_RBTREE_UNIQ(rlfa_tree);
 
 enum lfa_tiebreaker_type {
        LFA_TIEBREAKER_DOWNSTREAM = 0,
@@ -41,7 +44,7 @@ struct lfa_tiebreaker {
 int lfa_tiebreaker_cmp(const struct lfa_tiebreaker *a,
                       const struct lfa_tiebreaker *b);
 DECLARE_RBTREE_UNIQ(lfa_tiebreaker_tree, struct lfa_tiebreaker, entry,
-                   lfa_tiebreaker_cmp)
+                   lfa_tiebreaker_cmp);
 
 struct rlfa {
        struct rlfa_tree_item entry;
@@ -50,7 +53,7 @@ struct rlfa {
        struct in_addr pq_address;
 };
 int rlfa_cmp(const struct rlfa *a, const struct rlfa *b);
-DECLARE_RBTREE_UNIQ(rlfa_tree, struct rlfa, entry, rlfa_cmp)
+DECLARE_RBTREE_UNIQ(rlfa_tree, struct rlfa, entry, rlfa_cmp);
 
 enum isis_tilfa_sid_type {
        TILFA_SID_PREFIX = 1,
index 06a5a69e3f1463b93baf22e69d7c55d2013d2266..056e29e8de81c78e34a15604b986f0d5e1ae7638 100644 (file)
@@ -60,6 +60,8 @@
 #include "isisd/isis_tx_queue.h"
 #include "isisd/isis_nb.h"
 
+DEFINE_MTYPE_STATIC(ISISD, ISIS_LSP, "ISIS LSP");
+
 static int lsp_refresh(struct thread *thread);
 static int lsp_l1_refresh_pseudo(struct thread *thread);
 static int lsp_l2_refresh_pseudo(struct thread *thread);
@@ -1561,18 +1563,28 @@ int _lsp_regenerate_schedule(struct isis_area *area, int level,
                        /*
                         * Schedule LSP refresh ASAP
                         */
-                       timeout = 0;
-
                        if (area->bfd_signalled_down) {
                                sched_debug(
-                                       "ISIS (%s): Scheduling immediately due to BDF 'down' message.",
+                                       "ISIS (%s): Scheduling immediately due to BFD 'down' message.",
                                        area->area_tag);
                                area->bfd_signalled_down = false;
                                area->bfd_force_spf_refresh = true;
+                               timeout = 0;
                        } else {
-                               sched_debug(
-                                       "ISIS (%s): Last generation was more than lsp_gen_interval ago. Scheduling for execution now.",
-                                       area->area_tag);
+                               int64_t time_since_last = monotime_since(
+                                       &area->last_lsp_refresh_event[lvl - 1],
+                                       NULL);
+                               timeout = time_since_last < 100000L
+                                                 ? (100000L - time_since_last)/1000
+                                                 : 0;
+                               if (timeout > 0)
+                                       sched_debug(
+                                               "ISIS (%s): Last generation was more than lsp_gen_interval ago. Scheduling for execution in %ld ms due to the instability timer.",
+                                               area->area_tag, timeout);
+                               else
+                                       sched_debug(
+                                               "ISIS (%s): Last generation was more than lsp_gen_interval ago. Scheduling for execution now.",
+                                               area->area_tag);
                        }
                }
 
index 896d9576072cf888407b56ea24cddcf1547c71d9..f3d9f61bcfa4955a3b26ef216d350241e57764da 100644 (file)
@@ -27,7 +27,7 @@
 #include "lib/typesafe.h"
 #include "isisd/isis_pdu.h"
 
-PREDECL_RBTREE_UNIQ(lspdb)
+PREDECL_RBTREE_UNIQ(lspdb);
 
 struct isis;
 /* Structure for isis_lsp, this structure will only support the fixed
@@ -61,7 +61,7 @@ struct isis_lsp {
 };
 
 extern int lspdb_compare(const struct isis_lsp *a, const struct isis_lsp *b);
-DECLARE_RBTREE_UNIQ(lspdb, struct isis_lsp, dbe, lspdb_compare)
+DECLARE_RBTREE_UNIQ(lspdb, struct isis_lsp, dbe, lspdb_compare);
 
 void lsp_db_init(struct lspdb_head *head);
 void lsp_db_fini(struct lspdb_head *head);
index 1b04f4f7a0938112ac0e08ee361fdb4f81001c32..c03cedb1872e9416ab7c0715b01fef986369318c 100644 (file)
@@ -193,7 +193,8 @@ FRR_DAEMON_INFO(isisd, ISIS, .vty_port = ISISD_VTY_PORT,
                .n_signals = array_size(isisd_signals),
 
                .privs = &isisd_privs, .yang_modules = isisd_yang_modules,
-               .n_yang_modules = array_size(isisd_yang_modules), )
+               .n_yang_modules = array_size(isisd_yang_modules),
+);
 
 /*
  * Main routine of isisd. Parse arguments and handle IS-IS state machine.
diff --git a/isisd/isis_memory.c b/isisd/isis_memory.c
deleted file mode 100644 (file)
index f716e06..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/* isisd memory type definitions
- *
- * Copyright (C) 2015  David Lamparter
- *
- * This file is part of Quagga.
- *
- * Quagga 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.
- *
- * Quagga 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
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "isis_memory.h"
-
-DEFINE_MGROUP(ISISD, "isisd")
-DEFINE_MTYPE(ISISD, ISIS, "ISIS")
-DEFINE_MTYPE(ISISD, ISIS_TMP, "ISIS TMP")
-DEFINE_MTYPE(ISISD, ISIS_CIRCUIT, "ISIS circuit")
-DEFINE_MTYPE(ISISD, ISIS_LSP, "ISIS LSP")
-DEFINE_MTYPE(ISISD, ISIS_ADJACENCY, "ISIS adjacency")
-DEFINE_MTYPE(ISISD, ISIS_ADJACENCY_INFO, "ISIS adjacency info")
-DEFINE_MTYPE(ISISD, ISIS_AREA, "ISIS area")
-DEFINE_MTYPE(ISISD, ISIS_AREA_ADDR, "ISIS area address")
-DEFINE_MTYPE(ISISD, ISIS_DYNHN, "ISIS dyn hostname")
-DEFINE_MTYPE(ISISD, ISIS_SPFTREE, "ISIS SPFtree")
-DEFINE_MTYPE(ISISD, ISIS_VERTEX, "ISIS vertex")
-DEFINE_MTYPE(ISISD, ISIS_ROUTE_INFO, "ISIS route info")
-DEFINE_MTYPE(ISISD, ISIS_NEXTHOP, "ISIS nexthop")
-DEFINE_MTYPE(ISISD, ISIS_NEXTHOP_LABELS, "ISIS nexthop MPLS labels")
-DEFINE_MTYPE(ISISD, ISIS_DICT, "ISIS dictionary")
-DEFINE_MTYPE(ISISD, ISIS_DICT_NODE, "ISIS dictionary node")
-DEFINE_MTYPE(ISISD, ISIS_EXT_ROUTE, "ISIS redistributed route")
-DEFINE_MTYPE(ISISD, ISIS_EXT_INFO, "ISIS redistributed route info")
-DEFINE_MTYPE(ISISD, ISIS_MPLS_TE, "ISIS MPLS_TE parameters")
-DEFINE_MTYPE(ISISD, ISIS_ACL_NAME, "ISIS access-list name")
-DEFINE_MTYPE(ISISD, ISIS_PLIST_NAME, "ISIS prefix-list name")
diff --git a/isisd/isis_memory.h b/isisd/isis_memory.h
deleted file mode 100644 (file)
index 5bcd2a3..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/* isisd memory type declarations
- *
- * Copyright (C) 2015  David Lamparter
- *
- * This file is part of Quagga.
- *
- * Quagga 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.
- *
- * Quagga 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 _QUAGGA_ISIS_MEMORY_H
-#define _QUAGGA_ISIS_MEMORY_H
-
-#include "memory.h"
-
-DECLARE_MGROUP(ISISD)
-DECLARE_MTYPE(ISIS)
-DECLARE_MTYPE(ISIS_TMP)
-DECLARE_MTYPE(ISIS_CIRCUIT)
-DECLARE_MTYPE(ISIS_LSP)
-DECLARE_MTYPE(ISIS_ADJACENCY)
-DECLARE_MTYPE(ISIS_ADJACENCY_INFO)
-DECLARE_MTYPE(ISIS_AREA)
-DECLARE_MTYPE(ISIS_AREA_ADDR)
-DECLARE_MTYPE(ISIS_DYNHN)
-DECLARE_MTYPE(ISIS_SPFTREE)
-DECLARE_MTYPE(ISIS_VERTEX)
-DECLARE_MTYPE(ISIS_ROUTE_INFO)
-DECLARE_MTYPE(ISIS_NEXTHOP)
-DECLARE_MTYPE(ISIS_NEXTHOP_LABELS)
-DECLARE_MTYPE(ISIS_DICT)
-DECLARE_MTYPE(ISIS_DICT_NODE)
-DECLARE_MTYPE(ISIS_EXT_ROUTE)
-DECLARE_MTYPE(ISIS_EXT_INFO)
-DECLARE_MTYPE(ISIS_MPLS_TE)
-DECLARE_MTYPE(ISIS_ACL_NAME)
-DECLARE_MTYPE(ISIS_PLIST_NAME)
-
-#endif /* _QUAGGA_ISIS_MEMORY_H */
index 9465c5e75c0bc3b4c403a87e355d84c24fda4bf8..c024549fccfb71389f33fe01a40170d8ba523956 100644 (file)
@@ -21,7 +21,6 @@
  */
 #include <zebra.h>
 #include "isisd/isisd.h"
-#include "isisd/isis_memory.h"
 #include "isisd/isis_circuit.h"
 #include "isisd/isis_adjacency.h"
 #include "isisd/isis_misc.h"
@@ -29,9 +28,9 @@
 #include "isisd/isis_mt.h"
 #include "isisd/isis_tlvs.h"
 
-DEFINE_MTYPE_STATIC(ISISD, MT_AREA_SETTING, "ISIS MT Area Setting")
-DEFINE_MTYPE_STATIC(ISISD, MT_CIRCUIT_SETTING, "ISIS MT Circuit Setting")
-DEFINE_MTYPE_STATIC(ISISD, MT_ADJ_INFO, "ISIS MT Adjacency Info")
+DEFINE_MTYPE_STATIC(ISISD, MT_AREA_SETTING, "ISIS MT Area Setting");
+DEFINE_MTYPE_STATIC(ISISD, MT_CIRCUIT_SETTING, "ISIS MT Circuit Setting");
+DEFINE_MTYPE_STATIC(ISISD, MT_ADJ_INFO, "ISIS MT Adjacency Info");
 
 bool isis_area_ipv6_dstsrc_enabled(struct isis_area *area)
 {
index 259e10bbdd3833bc8ab272f98f662bbe63a1ae67..c8ad816b585bd6196d8c18c1be172a2b66e6208a 100644 (file)
 #include "isisd/isis_spf.h"
 #include "isisd/isis_spf_private.h"
 #include "isisd/isis_te.h"
-#include "isisd/isis_memory.h"
 #include "isisd/isis_mt.h"
 #include "isisd/isis_redist.h"
 #include "isisd/isis_ldp_sync.h"
 #include "isisd/isis_dr.h"
 
+DEFINE_MTYPE_STATIC(ISISD, ISIS_MPLS_TE,    "ISIS MPLS_TE parameters");
+DEFINE_MTYPE_STATIC(ISISD, ISIS_PLIST_NAME, "ISIS prefix-list name");
+
 extern struct zclient *zclient;
 
 /*
index 856c47b9b74906dbd89604fe179ec891a3be7237..c33d56e625e07b88c9408914a945820307d245a1 100644 (file)
@@ -24,7 +24,6 @@
 #include "if.h"
 #include "linklist.h"
 #include "memory.h"
-#include "isis_memory.h"
 #include "prefix.h"
 #include "routemap.h"
 #include "stream.h"
 #include "isisd/isis_route.h"
 #include "isisd/isis_zebra.h"
 
+DEFINE_MTYPE_STATIC(ISISD, ISIS_EXT_ROUTE, "ISIS redistributed route");
+DEFINE_MTYPE_STATIC(ISISD, ISIS_EXT_INFO,  "ISIS redistributed route info");
+DEFINE_MTYPE_STATIC(ISISD, ISIS_RMAP_NAME, "ISIS redistribute route-map name");
+
 static int redist_protocol(int family)
 {
        if (family == AF_INET)
@@ -327,13 +330,13 @@ static void isis_redist_routemap_set(struct isis_redist *redist,
                                     const char *routemap)
 {
        if (redist->map_name) {
-               XFREE(MTYPE_ISIS, redist->map_name);
+               XFREE(MTYPE_ISIS_RMAP_NAME, 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_name = XSTRDUP(MTYPE_ISIS_RMAP_NAME, routemap);
                redist->map = route_map_lookup_by_name(routemap);
                route_map_counter_increment(redist->map);
        }
@@ -507,7 +510,7 @@ void isis_redist_area_finish(struct isis_area *area)
                                redist = &area->redist_settings[protocol][type]
                                                               [level];
                                redist->redist = 0;
-                               XFREE(MTYPE_ISIS, redist->map_name);
+                               XFREE(MTYPE_ISIS_RMAP_NAME, redist->map_name);
                        }
                        route_table_finish(area->ext_reach[protocol][level]);
                }
index e1baf351f49952a22bad9fb68624c59a91e4784b..eb534a543a2be222c85ec3ac6b15ae90257712c2 100644 (file)
 #include "isis_route.h"
 #include "isis_zebra.h"
 
+DEFINE_MTYPE_STATIC(ISISD, ISIS_NEXTHOP,    "ISIS nexthop");
+DEFINE_MTYPE_STATIC(ISISD, ISIS_ROUTE_INFO, "ISIS route info");
+
 DEFINE_HOOK(isis_route_update_hook,
            (struct isis_area * area, struct prefix *prefix,
             struct isis_route_info *route_info),
-           (area, prefix, route_info))
+           (area, prefix, route_info));
 
 static struct isis_nexthop *nexthoplookup(struct list *nexthops, int family,
                                          union g_addr *ip, ifindex_t ifindex);
index d6763ec76c10e267ac3494aed32930eeae7b9e31..0e206d08f419bc80fd504eb986dad2cc02805a0d 100644 (file)
@@ -52,7 +52,7 @@ struct isis_route_info {
 DECLARE_HOOK(isis_route_update_hook,
             (struct isis_area * area, struct prefix *prefix,
              struct isis_route_info *route_info),
-            (area, prefix, route_info))
+            (area, prefix, route_info));
 
 void isis_nexthop_delete(struct isis_nexthop *nexthop);
 void adjinfo2nexthop(int family, struct list *nexthops,
index cab91997316c2a99aa0f2e19ce7ff61650d84f8a..522026dde4ef32fefdfdca3e787c46e25f3e9d48 100644 (file)
 #define ISIS_TRAP_LSP_ERROR 18
 
 /* Change this definition if number of traps changes */
-#define ISIS_TRAP_LAST_TRAP ISIS_TRAP_LSP_ERROR
+#define ISIS_TRAP_LAST_TRAP ISIS_TRAP_LSP_ERROR + 1
 
 #define ISIS_SNMP_TRAP_VAR 1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0
 
@@ -944,7 +944,7 @@ static int isis_snmp_circuit_lookup_next(oid *oid_idx, size_t oid_idx_len,
 
        start = 0;
 
-       if (oid_idx != NULL || oid_idx_len != 0) {
+       if (oid_idx != NULL && oid_idx_len != 0) {
                if (oid_idx[0] > SNMP_CIRCUITS_MAX)
                        return 0;
 
@@ -1018,7 +1018,7 @@ static int isis_snmp_circuit_level_lookup_next(
 
        start = 0;
 
-       if (oid_idx != NULL || oid_idx_len != 0) {
+       if (oid_idx != NULL && oid_idx_len != 0) {
                if (oid_idx[0] > SNMP_CIRCUITS_MAX)
                        return 0;
 
@@ -2012,8 +2012,8 @@ static uint8_t *isis_snmp_find_circ(struct variable *v, oid *name,
        oid *oid_idx;
        size_t oid_idx_len;
        struct isis_circuit *circuit;
-       uint64_t up_ticks;
-       uint64_t delta_ticks;
+       uint32_t up_ticks;
+       uint32_t delta_ticks;
        uint32_t now_time;
        int res;
 
@@ -2121,7 +2121,7 @@ static uint8_t *isis_snmp_find_circ(struct variable *v, oid *name,
                if (circuit->last_uptime == 0)
                        return SNMP_INTEGER(0);
 
-               up_ticks = netsnmp_get_agent_uptime();
+               up_ticks = (uint32_t)netsnmp_get_agent_uptime();
                now_time = isis_snmp_time();
 
                if (circuit->last_uptime >= now_time)
@@ -2132,7 +2132,7 @@ static uint8_t *isis_snmp_find_circ(struct variable *v, oid *name,
                if (up_ticks < delta_ticks)
                        return SNMP_INTEGER(up_ticks);
 
-               return SNMP_INTEGER((uint32_t)(up_ticks - delta_ticks));
+               return SNMP_INTEGER(up_ticks - delta_ticks);
 
        case ISIS_CIRC_3WAYENABLED:
                /* Not supported */
@@ -2434,8 +2434,8 @@ static uint8_t *isis_snmp_find_isadj(struct variable *v, oid *name,
        int res;
        uint32_t val;
        struct isis_adjacency *adj;
-       uint64_t up_ticks;
-       uint64_t delta_ticks;
+       uint32_t up_ticks;
+       uint32_t delta_ticks;
        uint32_t now_time;
 
        *write_method = NULL;
@@ -2561,7 +2561,7 @@ static uint8_t *isis_snmp_find_isadj(struct variable *v, oid *name,
                if (adj->flaps == 0)
                        return SNMP_INTEGER(0);
 
-               up_ticks = netsnmp_get_agent_uptime();
+               up_ticks = (uint32_t)netsnmp_get_agent_uptime();
 
                now_time = isis_snmp_time();
 
@@ -2573,7 +2573,7 @@ static uint8_t *isis_snmp_find_isadj(struct variable *v, oid *name,
                if (up_ticks < delta_ticks)
                        return SNMP_INTEGER(up_ticks);
 
-               return SNMP_INTEGER((uint32_t)(up_ticks - delta_ticks));
+               return SNMP_INTEGER(up_ticks - delta_ticks);
 
        default:
                break;
@@ -3452,6 +3452,9 @@ static int isis_snmp_module_init(void)
        return 0;
 }
 
-FRR_MODULE_SETUP(.name = "isis_snmp", .version = FRR_VERSION,
-                .description = "isis AgentX SNMP module",
-                .init = isis_snmp_module_init, )
+FRR_MODULE_SETUP(
+       .name = "isis_snmp",
+       .version = FRR_VERSION,
+       .description = "isis AgentX SNMP module",
+       .init = isis_snmp_module_init,
+);
index 7bcc6fea905ee8d8be23764ffea7d5ddd345205c..3e8ec8817e7e873dd6dd3d472959ab4ab7914c5c 100644 (file)
 #include "fabricd.h"
 #include "isis_spf_private.h"
 
-DEFINE_MTYPE_STATIC(ISISD, ISIS_SPF_RUN, "ISIS SPF Run Info");
-DEFINE_MTYPE_STATIC(ISISD, ISIS_SPF_ADJ, "ISIS SPF Adjacency");
+DEFINE_MTYPE_STATIC(ISISD, ISIS_SPFTREE,    "ISIS SPFtree");
+DEFINE_MTYPE_STATIC(ISISD, ISIS_SPF_RUN,    "ISIS SPF Run Info");
+DEFINE_MTYPE_STATIC(ISISD, ISIS_SPF_ADJ,    "ISIS SPF Adjacency");
+DEFINE_MTYPE_STATIC(ISISD, ISIS_VERTEX,     "ISIS vertex");
 DEFINE_MTYPE_STATIC(ISISD, ISIS_VERTEX_ADJ, "ISIS SPF Vertex Adjacency");
 
 static void spf_adj_list_parse_lsp(struct isis_spftree *spftree,
@@ -248,6 +250,20 @@ static struct isis_vertex *isis_vertex_new(struct isis_spftree *spftree,
        return vertex;
 }
 
+void isis_vertex_del(struct isis_vertex *vertex)
+{
+       list_delete(&vertex->Adj_N);
+       list_delete(&vertex->parents);
+       if (vertex->firsthops) {
+               hash_clean(vertex->firsthops, NULL);
+               hash_free(vertex->firsthops);
+               vertex->firsthops = NULL;
+       }
+
+       memset(vertex, 0, sizeof(struct isis_vertex));
+       XFREE(MTYPE_ISIS_VERTEX, vertex);
+}
+
 struct isis_vertex_adj *
 isis_vertex_adj_add(struct isis_spftree *spftree, struct isis_vertex *vertex,
                    struct list *vadj_list, struct isis_spf_adj *sadj,
index 79dfa3e164be09412598d9bb86a1423d096f7267..07d4ff5a0ec3fa50833e13d8c958753f59e956f6 100644 (file)
@@ -179,20 +179,7 @@ static void isis_vertex_queue_init(struct isis_vertex_queue *queue,
                                  isis_vertex_queue_hash_cmp, name);
 }
 
-__attribute__((__unused__))
-static void isis_vertex_del(struct isis_vertex *vertex)
-{
-       list_delete(&vertex->Adj_N);
-       list_delete(&vertex->parents);
-       if (vertex->firsthops) {
-               hash_clean(vertex->firsthops, NULL);
-               hash_free(vertex->firsthops);
-               vertex->firsthops = NULL;
-       }
-
-       memset(vertex, 0, sizeof(struct isis_vertex));
-       XFREE(MTYPE_ISIS_VERTEX, vertex);
-}
+void isis_vertex_del(struct isis_vertex *vertex);
 
 bool isis_vertex_adj_exists(const struct isis_spftree *spftree,
                            const struct isis_vertex *vertex,
index 21f534641cbf8fab1f32a72043c020a88069cc65..c4024772f5c9d8988e8162bae17f53cb249b6a25 100644 (file)
@@ -49,7 +49,7 @@
 #include "isisd/isis_errors.h"
 
 /* Local variables and functions */
-DEFINE_MTYPE_STATIC(ISISD, ISIS_SR_INFO, "ISIS segment routing information")
+DEFINE_MTYPE_STATIC(ISISD, ISIS_SR_INFO, "ISIS segment routing information");
 
 static void sr_local_block_delete(struct isis_area *area);
 static int sr_local_block_init(struct isis_area *area);
@@ -73,7 +73,7 @@ static inline int sr_prefix_sid_cfg_compare(const struct sr_prefix_cfg *a,
        return prefix_cmp(&a->prefix, &b->prefix);
 }
 DECLARE_RBTREE_UNIQ(srdb_prefix_cfg, struct sr_prefix_cfg, entry,
-                   sr_prefix_sid_cfg_compare)
+                   sr_prefix_sid_cfg_compare);
 
 /**
  * Find SRGB associated to a System ID.
index b012dfb00a03e50a0ff9dfff44755074d801504c..a933f366eb729053f42270ba7f237092f31ed5a2 100644 (file)
@@ -57,7 +57,7 @@
 #define SRLB_UPPER_BOUND               15999
 
 /* Segment Routing Data Base (SRDB) RB-Tree structure */
-PREDECL_RBTREE_UNIQ(srdb_prefix_cfg)
+PREDECL_RBTREE_UNIQ(srdb_prefix_cfg);
 
 /*
  * Segment Routing Prefix-SID information.
index a97c19a8bc54fa4e19b37ff9eb7f931a69e0df65..47fd684eb337c52dfb8812b587deb383112b3aff 100644 (file)
@@ -33,7 +33,6 @@
 #include "network.h"
 
 #include "isisd/isisd.h"
-#include "isisd/isis_memory.h"
 #include "isisd/isis_tlvs.h"
 #include "isisd/isis_common.h"
 #include "isisd/isis_mt.h"
@@ -45,9 +44,9 @@
 #include "isisd/isis_te.h"
 #include "isisd/isis_sr.h"
 
-DEFINE_MTYPE_STATIC(ISISD, ISIS_TLV, "ISIS TLVs")
-DEFINE_MTYPE(ISISD, ISIS_SUBTLV, "ISIS Sub-TLVs")
-DEFINE_MTYPE_STATIC(ISISD, ISIS_MT_ITEM_LIST, "ISIS MT Item Lists")
+DEFINE_MTYPE_STATIC(ISISD, ISIS_TLV, "ISIS TLVs");
+DEFINE_MTYPE(ISISD, ISIS_SUBTLV, "ISIS Sub-TLVs");
+DEFINE_MTYPE_STATIC(ISISD, ISIS_MT_ITEM_LIST, "ISIS MT Item Lists");
 
 typedef int (*unpack_tlv_func)(enum isis_tlv_context context, uint8_t tlv_type,
                               uint8_t tlv_len, struct stream *s,
@@ -4488,9 +4487,9 @@ static void tlvs_protocols_supported_to_adj(struct isis_tlvs *tlvs,
 }
 
 DEFINE_HOOK(isis_adj_ip_enabled_hook, (struct isis_adjacency *adj, int family),
-           (adj, family))
+           (adj, family));
 DEFINE_HOOK(isis_adj_ip_disabled_hook,
-           (struct isis_adjacency *adj, int family), (adj, family))
+           (struct isis_adjacency *adj, int family), (adj, family));
 
 static void tlvs_ipv4_addresses_to_adj(struct isis_tlvs *tlvs,
                                       struct isis_adjacency *adj,
index 037f91f0b87340e6cffc0d45432b886d887634ae..0438d13ae064569057db2e35e404759b75caa40d 100644 (file)
@@ -28,7 +28,7 @@
 #include "openbsd-tree.h"
 #include "prefix.h"
 
-DECLARE_MTYPE(ISIS_SUBTLV)
+DECLARE_MTYPE(ISIS_SUBTLV);
 
 struct lspdb_head;
 struct isis_subtlvs;
index 5c87e39157df4df8dc613b1a236ff7fb30260393..c7266152b70697055cf0b2f9263b715e92c46f9c 100644 (file)
 #include "jhash.h"
 
 #include "isisd/isisd.h"
-#include "isisd/isis_memory.h"
 #include "isisd/isis_flags.h"
 #include "isisd/isis_circuit.h"
 #include "isisd/isis_lsp.h"
 #include "isisd/isis_misc.h"
 #include "isisd/isis_tx_queue.h"
 
-DEFINE_MTYPE_STATIC(ISISD, TX_QUEUE, "ISIS TX Queue")
-DEFINE_MTYPE_STATIC(ISISD, TX_QUEUE_ENTRY, "ISIS TX Queue Entry")
+DEFINE_MTYPE_STATIC(ISISD, TX_QUEUE, "ISIS TX Queue");
+DEFINE_MTYPE_STATIC(ISISD, TX_QUEUE_ENTRY, "ISIS TX Queue Entry");
 
 struct isis_tx_queue {
        struct isis_circuit *circuit;
index 487a902c068b944a0f919ebd2a4e9e87710b1168..714961c1776d1b3e6e9ac164727e28e7a2e77580 100644 (file)
@@ -81,7 +81,15 @@ unsigned long debug_sr;
 unsigned long debug_ldp_sync;
 unsigned long debug_lfa;
 
-DEFINE_QOBJ_TYPE(isis_area)
+DEFINE_MGROUP(ISISD, "isisd");
+
+DEFINE_MTYPE_STATIC(ISISD, ISIS,      "ISIS process");
+DEFINE_MTYPE_STATIC(ISISD, ISIS_NAME, "ISIS process name");
+DEFINE_MTYPE_STATIC(ISISD, ISIS_AREA, "ISIS area");
+DEFINE_MTYPE(ISISD, ISIS_AREA_ADDR,   "ISIS area address");
+DEFINE_MTYPE(ISISD, ISIS_ACL_NAME,    "ISIS access-list name");
+
+DEFINE_QOBJ_TYPE(isis_area);
 
 /* ISIS process wide configuration. */
 static struct isis_master isis_master;
@@ -198,10 +206,10 @@ struct isis *isis_new(const char *vrf_name)
        if (vrf) {
                isis->vrf_id = vrf->vrf_id;
                isis_vrf_link(isis, vrf);
-               isis->name = XSTRDUP(MTYPE_ISIS, vrf->name);
+               isis->name = XSTRDUP(MTYPE_ISIS_NAME, vrf->name);
        } else {
                isis->vrf_id = VRF_UNKNOWN;
-               isis->name = XSTRDUP(MTYPE_ISIS, vrf_name);
+               isis->name = XSTRDUP(MTYPE_ISIS_NAME, vrf_name);
        }
 
        if (IS_DEBUG_EVENTS)
@@ -565,7 +573,7 @@ static int isis_vrf_enable(struct vrf *vrf)
        isis = isis_lookup_by_vrfname(vrf->name);
        if (isis) {
                if (isis->name && strmatch(vrf->name, VRF_DEFAULT_NAME)) {
-                       XFREE(MTYPE_ISIS, isis->name);
+                       XFREE(MTYPE_ISIS_NAME, isis->name);
                        isis->name = NULL;
                }
                old_vrf_id = isis->vrf_id;
@@ -631,7 +639,7 @@ void isis_finish(struct isis *isis)
                vrf = vrf_lookup_by_name(isis->name);
                if (vrf)
                        isis_vrf_unlink(isis, vrf);
-               XFREE(MTYPE_ISIS, isis->name);
+               XFREE(MTYPE_ISIS_NAME, isis->name);
        } else {
                vrf = vrf_lookup_by_id(VRF_DEFAULT);
                if (vrf)
index 1b0ec2b4f0ac233e592159bd2dea91496a2794d6..a2e821ad2ffab5d907f1627eb326b5f4b21a7d23 100644 (file)
@@ -24,6 +24,7 @@
 #define ISISD_H
 
 #include "vty.h"
+#include "memory.h"
 
 #include "isisd/isis_constants.h"
 #include "isisd/isis_common.h"
 #include "isis_flags.h"
 #include "isis_lsp.h"
 #include "isis_lfa.h"
-#include "isis_memory.h"
 #include "qobj.h"
 #include "ldp_sync.h"
 
+DECLARE_MGROUP(ISISD);
+
 #ifdef FABRICD
 static const bool fabricd = true;
 #define PROTO_TYPE ZEBRA_ROUTE_OPENFABRIC
@@ -236,11 +238,14 @@ struct isis_area {
        uint64_t id_len_mismatches[2];
        uint64_t lsp_error_counter[2];
 
-       QOBJ_FIELDS
+       QOBJ_FIELDS;
 };
-DECLARE_QOBJ_TYPE(isis_area)
+DECLARE_QOBJ_TYPE(isis_area);
+
+DECLARE_MTYPE(ISIS_ACL_NAME);  /* isis_area->spf_prefix_prioritites */
+DECLARE_MTYPE(ISIS_AREA_ADDR); /* isis_area->area_addrs */
 
-DECLARE_HOOK(isis_area_overload_bit_update, (struct isis_area * area), (area))
+DECLARE_HOOK(isis_area_overload_bit_update, (struct isis_area * area), (area));
 
 void isis_terminate(void);
 void isis_finish(struct isis *isis);
index 98674a6881cc8af8291f32a0f616978afcebe15a..4cefe6e10b9a3f38571d2a4bed608da9c0955e79 100644 (file)
@@ -57,7 +57,6 @@ noinst_HEADERS += \
        isisd/isis_ldp_sync.h \
        isisd/isis_lfa.h \
        isisd/isis_lsp.h \
-       isisd/isis_memory.h \
        isisd/isis_misc.h \
        isisd/isis_mt.h \
        isisd/isis_nb.h \
@@ -92,7 +91,6 @@ LIBISIS_SOURCES = \
        isisd/isis_ldp_sync.c \
        isisd/isis_lfa.c \
        isisd/isis_lsp.c \
-       isisd/isis_memory.c \
        isisd/isis_misc.c \
        isisd/isis_mt.c \
        isisd/isis_pdu.c \
@@ -142,7 +140,7 @@ nodist_isisd_isisd_SOURCES = \
        # end
 
 isisd_isisd_snmp_la_SOURCES = isisd/isis_snmp.c
-isisd_isisd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu99
+isisd_isisd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu11
 isisd_isisd_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
 isisd_isisd_snmp_la_LIBADD = lib/libfrrsnmp.la
 
index c9b37c0d2786baa65ff72e7e1b45cf7589ba11e4..3f59d18aa8e76da640eacc1c620ea635fefaa4b5 100644 (file)
@@ -374,6 +374,76 @@ static uint8_t *ldpEntityTable(struct variable *v, oid name[], size_t *length,
        return NULL;
 }
 
+static uint8_t *ldpEntityStatsTable(struct variable *v, oid name[],
+                                   size_t *length, int exact, size_t *var_len,
+                                   WriteMethod **write_method)
+{
+       struct in_addr entityLdpId = {.s_addr = 0};
+       int len;
+
+       *write_method = NULL;
+
+       if (smux_header_table(v, name, length, exact, var_len, write_method)
+           == MATCH_FAILED)
+               return NULL;
+
+       if (exact) {
+               if (*length != LDP_ENTITY_TOTAL_LEN)
+                       return NULL;
+       } else {
+               len = *length - v->namelen - LDP_ENTITY_MAX_IDX_LEN;
+               if (len > 0)
+                       return NULL;
+
+               entityLdpId.s_addr = ldp_rtr_id_get(leconf);
+
+               /* Copy the name out */
+               memcpy(name, v->name, v->namelen * sizeof(oid));
+
+               /* Append index */
+               *length = LDP_ENTITY_TOTAL_LEN;
+               oid_copy_addr(name + v->namelen, &entityLdpId,
+                             IN_ADDR_SIZE);
+               name[v->namelen + 4] = 0;
+               name[v->namelen + 5] = 0;
+               name[v->namelen + 6] = LDP_DEFAULT_ENTITY_INDEX;
+       }
+
+       /* Return the current value of the variable */
+       switch (v->magic) {
+       case MPLSLDPENTITYSTATSSESSIONATTEMPTS:
+               return SNMP_INTEGER(leconf->stats.session_attempts);
+       case MPLSLDPENTITYSTATSSESSIONREJHELLO:
+               return SNMP_INTEGER(leconf->stats.session_rejects_hello);
+       case MPLSLDPENTITYSTATSSESSIONREJAD:
+               return SNMP_INTEGER(leconf->stats.session_rejects_ad);
+       case MPLSLDPENTITYSTATSSESSIONREJMAXPDU:
+               return SNMP_INTEGER(leconf->stats.session_rejects_max_pdu);
+       case MPLSLDPENTITYSTATSSESSIONREJLR:
+               return SNMP_INTEGER(leconf->stats.session_rejects_lr);
+       case MPLSLDPENTITYSTATSBADLDPID:
+               return SNMP_INTEGER(leconf->stats.bad_ldp_id);
+       case MPLSLDPENTITYSTATSBADPDULENGTH:
+               return SNMP_INTEGER(leconf->stats.bad_pdu_len);
+       case MPLSLDPENTITYSTATSBADMSGLENGTH:
+               return SNMP_INTEGER(leconf->stats.bad_msg_len);
+       case MPLSLDPENTITYSTATSBADTLVLENGTH:
+               return SNMP_INTEGER(leconf->stats.bad_tlv_len);
+       case MPLSLDPENTITYSTATSMALFORMEDTLV:
+               return SNMP_INTEGER(leconf->stats.malformed_tlv);
+       case MPLSLDPENTITYSTATSKEEPALIVEEXP:
+               return SNMP_INTEGER(leconf->stats.keepalive_timer_exp);
+       case MPLSLDPENTITYSTATSSHUTDOWNRCVNOTIFY:
+               return SNMP_INTEGER(leconf->stats.shutdown_rcv_notify);
+       case MPLSLDPENTITYSTATSSHUTDOWNSENTNOTIFY:
+               return SNMP_INTEGER(leconf->stats.shutdown_send_notify);
+       default:
+               return NULL;
+       }
+
+       return NULL;
+}
+
 #define LDP_ADJACENCY_ENTRY_MAX_IDX_LEN        14
 
 static void ldpHelloAdjacencyTable_oid_to_index(
@@ -863,6 +933,59 @@ static uint8_t *ldpSessionTable(struct variable *v, oid name[], size_t *length,
        return NULL;
 }
 
+static uint8_t *ldpSessionStatsTable(struct variable *v, oid name[],
+                               size_t *length,
+                               int exact, size_t *var_len,
+                               WriteMethod **write_method)
+{
+       struct in_addr entityLdpId = {.s_addr = 0};
+       uint32_t entityIndex = 0;
+       struct in_addr peerLdpId = {.s_addr = 0};
+
+       if (smux_header_table(v, name, length, exact, var_len, write_method)
+           == MATCH_FAILED)
+               return NULL;
+
+       struct ctl_nbr *ctl_nbr = ldpPeerTable_lookup(v, name, length, exact,
+               &entityLdpId, &entityIndex, &peerLdpId);
+
+       if (!ctl_nbr)
+               return NULL;
+
+       if (!exact) {
+               entityLdpId.s_addr = ldp_rtr_id_get(leconf);
+               entityIndex = LDP_DEFAULT_ENTITY_INDEX;
+               peerLdpId = ctl_nbr->id;
+
+               /* Copy the name out */
+               memcpy(name, v->name, v->namelen * sizeof(oid));
+
+               /* Append index */
+               oid_copy_addr(name + v->namelen, &entityLdpId,
+                       sizeof(struct in_addr));
+               name[v->namelen + 4] = 0;
+               name[v->namelen + 5] = 0;
+               name[v->namelen + 6] = entityIndex;
+               oid_copy_addr(name + v->namelen + 7, &peerLdpId,
+                       sizeof(struct in_addr));
+               name[v->namelen + 11] = 0;
+               name[v->namelen + 12] = 0;
+
+                *length = v->namelen + LDP_PEER_ENTRY_MAX_IDX_LEN;
+       }
+
+       switch (v->magic) {
+       case MPLSLDPSESSIONSTATSUNKNOWNMESTYPEERRORS:
+               return SNMP_INTEGER(ctl_nbr->stats.unknown_msg);
+       case MPLSLDPSESSIONSTATSUNKNOWNTLVERRORS:
+               return SNMP_INTEGER(ctl_nbr->stats.unknown_tlv);
+       default:
+               return NULL;
+       }
+
+       return NULL;
+}
+
 static struct variable ldpe_variables[] = {
        {MPLS_LDP_LSR_ID, STRING, RONLY, ldpLsrId, 3, {1, 1, 1}},
        {MPLS_LDP_LSR_LOOP_DETECTION_CAPABLE, INTEGER, RONLY,
@@ -920,6 +1043,34 @@ static struct variable ldpe_variables[] = {
        {MPLSLDPENTITYROWSTATUS, INTEGER, RONLY, ldpEntityTable,
         5, {1, 2, 3, 1, 23}},
 
+       /* MPLS LDP mplsLdpEntityStatsTable. */
+       { MPLSLDPENTITYSTATSSESSIONATTEMPTS, COUNTER32, RONLY,
+         ldpEntityStatsTable, 5, {1, 2, 4, 1, 1}},
+       { MPLSLDPENTITYSTATSSESSIONREJHELLO, COUNTER32, RONLY,
+         ldpEntityStatsTable, 5, {1, 2, 4, 1, 2}},
+       { MPLSLDPENTITYSTATSSESSIONREJAD, COUNTER32, RONLY,
+         ldpEntityStatsTable, 5, {1, 2, 4, 1, 3}},
+       { MPLSLDPENTITYSTATSSESSIONREJMAXPDU, COUNTER32, RONLY,
+         ldpEntityStatsTable, 5, {1, 2, 4, 1, 4}},
+       { MPLSLDPENTITYSTATSSESSIONREJLR, COUNTER32, RONLY,
+         ldpEntityStatsTable, 5, {1, 2, 4, 1, 5}},
+       { MPLSLDPENTITYSTATSBADLDPID, COUNTER32, RONLY,
+         ldpEntityStatsTable, 5, {1, 2, 4, 1, 6}},
+       { MPLSLDPENTITYSTATSBADPDULENGTH, COUNTER32, RONLY,
+         ldpEntityStatsTable, 5, {1, 2, 4, 1, 7}},
+       { MPLSLDPENTITYSTATSBADMSGLENGTH, COUNTER32, RONLY,
+         ldpEntityStatsTable, 5, {1, 2, 4, 1, 8}},
+       { MPLSLDPENTITYSTATSBADTLVLENGTH, COUNTER32, RONLY,
+         ldpEntityStatsTable, 5, {1, 2, 4, 1, 9}},
+       { MPLSLDPENTITYSTATSMALFORMEDTLV, COUNTER32, RONLY,
+         ldpEntityStatsTable, 5, {1, 2, 4, 1, 10}},
+       { MPLSLDPENTITYSTATSKEEPALIVEEXP, COUNTER32, RONLY,
+         ldpEntityStatsTable, 5, {1, 2, 4, 1, 11}},
+       { MPLSLDPENTITYSTATSSHUTDOWNRCVNOTIFY, COUNTER32, RONLY,
+         ldpEntityStatsTable, 5, {1, 2, 4, 1, 12}},
+       { MPLSLDPENTITYSTATSSHUTDOWNSENTNOTIFY, COUNTER32, RONLY,
+         ldpEntityStatsTable, 5, {1, 2, 4, 1, 13}},
+
        /* MPLS LDP mplsLdpPeerTable */
        {MPLSLDPPEERLDPID, STRING, RONLY, ldpPeerTable, 5, {1, 3, 2, 1, 1}},
        {MPLSLDPPEERLABELDISTMETHOD, INTEGER, RONLY, ldpPeerTable,
@@ -949,6 +1100,12 @@ static struct variable ldpe_variables[] = {
        {MPLSLDPSESSIONDISCONTINUITYTIME, TIMESTAMP, RONLY, ldpSessionTable,
         5, {1, 3, 3, 1, 8}},
 
+       /* MPLS LDP mplsLdpSessionStatsTable */
+       {MPLSLDPSESSIONSTATSUNKNOWNMESTYPEERRORS, COUNTER32, RONLY,
+        ldpSessionStatsTable, 5, {1, 3, 4, 1, 1}},
+       {MPLSLDPSESSIONSTATSUNKNOWNTLVERRORS, COUNTER32, RONLY,
+        ldpSessionStatsTable, 5, {1, 3, 4, 1, 2}},
+
        /* MPLS LDP mplsLdpHelloAdjacencyTable. */
        {MPLSLDPHELLOADJACENCYINDEX, UNSIGNED32, RONLY,
         ldpHelloAdjacencyTable, 6, {1, 3, 5, 1, 1, 1}},
@@ -1082,6 +1239,9 @@ static int ldp_snmp_module_init(void)
        return 0;
 }
 
-FRR_MODULE_SETUP(.name = "ldp_snmp", .version = FRR_VERSION,
-                .description = "ldp AgentX SNMP module",
-                .init = ldp_snmp_module_init, )
+FRR_MODULE_SETUP(
+       .name = "ldp_snmp",
+       .version = FRR_VERSION,
+       .description = "ldp AgentX SNMP module",
+       .init = ldp_snmp_module_init,
+);
index 14235a0f1f971a04565463dc7d56bce12c73865a..d69a4dcd3c5ade83093b3241c41584a17abb9aa8 100644 (file)
@@ -69,13 +69,13 @@ static void          merge_l2vpns(struct ldpd_conf *, struct ldpd_conf *);
 static void             merge_l2vpn(struct ldpd_conf *, struct l2vpn *,
                            struct l2vpn *);
 
-DEFINE_QOBJ_TYPE(iface)
-DEFINE_QOBJ_TYPE(tnbr)
-DEFINE_QOBJ_TYPE(nbr_params)
-DEFINE_QOBJ_TYPE(l2vpn_if)
-DEFINE_QOBJ_TYPE(l2vpn_pw)
-DEFINE_QOBJ_TYPE(l2vpn)
-DEFINE_QOBJ_TYPE(ldpd_conf)
+DEFINE_QOBJ_TYPE(iface);
+DEFINE_QOBJ_TYPE(tnbr);
+DEFINE_QOBJ_TYPE(nbr_params);
+DEFINE_QOBJ_TYPE(l2vpn_if);
+DEFINE_QOBJ_TYPE(l2vpn_pw);
+DEFINE_QOBJ_TYPE(l2vpn);
+DEFINE_QOBJ_TYPE(ldpd_conf);
 
 struct ldpd_global      global;
 struct ldpd_init        init;
@@ -88,7 +88,7 @@ static pid_t           lde_pid;
 
 static struct frr_daemon_info ldpd_di;
 
-DEFINE_HOOK(ldp_register_mib, (struct thread_master * tm), (tm))
+DEFINE_HOOK(ldp_register_mib, (struct thread_master * tm), (tm));
 
 static void ldp_load_module(const char *name)
 {
@@ -218,7 +218,7 @@ FRR_DAEMON_INFO(ldpd, LDP,
 
        .yang_modules = ldpd_yang_modules,
        .n_yang_modules = array_size(ldpd_yang_modules),
-)
+);
 
 static int ldp_config_fork_apply(struct thread *t)
 {
index 103f4f228dfa799888b7bf27d7f592b5252883b7..8fdc16fc7b97b60a366147109df48c5510a332fc 100644 (file)
@@ -362,11 +362,11 @@ struct iface {
        struct iface_af          ipv4;
        struct iface_af          ipv6;
        struct iface_ldp_sync    ldp_sync;
-       QOBJ_FIELDS
+       QOBJ_FIELDS;
 };
 RB_HEAD(iface_head, iface);
 RB_PROTOTYPE(iface_head, iface, entry, iface_compare);
-DECLARE_QOBJ_TYPE(iface)
+DECLARE_QOBJ_TYPE(iface);
 
 /* source of targeted hellos */
 struct tnbr {
@@ -379,11 +379,11 @@ struct tnbr {
        uint16_t                 pw_count;
        uint32_t                 rlfa_count;
        uint8_t                  flags;
-       QOBJ_FIELDS
+       QOBJ_FIELDS;
 };
 RB_HEAD(tnbr_head, tnbr);
 RB_PROTOTYPE(tnbr_head, tnbr, entry, tnbr_compare);
-DECLARE_QOBJ_TYPE(tnbr)
+DECLARE_QOBJ_TYPE(tnbr);
 #define F_TNBR_CONFIGURED       0x01
 #define F_TNBR_DYNAMIC          0x02
 
@@ -405,11 +405,11 @@ struct nbr_params {
                uint8_t                  md5key_len;
        } auth;
        uint8_t                  flags;
-       QOBJ_FIELDS
+       QOBJ_FIELDS;
 };
 RB_HEAD(nbrp_head, nbr_params);
 RB_PROTOTYPE(nbrp_head, nbr_params, entry, nbr_params_compare);
-DECLARE_QOBJ_TYPE(nbr_params)
+DECLARE_QOBJ_TYPE(nbr_params);
 #define F_NBRP_KEEPALIVE        0x01
 #define F_NBRP_GTSM             0x02
 #define F_NBRP_GTSM_HOPS        0x04
@@ -435,9 +435,27 @@ struct ldp_stats {
        uint32_t                 labelrel_rcvd;
        uint32_t                 labelabreq_sent;
        uint32_t                 labelabreq_rcvd;
+       uint32_t                 unknown_tlv;
+       uint32_t                 unknown_msg;
 
 };
 
+struct ldp_entity_stats {
+       uint32_t                 session_attempts;
+       uint32_t                 session_rejects_hello;
+       uint32_t                 session_rejects_ad;
+       uint32_t                 session_rejects_max_pdu;
+       uint32_t                 session_rejects_lr;
+       uint32_t                 bad_ldp_id;
+       uint32_t                 bad_pdu_len;
+       uint32_t                 bad_msg_len;
+       uint32_t                 bad_tlv_len;
+       uint32_t                 malformed_tlv;
+       uint32_t                 keepalive_timer_exp;
+       uint32_t                 shutdown_rcv_notify;
+       uint32_t                 shutdown_send_notify;
+};
+
 struct l2vpn_if {
        RB_ENTRY(l2vpn_if)       entry;
        struct l2vpn            *l2vpn;
@@ -445,11 +463,11 @@ struct l2vpn_if {
        ifindex_t                ifindex;
        int                      operative;
        uint8_t                  mac[ETH_ALEN];
-       QOBJ_FIELDS
+       QOBJ_FIELDS;
 };
 RB_HEAD(l2vpn_if_head, l2vpn_if);
 RB_PROTOTYPE(l2vpn_if_head, l2vpn_if, entry, l2vpn_if_compare);
-DECLARE_QOBJ_TYPE(l2vpn_if)
+DECLARE_QOBJ_TYPE(l2vpn_if);
 
 struct l2vpn_pw {
        RB_ENTRY(l2vpn_pw)       entry;
@@ -467,11 +485,11 @@ struct l2vpn_pw {
        uint32_t                 remote_status;
        uint8_t                  flags;
        uint8_t                  reason;
-       QOBJ_FIELDS
+       QOBJ_FIELDS;
 };
 RB_HEAD(l2vpn_pw_head, l2vpn_pw);
 RB_PROTOTYPE(l2vpn_pw_head, l2vpn_pw, entry, l2vpn_pw_compare);
-DECLARE_QOBJ_TYPE(l2vpn_pw)
+DECLARE_QOBJ_TYPE(l2vpn_pw);
 #define F_PW_STATUSTLV_CONF    0x01    /* status tlv configured */
 #define F_PW_STATUSTLV         0x02    /* status tlv negotiated */
 #define F_PW_CWORD_CONF                0x04    /* control word configured */
@@ -495,11 +513,11 @@ struct l2vpn {
        struct l2vpn_if_head     if_tree;
        struct l2vpn_pw_head     pw_tree;
        struct l2vpn_pw_head     pw_inactive_tree;
-       QOBJ_FIELDS
+       QOBJ_FIELDS;
 };
 RB_HEAD(l2vpn_head, l2vpn);
 RB_PROTOTYPE(l2vpn_head, l2vpn, entry, l2vpn_compare);
-DECLARE_QOBJ_TYPE(l2vpn)
+DECLARE_QOBJ_TYPE(l2vpn);
 #define L2VPN_TYPE_VPWS                1
 #define L2VPN_TYPE_VPLS                2
 
@@ -565,9 +583,10 @@ struct ldpd_conf {
        uint16_t                 wait_for_sync_interval;
        int                      flags;
        time_t                   config_change_time;
-       QOBJ_FIELDS
+       struct ldp_entity_stats  stats;
+       QOBJ_FIELDS;
 };
-DECLARE_QOBJ_TYPE(ldpd_conf)
+DECLARE_QOBJ_TYPE(ldpd_conf);
 #define        F_LDPD_NO_FIB_UPDATE    0x0001
 #define        F_LDPD_DS_CISCO_INTEROP 0x0002
 #define        F_LDPD_ENABLED          0x0004
@@ -896,7 +915,7 @@ int          ldp_zebra_send_rlfa_labels(struct zapi_rlfa_response *
        (__IPV6_ADDR_MC_SCOPE(a) == __IPV6_ADDR_SCOPE_INTFACELOCAL))
 #endif
 
-DECLARE_HOOK(ldp_register_mib, (struct thread_master * tm), (tm))
+DECLARE_HOOK(ldp_register_mib, (struct thread_master * tm), (tm));
 
 extern void ldp_agentx_enabled(void);
 
index 9572f1ac1280311d9c2da291821509bd7bccc9c0..880722424e33d3771f8df25ca4610ffa33b07952 100644 (file)
@@ -321,6 +321,7 @@ void        ldpe_l2vpn_exit(struct l2vpn *);
 void   ldpe_l2vpn_pw_init(struct l2vpn_pw *);
 void   ldpe_l2vpn_pw_exit(struct l2vpn_pw *);
 
-DECLARE_HOOK(ldp_nbr_state_change, (struct nbr * nbr, int old_state), (nbr, old_state))
+DECLARE_HOOK(ldp_nbr_state_change, (struct nbr * nbr, int old_state),
+            (nbr, old_state));
 
 #endif /* _LDPE_H_ */
index 23c67ec1ca3380ef27a49a8bbdcb60918e3c1eb4..e884b3ebfc9ca6ec9158209dd2bcbab04fcda022 100644 (file)
@@ -26,7 +26,8 @@
 #include "lde.h"
 #include "log.h"
 
-DEFINE_HOOK(ldp_nbr_state_change, (struct nbr * nbr, int old_state), (nbr, old_state))
+DEFINE_HOOK(ldp_nbr_state_change, (struct nbr * nbr, int old_state),
+           (nbr, old_state));
 
 static __inline int     nbr_id_compare(const struct nbr *, const struct nbr *);
 static __inline int     nbr_addr_compare(const struct nbr *,
index f84e0f893b8787c3ea5c3de02402a399f4124e30..3ecf5d4ba5919af7fc7dc80292d0bb504950f332 100644 (file)
@@ -69,6 +69,36 @@ send_notification_full(struct tcp_conn *tcp, struct notify_msg *nm)
                tcp->nbr->stats.notif_sent++;
        }
 
+       /* update SNMP session counters */
+       switch (nm->status_code) {
+       case S_NO_HELLO:
+               leconf->stats.session_rejects_hello++;
+               break;
+       case S_BAD_LDP_ID:
+               leconf->stats.bad_ldp_id++;
+               break;
+       case S_BAD_PDU_LEN:
+               leconf->stats.bad_pdu_len++;
+               break;
+       case S_BAD_MSG_LEN:
+               leconf->stats.bad_msg_len++;
+               break;
+       case S_BAD_TLV_LEN:
+               leconf->stats.bad_tlv_len++;
+               break;
+       case S_BAD_TLV_VAL:
+               leconf->stats.malformed_tlv++;
+               break;
+       case S_KEEPALIVE_TMR:
+               leconf->stats.keepalive_timer_exp++;
+               break;
+       case S_SHUTDOWN:
+               leconf->stats.shutdown_send_notify++;
+               break;
+       default:
+               break;
+       }
+
        evbuf_enqueue(&tcp->wbuf, buf);
 }
 
@@ -122,6 +152,7 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len)
 
        if (len < STATUS_SIZE) {
                session_shutdown(nbr, S_BAD_MSG_LEN, msg.id, msg.type);
+               leconf->stats.bad_msg_len++;
                return (-1);
        }
        memcpy(&st, buf, sizeof(st));
@@ -129,6 +160,7 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len)
        if (ntohs(st.length) > STATUS_SIZE - TLV_HDR_SIZE ||
            ntohs(st.length) > len - TLV_HDR_SIZE) {
                session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
+               leconf->stats.bad_tlv_len++;
                return (-1);
        }
        buf += STATUS_SIZE;
@@ -145,6 +177,7 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len)
 
                if (len < sizeof(tlv)) {
                        session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
+                       leconf->stats.bad_tlv_len++;
                        return (-1);
                }
 
@@ -153,6 +186,7 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len)
                tlv_len = ntohs(tlv.length);
                if (tlv_len + TLV_HDR_SIZE > len) {
                        session_shutdown(nbr, S_BAD_TLV_LEN, msg.id, msg.type);
+                       leconf->stats.bad_tlv_len++;
                        return (-1);
                }
                buf += TLV_HDR_SIZE;
@@ -182,14 +216,17 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len)
                        if (tlen != tlv_len) {
                                session_shutdown(nbr, S_BAD_TLV_VAL,
                                    msg.id, msg.type);
+                               leconf->stats.bad_tlv_len++;
                                return (-1);
                        }
                        nm.flags |= F_NOTIF_FEC;
                        break;
                default:
-                       if (!(ntohs(tlv.type) & UNKNOWN_FLAG))
+                       if (!(ntohs(tlv.type) & UNKNOWN_FLAG)) {
+                               nbr->stats.unknown_tlv++;
                                send_notification_rtlvs(nbr, S_UNKNOWN_TLV,
                                    msg.id, msg.type, tlv_type, tlv_len, buf);
+                       }
                        /* ignore unknown tlv */
                        break;
                }
@@ -243,21 +280,57 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len)
                 * initialization, it SHOULD transmit a Shutdown message and
                 * then close the transport connection".
                 */
-               if (nbr->state != NBR_STA_OPER && nm.status_code == S_SHUTDOWN)
+               if (nbr->state != NBR_STA_OPER &&
+                   nm.status_code == S_SHUTDOWN) {
+                       leconf->stats.session_attempts++;
                        send_notification(nbr->tcp, S_SHUTDOWN,
                            msg.id, msg.type);
+               }
 
+               leconf->stats.shutdown_rcv_notify++;
                nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION);
                return (-1);
        }
 
-       /* lde needs to know about a few notification messages */
+       /* lde needs to know about a few notification messages
+        * and update SNMP session counters
+        */
        switch (nm.status_code) {
        case S_PW_STATUS:
        case S_ENDOFLIB:
                ldpe_imsg_compose_lde(IMSG_NOTIFICATION, nbr->peerid, 0,
                    &nm, sizeof(nm));
                break;
+       case S_NO_HELLO:
+               leconf->stats.session_rejects_hello++;
+               break;
+       case S_PARM_ADV_MODE:
+               leconf->stats.session_rejects_ad++;
+               break;
+       case S_MAX_PDU_LEN:
+               leconf->stats.session_rejects_max_pdu++;
+               break;
+       case S_PARM_L_RANGE:
+               leconf->stats.session_rejects_lr++;
+               break;
+       case S_BAD_LDP_ID:
+               leconf->stats.bad_ldp_id++;
+               break;
+       case S_BAD_PDU_LEN:
+               leconf->stats.bad_pdu_len++;
+               break;
+       case S_BAD_MSG_LEN:
+               leconf->stats.bad_msg_len++;
+               break;
+       case S_BAD_TLV_LEN:
+               leconf->stats.bad_tlv_len++;
+               break;
+       case S_BAD_TLV_VAL:
+               leconf->stats.malformed_tlv++;
+               break;
+       case S_SHUTDOWN:
+               leconf->stats.shutdown_rcv_notify++;
+               break;
        default:
                break;
        }
index fdcaa79d2396015c1d32b921aff4eefe35ba2792..8735faf3dd1aefd08367833d601d3bc54fdada8b 100644 (file)
@@ -560,9 +560,11 @@ session_read(struct thread *thread)
                        default:
                                log_debug("%s: unknown LDP message from nbr %pI4",
                                    __func__, &nbr->id);
-                               if (!(ntohs(msg->type) & UNKNOWN_FLAG))
+                               if (!(ntohs(msg->type) & UNKNOWN_FLAG)) {
+                                       nbr->stats.unknown_msg++;
                                        send_notification(nbr->tcp,
                                            S_UNKNOWN_MSG, msg->id, msg->type);
+                               }
                                /* ignore the message */
                                ret = 0;
                                break;
@@ -667,6 +669,12 @@ session_shutdown(struct nbr *nbr, uint32_t status, uint32_t msg_id,
        case NBR_STA_INITIAL:
        case NBR_STA_OPENREC:
        case NBR_STA_OPENSENT:
+               /* update SNMP session counters during initialization */
+               leconf->stats.session_attempts++;
+               send_notification(nbr->tcp, status, msg_id, msg_type);
+
+               nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION);
+               break;
        case NBR_STA_OPER:
                send_notification(nbr->tcp, status, msg_id, msg_type);
 
index b01d414de8c671ca6e19fc462808e48877435ca2..aa9b751bcc9c9e85060e13672c3a687ca29cf979 100644 (file)
@@ -65,6 +65,6 @@ ldpd_ldpd_SOURCES = ldpd/ldpd.c
 ldpd_ldpd_LDADD = ldpd/libldp.a lib/libfrr.la $(LIBCAP)
 
 ldpd_ldpd_snmp_la_SOURCES = ldpd/ldp_snmp.c
-ldpd_ldpd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu99
+ldpd_ldpd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu11
 ldpd_ldpd_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
 ldpd_ldpd_snmp_la_LIBADD = lib/libfrrsnmp.la
index c1ff7a61b1039da702f6045d9cc0cf95069f14af..b5a035ee2be81e31ad558fb4c8760022691ae096 100644 (file)
@@ -34,9 +34,9 @@
 #include "lib_errors.h"
 #include "xref.h"
 
-XREF_SETUP()
+XREF_SETUP();
 
-DEFINE_HOOK(agentx_enabled, (), ())
+DEFINE_HOOK(agentx_enabled, (), ());
 
 static int agentx_enabled = 0;
 
index 5ca19cbcd4c7f21c8ada9c9225ca4e018f26e92f..c795128a34d5f56af5fb5b2fa2e49a3461ca2fb4 100644 (file)
@@ -123,15 +123,16 @@ struct atomlist_head {
 
 /* use as:
  *
- * PREDECL_ATOMLIST(namelist)
+ * PREDECL_ATOMLIST(namelist);
  * struct name {
  *   struct namelist_item nlitem;
  * }
- * DECLARE_ATOMLIST(namelist, struct name, nlitem)
+ * DECLARE_ATOMLIST(namelist, struct name, nlitem);
  */
 #define PREDECL_ATOMLIST(prefix)                                               \
 struct prefix ## _head { struct atomlist_head ah; };                           \
-struct prefix ## _item { struct atomlist_item ai; };
+struct prefix ## _item { struct atomlist_item ai; };                           \
+MACRO_REQUIRE_SEMICOLON() /* end */
 
 #define INIT_ATOMLIST(var) { }
 
@@ -171,7 +172,7 @@ macro_inline void prefix ## _fini(struct prefix##_head *h)                     \
        assert(prefix ## _count(h) == 0);                                      \
        memset(h, 0, sizeof(*h));                                              \
 }                                                                              \
-/* ... */
+MACRO_REQUIRE_SEMICOLON() /* end */
 
 /* add_head:
  * - contention on ->first pointer
@@ -221,7 +222,8 @@ struct atomsort_head {
 
 #define _PREDECL_ATOMSORT(prefix)                                              \
 struct prefix ## _head { struct atomsort_head ah; };                           \
-struct prefix ## _item { struct atomsort_item ai; };
+struct prefix ## _item { struct atomsort_item ai; };                           \
+MACRO_REQUIRE_SEMICOLON() /* end */
 
 #define INIT_ATOMSORT_UNIQ(var)                { }
 #define INIT_ATOMSORT_NONUNIQ(var)     { }
@@ -298,7 +300,7 @@ macro_inline type *prefix ## _pop(struct prefix##_head *h)                     \
        struct atomsort_item *p = atomsort_pop(&h->ah);                        \
        return p ? container_of(p, type, field.ai) : NULL;                     \
 }                                                                              \
-/* ... */
+MACRO_REQUIRE_SEMICOLON() /* end */
 
 #define PREDECL_ATOMSORT_UNIQ(prefix)                                          \
        _PREDECL_ATOMSORT(prefix)
@@ -312,7 +314,7 @@ macro_inline int prefix ## __cmp(const struct atomsort_item *a,                \
 }                                                                              \
                                                                                \
 _DECLARE_ATOMSORT(prefix, type, field,                                         \
-               prefix ## __cmp, prefix ## __cmp)                              \
+               prefix ## __cmp, prefix ## __cmp);                             \
                                                                                \
 atomic_find_warn                                                               \
 macro_inline type *prefix ## _find(struct prefix##_head *h, const type *item)  \
@@ -325,7 +327,7 @@ macro_inline type *prefix ## _find(struct prefix##_head *h, const type *item)  \
                return NULL;                                                   \
        return p;                                                              \
 }                                                                              \
-/* ... */
+MACRO_REQUIRE_SEMICOLON() /* end */
 
 #define PREDECL_ATOMSORT_NONUNIQ(prefix)                                       \
        _PREDECL_ATOMSORT(prefix)
@@ -352,8 +354,8 @@ macro_inline int prefix ## __cmp_uq(const struct atomsort_item *a,             \
 }                                                                              \
                                                                                \
 _DECLARE_ATOMSORT(prefix, type, field,                                         \
-               prefix ## __cmp, prefix ## __cmp_uq)                           \
-/* ... */
+               prefix ## __cmp, prefix ## __cmp_uq);                          \
+MACRO_REQUIRE_SEMICOLON() /* end */
 
 struct atomsort_item *atomsort_add(struct atomsort_head *h,
                struct atomsort_item *item, int (*cmpfn)(
index 3ab0e21af5249a1805ce2553c37edf8008c8a198..176269cc5b2704149d0a9f98289bc813bc4f8165 100644 (file)
--- a/lib/bfd.c
+++ b/lib/bfd.c
 #include "prefix.h"
 #include "thread.h"
 #include "stream.h"
+#include "vrf.h"
 #include "zclient.h"
 #include "table.h"
 #include "vty.h"
 #include "bfd.h"
 
-DEFINE_MTYPE_STATIC(LIB, BFD_INFO, "BFD info")
+DEFINE_MTYPE_STATIC(LIB, BFD_INFO, "BFD info");
 
 static int bfd_debug = 0;
 static struct bfd_gbl bfd_gbl;
@@ -568,3 +569,640 @@ int zclient_bfd_command(struct zclient *zc, struct bfd_session_arg *args)
 
        return 0;
 }
+
+/**
+ * BFD protocol integration configuration.
+ */
+
+/** Events definitions. */
+enum bfd_session_event {
+       /** Remove the BFD session configuration. */
+       BSE_UNINSTALL,
+       /** Install the BFD session configuration. */
+       BSE_INSTALL,
+};
+
+/**
+ * Data structure to do the necessary tricks to hide the BFD protocol
+ * integration internals.
+ */
+struct bfd_session_params {
+       /** Contains the session parameters and more. */
+       struct bfd_session_arg args;
+       /** Contains the session state. */
+       struct bfd_session_status bss;
+       /** Protocol implementation status update callback. */
+       bsp_status_update updatecb;
+       /** Protocol implementation custom data pointer. */
+       void *arg;
+
+       /**
+        * Next event.
+        *
+        * This variable controls what action to execute when the command batch
+        * finishes. Normally we'd use `thread_add_event` value, however since
+        * that function is going to be called multiple times and the value
+        * might be different we'll use this variable to keep track of it.
+        */
+       enum bfd_session_event lastev;
+       /**
+        * BFD session configuration event.
+        *
+        * Multiple actions might be asked during a command batch (either via
+        * configuration load or northbound batch), so we'll use this to
+        * install/uninstall the BFD session parameters only once.
+        */
+       struct thread *installev;
+
+       /** BFD session installation state. */
+       bool installed;
+       /** BFD session enabled. */
+       bool enabled;
+
+       /** Global BFD paramaters list. */
+       TAILQ_ENTRY(bfd_session_params) entry;
+};
+
+struct bfd_sessions_global {
+       /**
+        * Global BFD session parameters list for (re)installation and update
+        * without code duplication among daemons.
+        */
+       TAILQ_HEAD(bsplist, bfd_session_params) bsplist;
+
+       /** Pointer to FRR's event manager. */
+       struct thread_master *tm;
+       /** Pointer to zebra client data structure. */
+       struct zclient *zc;
+
+       /** Debugging state. */
+       bool debugging;
+       /** Is shutting down? */
+       bool shutting_down;
+};
+
+/** Global configuration variable. */
+static struct bfd_sessions_global bsglobal;
+
+/** Global empty address for IPv4/IPv6. */
+static const struct in6_addr i6a_zero;
+
+struct bfd_session_params *bfd_sess_new(bsp_status_update updatecb, void *arg)
+{
+       struct bfd_session_params *bsp;
+
+       bsp = XCALLOC(MTYPE_BFD_INFO, sizeof(*bsp));
+
+       /* Save application data. */
+       bsp->updatecb = updatecb;
+       bsp->arg = arg;
+
+       /* Set defaults. */
+       bsp->args.detection_multiplier = BFD_DEF_DETECT_MULT;
+       bsp->args.ttl = BFD_SINGLE_HOP_TTL;
+       bsp->args.min_rx = BFD_DEF_MIN_RX;
+       bsp->args.min_tx = BFD_DEF_MIN_TX;
+       bsp->args.vrf_id = VRF_DEFAULT;
+
+       /* Register in global list. */
+       TAILQ_INSERT_TAIL(&bsglobal.bsplist, bsp, entry);
+
+       return bsp;
+}
+
+static bool _bfd_sess_valid(const struct bfd_session_params *bsp)
+{
+       /* Peer/local address not configured. */
+       if (bsp->args.family == 0)
+               return false;
+
+       /* Address configured but invalid. */
+       if (bsp->args.family != AF_INET && bsp->args.family != AF_INET6) {
+               if (bsglobal.debugging)
+                       zlog_debug("%s: invalid session family: %d", __func__,
+                                  bsp->args.family);
+               return false;
+       }
+
+       /* Invalid address. */
+       if (memcmp(&bsp->args.dst, &i6a_zero, sizeof(i6a_zero)) == 0) {
+               if (bsglobal.debugging) {
+                       if (bsp->args.family == AF_INET)
+                               zlog_debug("%s: invalid address: %pI4",
+                                          __func__,
+                                          (struct in_addr *)&bsp->args.dst);
+                       else
+                               zlog_debug("%s: invalid address: %pI6",
+                                          __func__, &bsp->args.dst);
+               }
+               return false;
+       }
+
+       /* Multi hop requires local address. */
+       if (bsp->args.mhop
+           && memcmp(&i6a_zero, &bsp->args.src, sizeof(i6a_zero)) == 0) {
+               if (bsglobal.debugging)
+                       zlog_debug(
+                               "%s: multi hop but no local address provided",
+                               __func__);
+               return false;
+       }
+
+       /* Check VRF ID. */
+       if (bsp->args.vrf_id == VRF_UNKNOWN) {
+               if (bsglobal.debugging)
+                       zlog_debug("%s: asked for unknown VRF", __func__);
+               return false;
+       }
+
+       return true;
+}
+
+static int _bfd_sess_send(struct thread *t)
+{
+       struct bfd_session_params *bsp = THREAD_ARG(t);
+       int rv;
+
+       /* Validate configuration before trying to send bogus data. */
+       if (!_bfd_sess_valid(bsp))
+               return 0;
+
+       if (bsp->lastev == BSE_INSTALL) {
+               bsp->args.command = bsp->installed ? ZEBRA_BFD_DEST_UPDATE
+                                                  : ZEBRA_BFD_DEST_REGISTER;
+       } else
+               bsp->args.command = ZEBRA_BFD_DEST_DEREGISTER;
+
+       /* If not installed and asked for uninstall, do nothing. */
+       if (!bsp->installed && bsp->args.command == ZEBRA_BFD_DEST_DEREGISTER)
+               return 0;
+
+       rv = zclient_bfd_command(bsglobal.zc, &bsp->args);
+       /* Command was sent successfully. */
+       if (rv == 0) {
+               /* Update installation status. */
+               if (bsp->args.command == ZEBRA_BFD_DEST_DEREGISTER)
+                       bsp->installed = false;
+               else if (bsp->args.command == ZEBRA_BFD_DEST_REGISTER)
+                       bsp->installed = true;
+       }
+
+       return 0;
+}
+
+static void _bfd_sess_remove(struct bfd_session_params *bsp)
+{
+       /* Not installed, nothing to do. */
+       if (!bsp->installed)
+               return;
+
+       /* Cancel any pending installation request. */
+       THREAD_OFF(bsp->installev);
+
+       /* Send request to remove any session. */
+       bsp->lastev = BSE_UNINSTALL;
+       thread_execute(bsglobal.tm, _bfd_sess_send, bsp, 0);
+}
+
+void bfd_sess_free(struct bfd_session_params **bsp)
+{
+       if (*bsp == NULL)
+               return;
+
+       /* Remove any installed session. */
+       _bfd_sess_remove(*bsp);
+
+       /* Remove from global list. */
+       TAILQ_REMOVE(&bsglobal.bsplist, (*bsp), entry);
+
+       /* Free the memory and point to NULL. */
+       XFREE(MTYPE_BFD_INFO, (*bsp));
+}
+
+void bfd_sess_enable(struct bfd_session_params *bsp, bool enable)
+{
+       /* Remove the session when disabling. */
+       if (!enable)
+               _bfd_sess_remove(bsp);
+
+       bsp->enabled = enable;
+}
+
+void bfd_sess_set_ipv4_addrs(struct bfd_session_params *bsp,
+                            struct in_addr *src, struct in_addr *dst)
+{
+       /* If already installed, remove the old setting. */
+       _bfd_sess_remove(bsp);
+
+       bsp->args.family = AF_INET;
+
+       /* Clean memory, set zero value and avoid static analyser warnings. */
+       memset(&bsp->args.src, 0, sizeof(bsp->args.src));
+       memset(&bsp->args.dst, 0, sizeof(bsp->args.dst));
+
+       /* Copy the equivalent of IPv4 to arguments structure. */
+       if (src)
+               memcpy(&bsp->args.src, src, sizeof(struct in_addr));
+
+       assert(dst);
+       memcpy(&bsp->args.dst, dst, sizeof(struct in_addr));
+}
+
+void bfd_sess_set_ipv6_addrs(struct bfd_session_params *bsp,
+                            struct in6_addr *src, struct in6_addr *dst)
+{
+       /* If already installed, remove the old setting. */
+       _bfd_sess_remove(bsp);
+
+       bsp->args.family = AF_INET6;
+
+       /* Clean memory, set zero value and avoid static analyser warnings. */
+       memset(&bsp->args.src, 0, sizeof(bsp->args.src));
+
+       if (src)
+               bsp->args.src = *src;
+
+       assert(dst);
+       bsp->args.dst = *dst;
+}
+
+void bfd_sess_set_interface(struct bfd_session_params *bsp, const char *ifname)
+{
+       /* If already installed, remove the old setting. */
+       _bfd_sess_remove(bsp);
+
+       if (ifname == NULL) {
+               bsp->args.ifname[0] = 0;
+               bsp->args.ifnamelen = 0;
+               return;
+       }
+
+       if (strlcpy(bsp->args.ifname, ifname, sizeof(bsp->args.ifname))
+           > sizeof(bsp->args.ifname))
+               zlog_warn("%s: interface name truncated: %s", __func__, ifname);
+
+       bsp->args.ifnamelen = strlen(bsp->args.ifname);
+}
+
+void bfd_sess_set_profile(struct bfd_session_params *bsp, const char *profile)
+{
+       if (profile == NULL) {
+               bsp->args.profile[0] = 0;
+               bsp->args.profilelen = 0;
+               return;
+       }
+
+       if (strlcpy(bsp->args.profile, profile, sizeof(bsp->args.profile))
+           > sizeof(bsp->args.profile))
+               zlog_warn("%s: profile name truncated: %s", __func__, profile);
+
+       bsp->args.profilelen = strlen(bsp->args.profile);
+}
+
+void bfd_sess_set_vrf(struct bfd_session_params *bsp, vrf_id_t vrf_id)
+{
+       /* If already installed, remove the old setting. */
+       _bfd_sess_remove(bsp);
+
+       bsp->args.vrf_id = vrf_id;
+}
+
+void bfd_sess_set_mininum_ttl(struct bfd_session_params *bsp, uint8_t min_ttl)
+{
+       assert(min_ttl != 0);
+
+       /* If already installed, remove the old setting. */
+       _bfd_sess_remove(bsp);
+
+       /* Invert TTL value: protocol expects number of hops. */
+       min_ttl = (BFD_SINGLE_HOP_TTL + 1) - min_ttl;
+       bsp->args.ttl = min_ttl;
+       bsp->args.mhop = (min_ttl > 1);
+}
+
+void bfd_sess_set_hop_count(struct bfd_session_params *bsp, uint8_t min_ttl)
+{
+       /* If already installed, remove the old setting. */
+       _bfd_sess_remove(bsp);
+
+       bsp->args.ttl = min_ttl;
+       bsp->args.mhop = (min_ttl > 1);
+}
+
+
+void bfd_sess_set_cbit(struct bfd_session_params *bsp, bool enable)
+{
+       bsp->args.cbit = enable;
+}
+
+void bfd_sess_set_timers(struct bfd_session_params *bsp,
+                        uint8_t detection_multiplier, uint32_t min_rx,
+                        uint32_t min_tx)
+{
+       bsp->args.detection_multiplier = detection_multiplier;
+       bsp->args.min_rx = min_rx;
+       bsp->args.min_tx = min_tx;
+}
+
+void bfd_sess_install(struct bfd_session_params *bsp)
+{
+       /* Don't attempt to install/update when disabled. */
+       if (!bsp->enabled)
+               return;
+
+       bsp->lastev = BSE_INSTALL;
+       thread_add_event(bsglobal.tm, _bfd_sess_send, bsp, 0, &bsp->installev);
+}
+
+void bfd_sess_uninstall(struct bfd_session_params *bsp)
+{
+       bsp->lastev = BSE_UNINSTALL;
+       thread_add_event(bsglobal.tm, _bfd_sess_send, bsp, 0, &bsp->installev);
+}
+
+enum bfd_session_state bfd_sess_status(const struct bfd_session_params *bsp)
+{
+       return bsp->bss.state;
+}
+
+uint8_t bfd_sess_minimum_ttl(const struct bfd_session_params *bsp)
+{
+       return ((BFD_SINGLE_HOP_TTL + 1) - bsp->args.ttl);
+}
+
+uint8_t bfd_sess_hop_count(const struct bfd_session_params *bsp)
+{
+       return bsp->args.ttl;
+}
+
+const char *bfd_sess_profile(const struct bfd_session_params *bsp)
+{
+       return bsp->args.profilelen ? bsp->args.profile : NULL;
+}
+
+void bfd_sess_addresses(const struct bfd_session_params *bsp, int *family,
+                       struct in6_addr *src, struct in6_addr *dst)
+{
+       *family = bsp->args.family;
+       if (src)
+               *src = bsp->args.src;
+       if (dst)
+               *dst = bsp->args.dst;
+}
+
+const char *bfd_sess_interface(const struct bfd_session_params *bsp)
+{
+       if (bsp->args.ifnamelen)
+               return bsp->args.ifname;
+
+       return NULL;
+}
+
+const char *bfd_sess_vrf(const struct bfd_session_params *bsp)
+{
+       return vrf_id_to_name(bsp->args.vrf_id);
+}
+
+vrf_id_t bfd_sess_vrf_id(const struct bfd_session_params *bsp)
+{
+       return bsp->args.vrf_id;
+}
+
+bool bfd_sess_cbit(const struct bfd_session_params *bsp)
+{
+       return bsp->args.cbit;
+}
+
+void bfd_sess_timers(const struct bfd_session_params *bsp,
+                    uint8_t *detection_multiplier, uint32_t *min_rx,
+                    uint32_t *min_tx)
+{
+       *detection_multiplier = bsp->args.detection_multiplier;
+       *min_rx = bsp->args.min_rx;
+       *min_tx = bsp->args.min_tx;
+}
+
+void bfd_sess_show(struct vty *vty, struct json_object *json,
+                  struct bfd_session_params *bsp)
+{
+       json_object *json_bfd = NULL;
+       char time_buf[64];
+
+       /* Show type. */
+       if (json) {
+               json_bfd = json_object_new_object();
+               if (bsp->args.mhop)
+                       json_object_string_add(json_bfd, "type", "multi hop");
+               else
+                       json_object_string_add(json_bfd, "type", "single hop");
+       } else
+               vty_out(vty, "  BFD: Type: %s\n",
+                       bsp->args.mhop ? "multi hop" : "single hop");
+
+       /* Show configuration. */
+       if (json) {
+               json_object_int_add(json_bfd, "detectMultiplier",
+                                   bsp->args.detection_multiplier);
+               json_object_int_add(json_bfd, "rxMinInterval",
+                                   bsp->args.min_rx);
+               json_object_int_add(json_bfd, "txMinInterval",
+                                   bsp->args.min_tx);
+       } else {
+               vty_out(vty,
+                       "  Detect Multiplier: %d, Min Rx interval: %d, Min Tx interval: %d\n",
+                       bsp->args.detection_multiplier, bsp->args.min_rx,
+                       bsp->args.min_tx);
+       }
+
+       bfd_last_update(bsp->bss.last_event, time_buf, sizeof(time_buf));
+       if (json) {
+               json_object_string_add(json_bfd, "status",
+                                      bfd_get_status_str(bsp->bss.state));
+               json_object_string_add(json_bfd, "lastUpdate", time_buf);
+       } else
+               vty_out(vty, "  Status: %s, Last update: %s\n",
+                       bfd_get_status_str(bsp->bss.state), time_buf);
+
+       if (json)
+               json_object_object_add(json, "peerBfdInfo", json_bfd);
+       else
+               vty_out(vty, "\n");
+}
+
+/*
+ * Zebra communication related.
+ */
+
+/**
+ * Callback for reinstallation of all registered BFD sessions.
+ *
+ * Use this as `zclient` `bfd_dest_replay` callback.
+ */
+static int zclient_bfd_session_reply(ZAPI_CALLBACK_ARGS)
+{
+       struct bfd_session_params *bsp;
+
+       /* Do nothing when shutting down. */
+       if (bsglobal.shutting_down)
+               return 0;
+
+       if (bsglobal.debugging)
+               zlog_debug("%s: sending all sessions registered", __func__);
+
+       /* Send the client registration */
+       bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, vrf_id);
+
+       /* Replay all activated peers. */
+       TAILQ_FOREACH (bsp, &bsglobal.bsplist, entry) {
+               /* Skip disabled sessions. */
+               if (!bsp->enabled)
+                       continue;
+
+               /* We are reconnecting, so we must send installation. */
+               bsp->installed = false;
+
+               /* Cancel any pending installation request. */
+               THREAD_OFF(bsp->installev);
+
+               /* Ask for installation. */
+               bsp->lastev = BSE_INSTALL;
+               thread_execute(bsglobal.tm, _bfd_sess_send, bsp, 0);
+       }
+
+       return 0;
+}
+
+static int zclient_bfd_session_update(ZAPI_CALLBACK_ARGS)
+{
+       struct bfd_session_params *bsp;
+       size_t sessions_updated = 0;
+       struct interface *ifp;
+       int remote_cbit = false;
+       int state = BFD_STATUS_UNKNOWN;
+       time_t now;
+       size_t addrlen;
+       struct prefix dp;
+       struct prefix sp;
+       char ifstr[128], cbitstr[32];
+
+       /* Do nothing when shutting down. */
+       if (bsglobal.shutting_down)
+               return 0;
+
+       ifp = bfd_get_peer_info(zclient->ibuf, &dp, &sp, &state, &remote_cbit,
+                               vrf_id);
+
+       if (bsglobal.debugging) {
+               ifstr[0] = 0;
+               if (ifp)
+                       snprintf(ifstr, sizeof(ifstr), " (interface %s)",
+                                ifp->name);
+
+               snprintf(cbitstr, sizeof(cbitstr), " (CPI bit %s)",
+                        remote_cbit ? "yes" : "no");
+
+               zlog_debug("%s: %pFX -> %pFX%s VRF %s(%u)%s: %s", __func__, &sp,
+                          &dp, ifstr, vrf_id_to_name(vrf_id), vrf_id, cbitstr,
+                          bfd_get_status_str(state));
+       }
+
+       switch (dp.family) {
+       case AF_INET:
+               addrlen = sizeof(struct in_addr);
+               break;
+       case AF_INET6:
+               addrlen = sizeof(struct in6_addr);
+               break;
+
+       default:
+               /* Unexpected value. */
+               assert(0);
+               break;
+       }
+
+       /* Cache current time to avoid multiple monotime clock calls. */
+       now = monotime(NULL);
+
+       /* Notify all matching sessions about update. */
+       TAILQ_FOREACH (bsp, &bsglobal.bsplist, entry) {
+               /* Skip disabled or not installed entries. */
+               if (!bsp->enabled || !bsp->installed)
+                       continue;
+               /* Skip different VRFs. */
+               if (bsp->args.vrf_id != vrf_id)
+                       continue;
+               /* Skip different families. */
+               if (bsp->args.family != dp.family)
+                       continue;
+               /* Skip different interface. */
+               if (bsp->args.ifnamelen && ifp
+                   && strcmp(bsp->args.ifname, ifp->name) != 0)
+                       continue;
+               /* Skip non matching destination addresses. */
+               if (memcmp(&bsp->args.dst, &dp.u, addrlen) != 0)
+                       continue;
+               /*
+                * Source comparison test:
+                * We will only compare source if BFD daemon provided the
+                * source address and the protocol set a source address in
+                * the configuration otherwise we'll just skip it.
+                */
+               if (sp.family && memcmp(&bsp->args.src, &i6a_zero, addrlen) != 0
+                   && memcmp(&sp.u, &i6a_zero, addrlen) != 0
+                   && memcmp(&bsp->args.src, &sp.u, addrlen) != 0)
+                       continue;
+               /* No session state change. */
+               if ((int)bsp->bss.state == state)
+                       continue;
+
+               bsp->bss.last_event = now;
+               bsp->bss.previous_state = bsp->bss.state;
+               bsp->bss.state = state;
+               bsp->bss.remote_cbit = remote_cbit;
+               bsp->updatecb(bsp, &bsp->bss, bsp->arg);
+               sessions_updated++;
+       }
+
+       if (bsglobal.debugging)
+               zlog_debug("%s:   sessions updated: %zu", __func__,
+                          sessions_updated);
+
+       return 0;
+}
+
+void bfd_protocol_integration_init(struct zclient *zc, struct thread_master *tm)
+{
+       /* Initialize data structure. */
+       TAILQ_INIT(&bsglobal.bsplist);
+
+       /* Copy pointers. */
+       bsglobal.zc = zc;
+       bsglobal.tm = tm;
+
+       /* Install our callbacks. */
+       zc->interface_bfd_dest_update = zclient_bfd_session_update;
+       zc->bfd_dest_replay = zclient_bfd_session_reply;
+
+       /* Send the client registration */
+       bfd_client_sendmsg(zc, ZEBRA_BFD_CLIENT_REGISTER, VRF_DEFAULT);
+}
+
+void bfd_protocol_integration_set_debug(bool enable)
+{
+       bsglobal.debugging = enable;
+}
+
+void bfd_protocol_integration_set_shutdown(bool enable)
+{
+       bsglobal.shutting_down = enable;
+}
+
+bool bfd_protocol_integration_debug(void)
+{
+       return bsglobal.debugging;
+}
+
+bool bfd_protocol_integration_shutting_down(void)
+{
+       return bsglobal.shutting_down;
+}
index ceab4628b698807e333c14e099ae7c62b6a04cee..1325f86a303a928bff1fb821376b1370b305ceae 100644 (file)
--- a/lib/bfd.h
+++ b/lib/bfd.h
@@ -128,6 +128,305 @@ extern void bfd_gbl_exit(void);
  * BFD new API.
  */
 
+/* Forward declaration of argument struct. */
+struct bfd_session_params;
+
+/** Session state definitions. */
+enum bfd_session_state {
+       /** Session state is unknown or not initialized. */
+       BSS_UNKNOWN = BFD_STATUS_UNKNOWN,
+       /** Local or remote peer administratively shutdown the session. */
+       BSS_ADMIN_DOWN = BFD_STATUS_ADMIN_DOWN,
+       /** Session is down. */
+       BSS_DOWN = BFD_STATUS_DOWN,
+       /** Session is up and working correctly. */
+       BSS_UP = BFD_STATUS_UP,
+};
+
+/** BFD session status information */
+struct bfd_session_status {
+       /** Current session state. */
+       enum bfd_session_state state;
+       /** Previous session state. */
+       enum bfd_session_state previous_state;
+       /** Remote Control Plane Independent bit state. */
+       bool remote_cbit;
+       /** Last event occurrence. */
+       time_t last_event;
+};
+
+/**
+ * Session status update callback.
+ *
+ * \param bsp BFD session parameters.
+ * \param bss BFD session status.
+ * \param arg application independent data.
+ */
+typedef void (*bsp_status_update)(struct bfd_session_params *bsp,
+                                 const struct bfd_session_status *bss,
+                                 void *arg);
+
+/**
+ * Allocates and initializes the session parameters.
+ *
+ * \param updatedb status update notification callback.
+ * \param args application independent data.
+ *
+ * \returns pointer to configuration storage.
+ */
+struct bfd_session_params *bfd_sess_new(bsp_status_update updatecb, void *args);
+
+/**
+ * Uninstall session if installed and free resources allocated by the
+ * parameters. Already sets pointer to `NULL` to avoid dangling references.
+ *
+ * \param bsp session parameters.
+ */
+void bfd_sess_free(struct bfd_session_params **bsp);
+
+/**
+ * Enable/disable session installation.
+ *
+ * \param bsp session parameters.
+ * \param enable knob variable.
+ */
+void bfd_sess_enable(struct bfd_session_params *bsp, bool enable);
+
+/**
+ * Set the local and peer address of the BFD session.
+ *
+ * \param bsp BFD session parameters.
+ * \param src local address (optional, can be `NULL`).
+ * \param dst remote address (mandatory).
+ */
+void bfd_sess_set_ipv4_addrs(struct bfd_session_params *bsp,
+                            struct in_addr *src, struct in_addr *dst);
+
+/**
+ * Set the local and peer address of the BFD session.
+ *
+ * \param bsp BFD session parameters.
+ * \param src local address (optional, can be `NULL`).
+ * \param dst remote address (mandatory).
+ */
+void bfd_sess_set_ipv6_addrs(struct bfd_session_params *bsp,
+                            struct in6_addr *src, struct in6_addr *dst);
+
+/**
+ * Configure the BFD session interface.
+ *
+ * \param bsp BFD session parameters.
+ * \param ifname interface name (or `NULL` to remove it).
+ */
+void bfd_sess_set_interface(struct bfd_session_params *bsp, const char *ifname);
+
+/**
+ * Configure the BFD session profile name.
+ *
+ * \param bsp BFD session parameters.
+ * \param profile profile name (or `NULL` to remove it).
+ */
+void bfd_sess_set_profile(struct bfd_session_params *bsp, const char *profile);
+
+/**
+ * Configure the BFD session VRF.
+ *
+ * \param bsp BFD session parameters.
+ * \param vrf_id the VRF identification number.
+ */
+void bfd_sess_set_vrf(struct bfd_session_params *bsp, vrf_id_t vrf_id);
+
+/**
+ * Configure the BFD session single/multi hop setting.
+ *
+ * \param bsp BFD session parameters.
+ * \param min_ttl minimum TTL value expected (255 for single hop, 254 for
+ *                multi hop with single hop, 253 for multi hop with two hops
+ *                and so on). See `BFD_SINGLE_HOP_TTL` and
+ *                `BFD_MULTI_HOP_MIN_TTL` for defaults.
+ *
+ * To simplify things if your protocol only knows the amount of hops it is
+ * better to use `bfd_sess_set_hops` instead.
+ */
+void bfd_sess_set_mininum_ttl(struct bfd_session_params *bsp, uint8_t min_ttl);
+
+/** To use single hop the minimum TTL must be set to this. */
+#define BFD_SINGLE_HOP_TTL 255
+/** To use multi hop the minimum TTL must be set to this or less. */
+#define BFD_MULTI_HOP_MIN_TTL 254
+
+/**
+ * This function is the inverted version of `bfd_sess_set_minimum_ttl`.
+ * Instead of receiving the minimum expected TTL, it receives the amount of
+ * hops the protocol will jump.
+ *
+ * \param bsp BFD session parameters.
+ * \param min_ttl minimum amount of hops expected (1 for single hop, 2 or
+ *                more for multi hop).
+ */
+void bfd_sess_set_hop_count(struct bfd_session_params *bsp, uint8_t min_ttl);
+
+/**
+ * Configure the BFD session to set the Control Plane Independent bit.
+ *
+ * \param bsp BFD session parameters.
+ * \param enable BFD Control Plane Independent state.
+ */
+void bfd_sess_set_cbit(struct bfd_session_params *bsp, bool enable);
+
+/**
+ * DEPRECATED: please avoid using timers directly and use profiles instead.
+ *
+ * Configures the BFD session timers to use. This is specially useful with
+ * `ptm-bfd` which does not support timers.
+ *
+ * \param bsp BFD session parameters.
+ * \param detection_multiplier the detection multiplier value.
+ * \param min_rx minimum required receive period.
+ * \param min_tx minimum required transmission period.
+ */
+void bfd_sess_set_timers(struct bfd_session_params *bsp,
+                        uint8_t detection_multiplier, uint32_t min_rx,
+                        uint32_t min_tx);
+
+/**
+ * Installs or updates the BFD session based on the saved session arguments.
+ *
+ * \param bsp session parameters.
+ */
+void bfd_sess_install(struct bfd_session_params *bsp);
+
+/**
+ * Uninstall the BFD session based on the saved session arguments.
+ *
+ * \param bsp session parameters.
+ */
+void bfd_sess_uninstall(struct bfd_session_params *bsp);
+
+/**
+ * Get BFD session current status.
+ *
+ * \param bsp session parameters.
+ *
+ * \returns BFD session status data structure.
+ */
+enum bfd_session_state bfd_sess_status(const struct bfd_session_params *bsp);
+
+/**
+ * Get BFD session minimum TTL configured value.
+ *
+ * \param bsp session parameters.
+ *
+ * \returns configured minimum TTL.
+ */
+uint8_t bfd_sess_minimum_ttl(const struct bfd_session_params *bsp);
+
+/**
+ * Inverted version of `bfd_sess_minimum_ttl`. Gets the amount of hops in the
+ * way to the peer.
+ *
+ * \param bsp session parameters.
+ *
+ * \returns configured amount of hops.
+ */
+uint8_t bfd_sess_hop_count(const struct bfd_session_params *bsp);
+
+/**
+ * Get BFD session profile configured value.
+ *
+ * \param bsp session parameters.
+ *
+ * \returns configured profile name (or `NULL` if empty).
+ */
+const char *bfd_sess_profile(const struct bfd_session_params *bsp);
+
+/**
+ * Get BFD session addresses.
+ *
+ * \param bsp session parameters.
+ * \param family the address family being used (AF_INET or AF_INET6).
+ * \param src source address (optional, may be `NULL`).
+ * \param dst peer address (optional, may be `NULL`).
+ */
+void bfd_sess_addresses(const struct bfd_session_params *bsp, int *family,
+                       struct in6_addr *src, struct in6_addr *dst);
+/**
+ * Get BFD session interface name.
+ *
+ * \param bsp session parameters.
+ *
+ * \returns `NULL` if not set otherwise the interface name.
+ */
+const char *bfd_sess_interface(const struct bfd_session_params *bsp);
+
+/**
+ * Get BFD session VRF name.
+ *
+ * \param bsp session parameters.
+ *
+ * \returns the VRF name.
+ */
+const char *bfd_sess_vrf(const struct bfd_session_params *bsp);
+
+/**
+ * Get BFD session VRF ID.
+ *
+ * \param bsp session parameters.
+ *
+ * \returns the VRF name.
+ */
+vrf_id_t bfd_sess_vrf_id(const struct bfd_session_params *bsp);
+
+/**
+ * Get BFD session control plane independent bit configuration state.
+ *
+ * \param bsp session parameters.
+ *
+ * \returns `true` if enabled otherwise `false`.
+ */
+bool bfd_sess_cbit(const struct bfd_session_params *bsp);
+
+/**
+ * DEPRECATED: please avoid using timers directly and use profiles instead.
+ *
+ * Gets the configured timers.
+ *
+ * \param bsp BFD session parameters.
+ * \param detection_multiplier the detection multiplier value.
+ * \param min_rx minimum required receive period.
+ * \param min_tx minimum required transmission period.
+ */
+void bfd_sess_timers(const struct bfd_session_params *bsp,
+                    uint8_t *detection_multiplier, uint32_t *min_rx,
+                    uint32_t *min_tx);
+
+/**
+ * Show BFD session configuration and status. If `json` is provided (e.g. not
+ * `NULL`) then information will be inserted in object, otherwise printed to
+ * `vty`.
+ *
+ * \param vty Pointer to `vty` for outputting text.
+ * \param json (optional) JSON object pointer.
+ * \param bsp session parameters.
+ */
+void bfd_sess_show(struct vty *vty, struct json_object *json,
+                  struct bfd_session_params *bsp);
+
+/**
+ * Initializes the BFD integration library. This function executes the
+ * following actions:
+ *
+ * - Copy the `struct thread_master` pointer to use as "thread" to execute
+ *   the BFD session parameters installation.
+ * - Copy the `struct zclient` pointer to install its callbacks.
+ * - Initializes internal data structures.
+ *
+ * \param tm normally the daemon main thread event manager.
+ * \param zc the zebra client of the daemon.
+ */
+void bfd_protocol_integration_init(struct zclient *zc,
+                                  struct thread_master *tm);
+
 /**
  * BFD session registration arguments.
  */
@@ -205,6 +504,34 @@ struct bfd_session_arg {
  */
 extern int zclient_bfd_command(struct zclient *zc, struct bfd_session_arg *arg);
 
+/**
+ * Enables or disables BFD protocol integration API debugging.
+ *
+ * \param enable new API debug state.
+ */
+extern void bfd_protocol_integration_set_debug(bool enable);
+
+/**
+ * Sets shutdown mode so no more events are processed.
+ *
+ * This is useful to avoid the event storm that happens caused by network,
+ * interfaces or VRFs removal. It should also avoid some crashes due hanging
+ * pointers left overs by protocol.
+ *
+ * \param enable new API shutdown state.
+ */
+extern void bfd_protocol_integration_set_shutdown(bool enable);
+
+/**
+ * Get API debugging state.
+ */
+extern bool bfd_protocol_integration_debug(void);
+
+/**
+ * Get API shutdown state.
+ */
+extern bool bfd_protocol_integration_shutting_down(void);
+
 #ifdef __cplusplus
 }
 #endif
index 42796faae82b41a2b5512bfc6a715eaa0a9efa09..7929b3709dc1d7cfc239533f42e5997d81efcfdd 100644 (file)
@@ -29,8 +29,8 @@
 
 #include <stddef.h>
 
-DEFINE_MTYPE_STATIC(LIB, BUFFER, "Buffer")
-DEFINE_MTYPE_STATIC(LIB, BUFFER_DATA, "Buffer data")
+DEFINE_MTYPE_STATIC(LIB, BUFFER, "Buffer");
+DEFINE_MTYPE_STATIC(LIB, BUFFER_DATA, "Buffer data");
 
 /* Buffer master. */
 struct buffer {
index 6a4d504b2f8fe22aef9274ce08318a180809556c..770e2fc5ace68d625fcea2ba2e6dca79af2cbdf6 100644 (file)
@@ -51,8 +51,8 @@
 
 #include "frrscript.h"
 
-DEFINE_MTYPE_STATIC(LIB, HOST, "Host config")
-DEFINE_MTYPE(LIB, COMPLETION, "Completion item")
+DEFINE_MTYPE_STATIC(LIB, HOST, "Host config");
+DEFINE_MTYPE(LIB, COMPLETION, "Completion item");
 
 #define item(x)                                                                \
        {                                                                      \
index 71abb20b0512ea03f0e8598fa96b74b63b6eb704..14e51486eab8fb1c949f54ed81b386e264830f2d 100644 (file)
@@ -34,7 +34,7 @@
 extern "C" {
 #endif
 
-DECLARE_MTYPE(COMPLETION)
+DECLARE_MTYPE(COMPLETION);
 
 /*
  * From RFC 1123 (Requirements for Internet Hosts), Section 2.1 on hostnames:
index d30d9ab702c27d4eb875a1561b8e6b265dc88a5b..c6c38404559a4fb58d52ee3bac9e962c8bfc14cd 100644 (file)
 
 #include "command_graph.h"
 
-DEFINE_MTYPE_STATIC(LIB, CMD_TOKENS, "Command Tokens")
-DEFINE_MTYPE_STATIC(LIB, CMD_DESC, "Command Token Text")
-DEFINE_MTYPE_STATIC(LIB, CMD_TEXT, "Command Token Help")
-DEFINE_MTYPE(LIB, CMD_ARG, "Command Argument")
-DEFINE_MTYPE_STATIC(LIB, CMD_VAR, "Command Argument Name")
+DEFINE_MTYPE_STATIC(LIB, CMD_TOKENS, "Command Tokens");
+DEFINE_MTYPE_STATIC(LIB, CMD_DESC, "Command Token Text");
+DEFINE_MTYPE_STATIC(LIB, CMD_TEXT, "Command Token Help");
+DEFINE_MTYPE(LIB, CMD_ARG, "Command Argument");
+DEFINE_MTYPE_STATIC(LIB, CMD_VAR, "Command Argument Name");
 
 struct cmd_token *cmd_token_new(enum cmd_token_type type, uint8_t attr,
                                const char *text, const char *desc)
index 86715410ce69437962ec3e372a0964b4b79f7022..2754dca67d788e64f443b82dabdbc634fec40d2f 100644 (file)
@@ -37,7 +37,7 @@
 extern "C" {
 #endif
 
-DECLARE_MTYPE(CMD_ARG)
+DECLARE_MTYPE(CMD_ARG);
 
 struct vty;
 
index 801b05f1573b42a1b857503a3f9c2cc28c3cc006..e9e8466ffde51a43d549ef00e07e174d79475a2f 100644 (file)
@@ -26,7 +26,7 @@
 #include "command_match.h"
 #include "memory.h"
 
-DEFINE_MTYPE_STATIC(LIB, CMD_MATCHSTACK, "Command Match Stack")
+DEFINE_MTYPE_STATIC(LIB, CMD_MATCHSTACK, "Command Match Stack");
 
 #ifdef TRACE_MATCHER
 #define TM 1
index 8135d02b4ba16e986161160983f85cc56948c7c7..5ebc19b2789b97dade616233a3c38075cf1cf5cd 100644 (file)
@@ -54,7 +54,7 @@
   #include "command_graph.h"
   #include "log.h"
 
-  DECLARE_MTYPE(LEX)
+  DECLARE_MTYPE(LEX);
 
   #define YYSTYPE CMD_YYSTYPE
   #define YYLTYPE CMD_YYLTYPE
@@ -376,7 +376,7 @@ selector: '[' selector_seq_seq ']' varname_token
 
 #undef scanner
 
-DEFINE_MTYPE(LIB, LEX, "Lexer token (temporary)")
+DEFINE_MTYPE(LIB, LEX, "Lexer token (temporary)");
 
 void
 cmd_graph_parse (struct graph *graph, const struct cmd_element *cmd)
index 70ef8e9bc80255eb3a4996a2464d0fdf611de2ed..b7a142bdee5ac5aa3129262929d31d8f0239993d 100644 (file)
 extern "C" {
 #endif
 
+#ifdef __cplusplus
+# if __cplusplus < 201103L
+#  error FRRouting headers must be compiled in C++11 mode or newer
+# endif
+/* C++ defines static_assert(), but not _Static_assert().  C defines
+ * _Static_assert() and has static_assert() in <assert.h>.  However, we mess
+ * with assert() in zassert.h so let's not include <assert.h> here.
+ */
+# define _Static_assert static_assert
+#else
+# if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 201112L
+#  error FRRouting must be compiled with min. -std=gnu11 (GNU ISO C11 dialect)
+# endif
+#endif
+
 /* function attributes, use like
  *   void prototype(void) __attribute__((_CONSTRUCTOR(100)));
  */
@@ -121,6 +136,24 @@ extern "C" {
 #define macro_inline   static inline __attribute__((unused))
 #define macro_pure     static inline __attribute__((unused, pure))
 
+/* if the macro ends with a function definition */
+#define MACRO_REQUIRE_SEMICOLON() \
+       _Static_assert(1, "please add a semicolon after this macro")
+
+#if CONFDATE < 20210601
+#ifdef ENABLE_BGP_VNC
+/* temporarily disabled for transition for LabN CI
+ * NB: it's not possible to generate a deprecation warning for this, hence
+ * the shortened transition period (since otherwise new uses of the old syntax
+ * may creep in without errors)
+ */
+#undef MACRO_REQUIRE_SEMICOLON
+#define MACRO_REQUIRE_SEMICOLON() \
+       /* nothing */
+#endif /* ENABLE_BGP_VNC */
+#else /* CONFDATE >= 20210601 */
+CPP_NOTICE("time to remove this CONFDATE block")
+#endif
 
 /* variadic macros, use like:
  * #define V_0()  ...
@@ -357,10 +390,8 @@ typedef signed long long _int64_t;
 /* if this breaks, 128-bit machines may have entered reality (or <long long>
  * is something weird)
  */
-#if __STDC_VERSION__ >= 201112L
 _Static_assert(sizeof(_uint64_t) == 8 && sizeof(_int64_t) == 8,
               "nobody expects the spanish intquisition");
-#endif
 
 /* since we redefined int64_t, we also need to redefine PRI*64 */
 #undef PRIu64
index 3248ceb13b53222e84a143a5a532a73c4cf8d0dd..e2ba4cd4ef118fb9e47f2016788b254da509f0b7 100644 (file)
@@ -24,7 +24,7 @@
 
 static struct debug_cb_list_head cb_head;
 
-DECLARE_LIST(debug_cb_list, struct debug_callbacks, item)
+DECLARE_LIST(debug_cb_list, struct debug_callbacks, item);
 
 /* All code in this section should be reentrant and MT-safe */
 
index f25cd426913f8a0bb518df0e77b6e1933c6d060c..a72657bdafaf78d020a72f0c817a3aa9a0178f34 100644 (file)
@@ -84,7 +84,7 @@ struct debug {
        const char *desc;
 };
 
-PREDECL_LIST(debug_cb_list)
+PREDECL_LIST(debug_cb_list);
 /*
  * Callback set for debugging code.
  *
index 20ef28db312bc58bb37c977dfe9e5e9acbefdeb6..55250f0f81ac2b69e0e011d332d1c23d3ddfd85c 100644 (file)
@@ -98,7 +98,8 @@ struct frr_default {
        static void _dfltinit_##varname(void)                                  \
        {                                                                      \
                frr_default_add(&_dflt_##varname);                             \
-       }
+       }                                                                      \
+       MACRO_REQUIRE_SEMICOLON() /* end */
 
 /* use:
  *   FRR_CFG_DEFAULT_LONG(SHARP_BLUNTNESS,
index 3ea60c8772df3911dbd2d1a80ece546215182624..60bd0a47bb0c00f2f7f01da7b004a5834ff35c2e 100644 (file)
 #include "distribute.h"
 #include "memory.h"
 
-DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE_CTX, "Distribute ctx")
-DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE, "Distribute list")
-DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE_IFNAME, "Dist-list ifname")
-DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE_NAME, "Dist-list name")
+DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE_CTX, "Distribute ctx");
+DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE, "Distribute list");
+DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE_IFNAME, "Dist-list ifname");
+DEFINE_MTYPE_STATIC(LIB, DISTRIBUTE_NAME, "Dist-list name");
 
 static struct list *dist_ctx_list;
 
index 0d8ad76e1c4abb7f8016a2582b9fce56756da0bf..d26e443b82d9069c134a2c60d2bfe4aacf38641f 100644 (file)
@@ -100,7 +100,7 @@ static PyObject *refuse_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
 struct elfreloc;
 struct elfsect;
 
-PREDECL_HASH(elfrelocs)
+PREDECL_HASH(elfrelocs);
 
 /* ELFFile and ELFSection intentionally share some behaviour, particularly
  * subscript[123:456] access to file data.  This is because relocatables
@@ -200,7 +200,7 @@ static int elfreloc_cmp(const struct elfreloc *a, const struct elfreloc *b);
 static uint32_t elfreloc_hash(const struct elfreloc *reloc);
 
 DECLARE_HASH(elfrelocs, struct elfreloc, elfrelocs_item,
-            elfreloc_cmp, elfreloc_hash)
+            elfreloc_cmp, elfreloc_hash);
 
 static Elf_Scn *elf_find_addr(struct elffile *ef, uint64_t addr, size_t *idx);
 static PyObject *elffile_secbyidx(struct elffile *w, Elf_Scn *scn, size_t idx);
index 691da495cf13dd318fa08fdef23c87defb1fed63..513ef5ebec4fda359244a89b03da155578037fe3 100644 (file)
@@ -35,7 +35,7 @@
 #include "linklist.h"
 #include "frr_pthread.h"
 
-DEFINE_MTYPE_STATIC(LIB, ERRINFO, "error information")
+DEFINE_MTYPE_STATIC(LIB, ERRINFO, "error information");
 
 /*
  * Thread-specific key for temporary storage of allocated ferr.
index f5ae9ee2b75e321b19f88223932a6a60b684372c..83423ba321922255865e7613a147a3d865488d88 100644 (file)
@@ -31,9 +31,9 @@
 #include "libfrr.h"
 #include "northbound_cli.h"
 
-DEFINE_MTYPE_STATIC(LIB, ACCESS_LIST, "Access List")
-DEFINE_MTYPE_STATIC(LIB, ACCESS_LIST_STR, "Access List Str")
-DEFINE_MTYPE_STATIC(LIB, ACCESS_FILTER, "Access Filter")
+DEFINE_MTYPE_STATIC(LIB, ACCESS_LIST, "Access List");
+DEFINE_MTYPE_STATIC(LIB, ACCESS_LIST_STR, "Access List Str");
+DEFINE_MTYPE_STATIC(LIB, ACCESS_FILTER, "Access Filter");
 
 /* Static structure for mac access_list's master. */
 static struct access_master access_master_mac = {
index 2007b37cdfe1cd6d971c37af097f5bd608b32257..c83738e72957bf308c2c2017423dfa0009914e06 100644 (file)
@@ -120,6 +120,101 @@ static void prefix_list_entry_set_empty(struct prefix_list_entry *ple)
        ple->le = 0;
 }
 
+static int
+prefix_list_nb_validate_v4_af_type(const struct lyd_node *plist_dnode,
+                                  char *errmsg, size_t errmsg_len)
+{
+       int af_type;
+
+       af_type = yang_dnode_get_enum(plist_dnode, "./type");
+       if (af_type != YPLT_IPV4) {
+               snprintf(errmsg, errmsg_len,
+                        "prefix-list type %u is mismatched.", af_type);
+               return NB_ERR_VALIDATION;
+       }
+
+       return NB_OK;
+}
+
+static int
+prefix_list_nb_validate_v6_af_type(const struct lyd_node *plist_dnode,
+                                  char *errmsg, size_t errmsg_len)
+{
+       int af_type;
+
+       af_type = yang_dnode_get_enum(plist_dnode, "./type");
+       if (af_type != YPLT_IPV6) {
+               snprintf(errmsg, errmsg_len,
+                        "prefix-list type %u is mismatched.", af_type);
+               return NB_ERR_VALIDATION;
+       }
+
+       return NB_OK;
+}
+
+static int lib_prefix_list_entry_prefix_length_lesser_or_equal_modify(
+       struct nb_cb_modify_args *args)
+{
+       struct prefix_list_entry *ple;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       ple = nb_running_get_entry(args->dnode, NULL, true);
+
+       /* Start prefix entry update procedure. */
+       prefix_list_entry_update_start(ple);
+
+       ple->le = yang_dnode_get_uint8(args->dnode, NULL);
+
+       /* Finish prefix entry update procedure. */
+       prefix_list_entry_update_finish(ple);
+
+       return NB_OK;
+}
+
+static int lib_prefix_list_entry_prefix_length_greater_or_equal_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       struct prefix_list_entry *ple;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       ple = nb_running_get_entry(args->dnode, NULL, true);
+
+       /* Start prefix entry update procedure. */
+       prefix_list_entry_update_start(ple);
+
+       ple->ge = 0;
+
+       /* Finish prefix entry update procedure. */
+       prefix_list_entry_update_finish(ple);
+
+       return NB_OK;
+}
+
+static int lib_prefix_list_entry_prefix_length_lesser_or_equal_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       struct prefix_list_entry *ple;
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       ple = nb_running_get_entry(args->dnode, NULL, true);
+
+       /* Start prefix entry update procedure. */
+       prefix_list_entry_update_start(ple);
+
+       ple->le = 0;
+
+       /* Finish prefix entry update procedure. */
+       prefix_list_entry_update_finish(ple);
+
+       return NB_OK;
+}
+
 /**
  * Unsets the cisco style rule for addresses so it becomes disabled (the
  * equivalent of setting: `0.0.0.0/32`).
@@ -308,45 +403,6 @@ bool plist_is_dup(const struct lyd_node *dnode, struct plist_dup_args *pda)
        return pda->pda_found;
 }
 
-static bool plist_is_dup_nb(const struct lyd_node *dnode)
-{
-       const struct lyd_node *entry_dnode =
-               yang_dnode_get_parent(dnode, "entry");
-       struct plist_dup_args pda = {};
-       int idx = 0, arg_idx = 0;
-       static const char *entries[] = {
-               "./ipv4-prefix",
-               "./ipv4-prefix-length-greater-or-equal",
-               "./ipv4-prefix-length-lesser-or-equal",
-               "./ipv6-prefix",
-               "./ipv6-prefix-length-greater-or-equal",
-               "./ipv6-prefix-length-lesser-or-equal",
-               "./any",
-               NULL
-       };
-
-       /* Initialize. */
-       pda.pda_type = yang_dnode_get_string(entry_dnode, "../type");
-       pda.pda_name = yang_dnode_get_string(entry_dnode, "../name");
-       pda.pda_entry_dnode = entry_dnode;
-
-       /* Load all values/XPaths. */
-       while (entries[idx] != NULL) {
-               if (!yang_dnode_exists(entry_dnode, entries[idx])) {
-                       idx++;
-                       continue;
-               }
-
-               pda.pda_xpath[arg_idx] = entries[idx];
-               pda.pda_value[arg_idx] =
-                       yang_dnode_get_string(entry_dnode, entries[idx]);
-               arg_idx++;
-               idx++;
-       }
-
-       return plist_is_dup(entry_dnode, &pda);
-}
-
 /*
  * XPath: /frr-filter:lib/access-list
  */
@@ -1148,25 +1204,11 @@ static int lib_prefix_list_entry_action_modify(struct nb_cb_modify_args *args)
        return NB_OK;
 }
 
-/*
- * XPath: /frr-filter:lib/prefix-list/entry/ipv4-prefix
- */
-static int
-lib_prefix_list_entry_ipv4_prefix_modify(struct nb_cb_modify_args *args)
+static int lib_prefix_list_entry_prefix_modify(struct nb_cb_modify_args *args)
 {
        struct prefix_list_entry *ple;
        struct prefix p;
 
-       if (args->event == NB_EV_VALIDATE) {
-               if (plist_is_dup_nb(args->dnode)) {
-                       snprintf(args->errmsg, args->errmsg_len,
-                                "duplicated prefix list value: %s",
-                                yang_dnode_get_string(args->dnode, NULL));
-                       return NB_ERR_VALIDATION;
-               }
-               return NB_OK;
-       }
-
        if (args->event != NB_EV_APPLY)
                return NB_OK;
 
@@ -1193,8 +1235,7 @@ lib_prefix_list_entry_ipv4_prefix_modify(struct nb_cb_modify_args *args)
        return NB_OK;
 }
 
-static int
-lib_prefix_list_entry_ipv4_prefix_destroy(struct nb_cb_destroy_args *args)
+static int lib_prefix_list_entry_prefix_destroy(struct nb_cb_destroy_args *args)
 {
        struct prefix_list_entry *ple;
 
@@ -1214,6 +1255,61 @@ lib_prefix_list_entry_ipv4_prefix_destroy(struct nb_cb_destroy_args *args)
        return NB_OK;
 }
 
+/*
+ * XPath: /frr-filter:lib/prefix-list/entry/ipv4-prefix
+ */
+static int
+lib_prefix_list_entry_ipv4_prefix_modify(struct nb_cb_modify_args *args)
+{
+       if (args->event == NB_EV_VALIDATE) {
+               const struct lyd_node *plist_dnode =
+                       yang_dnode_get_parent(args->dnode, "prefix-list");
+
+               return prefix_list_nb_validate_v4_af_type(
+                       plist_dnode, args->errmsg, args->errmsg_len);
+       }
+
+       return lib_prefix_list_entry_prefix_modify(args);
+}
+
+static int
+lib_prefix_list_entry_ipv4_prefix_destroy(struct nb_cb_destroy_args *args)
+{
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       return lib_prefix_list_entry_prefix_destroy(args);
+}
+
+/*
+ * XPath: /frr-filter:lib/prefix-list/entry/ipv6-prefix
+ */
+static int
+lib_prefix_list_entry_ipv6_prefix_modify(struct nb_cb_modify_args *args)
+{
+
+       if (args->event == NB_EV_VALIDATE) {
+               const struct lyd_node *plist_dnode =
+                       yang_dnode_get_parent(args->dnode, "prefix-list");
+
+               return prefix_list_nb_validate_v6_af_type(
+                       plist_dnode, args->errmsg, args->errmsg_len);
+       }
+
+       return lib_prefix_list_entry_prefix_modify(args);
+}
+
+static int
+lib_prefix_list_entry_ipv6_prefix_destroy(struct nb_cb_destroy_args *args)
+{
+
+       if (args->event != NB_EV_APPLY)
+               return NB_OK;
+
+       return lib_prefix_list_entry_prefix_destroy(args);
+}
+
 /*
  * XPath: /frr-filter:lib/prefix-list/entry/ipv4-prefix-length-greater-or-equal
  */
@@ -1226,16 +1322,6 @@ static int lib_prefix_list_entry_ipv4_prefix_length_greater_or_equal_modify(
            prefix_list_length_validate(args) != NB_OK)
                return NB_ERR_VALIDATION;
 
-       if (args->event == NB_EV_VALIDATE) {
-               if (plist_is_dup_nb(args->dnode)) {
-                       snprintf(args->errmsg, args->errmsg_len,
-                                "duplicated prefix list value: %s",
-                                yang_dnode_get_string(args->dnode, NULL));
-                       return NB_ERR_VALIDATION;
-               }
-               return NB_OK;
-       }
-
        if (args->event != NB_EV_APPLY)
                return NB_OK;
 
@@ -1255,44 +1341,72 @@ static int lib_prefix_list_entry_ipv4_prefix_length_greater_or_equal_modify(
 static int lib_prefix_list_entry_ipv4_prefix_length_greater_or_equal_destroy(
        struct nb_cb_destroy_args *args)
 {
-       struct prefix_list_entry *ple;
+       if (args->event == NB_EV_VALIDATE) {
+               const struct lyd_node *plist_dnode =
+                       yang_dnode_get_parent(args->dnode, "prefix-list");
 
-       if (args->event != NB_EV_APPLY)
-               return NB_OK;
+               return prefix_list_nb_validate_v4_af_type(
+                       plist_dnode, args->errmsg, args->errmsg_len);
+       }
 
-       ple = nb_running_get_entry(args->dnode, NULL, true);
+       return lib_prefix_list_entry_prefix_length_greater_or_equal_destroy(
+               args);
+}
 
-       /* Start prefix entry update procedure. */
-       prefix_list_entry_update_start(ple);
+/*
+ * XPath: /frr-filter:lib/prefix-list/entry/ipv4-prefix-length-lesser-or-equal
+ */
+static int lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_modify(
+       struct nb_cb_modify_args *args)
+{
+       if (args->event == NB_EV_VALIDATE
+           && prefix_list_length_validate(args) != NB_OK)
+               return NB_ERR_VALIDATION;
 
-       ple->ge = 0;
+       if (args->event == NB_EV_VALIDATE) {
+               const struct lyd_node *plist_dnode =
+                       yang_dnode_get_parent(args->dnode, "prefix-list");
 
-       /* Finish prefix entry update procedure. */
-       prefix_list_entry_update_finish(ple);
+               return prefix_list_nb_validate_v4_af_type(
+                       plist_dnode, args->errmsg, args->errmsg_len);
+       }
 
-       return NB_OK;
+       return lib_prefix_list_entry_prefix_length_lesser_or_equal_modify(args);
+}
+
+static int lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       if (args->event == NB_EV_VALIDATE) {
+               const struct lyd_node *plist_dnode =
+                       yang_dnode_get_parent(args->dnode, "prefix-list");
+
+               return prefix_list_nb_validate_v4_af_type(
+                       plist_dnode, args->errmsg, args->errmsg_len);
+       }
+
+       return lib_prefix_list_entry_prefix_length_lesser_or_equal_destroy(
+               args);
 }
 
 /*
- * XPath: /frr-filter:lib/prefix-list/entry/ipv4-prefix-length-lesser-or-equal
+ * XPath: /frr-filter:lib/prefix-list/entry/ipv6-prefix-length-greater-or-equal
  */
-static int lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_modify(
+static int lib_prefix_list_entry_ipv6_prefix_length_greater_or_equal_modify(
        struct nb_cb_modify_args *args)
 {
        struct prefix_list_entry *ple;
 
-       if (args->event == NB_EV_VALIDATE &&
-           prefix_list_length_validate(args) != NB_OK)
+       if (args->event == NB_EV_VALIDATE
+           && prefix_list_length_validate(args) != NB_OK)
                return NB_ERR_VALIDATION;
 
        if (args->event == NB_EV_VALIDATE) {
-               if (plist_is_dup_nb(args->dnode)) {
-                       snprintf(args->errmsg, args->errmsg_len,
-                                "duplicated prefix list value: %s",
-                                yang_dnode_get_string(args->dnode, NULL));
-                       return NB_ERR_VALIDATION;
-               }
-               return NB_OK;
+               const struct lyd_node *plist_dnode =
+                       yang_dnode_get_parent(args->dnode, "prefix-list");
+
+               return prefix_list_nb_validate_v6_af_type(
+                       plist_dnode, args->errmsg, args->errmsg_len);
        }
 
        if (args->event != NB_EV_APPLY)
@@ -1303,7 +1417,7 @@ static int lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_modify(
        /* Start prefix entry update procedure. */
        prefix_list_entry_update_start(ple);
 
-       ple->le = yang_dnode_get_uint8(args->dnode, NULL);
+       ple->ge = yang_dnode_get_uint8(args->dnode, NULL);
 
        /* Finish prefix entry update procedure. */
        prefix_list_entry_update_finish(ple);
@@ -1311,45 +1425,71 @@ static int lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_modify(
        return NB_OK;
 }
 
-static int lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_destroy(
+static int lib_prefix_list_entry_ipv6_prefix_length_greater_or_equal_destroy(
        struct nb_cb_destroy_args *args)
 {
-       struct prefix_list_entry *ple;
+       if (args->event == NB_EV_VALIDATE) {
+               const struct lyd_node *plist_dnode =
+                       yang_dnode_get_parent(args->dnode, "prefix-list");
 
-       if (args->event != NB_EV_APPLY)
-               return NB_OK;
+               return prefix_list_nb_validate_v6_af_type(
+                       plist_dnode, args->errmsg, args->errmsg_len);
+       }
 
-       ple = nb_running_get_entry(args->dnode, NULL, true);
+       return lib_prefix_list_entry_prefix_length_greater_or_equal_destroy(
+               args);
+}
 
-       /* Start prefix entry update procedure. */
-       prefix_list_entry_update_start(ple);
+/*
+ * XPath: /frr-filter:lib/prefix-list/entry/ipv6-prefix-length-lesser-or-equal
+ */
+static int lib_prefix_list_entry_ipv6_prefix_length_lesser_or_equal_modify(
+       struct nb_cb_modify_args *args)
+{
+       if (args->event == NB_EV_VALIDATE
+           && prefix_list_length_validate(args) != NB_OK)
+               return NB_ERR_VALIDATION;
 
-       ple->le = 0;
+       if (args->event == NB_EV_VALIDATE) {
+               const struct lyd_node *plist_dnode =
+                       yang_dnode_get_parent(args->dnode, "prefix-list");
 
-       /* Finish prefix entry update procedure. */
-       prefix_list_entry_update_finish(ple);
+               return prefix_list_nb_validate_v6_af_type(
+                       plist_dnode, args->errmsg, args->errmsg_len);
+       }
 
-       return NB_OK;
+       return lib_prefix_list_entry_prefix_length_lesser_or_equal_modify(args);
 }
 
-/*
- * XPath: /frr-filter:lib/prefix-list/entry/any
- */
-static int lib_prefix_list_entry_any_create(struct nb_cb_create_args *args)
+static int lib_prefix_list_entry_ipv6_prefix_length_lesser_or_equal_destroy(
+       struct nb_cb_destroy_args *args)
 {
-       struct prefix_list_entry *ple;
-       int type;
+       int af_type;
 
        if (args->event == NB_EV_VALIDATE) {
-               if (plist_is_dup_nb(args->dnode)) {
+               const struct lyd_node *plist_dnode =
+                       yang_dnode_get_parent(args->dnode, "prefix-list");
+               af_type = yang_dnode_get_enum(plist_dnode, "./type");
+               if (af_type != YPLT_IPV6) {
                        snprintf(args->errmsg, args->errmsg_len,
-                                "duplicated prefix list value: %s",
-                                yang_dnode_get_string(args->dnode, NULL));
+                                "prefix-list type %u is mismatched.", af_type);
                        return NB_ERR_VALIDATION;
                }
                return NB_OK;
        }
 
+       return lib_prefix_list_entry_prefix_length_lesser_or_equal_destroy(
+               args);
+}
+
+/*
+ * XPath: /frr-filter:lib/prefix-list/entry/any
+ */
+static int lib_prefix_list_entry_any_create(struct nb_cb_create_args *args)
+{
+       struct prefix_list_entry *ple;
+       int type;
+
        if (args->event != NB_EV_APPLY)
                return NB_OK;
 
@@ -1583,22 +1723,22 @@ const struct frr_yang_module_info frr_filter_info = {
                {
                        .xpath = "/frr-filter:lib/prefix-list/entry/ipv6-prefix",
                        .cbs = {
-                               .modify = lib_prefix_list_entry_ipv4_prefix_modify,
-                               .destroy = lib_prefix_list_entry_ipv4_prefix_destroy,
+                               .modify = lib_prefix_list_entry_ipv6_prefix_modify,
+                               .destroy = lib_prefix_list_entry_ipv6_prefix_destroy,
                        }
                },
                {
                        .xpath = "/frr-filter:lib/prefix-list/entry/ipv6-prefix-length-greater-or-equal",
                        .cbs = {
-                               .modify = lib_prefix_list_entry_ipv4_prefix_length_greater_or_equal_modify,
-                               .destroy = lib_prefix_list_entry_ipv4_prefix_length_greater_or_equal_destroy,
+                               .modify = lib_prefix_list_entry_ipv6_prefix_length_greater_or_equal_modify,
+                               .destroy = lib_prefix_list_entry_ipv6_prefix_length_greater_or_equal_destroy,
                        }
                },
                {
                        .xpath = "/frr-filter:lib/prefix-list/entry/ipv6-prefix-length-lesser-or-equal",
                        .cbs = {
-                               .modify = lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_modify,
-                               .destroy = lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_destroy,
+                               .modify = lib_prefix_list_entry_ipv6_prefix_length_lesser_or_equal_modify,
+                               .destroy = lib_prefix_list_entry_ipv6_prefix_length_lesser_or_equal_destroy,
                        }
                },
                {
index 3f0179fbc1386e805430ffd20c8a446b7a28ad4c..03359f4d18ea1e1913feeff80bb08a969468be1a 100644 (file)
@@ -30,8 +30,8 @@
 #include "zlog.h"
 #include "libfrr_trace.h"
 
-DEFINE_MTYPE_STATIC(LIB, FRR_PTHREAD, "FRR POSIX Thread")
-DEFINE_MTYPE_STATIC(LIB, PTHREAD_PRIM, "POSIX sync primitives")
+DEFINE_MTYPE_STATIC(LIB, FRR_PTHREAD, "FRR POSIX Thread");
+DEFINE_MTYPE_STATIC(LIB, PTHREAD_PRIM, "POSIX sync primitives");
 
 /* default frr_pthread start/stop routine prototypes */
 static void *fpt_run(void *arg);
index 33adcd7b8026ee27e1d86fb81546c56d99041295..05f0fce5fcf1946613b1f4b70f574f3e0822240e 100644 (file)
@@ -26,7 +26,7 @@
 #include "log.h"
 #include "lib_errors.h"
 
-DEFINE_MTYPE_STATIC(LIB, ZEROMQ_CB, "ZeroMQ callback")
+DEFINE_MTYPE_STATIC(LIB, ZEROMQ_CB, "ZeroMQ callback");
 
 /* libzmq's context */
 void *frrzmq_context = NULL;
index 7e6475b6487e5992a74b8cba5c83632ee5c2d480..0e717a98a5d98ad588f19b29e7c635368c758a75 100644 (file)
 #include "seqlock.h"
 #include "atomlist.h"
 
-DEFINE_MTYPE_STATIC(LIB, RCU_THREAD,    "RCU thread")
-DEFINE_MTYPE_STATIC(LIB, RCU_NEXT,      "RCU sequence barrier")
+DEFINE_MTYPE_STATIC(LIB, RCU_THREAD,    "RCU thread");
+DEFINE_MTYPE_STATIC(LIB, RCU_NEXT,      "RCU sequence barrier");
 
-DECLARE_ATOMLIST(rcu_heads, struct rcu_head, head)
+DECLARE_ATOMLIST(rcu_heads, struct rcu_head, head);
 
-PREDECL_ATOMLIST(rcu_threads)
+PREDECL_ATOMLIST(rcu_threads);
 struct rcu_thread {
        struct rcu_threads_item head;
 
@@ -70,7 +70,7 @@ struct rcu_thread {
        /* only accessed by thread itself, not atomic */
        unsigned depth;
 };
-DECLARE_ATOMLIST(rcu_threads, struct rcu_thread, head)
+DECLARE_ATOMLIST(rcu_threads, struct rcu_thread, head);
 
 static const struct rcu_action rcua_next  = { .type = RCUA_NEXT };
 static const struct rcu_action rcua_end   = { .type = RCUA_END };
index 47751ae7df395a01fd82b0c1ff6d53cd1597737a..38082590405ee887a4bd1618e14bca3f5c36349d 100644 (file)
@@ -116,7 +116,7 @@ struct rcu_action {
 };
 
 /* RCU cleanup function queue item */
-PREDECL_ATOMLIST(rcu_heads)
+PREDECL_ATOMLIST(rcu_heads);
 struct rcu_head {
        struct rcu_heads_item head;
        const struct rcu_action *action;
index a40b815caa74329dae7df28453ee3a4aed74945d..209765bd6f9aa5b561ac86ee911056f55abef376 100644 (file)
@@ -34,7 +34,7 @@
 
 #define GRAMMAR_STR "CLI grammar sandbox\n"
 
-DEFINE_MTYPE_STATIC(LIB, CMD_TOKENS, "Command desc")
+DEFINE_MTYPE_STATIC(LIB, CMD_TOKENS, "Command desc");
 
 /** headers **/
 void grammar_sandbox_init(void);
index 128e45c57002951d8e64ef70bb30f10dcb51d176..1cbe1b90f96dcc1060b19aa66e7ccaabc8192edc 100644 (file)
@@ -25,8 +25,8 @@
 #include "memory.h"
 #include "buffer.h"
 
-DEFINE_MTYPE_STATIC(LIB, GRAPH, "Graph")
-DEFINE_MTYPE_STATIC(LIB, GRAPH_NODE, "Graph Node")
+DEFINE_MTYPE_STATIC(LIB, GRAPH, "Graph");
+DEFINE_MTYPE_STATIC(LIB, GRAPH_NODE, "Graph Node");
 struct graph *graph_new(void)
 {
        struct graph *graph = XCALLOC(MTYPE_GRAPH, sizeof(struct graph));
index ec616ee724b9a1d559a99c6aa76c57b00f3a461f..e9132f790734607a01063964c1853a845c11fb2d 100644 (file)
@@ -31,9 +31,9 @@
 #include "frr_pthread.h"
 #include "libfrr_trace.h"
 
-DEFINE_MTYPE_STATIC(LIB, HASH, "Hash")
-DEFINE_MTYPE_STATIC(LIB, HASH_BUCKET, "Hash Bucket")
-DEFINE_MTYPE_STATIC(LIB, HASH_INDEX, "Hash Index")
+DEFINE_MTYPE_STATIC(LIB, HASH, "Hash");
+DEFINE_MTYPE_STATIC(LIB, HASH_BUCKET, "Hash Bucket");
+DEFINE_MTYPE_STATIC(LIB, HASH_INDEX, "Hash Index");
 
 static pthread_mutex_t _hashes_mtx = PTHREAD_MUTEX_INITIALIZER;
 static struct list *_hashes;
index 5a8ad00d660d437f2d3a972f7cec003cd299752a..895243aad7265239815b17b619160dd79e97e5cd 100644 (file)
@@ -23,7 +23,7 @@
 #include "memory.h"
 #include "hook.h"
 
-DEFINE_MTYPE_STATIC(LIB, HOOK_ENTRY, "Hook entry")
+DEFINE_MTYPE_STATIC(LIB, HOOK_ENTRY, "Hook entry");
 
 void _hook_register(struct hook *hook, struct hookent *stackent, void *funcptr,
                    void *arg, bool has_arg, struct frrmod_runtime *module,
index bef5351e905765d5defc7922ab61c987e9709e79..ff3ef29fa3f25c09352a364eee4c04e024eab323 100644 (file)
@@ -35,10 +35,10 @@ extern "C" {
  *
  *   mydaemon.h:
  *     #include "hook.h"
- *     DECLARE_HOOK (some_update_event, (struct eventinfo *info), (info))
+ *     DECLARE_HOOK (some_update_event, (struct eventinfo *info), (info));
  *
  *   mydaemon.c:
- *     DEFINE_HOOK (some_update_event, (struct eventinfo *info), (info))
+ *     DEFINE_HOOK (some_update_event, (struct eventinfo *info), (info));
  *     ...
  *     hook_call (some_update_event, info)
  *
@@ -184,7 +184,7 @@ extern void _hook_unregister(struct hook *hook, void *funcptr, void *arg,
 #define HOOK_ADDARG(...) (hookarg , ## __VA_ARGS__)
 
 /* use in header file - declares the hook and its arguments
- * usage:  DECLARE_HOOK(my_hook, (int arg1, struct foo *arg2), (arg1, arg2))
+ * usage:  DECLARE_HOOK(my_hook, (int arg1, struct foo *arg2), (arg1, arg2));
  * as above, "passlist" must use the same order and same names as "arglist"
  *
  * theoretically passlist is not neccessary, but let's keep things simple and
@@ -201,7 +201,9 @@ extern void _hook_unregister(struct hook *hook, void *funcptr, void *arg,
                int(*funcptr) HOOK_ADDDEF arglist)                             \
        {                                                                      \
                return (void *)funcptr;                                        \
-       }
+       }                                                                      \
+       MACRO_REQUIRE_SEMICOLON() /* end */
+
 #define DECLARE_KOOH(hookname, arglist, passlist)                              \
        DECLARE_HOOK(hookname, arglist, passlist)
 
@@ -230,7 +232,8 @@ extern void _hook_unregister(struct hook *hook, void *funcptr, void *arg,
                                hooksum += hookp.farg HOOK_ADDARG passlist;    \
                }                                                              \
                return hooksum;                                                \
-       }
+       }                                                                      \
+       MACRO_REQUIRE_SEMICOLON() /* end */
 
 #define DEFINE_HOOK(hookname, arglist, passlist)                               \
        DEFINE_HOOK_INT(hookname, arglist, passlist, false)
index 95096fa5f0fb3a4bf032c61f05ce1a67be2a3f4c..9179dc4299428da8e0173a01e800d44b54b3f04b 100644 (file)
 
 #include <inttypes.h>
 
-DEFINE_MTYPE_STATIC(LIB, IDALLOC_ALLOCATOR, "ID Number Allocator")
-DEFINE_MTYPE_STATIC(LIB, IDALLOC_ALLOCATOR_NAME, "ID Number Allocator Name")
-DEFINE_MTYPE_STATIC(LIB, IDALLOC_DIRECTORY, "ID Number Allocator Directory")
+DEFINE_MTYPE_STATIC(LIB, IDALLOC_ALLOCATOR, "ID Number Allocator");
+DEFINE_MTYPE_STATIC(LIB, IDALLOC_ALLOCATOR_NAME, "ID Number Allocator Name");
+DEFINE_MTYPE_STATIC(LIB, IDALLOC_DIRECTORY, "ID Number Allocator Directory");
 DEFINE_MTYPE_STATIC(LIB, IDALLOC_SUBDIRECTORY,
-                   "ID Number Allocator Subdirectory")
-DEFINE_MTYPE_STATIC(LIB, IDALLOC_PAGE, "ID Number Allocator Page")
-DEFINE_MTYPE_STATIC(LIB, IDALLOC_POOL, "ID Number temporary holding pool entry")
+                   "ID Number Allocator Subdirectory");
+DEFINE_MTYPE_STATIC(LIB, IDALLOC_PAGE, "ID Number Allocator Page");
+DEFINE_MTYPE_STATIC(LIB, IDALLOC_POOL,
+                   "ID Number temporary holding pool entry");
 
 #if UINT_MAX >= UINT32_MAX
 #define FFS32(x) ffs(x)
index 7ec53d356d9b6ea224b3f7ea70c0c8610deb5e05..629ef4e70878b3e401392304cf31eb5d6fb6eddc 100644 (file)
--- a/lib/if.c
+++ b/lib/if.c
 #include "lib/if_clippy.c"
 #endif
 
-DEFINE_MTYPE_STATIC(LIB, IF, "Interface")
-DEFINE_MTYPE_STATIC(LIB, CONNECTED, "Connected")
-DEFINE_MTYPE_STATIC(LIB, NBR_CONNECTED, "Neighbor Connected")
-DEFINE_MTYPE(LIB, CONNECTED_LABEL, "Connected interface label")
-DEFINE_MTYPE_STATIC(LIB, IF_LINK_PARAMS, "Informational Link Parameters")
+DEFINE_MTYPE_STATIC(LIB, IF, "Interface");
+DEFINE_MTYPE_STATIC(LIB, CONNECTED, "Connected");
+DEFINE_MTYPE_STATIC(LIB, NBR_CONNECTED, "Neighbor Connected");
+DEFINE_MTYPE(LIB, CONNECTED_LABEL, "Connected interface label");
+DEFINE_MTYPE_STATIC(LIB, IF_LINK_PARAMS, "Informational Link Parameters");
 
 static struct interface *if_lookup_by_ifindex(ifindex_t ifindex,
                                              vrf_id_t vrf_id);
@@ -53,10 +53,10 @@ static int if_cmp_index_func(const struct interface *ifp1,
 RB_GENERATE(if_name_head, interface, name_entry, if_cmp_func);
 RB_GENERATE(if_index_head, interface, index_entry, if_cmp_index_func);
 
-DEFINE_QOBJ_TYPE(interface)
+DEFINE_QOBJ_TYPE(interface);
 
-DEFINE_HOOK(if_add, (struct interface * ifp), (ifp))
-DEFINE_KOOH(if_del, (struct interface * ifp), (ifp))
+DEFINE_HOOK(if_add, (struct interface * ifp), (ifp));
+DEFINE_KOOH(if_del, (struct interface * ifp), (ifp));
 
 static struct interface_master{
        int (*create_hook)(struct interface *ifp);
index 5bf52936aebec7f2ac724accb4da87ac35fedbda..f425ba8bceaa7e2345dd9c880a548be8cb8bb9bf 100644 (file)
--- a/lib/if.h
+++ b/lib/if.h
@@ -31,7 +31,7 @@
 extern "C" {
 #endif
 
-DECLARE_MTYPE(CONNECTED_LABEL)
+DECLARE_MTYPE(CONNECTED_LABEL);
 
 /* Interface link-layer type, if known. Derived from:
  *
@@ -301,14 +301,14 @@ struct interface {
         */
        bool configured;
 
-       QOBJ_FIELDS
+       QOBJ_FIELDS;
 };
 
 RB_HEAD(if_name_head, interface);
 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_index_func)
-DECLARE_QOBJ_TYPE(interface)
+DECLARE_QOBJ_TYPE(interface);
 
 #define IFNAME_RB_INSERT(vrf, ifp)                                                    \
        ({                                                                            \
@@ -378,8 +378,8 @@ DECLARE_QOBJ_TYPE(interface)
  * can use 1000+ so they run after the daemon has initialised daemon-specific
  * interface data
  */
-DECLARE_HOOK(if_add, (struct interface * ifp), (ifp))
-DECLARE_KOOH(if_del, (struct interface * ifp), (ifp))
+DECLARE_HOOK(if_add, (struct interface * ifp), (ifp));
+DECLARE_KOOH(if_del, (struct interface * ifp), (ifp));
 
 #define METRIC_MAX (~0)
 
index 1973d40be4ec97e223e71f59528b8aa34323a532..8282e476dfac191bd5d0dd0ef10518f5d18d54a2 100644 (file)
 #include "if.h"
 #include "if_rmap.h"
 
-DEFINE_MTYPE_STATIC(LIB, IF_RMAP_CTX, "Interface route map container")
-DEFINE_MTYPE_STATIC(LIB, IF_RMAP_CTX_NAME, "Interface route map container name")
-DEFINE_MTYPE_STATIC(LIB, IF_RMAP, "Interface route map")
-DEFINE_MTYPE_STATIC(LIB, IF_RMAP_NAME, "I.f. route map name")
+DEFINE_MTYPE_STATIC(LIB, IF_RMAP_CTX, "Interface route map container");
+DEFINE_MTYPE_STATIC(LIB, IF_RMAP_CTX_NAME,
+                   "Interface route map container name");
+DEFINE_MTYPE_STATIC(LIB, IF_RMAP, "Interface route map");
+DEFINE_MTYPE_STATIC(LIB, IF_RMAP_NAME, "I.f. route map name");
 
 static struct list *if_rmap_ctx_list;
 
index 82fd6a65f2249989d3eb693643a692cd3d32bf96..db5c23b1bae4c203cb180dd31aad61aa469deeba 100644 (file)
 #include "linklist.h"
 #include "keychain.h"
 
-DEFINE_MTYPE_STATIC(LIB, KEY, "Key")
-DEFINE_MTYPE_STATIC(LIB, KEYCHAIN, "Key chain")
+DEFINE_MTYPE_STATIC(LIB, KEY, "Key");
+DEFINE_MTYPE_STATIC(LIB, KEYCHAIN, "Key chain");
 
-DEFINE_QOBJ_TYPE(keychain)
-DEFINE_QOBJ_TYPE(key)
+DEFINE_QOBJ_TYPE(keychain);
+DEFINE_QOBJ_TYPE(key);
 
 /* Master list of key chain. */
 static struct list *keychain_list;
index e5cf39f7c6557a2c7a154b7b5d4ed699db5b4d06..eb6d2f175edd7c9670aa79d451b235705a56916d 100644 (file)
@@ -32,9 +32,9 @@ struct keychain {
 
        struct list *key;
 
-       QOBJ_FIELDS
+       QOBJ_FIELDS;
 };
-DECLARE_QOBJ_TYPE(keychain)
+DECLARE_QOBJ_TYPE(keychain);
 
 struct key_range {
        time_t start;
@@ -51,9 +51,9 @@ struct key {
        struct key_range send;
        struct key_range accept;
 
-       QOBJ_FIELDS
+       QOBJ_FIELDS;
 };
-DECLARE_QOBJ_TYPE(key)
+DECLARE_QOBJ_TYPE(key);
 
 extern void keychain_init(void);
 extern struct keychain *keychain_lookup(const char *);
index c9d7eb37cfd2d0ba9fa551b46882095c0999c761..8912d15589f2c330b4fc8fb0beddc7934e70c5e9 100644 (file)
@@ -31,7 +31,7 @@
 #include "ldp_sync.h"
 
 /* Library code */
-DEFINE_MTYPE_STATIC(LIB, LDP_SYNC_INFO, "LDP SYNC info")
+DEFINE_MTYPE_STATIC(LIB, LDP_SYNC_INFO, "LDP SYNC info");
 
 /*
  * ldp_sync_info_create - Allocate the LDP_SYNC information
index 51b97369c92232c315d90d73f2f8a2c1e9788f8b..5b0a523fb51e76091b035d5cbc78178cfc51bae0 100644 (file)
 #include "defaults.h"
 #include "frrscript.h"
 
-DEFINE_HOOK(frr_late_init, (struct thread_master * tm), (tm))
-DEFINE_HOOK(frr_very_late_init, (struct thread_master * tm), (tm))
-DEFINE_KOOH(frr_early_fini, (), ())
-DEFINE_KOOH(frr_fini, (), ())
+DEFINE_HOOK(frr_late_init, (struct thread_master * tm), (tm));
+DEFINE_HOOK(frr_very_late_init, (struct thread_master * tm), (tm));
+DEFINE_KOOH(frr_early_fini, (), ());
+DEFINE_KOOH(frr_fini, (), ());
 
 const char frr_sysconfdir[] = SYSCONFDIR;
 char frr_vtydir[256];
index 825f502bdf6dcd6a975ac96aea0dbb12c4100deb..db0f36498668c9d7ea8061539fcc3cfd5b312480 100644 (file)
@@ -124,8 +124,8 @@ struct frr_daemon_info {
                                                       __VA_ARGS__};           \
        FRR_COREMOD_SETUP(.name = #execname,                                   \
                          .description = #execname " daemon",                  \
-                         .version = FRR_VERSION, )                            \
-/* end */
+                         .version = FRR_VERSION, );                           \
+       MACRO_REQUIRE_SEMICOLON() /* end */
 
 extern void frr_init_vtydir(void);
 extern void frr_preinit(struct frr_daemon_info *daemon, int argc, char **argv);
@@ -141,8 +141,8 @@ extern enum frr_cli_mode frr_get_cli_mode(void);
 extern uint32_t frr_get_fd_limit(void);
 extern bool frr_is_startup_fd(int fd);
 
-DECLARE_HOOK(frr_late_init, (struct thread_master * tm), (tm))
-DECLARE_HOOK(frr_very_late_init, (struct thread_master * tm), (tm))
+DECLARE_HOOK(frr_late_init, (struct thread_master * tm), (tm));
+DECLARE_HOOK(frr_very_late_init, (struct thread_master * tm), (tm));
 extern void frr_config_fork(void);
 
 extern void frr_run(struct thread_master *master);
@@ -153,10 +153,10 @@ extern bool frr_zclient_addr(struct sockaddr_storage *sa, socklen_t *sa_len,
 
 /* these two are before the protocol daemon does its own shutdown
  * it's named this way being the counterpart to frr_late_init */
-DECLARE_KOOH(frr_early_fini, (), ())
+DECLARE_KOOH(frr_early_fini, (), ());
 extern void frr_early_fini(void);
 /* and these two are after the daemon did its own cleanup */
-DECLARE_KOOH(frr_fini, (), ())
+DECLARE_KOOH(frr_fini, (), ());
 extern void frr_fini(void);
 
 extern char config_default[512];
index ecf0d0698dfc56140d61b5bacbbf455536feb7b0..7f0d2a1245162af6ea7dafa725ea235ccdbadcfe 100644 (file)
@@ -36,7 +36,7 @@
 #include "link_state.h"
 
 /* Link State Memory allocation */
-DEFINE_MTYPE_STATIC(LIB, LS_DB, "Link State Database")
+DEFINE_MTYPE_STATIC(LIB, LS_DB, "Link State Database");
 
 /**
  *  Link State Node management functions
index 93669f5b234553e22d4dc9315ce095e5c924fd18..f9eb59b76a3409c4954adb063b299d03a3fa555f 100644 (file)
@@ -324,7 +324,7 @@ extern int ls_attributes_same(struct ls_attributes *a1,
  */
 
 /* Link State Vertex structure */
-PREDECL_RBTREE_UNIQ(vertices)
+PREDECL_RBTREE_UNIQ(vertices);
 struct ls_vertex {
        struct vertices_item entry;     /* Entry in RB Tree */
        uint64_t key;                   /* Unique Key identifier */
@@ -335,7 +335,7 @@ struct ls_vertex {
 };
 
 /* Link State Edge structure */
-PREDECL_RBTREE_UNIQ(edges)
+PREDECL_RBTREE_UNIQ(edges);
 struct ls_edge {
        struct edges_item entry;        /* Entry in RB tree */
        uint64_t key;                   /* Unique Key identifier */
@@ -345,7 +345,7 @@ struct ls_edge {
 };
 
 /* Link State Subnet structure */
-PREDECL_RBTREE_UNIQ(subnets)
+PREDECL_RBTREE_UNIQ(subnets);
 struct ls_subnet {
        struct subnets_item entry;      /* Entry in RB tree */
        struct prefix key;              /* Unique Key identifier */
@@ -359,21 +359,21 @@ macro_inline int vertex_cmp(const struct ls_vertex *node1,
 {
        return (node1->key - node2->key);
 }
-DECLARE_RBTREE_UNIQ(vertices, struct ls_vertex, entry, vertex_cmp)
+DECLARE_RBTREE_UNIQ(vertices, struct ls_vertex, entry, vertex_cmp);
 
 macro_inline int edge_cmp(const struct ls_edge *edge1,
                          const struct ls_edge *edge2)
 {
        return (edge1->key - edge2->key);
 }
-DECLARE_RBTREE_UNIQ(edges, struct ls_edge, entry, edge_cmp)
+DECLARE_RBTREE_UNIQ(edges, struct ls_edge, entry, edge_cmp);
 
 macro_inline int subnet_cmp(const struct ls_subnet *a,
                             const struct ls_subnet *b)
 {
        return prefix_cmp(&a->key, &b->key);
 }
-DECLARE_RBTREE_UNIQ(subnets, struct ls_subnet, entry, subnet_cmp)
+DECLARE_RBTREE_UNIQ(subnets, struct ls_subnet, entry, subnet_cmp);
 
 /* Link State TED Structure */
 struct ls_ted {
index 43c2002231d6b7c58c608eadfc04ea5419838be8..5de6c8a81729bddf8df27f64999a09ac2d944750 100644 (file)
@@ -25,8 +25,8 @@
 #include "memory.h"
 #include "libfrr_trace.h"
 
-DEFINE_MTYPE_STATIC(LIB, LINK_LIST, "Link List")
-DEFINE_MTYPE_STATIC(LIB, LINK_NODE, "Link Node")
+DEFINE_MTYPE_STATIC(LIB, LINK_LIST, "Link List");
+DEFINE_MTYPE_STATIC(LIB, LINK_NODE, "Link Node");
 
 struct list *list_new(void)
 {
index d1dcac23401203d523ec790d15ed0018863df28e..c26621ae99d1e3e1aac6e98ed6e8ff574160dce4 100644 (file)
@@ -33,7 +33,7 @@
 
 #define ZLOG_MAXLVL(a, b) MAX(a, b)
 
-DEFINE_HOOK(zlog_rotate, (), ())
+DEFINE_HOOK(zlog_rotate, (), ());
 
 static const int log_default_lvl = LOG_DEBUG;
 
@@ -532,6 +532,28 @@ DEFUN (no_config_log_timestamp_precision,
        return CMD_SUCCESS;
 }
 
+DEFPY (config_log_ec,
+       config_log_ec_cmd,
+       "[no] log error-category",
+       NO_STR
+       "Logging control\n"
+       "Prefix log message text with [EC 9999] code\n")
+{
+       zlog_set_prefix_ec(!no);
+       return CMD_SUCCESS;
+}
+
+DEFPY (config_log_xid,
+       config_log_xid_cmd,
+       "[no] log unique-id",
+       NO_STR
+       "Logging control\n"
+       "Prefix log message text with [XXXXX-XXXXX] identifier\n")
+{
+       zlog_set_prefix_xid(!no);
+       return CMD_SUCCESS;
+}
+
 DEFPY (config_log_filterfile,
        config_log_filterfile_cmd,
        "log filtered-file FILENAME [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>$levelarg]",
@@ -699,6 +721,11 @@ void log_config_write(struct vty *vty)
        if (zt_file.ts_subsec > 0)
                vty_out(vty, "log timestamp precision %d\n",
                        zt_file.ts_subsec);
+
+       if (!zlog_get_prefix_ec())
+               vty_out(vty, "no log error-category\n");
+       if (!zlog_get_prefix_xid())
+               vty_out(vty, "no log unique-id\n");
 }
 
 static int log_vty_init(const char *progname, const char *protoname,
@@ -707,6 +734,9 @@ static int log_vty_init(const char *progname, const char *protoname,
        zlog_progname = progname;
        zlog_protoname = protoname;
 
+       zlog_set_prefix_ec(true);
+       zlog_set_prefix_xid(true);
+
        zlog_filterfile_init(&zt_filterfile);
 
        zlog_file_set_fd(&zt_stdout, STDOUT_FILENO);
@@ -737,6 +767,8 @@ void log_cmd_init(void)
        install_element(CONFIG_NODE, &no_config_log_record_priority_cmd);
        install_element(CONFIG_NODE, &config_log_timestamp_precision_cmd);
        install_element(CONFIG_NODE, &no_config_log_timestamp_precision_cmd);
+       install_element(CONFIG_NODE, &config_log_ec_cmd);
+       install_element(CONFIG_NODE, &config_log_xid_cmd);
 
        install_element(VIEW_NODE, &show_log_filter_cmd);
        install_element(CONFIG_NODE, &log_filter_cmd);
index 16c447546736a5c16b1b9c9706df97a786d37794..f0fb7d3dba0235db5be51355d048bf15fe79611a 100644 (file)
@@ -34,7 +34,7 @@ extern void log_config_write(struct vty *vty);
 extern int log_level_match(const char *s);
 extern void log_show_syslog(struct vty *vty);
 
-DECLARE_HOOK(zlog_rotate, (), ())
+DECLARE_HOOK(zlog_rotate, (), ());
 extern void zlog_rotate(void);
 
 #ifdef __cplusplus
index a377d3b945e0047b36ce5ad1825acb8d11c590ae..0dc8e905247acf462b9fec70a617f3fd34024856 100644 (file)
@@ -34,8 +34,8 @@
 static struct memgroup *mg_first = NULL;
 struct memgroup **mg_insert = &mg_first;
 
-DEFINE_MGROUP(LIB, "libfrr")
-DEFINE_MTYPE(LIB, TMP, "Temporary memory")
+DEFINE_MGROUP(LIB, "libfrr");
+DEFINE_MTYPE(LIB, TMP, "Temporary memory");
 
 static inline void mt_count_alloc(struct memtype *mt, size_t size, void *ptr)
 {
index e9db12fce2ca85738165df3a7c9b4e0fba6f3d03..c95602f4853842888afdd45a74a631f5d42b21d7 100644 (file)
@@ -56,20 +56,20 @@ struct memgroup {
 /* macro usage:
  *
  *  mydaemon.h
- *    DECLARE_MGROUP(MYDAEMON)
- *    DECLARE_MTYPE(MYDAEMON_COMMON)
+ *    DECLARE_MGROUP(MYDAEMON);
+ *    DECLARE_MTYPE(MYDAEMON_COMMON);
  *
  *  mydaemon.c
- *    DEFINE_MGROUP(MYDAEMON, "my daemon memory")
+ *    DEFINE_MGROUP(MYDAEMON, "my daemon memory");
  *    DEFINE_MTYPE(MYDAEMON, MYDAEMON_COMMON,
- *                   "this mtype is used in multiple files in mydaemon")
+ *                   "this mtype is used in multiple files in mydaemon");
  *    foo = qmalloc(MTYPE_MYDAEMON_COMMON, sizeof(*foo))
  *
  *  mydaemon_io.c
  *    bar = qmalloc(MTYPE_MYDAEMON_COMMON, sizeof(*bar))
  *
  *    DEFINE_MTYPE_STATIC(MYDAEMON, MYDAEMON_IO,
- *                          "this mtype is used only in this file")
+ *                          "this mtype is used only in this file");
  *    baz = qmalloc(MTYPE_MYDAEMON_IO, sizeof(*baz))
  *
  *  Note:  Naming conventions (MGROUP_ and MTYPE_ prefixes are enforced
@@ -78,7 +78,7 @@ struct memgroup {
  *         but MGROUP_* aren't.
  */
 
-#define DECLARE_MGROUP(name) extern struct memgroup _mg_##name;
+#define DECLARE_MGROUP(name) extern struct memgroup _mg_##name
 #define _DEFINE_MGROUP(mname, desc, ...)                                       \
        struct memgroup _mg_##mname                                            \
                __attribute__((section(".data.mgroups"))) = {                  \
@@ -104,7 +104,7 @@ struct memgroup {
                        _mg_##mname.next->ref = _mg_##mname.ref;               \
                *_mg_##mname.ref = _mg_##mname.next;                           \
        }                                                                      \
-       /* end */
+       MACRO_REQUIRE_SEMICOLON() /* end */
 
 #define DEFINE_MGROUP(mname, desc) \
        _DEFINE_MGROUP(mname, desc, )
@@ -112,7 +112,7 @@ struct memgroup {
        _DEFINE_MGROUP(mname, desc, .active_at_exit = true)
 
 #define DECLARE_MTYPE(name)                                                    \
-       extern struct memtype MTYPE_##name[1];                                 \
+       extern struct memtype MTYPE_##name[1]                                  \
        /* end */
 
 #define DEFINE_MTYPE_ATTR(group, mname, attr, desc)                            \
@@ -140,7 +140,7 @@ struct memgroup {
                        MTYPE_##mname->next->ref = MTYPE_##mname->ref;         \
                *MTYPE_##mname->ref = MTYPE_##mname->next;                     \
        }                                                                      \
-       /* end */
+       MACRO_REQUIRE_SEMICOLON() /* end */
 
 #define DEFINE_MTYPE(group, name, desc)                                        \
        DEFINE_MTYPE_ATTR(group, name, , desc)                                 \
@@ -150,8 +150,8 @@ struct memgroup {
        DEFINE_MTYPE_ATTR(group, name, static, desc)                           \
        /* end */
 
-DECLARE_MGROUP(LIB)
-DECLARE_MTYPE(TMP)
+DECLARE_MGROUP(LIB);
+DECLARE_MTYPE(TMP);
 
 
 extern void *qmalloc(struct memtype *mt, size_t size)
index 3d299a6a2e0d682bbd819a155fbd3992bf98432e..d2491a34797cd86c8aab91f0e084834557976e4c 100644 (file)
@@ -27,8 +27,8 @@
 #include "memory.h"
 #include "version.h"
 
-DEFINE_MTYPE_STATIC(LIB, MODULE_LOADNAME, "Module loading name")
-DEFINE_MTYPE_STATIC(LIB, MODULE_LOADARGS, "Module loading arguments")
+DEFINE_MTYPE_STATIC(LIB, MODULE_LOADNAME, "Module loading name");
+DEFINE_MTYPE_STATIC(LIB, MODULE_LOADARGS, "Module loading arguments");
 
 static struct frrmod_info frrmod_default_info = {
        .name = "libfrr",
@@ -43,7 +43,7 @@ union _frrmod_runtime_u frrmod_default = {
                },
 };
 
-XREF_SETUP()
+XREF_SETUP();
 
 // if defined(HAVE_SYS_WEAK_ALIAS_ATTRIBUTE)
 // union _frrmod_runtime_u _frrmod_this_module
index 5d8d9cfbcc2126625555f7c2815cca095ca41742..6275877cb37423e6b9919202f0cafaded6cba5bf 100644 (file)
@@ -79,12 +79,13 @@ extern union _frrmod_runtime_u _frrmod_this_module;
                NULL,                                                          \
                &_frrmod_info,                                                 \
        }};                                                                    \
-       XREF_SETUP()                                                           \
-       /* end */
+       XREF_SETUP();                                                          \
+       MACRO_REQUIRE_SEMICOLON() /* end */
 
 #define FRR_MODULE_SETUP(...)                                                  \
-       FRR_COREMOD_SETUP(__VA_ARGS__)                                         \
-       DSO_SELF struct frrmod_runtime *frr_module = &_frrmod_this_module.r;
+       FRR_COREMOD_SETUP(__VA_ARGS__);                                        \
+       DSO_SELF struct frrmod_runtime *frr_module = &_frrmod_this_module.r;   \
+       MACRO_REQUIRE_SEMICOLON() /* end */
 
 extern struct frrmod_runtime *frrmod_list;
 
index c6884339834f3d8bf4e29a694945701e47f67b26..cde842b88c4c25eb2a910129732df3364fb1294e 100644 (file)
@@ -40,8 +40,8 @@
 #include "vrf.h"
 #include "lib_errors.h"
 
-DEFINE_MTYPE_STATIC(LIB, NS, "NetNS Context")
-DEFINE_MTYPE_STATIC(LIB, NS_NAME, "NetNS Name")
+DEFINE_MTYPE_STATIC(LIB, NS, "NetNS Context");
+DEFINE_MTYPE_STATIC(LIB, NS_NAME, "NetNS Name");
 
 static inline int ns_compare(const struct ns *ns, const struct ns *ns2);
 static struct ns *ns_lookup_name_internal(const char *name);
index 3fc4b8df4bffe3e17db6bfd2763c85a0873d8f5e..b6570d3b9e58627576d254f8b7f3941f6298634f 100644 (file)
@@ -26,8 +26,8 @@
 #include "log.h"
 #include "memory.h"
 
-DEFINE_MTYPE_STATIC(LIB, NS, "NetNS Context")
-DEFINE_MTYPE_STATIC(LIB, NS_NAME, "NetNS Name")
+DEFINE_MTYPE_STATIC(LIB, NS, "NetNS Context");
+DEFINE_MTYPE_STATIC(LIB, NS_NAME, "NetNS Name");
 
 
 static inline int ns_compare(const struct ns *ns, const struct ns *ns2);
index dd8c1082057667e8acbcaaf94338b02593380de4..17ef95c68727290ee9885855cd9814d08220b34d 100644 (file)
@@ -34,8 +34,8 @@
 #include "vrf.h"
 #include "nexthop_group.h"
 
-DEFINE_MTYPE_STATIC(LIB, NEXTHOP, "Nexthop")
-DEFINE_MTYPE_STATIC(LIB, NH_LABEL, "Nexthop label")
+DEFINE_MTYPE_STATIC(LIB, NEXTHOP, "Nexthop");
+DEFINE_MTYPE_STATIC(LIB, NH_LABEL, "Nexthop label");
 
 static int _nexthop_labels_cmp(const struct nexthop *nh1,
                               const struct nexthop *nh2)
index dee98ad8d73ab7ee06b25e50483102ad01ef70e6..4fee9bde3c2cd06c141ba142ce89afd1feebdcf6 100644 (file)
@@ -32,7 +32,7 @@
 #include "lib/nexthop_group_clippy.c"
 #endif
 
-DEFINE_MTYPE_STATIC(LIB, NEXTHOP_GROUP, "Nexthop Group")
+DEFINE_MTYPE_STATIC(LIB, NEXTHOP_GROUP, "Nexthop Group");
 
 /*
  * Internal struct used to hold nhg config strings
@@ -620,7 +620,7 @@ static void nhgc_delete(struct nexthop_group_cmd *nhgc)
        XFREE(MTYPE_TMP, nhgc);
 }
 
-DEFINE_QOBJ_TYPE(nexthop_group_cmd)
+DEFINE_QOBJ_TYPE(nexthop_group_cmd);
 
 DEFUN_NOSH(nexthop_group, nexthop_group_cmd, "nexthop-group NHGNAME",
           "Enter into the nexthop-group submode\n"
index 5f7bde0defbd1bb470723b8e4d49fe67c435db3b..8e75e5c6ac441f0ed495e8c9818fd58952eeff91 100644 (file)
@@ -97,12 +97,12 @@ struct nexthop_group_cmd {
 
        struct list *nhg_list;
 
-       QOBJ_FIELDS
+       QOBJ_FIELDS;
 };
 RB_HEAD(nhgc_entry_head, nexthp_group_cmd);
 RB_PROTOTYPE(nhgc_entry_head, nexthop_group_cmd, nhgc_entry,
             nexthop_group_cmd_compare)
-DECLARE_QOBJ_TYPE(nexthop_group_cmd)
+DECLARE_QOBJ_TYPE(nexthop_group_cmd);
 
 /*
  * Initialize nexthop_groups.  If you are interested in when
index b6d351828572cb23f78d06f05d92f492602a59e9..34ad5dbfa962226ebb1164673fe63d4df51147e9 100644 (file)
@@ -32,9 +32,9 @@
 #include "northbound_db.h"
 #include "frrstr.h"
 
-DEFINE_MTYPE_STATIC(LIB, NB_NODE, "Northbound Node")
-DEFINE_MTYPE_STATIC(LIB, NB_CONFIG, "Northbound Configuration")
-DEFINE_MTYPE_STATIC(LIB, NB_CONFIG_ENTRY, "Northbound Configuration Entry")
+DEFINE_MTYPE_STATIC(LIB, NB_NODE, "Northbound Node");
+DEFINE_MTYPE_STATIC(LIB, NB_CONFIG, "Northbound Configuration");
+DEFINE_MTYPE_STATIC(LIB, NB_CONFIG_ENTRY, "Northbound Configuration Entry");
 
 /* Running configuration - shouldn't be modified directly. */
 struct nb_config *running_config;
@@ -1260,27 +1260,36 @@ static int nb_callback_configuration(struct nb_context *context,
        }
 
        if (ret != NB_OK) {
-               int priority;
-               enum lib_log_refs ref;
-
                yang_dnode_get_path(dnode, xpath, sizeof(xpath));
 
                switch (event) {
                case NB_EV_VALIDATE:
-                       priority = LOG_WARNING;
-                       ref = EC_LIB_NB_CB_CONFIG_VALIDATE;
+                       flog_warn(EC_LIB_NB_CB_CONFIG_VALIDATE,
+                                 "error processing configuration change: error [%s] event [%s] operation [%s] xpath [%s]%s%s",
+                                 nb_err_name(ret), nb_event_name(event),
+                                 nb_operation_name(operation), xpath,
+                                 errmsg[0] ? " message: " : "", errmsg);
                        break;
                case NB_EV_PREPARE:
-                       priority = LOG_WARNING;
-                       ref = EC_LIB_NB_CB_CONFIG_PREPARE;
+                       flog_warn(EC_LIB_NB_CB_CONFIG_PREPARE,
+                                 "error processing configuration change: error [%s] event [%s] operation [%s] xpath [%s]%s%s",
+                                 nb_err_name(ret), nb_event_name(event),
+                                 nb_operation_name(operation), xpath,
+                                 errmsg[0] ? " message: " : "", errmsg);
                        break;
                case NB_EV_ABORT:
-                       priority = LOG_WARNING;
-                       ref = EC_LIB_NB_CB_CONFIG_ABORT;
+                       flog_warn(EC_LIB_NB_CB_CONFIG_ABORT,
+                                 "error processing configuration change: error [%s] event [%s] operation [%s] xpath [%s]%s%s",
+                                 nb_err_name(ret), nb_event_name(event),
+                                 nb_operation_name(operation), xpath,
+                                 errmsg[0] ? " message: " : "", errmsg);
                        break;
                case NB_EV_APPLY:
-                       priority = LOG_ERR;
-                       ref = EC_LIB_NB_CB_CONFIG_APPLY;
+                       flog_err(EC_LIB_NB_CB_CONFIG_APPLY,
+                                "error processing configuration change: error [%s] event [%s] operation [%s] xpath [%s]%s%s",
+                                nb_err_name(ret), nb_event_name(event),
+                                nb_operation_name(operation), xpath,
+                                errmsg[0] ? " message: " : "", errmsg);
                        break;
                default:
                        flog_err(EC_LIB_DEVELOPMENT,
@@ -1288,15 +1297,6 @@ static int nb_callback_configuration(struct nb_context *context,
                                 event, xpath);
                        exit(1);
                }
-
-               flog(priority, ref,
-                    "error processing configuration change: error [%s] event [%s] operation [%s] xpath [%s]",
-                    nb_err_name(ret), nb_event_name(event),
-                    nb_operation_name(operation), xpath);
-               if (strlen(errmsg) > 0)
-                       flog(priority, ref,
-                            "error processing configuration change: %s",
-                            errmsg);
        }
 
        return ret;
index 3e1342f985b50bbf95612814b9339778bda21de0..21aad64a09f6b107341c472f1ff17249e3f939f2 100644 (file)
@@ -677,9 +677,9 @@ typedef int (*nb_oper_data_cb)(const struct lys_node *snode,
 
 /* Hooks. */
 DECLARE_HOOK(nb_notification_send, (const char *xpath, struct list *arguments),
-            (xpath, arguments))
-DECLARE_HOOK(nb_client_debug_config_write, (struct vty *vty), (vty))
-DECLARE_HOOK(nb_client_debug_set_all, (uint32_t flags, bool set), (flags, set))
+            (xpath, arguments));
+DECLARE_HOOK(nb_client_debug_config_write, (struct vty *vty), (vty));
+DECLARE_HOOK(nb_client_debug_set_all, (uint32_t flags, bool set), (flags, set));
 
 /* Northbound debugging records */
 extern struct debug nb_dbg_cbs_config;
index 8acba9fd2bef01c1c78b3962fc40b3f74d5991c1..3d8771ffbce0b6f62bd994d7db90aa75c2efd77d 100644 (file)
@@ -32,7 +32,7 @@
 #include <confd_dp.h>
 #include <confd_maapi.h>
 
-DEFINE_MTYPE_STATIC(LIB, CONFD, "ConfD module")
+DEFINE_MTYPE_STATIC(LIB, CONFD, "ConfD module");
 
 static struct debug nb_dbg_client_confd = {0, "Northbound client: ConfD"};
 
@@ -1483,4 +1483,5 @@ static int frr_confd_module_init(void)
 
 FRR_MODULE_SETUP(.name = "frr_confd", .version = FRR_VERSION,
                 .description = "FRR ConfD integration module",
-                .init = frr_confd_module_init, )
+                .init = frr_confd_module_init,
+);
index abdae993b10fe55ededc88f323a62a32e7f237ff..d042e15dad302ffe64ab8c620654e4615bbf2398 100644 (file)
@@ -1412,4 +1412,5 @@ static int frr_grpc_module_init(void)
 
 FRR_MODULE_SETUP(.name = "frr_grpc", .version = FRR_VERSION,
                 .description = "FRR gRPC northbound module",
-                .init = frr_grpc_module_init, )
+                .init = frr_grpc_module_init,
+);
index c027f4de726f6677fce214f267922737a70debcb..9fc640ceea2dee016de070bb8e81804e91fb2681 100644 (file)
@@ -32,7 +32,7 @@
 #include <sysrepo/values.h>
 #include <sysrepo/xpath.h>
 
-DEFINE_MTYPE_STATIC(LIB, SYSREPO, "Sysrepo module")
+DEFINE_MTYPE_STATIC(LIB, SYSREPO, "Sysrepo module");
 
 static struct debug nb_dbg_client_sysrepo = {0, "Northbound client: Sysrepo"};
 
@@ -768,4 +768,5 @@ static int frr_sr_module_init(void)
 
 FRR_MODULE_SETUP(.name = "frr_sysrepo", .version = FRR_VERSION,
                 .description = "FRR sysrepo integration module",
-                .init = frr_sr_module_init, )
+                .init = frr_sr_module_init,
+);
index 4588dfe1d36d4a30b3de06d0e31010bf14f0eeb6..92c8b8ee557115cce21f88a5d895389644a6f23d 100644 (file)
 
 #include "plist_int.h"
 
-DEFINE_MTYPE_STATIC(LIB, PREFIX_LIST, "Prefix List")
-DEFINE_MTYPE_STATIC(LIB, MPREFIX_LIST_STR, "Prefix List Str")
-DEFINE_MTYPE_STATIC(LIB, PREFIX_LIST_ENTRY, "Prefix List Entry")
-DEFINE_MTYPE_STATIC(LIB, PREFIX_LIST_TRIE, "Prefix List Trie Table")
+DEFINE_MTYPE_STATIC(LIB, PREFIX_LIST, "Prefix List");
+DEFINE_MTYPE_STATIC(LIB, MPREFIX_LIST_STR, "Prefix List Str");
+DEFINE_MTYPE_STATIC(LIB, PREFIX_LIST_ENTRY, "Prefix List Entry");
+DEFINE_MTYPE_STATIC(LIB, PREFIX_LIST_TRIE, "Prefix List Trie Table");
 
 /* not currently changeable, code assumes bytes further down */
 #define PLC_BITS       8
@@ -684,6 +684,7 @@ void prefix_list_entry_update_start(struct prefix_list_entry *ple)
        if (pl->head || pl->tail || pl->desc)
                pl->master->recent = pl;
 
+       ple->next_best = NULL;
        ple->installed = false;
 }
 
index 5e5c2d89a83509c7c6ad1aa4a27afba692bd8aa4..afc4d3d5c22f5bfaa05b446e0eb952a79b61d19d 100644 (file)
@@ -32,8 +32,8 @@
 #include "printfrr.h"
 #include "vxlan.h"
 
-DEFINE_MTYPE_STATIC(LIB, PREFIX, "Prefix")
-DEFINE_MTYPE_STATIC(LIB, PREFIX_FLOWSPEC, "Prefix Flowspec")
+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,
index a775e1517ba7ddb905748352f746f906de50a13d..418e839d97ce5bbe9c6119d5abc13f32c722c02a 100644 (file)
@@ -160,6 +160,30 @@ void printfrr_ext_reg(const struct printfrr_ext *);
        }                                                                      \
        /* end */
 
+/* fbuf helper functions */
+
+static inline ssize_t bputs(struct fbuf *buf, const char *str)
+{
+       size_t len = strlen(str);
+       size_t ncopy;
+
+       if (!buf)
+               return len;
+
+       ncopy = MIN(len, (size_t)(buf->buf + buf->len - buf->pos));
+       memcpy(buf->pos, str, ncopy);
+       buf->pos += ncopy;
+
+       return len;
+}
+
+static inline ssize_t bputch(struct fbuf *buf, char ch)
+{
+       if (buf && buf->pos < buf->buf + buf->len)
+               *buf->pos++ = ch;
+       return 1;
+}
+
 #ifdef __cplusplus
 }
 #endif
index 5ca3c0d886efbaf9c5f6deb92e7ddcd558b1128f..49761af8716e209fd8aa284511c2f388bc2ac0bf 100644 (file)
@@ -28,7 +28,7 @@
 #include "lib_errors.h"
 #include "lib/queue.h"
 
-DEFINE_MTYPE_STATIC(LIB, PRIVS, "Privilege information")
+DEFINE_MTYPE_STATIC(LIB, PRIVS, "Privilege information");
 
 /*
  * Different capabilities/privileges apis have different characteristics: some
index 0c326f29d4ceee05cf40976fc7e0425c46bf484c..15563d2471ac267c3b8c3797a79084c14a1ed05f 100644 (file)
@@ -48,8 +48,8 @@ struct pullwr {
        int64_t maxspin;        /* PULLWR_MAXSPIN */
 };
 
-DEFINE_MTYPE_STATIC(LIB, PULLWR_HEAD, "pull-driven write controller")
-DEFINE_MTYPE_STATIC(LIB, PULLWR_BUF,  "pull-driven write buffer")
+DEFINE_MTYPE_STATIC(LIB, PULLWR_HEAD, "pull-driven write controller");
+DEFINE_MTYPE_STATIC(LIB, PULLWR_BUF,  "pull-driven write buffer");
 
 static int pullwr_run(struct thread *t);
 
index cb3254cbe9305e9fd5824d346884487525c1d80c..c6cb36c058b3b052d46938303947069a4eb4cfb2 100644 (file)
@@ -43,7 +43,7 @@ static int qobj_cmp(const struct qobj_node *na, const struct qobj_node *nb)
 }
 
 DECLARE_HASH(qobj_nodes, struct qobj_node, nodehash,
-                       qobj_cmp, qobj_hash)
+                       qobj_cmp, qobj_hash);
 
 static pthread_rwlock_t nodes_lock;
 static struct qobj_nodes_head nodes = { };
index 400ae0151cc7b5bd13bc6de5579c92c11270db67..5012c98d7482eb04826138678caf4db42f6d360a 100644 (file)
@@ -83,7 +83,7 @@ struct qobj_nodetype {
        RESERVED_SPACE_STRUCT(qobj_nodetype_capnp, capnp, 256)
 };
 
-PREDECL_HASH(qobj_nodes)
+PREDECL_HASH(qobj_nodes);
 
 /* anchor to be embedded somewhere in the object's struct */
 struct qobj_node {
@@ -92,7 +92,7 @@ struct qobj_node {
        const struct qobj_nodetype *type;
 };
 
-#define QOBJ_FIELDS struct qobj_node qobj_node;
+#define QOBJ_FIELDS struct qobj_node qobj_node
 
 /* call these at the end of any _create function (QOBJ_REG)
  * and beginning of any _destroy function (QOBJ_UNREG) */
@@ -118,16 +118,19 @@ void *qobj_get_typed(uint64_t id, const struct qobj_nodetype *type);
 
 /* type declarations */
 #define DECLARE_QOBJ_TYPE(structname)                                          \
-       extern const struct qobj_nodetype qobj_t_##structname;
+       extern const struct qobj_nodetype qobj_t_##structname                  \
+       /* end */
 #define DEFINE_QOBJ_TYPE(structname)                                           \
        const struct qobj_nodetype qobj_t_##structname = {                     \
                .node_member_offset =                                          \
-                       (ptrdiff_t)offsetof(struct structname, qobj_node)};
+                       (ptrdiff_t)offsetof(struct structname, qobj_node)}     \
+       /* end */
 #define DEFINE_QOBJ_TYPE_INIT(structname, ...)                                 \
        const struct qobj_nodetype qobj_t_##structname = {                     \
                .node_member_offset =                                          \
                        (ptrdiff_t)offsetof(struct structname, qobj_node),     \
-               __VA_ARGS__};
+               __VA_ARGS__}                                                   \
+       /* end */
 
 /* ID dereference with typecheck.
  * will return NULL if id not found or wrong type. */
index c01284e29e10103187d8a40b2fd3df26706b21bc..c2153e0a5e4481444e129e252a2ec3269c54c052 100644 (file)
@@ -21,7 +21,7 @@
 #include "command.h"
 #include "xref.h"
 
-XREF_SETUP()
+XREF_SETUP();
 
 struct resolver_state {
        ares_channel channel;
index 26c4e744b4973c85c9aac52a1c83a0f022c5516b..49221e7cb356783aae4ebfeeb48a06c13d453667 100644 (file)
@@ -22,7 +22,7 @@
 #include "ringbuf.h"
 #include "memory.h"
 
-DEFINE_MTYPE_STATIC(LIB, RINGBUFFER, "Ring buffer")
+DEFINE_MTYPE_STATIC(LIB, RINGBUFFER, "Ring buffer");
 
 struct ringbuf *ringbuf_new(size_t size)
 {
index 77140866723f2858f019ef0d702011f334fe3422..b836b55aad467691e241534a5818b0dced09cbcc 100644 (file)
 #include "lib_errors.h"
 #include "table.h"
 
-DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP, "Route map")
-DEFINE_MTYPE(LIB, ROUTE_MAP_NAME, "Route map name")
-DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_INDEX, "Route map index")
-DEFINE_MTYPE(LIB, ROUTE_MAP_RULE, "Route map rule")
-DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_RULE_STR, "Route map rule str")
-DEFINE_MTYPE(LIB, ROUTE_MAP_COMPILED, "Route map compiled")
-DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_DEP, "Route map dependency")
-DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_DEP_DATA, "Route map dependency data")
-
-DEFINE_QOBJ_TYPE(route_map_index)
-DEFINE_QOBJ_TYPE(route_map)
+DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP, "Route map");
+DEFINE_MTYPE(LIB, ROUTE_MAP_NAME, "Route map name");
+DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_INDEX, "Route map index");
+DEFINE_MTYPE(LIB, ROUTE_MAP_RULE, "Route map rule");
+DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_RULE_STR, "Route map rule str");
+DEFINE_MTYPE(LIB, ROUTE_MAP_COMPILED, "Route map compiled");
+DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_DEP, "Route map dependency");
+DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_DEP_DATA, "Route map dependency data");
+
+DEFINE_QOBJ_TYPE(route_map_index);
+DEFINE_QOBJ_TYPE(route_map);
 
 #define IPv4_PREFIX_LIST "ip address prefix-list"
 #define IPv6_PREFIX_LIST "ipv6 address prefix-list"
index 3e208c8cb56d0f571e99a4755e5571ef14756d23..bad3ca6d3d513a5ac3314a159c068e30727bc7f8 100644 (file)
@@ -32,9 +32,9 @@
 extern "C" {
 #endif
 
-DECLARE_MTYPE(ROUTE_MAP_NAME)
-DECLARE_MTYPE(ROUTE_MAP_RULE)
-DECLARE_MTYPE(ROUTE_MAP_COMPILED)
+DECLARE_MTYPE(ROUTE_MAP_NAME);
+DECLARE_MTYPE(ROUTE_MAP_RULE);
+DECLARE_MTYPE(ROUTE_MAP_COMPILED);
 
 /* Route map's type. */
 enum route_map_type { RMAP_PERMIT, RMAP_DENY, RMAP_ANY };
@@ -190,9 +190,9 @@ struct route_map_index {
        /* List of match/sets contexts. */
        TAILQ_HEAD(, routemap_hook_context) rhclist;
 
-       QOBJ_FIELDS
+       QOBJ_FIELDS;
 };
-DECLARE_QOBJ_TYPE(route_map_index)
+DECLARE_QOBJ_TYPE(route_map_index);
 
 /* Route map list structure. */
 struct route_map {
@@ -225,9 +225,9 @@ struct route_map {
        struct route_table *ipv4_prefix_table;
        struct route_table *ipv6_prefix_table;
 
-       QOBJ_FIELDS
+       QOBJ_FIELDS;
 };
-DECLARE_QOBJ_TYPE(route_map)
+DECLARE_QOBJ_TYPE(route_map);
 
 /* Prototypes. */
 extern void route_map_init(void);
index ffba631a10763fd197e5754f1d86b09fa69b3cc6..bdd12b262b0ec4d42d554f041b474417f988d5bd 100644 (file)
@@ -24,7 +24,7 @@ int routing_control_plane_protocols_control_plane_protocol_destroy(
  * callbacks for routing to handle configuration events
  * based on the control plane protocol
  */
-DECLARE_HOOK(routing_conf_event, (struct nb_cb_create_args *args), (args))
+DECLARE_HOOK(routing_conf_event, (struct nb_cb_create_args *args), (args));
 
 void routing_control_plane_protocols_register_vrf_dependency(void);
 
index 17698d2b87984d358f762b80afa27e57884df1af..f66f32015dc141ffc7c25d8a1bee5115e64b0a38 100644 (file)
@@ -24,7 +24,7 @@
 #include "routing_nb.h"
 
 
-DEFINE_HOOK(routing_conf_event, (struct nb_cb_create_args *args), (args))
+DEFINE_HOOK(routing_conf_event, (struct nb_cb_create_args *args), (args));
 
 /*
  * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol
index b79dfa67722f1c4b8ce27d8df97f02c1fa372224..fc42857418ef1f20e445f4110a0f9938f602320f 100644 (file)
@@ -63,8 +63,8 @@
 #include "lib_errors.h"
 #include "network.h"
 
-DEFINE_MTYPE_STATIC(LIB, SKIP_LIST, "Skip List")
-DEFINE_MTYPE_STATIC(LIB, SKIP_LIST_NODE, "Skip Node")
+DEFINE_MTYPE_STATIC(LIB, SKIP_LIST, "Skip List");
+DEFINE_MTYPE_STATIC(LIB, SKIP_LIST_NODE, "Skip Node");
 
 #define BitsInRandom 31
 
index 57128b79284d42d8f8c17d7b10af584ddcafa580..c063833e41518e49910badea14e046d007e072da 100644 (file)
@@ -157,7 +157,7 @@ extern void oid_copy_int(oid oid[], int *val);
 extern void oid2string(oid oid[], int len, char *string);
 extern void oid_copy_str(oid oid[], const char *string, int len);
 
-DECLARE_HOOK(agentx_enabled, (), ())
+DECLARE_HOOK(agentx_enabled, (), ());
 
 #ifdef __cplusplus
 }
index c701da1e0371c0af6244189d5d43f98c9d9a5bf8..d65235b41cb3435fdd6abf526be05b5ed93cc3f8 100644 (file)
@@ -29,7 +29,7 @@
 #include "lib_errors.h"
 #include "printfrr.h"
 
-DEFINE_MTYPE_STATIC(LIB, SOCKUNION, "Socket union")
+DEFINE_MTYPE_STATIC(LIB, SOCKUNION, "Socket union");
 
 const char *inet_sutop(const union sockunion *su, char *str)
 {
index ac6dd29f06bd4832d090d1ad833ca9546b720d44..a273e934631a03dcbb022c02197ae7478e95c993 100644 (file)
@@ -33,8 +33,8 @@
 #include "thread.h"
 #include "vty.h"
 
-DEFINE_MTYPE_STATIC(LIB, SPF_BACKOFF, "SPF backoff")
-DEFINE_MTYPE_STATIC(LIB, SPF_BACKOFF_NAME, "SPF backoff name")
+DEFINE_MTYPE_STATIC(LIB, SPF_BACKOFF, "SPF backoff");
+DEFINE_MTYPE_STATIC(LIB, SPF_BACKOFF_NAME, "SPF backoff name");
 
 static bool debug_spf_backoff = false;
 #define backoff_debug(...)                                                     \
index ef82b7ac01feda029034f7028c4bde6d3a0affee..a115507192ccfac9b1f7287c961652f1be4bf2c3 100644 (file)
@@ -30,7 +30,7 @@
 #include "table.h"
 #include "printfrr.h"
 
-DEFINE_MTYPE_STATIC(LIB, ROUTE_SRC_NODE, "Route source node")
+DEFINE_MTYPE_STATIC(LIB, ROUTE_SRC_NODE, "Route source node");
 
 /* ----- functions to manage rnodes _with_ srcdest table ----- */
 struct srcdest_rnode {
index ef73c2fdc9508cf9a61e1fb046684f460ab5db5d..904ee73b10ce2da231791cfbda1786960d45db1a 100644 (file)
@@ -31,8 +31,8 @@
 #include "frr_pthread.h"
 #include "lib_errors.h"
 
-DEFINE_MTYPE_STATIC(LIB, STREAM, "Stream")
-DEFINE_MTYPE_STATIC(LIB, STREAM_FIFO, "Stream FIFO")
+DEFINE_MTYPE_STATIC(LIB, STREAM, "Stream");
+DEFINE_MTYPE_STATIC(LIB, STREAM_FIFO, "Stream FIFO");
 
 /* Tests whether a position is valid */
 #define GETP_VALID(S, G) ((G) <= (S)->endp)
index 39773d9ac89ef7cfe022cc444266eea243b9eee5..a046822a94389b5f9f003a18054a9edd94c10858 100644 (file)
@@ -64,10 +64,8 @@ size_t strlcat(char *__restrict dest,
    (which the static_assert checks), then by the pigeonhole
    principle, the two input strings must overlap, which is
    undefined.  */
-#if __STDC_VERSION__ >= 201112L
        _Static_assert(sizeof(uintptr_t) == sizeof(size_t),
                       "theoretical maximum object size covers address space");
-#endif
        return dest_length + src_length;
 }
 #endif /* HAVE_STRLCAT */
index 38d1a3f773dc83f8eab123dea8b73f9a9c83299e..bfd367b1342660ebdae98c701f68b6cedae42d0d 100644 (file)
@@ -313,7 +313,7 @@ if SNMP
 lib_LTLIBRARIES += lib/libfrrsnmp.la
 endif
 
-lib_libfrrsnmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu99
+lib_libfrrsnmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu11
 lib_libfrrsnmp_la_LDFLAGS = -version-info 0:0:0
 lib_libfrrsnmp_la_LIBADD = $(SNMP_LIBS)
 lib_libfrrsnmp_la_SOURCES = \
index 89e32182b5c14d062c46a944604a740e4c31f8f3..dfd92c6189f58c47ba2ebc1a22ac7b775978642f 100644 (file)
@@ -29,8 +29,8 @@
 #include "sockunion.h"
 #include "libfrr_trace.h"
 
-DEFINE_MTYPE_STATIC(LIB, ROUTE_TABLE, "Route table")
-DEFINE_MTYPE(LIB, ROUTE_NODE, "Route node")
+DEFINE_MTYPE_STATIC(LIB, ROUTE_TABLE, "Route table");
+DEFINE_MTYPE(LIB, ROUTE_NODE, "Route node");
 
 static void route_table_free(struct route_table *);
 
@@ -41,7 +41,7 @@ static int route_table_hash_cmp(const struct route_node *a,
 }
 
 DECLARE_HASH(rn_hash_node, struct route_node, nodehash, route_table_hash_cmp,
-            prefix_hash_key)
+            prefix_hash_key);
 /*
  * route_table_init_with_delegate
  */
index 5d620d332b93379d37eeede238a6f954921ab6e5..7e383dce80874fa03384396d3726ce0a06ff07a7 100644 (file)
@@ -31,7 +31,7 @@
 extern "C" {
 #endif
 
-DECLARE_MTYPE(ROUTE_NODE)
+DECLARE_MTYPE(ROUTE_NODE);
 
 /*
  * Forward declarations.
@@ -59,7 +59,7 @@ struct route_table_delegate_t_ {
        route_table_destroy_node_func_t destroy_node;
 };
 
-PREDECL_HASH(rn_hash_node)
+PREDECL_HASH(rn_hash_node);
 
 /* Routing table top structure. */
 struct route_table {
index b22a1ad38778e4ca18cd4d8e2693961b436907aa..ddf8822853775aff9854d6d41c975bcfef759cce 100644 (file)
@@ -24,7 +24,7 @@
 #include "memory.h"
 #include "termtable.h"
 
-DEFINE_MTYPE_STATIC(LIB, TTABLE, "ASCII table")
+DEFINE_MTYPE_STATIC(LIB, TTABLE, "ASCII table");
 
 /* clang-format off */
 const struct ttable_style ttable_styles[] = {
index af01c75a4441f0c1740d3c9af4bbae62095c5631..866090341e29071456631174e995424bbe5e82b4 100644 (file)
 #include "libfrr_trace.h"
 #include "libfrr.h"
 
-DEFINE_MTYPE_STATIC(LIB, THREAD, "Thread")
-DEFINE_MTYPE_STATIC(LIB, THREAD_MASTER, "Thread master")
-DEFINE_MTYPE_STATIC(LIB, THREAD_POLL, "Thread Poll Info")
-DEFINE_MTYPE_STATIC(LIB, THREAD_STATS, "Thread stats")
+DEFINE_MTYPE_STATIC(LIB, THREAD, "Thread");
+DEFINE_MTYPE_STATIC(LIB, THREAD_MASTER, "Thread master");
+DEFINE_MTYPE_STATIC(LIB, THREAD_POLL, "Thread Poll Info");
+DEFINE_MTYPE_STATIC(LIB, THREAD_STATS, "Thread stats");
 
-DECLARE_LIST(thread_list, struct thread, threaditem)
+DECLARE_LIST(thread_list, struct thread, threaditem);
 
 struct cancel_req {
        int flags;
@@ -68,7 +68,7 @@ static int thread_timer_cmp(const struct thread *a, const struct thread *b)
        return 0;
 }
 
-DECLARE_HEAP(thread_timer_list, struct thread, timeritem, thread_timer_cmp)
+DECLARE_HEAP(thread_timer_list, struct thread, timeritem, thread_timer_cmp);
 
 #if defined(__APPLE__)
 #include <mach/mach.h>
index cdef531ad461cbffa1ea6bf31e91cb298cda64f5..af6833113100b15442234585f886a9650eeba2e0 100644 (file)
@@ -41,8 +41,8 @@ struct rusage_t {
 
 #define GETRUSAGE(X) thread_getrusage(X)
 
-PREDECL_LIST(thread_list)
-PREDECL_HEAP(thread_timer_list)
+PREDECL_LIST(thread_list);
+PREDECL_HEAP(thread_timer_list);
 
 struct fd_handler {
        /* number of pfd that fit in the allocated space of pfds. This is a
index fca45e20d1c6a83f7cb21fa05785f061ba1c80d0..60e6d0901677f54a786ceec470759bdc0aa09b8c 100644 (file)
@@ -65,7 +65,8 @@ struct typed_rb_entry *typed_rb_next(const struct typed_rb_entry *rbe);
 
 #define _PREDECL_RBTREE(prefix)                                                \
 struct prefix ## _head { struct typed_rb_root rr; };                           \
-struct prefix ## _item { struct typed_rb_entry re; };
+struct prefix ## _item { struct typed_rb_entry re; };                          \
+MACRO_REQUIRE_SEMICOLON() /* end */
 
 #define INIT_RBTREE_UNIQ(var)          { }
 #define INIT_RBTREE_NONUNIQ(var)       { }
@@ -140,7 +141,7 @@ macro_pure size_t prefix ## _count(const struct prefix##_head *h)              \
 {                                                                              \
        return h->rr.count;                                                    \
 }                                                                              \
-/* ... */
+MACRO_REQUIRE_SEMICOLON() /* end */
 
 #define PREDECL_RBTREE_UNIQ(prefix)                                            \
        _PREDECL_RBTREE(prefix)
@@ -161,8 +162,8 @@ macro_inline const type *prefix ## _const_find(const struct prefix##_head *h,  \
 }                                                                              \
 TYPESAFE_FIND(prefix, type)                                                    \
                                                                                \
-_DECLARE_RBTREE(prefix, type, field, prefix ## __cmp, prefix ## __cmp)         \
-/* ... */
+_DECLARE_RBTREE(prefix, type, field, prefix ## __cmp, prefix ## __cmp);        \
+MACRO_REQUIRE_SEMICOLON() /* end */
 
 #define PREDECL_RBTREE_NONUNIQ(prefix)                                         \
        _PREDECL_RBTREE(prefix)
@@ -188,8 +189,8 @@ macro_inline int prefix ## __cmp_uq(const struct typed_rb_entry *a,            \
        return 0;                                                              \
 }                                                                              \
                                                                                \
-_DECLARE_RBTREE(prefix, type, field, prefix ## __cmp, prefix ## __cmp_uq)      \
-/* ... */
+_DECLARE_RBTREE(prefix, type, field, prefix ## __cmp, prefix ## __cmp_uq);     \
+MACRO_REQUIRE_SEMICOLON() /* end */
 
 #ifdef __cplusplus
 }
index 69796e2d8186159d4ce9377002897d47c5cf31e3..76705fad0d3607937921c860b2f9cf228b95486b 100644 (file)
@@ -25,9 +25,9 @@
 #include "memory.h"
 #include "network.h"
 
-DEFINE_MTYPE_STATIC(LIB, TYPEDHASH_BUCKET, "Typed-hash bucket")
-DEFINE_MTYPE_STATIC(LIB, SKIPLIST_OFLOW, "Skiplist overflow")
-DEFINE_MTYPE_STATIC(LIB, HEAP_ARRAY, "Typed-heap array")
+DEFINE_MTYPE_STATIC(LIB, TYPEDHASH_BUCKET, "Typed-hash bucket");
+DEFINE_MTYPE_STATIC(LIB, SKIPLIST_OFLOW, "Skiplist overflow");
+DEFINE_MTYPE_STATIC(LIB, HEAP_ARRAY, "Typed-heap array");
 
 #if 0
 static void hash_consistency_check(struct thash_head *head)
index e134316dd9ddaff6002776866a419e465a1539bf..27e7be1286a2d4684ae34fd7d9b34c04e3bcc986 100644 (file)
@@ -105,15 +105,16 @@ static inline void typesafe_list_add(struct slist_head *head,
 
 /* use as:
  *
- * PREDECL_LIST(namelist)
+ * PREDECL_LIST(namelist);
  * struct name {
  *   struct namelist_item nlitem;
  * }
- * DECLARE_LIST(namelist, struct name, nlitem)
+ * DECLARE_LIST(namelist, struct name, nlitem);
  */
 #define PREDECL_LIST(prefix)                                                   \
 struct prefix ## _head { struct slist_head sh; };                              \
-struct prefix ## _item { struct slist_item si; };
+struct prefix ## _item { struct slist_item si; };                              \
+MACRO_REQUIRE_SEMICOLON() /* end */
 
 #define INIT_LIST(var) { .sh = { .last_next = &var.sh.first, }, }
 
@@ -191,7 +192,7 @@ macro_pure size_t prefix ## _count(const struct prefix##_head *h)              \
 {                                                                              \
        return h->sh.count;                                                    \
 }                                                                              \
-/* ... */
+MACRO_REQUIRE_SEMICOLON() /* end */
 
 /* don't use these structs directly */
 struct dlist_item {
@@ -218,7 +219,8 @@ static inline void typesafe_dlist_add(struct dlist_head *head,
  */
 #define PREDECL_DLIST(prefix)                                                  \
 struct prefix ## _head { struct dlist_head dh; };                              \
-struct prefix ## _item { struct dlist_item di; };
+struct prefix ## _item { struct dlist_item di; };                              \
+MACRO_REQUIRE_SEMICOLON() /* end */
 
 #define INIT_DLIST(var) { .dh = { \
        .hitem = { &var.dh.hitem, &var.dh.hitem }, }, }
@@ -295,7 +297,7 @@ macro_pure size_t prefix ## _count(const struct prefix##_head *h)              \
 {                                                                              \
        return h->dh.count;                                                    \
 }                                                                              \
-/* ... */
+MACRO_REQUIRE_SEMICOLON() /* end */
 
 /* note: heap currently caps out at 4G items */
 
@@ -319,7 +321,8 @@ struct heap_head {
 
 #define PREDECL_HEAP(prefix)                                                   \
 struct prefix ## _head { struct heap_head hh; };                               \
-struct prefix ## _item { struct heap_item hi; };
+struct prefix ## _item { struct heap_item hi; };                               \
+MACRO_REQUIRE_SEMICOLON() /* end */
 
 #define INIT_HEAP(var)         { }
 
@@ -402,7 +405,7 @@ macro_pure size_t prefix ## _count(const struct prefix##_head *h)              \
 {                                                                              \
        return h->hh.count;                                                    \
 }                                                                              \
-/* ... */
+MACRO_REQUIRE_SEMICOLON() /* end */
 
 extern void typesafe_heap_resize(struct heap_head *head, bool grow);
 extern void typesafe_heap_pushdown(struct heap_head *head, uint32_t index,
@@ -438,7 +441,8 @@ struct ssort_head {
  */
 #define _PREDECL_SORTLIST(prefix)                                              \
 struct prefix ## _head { struct ssort_head sh; };                              \
-struct prefix ## _item { struct ssort_item si; };
+struct prefix ## _item { struct ssort_item si; };                              \
+MACRO_REQUIRE_SEMICOLON() /* end */
 
 #define INIT_SORTLIST_UNIQ(var)                { }
 #define INIT_SORTLIST_NONUNIQ(var)     { }
@@ -537,10 +541,10 @@ macro_pure size_t prefix ## _count(const struct prefix##_head *h)              \
 {                                                                              \
        return h->sh.count;                                                    \
 }                                                                              \
-/* ... */
+MACRO_REQUIRE_SEMICOLON() /* end */
 
 #define DECLARE_SORTLIST_UNIQ(prefix, type, field, cmpfn)                      \
-       _DECLARE_SORTLIST(prefix, type, field, cmpfn, cmpfn)                   \
+       _DECLARE_SORTLIST(prefix, type, field, cmpfn, cmpfn);                  \
                                                                               \
 macro_inline const type *prefix ## _const_find(const struct prefix##_head *h,  \
                                               const type *item)               \
@@ -555,7 +559,7 @@ macro_inline const type *prefix ## _const_find(const struct prefix##_head *h,  \
        return container_of(sitem, type, field.si);                            \
 }                                                                              \
 TYPESAFE_FIND(prefix, type)                                                    \
-/* ... */
+MACRO_REQUIRE_SEMICOLON() /* end */
 
 #define DECLARE_SORTLIST_NONUNIQ(prefix, type, field, cmpfn)                   \
 macro_inline int _ ## prefix ## _cmp(const type *a, const type *b)             \
@@ -569,8 +573,8 @@ macro_inline int _ ## prefix ## _cmp(const type *a, const type *b)             \
                return 1;                                                      \
        return 0;                                                              \
 }                                                                              \
-       _DECLARE_SORTLIST(prefix, type, field, cmpfn, _ ## prefix ## _cmp)     \
-/* ... */
+       _DECLARE_SORTLIST(prefix, type, field, cmpfn, _ ## prefix ## _cmp);    \
+MACRO_REQUIRE_SEMICOLON() /* end */
 
 
 /* hash, "sorted" by hash value
@@ -616,7 +620,8 @@ extern void typesafe_hash_shrink(struct thash_head *head);
  */
 #define PREDECL_HASH(prefix)                                                   \
 struct prefix ## _head { struct thash_head hh; };                              \
-struct prefix ## _item { struct thash_item hi; };
+struct prefix ## _item { struct thash_item hi; };                              \
+MACRO_REQUIRE_SEMICOLON() /* end */
 
 #define INIT_HASH(var) { }
 
@@ -734,7 +739,7 @@ macro_pure size_t prefix ## _count(const struct prefix##_head *h)              \
 {                                                                              \
        return h->hh.count;                                                    \
 }                                                                              \
-/* ... */
+MACRO_REQUIRE_SEMICOLON() /* end */
 
 /* skiplist, sorted.
  * can be used as priority queue with add / pop
@@ -769,7 +774,8 @@ struct sskip_head {
  */
 #define _PREDECL_SKIPLIST(prefix)                                              \
 struct prefix ## _head { struct sskip_head sh; };                              \
-struct prefix ## _item { struct sskip_item si; };
+struct prefix ## _item { struct sskip_item si; };                              \
+MACRO_REQUIRE_SEMICOLON() /* end */
 
 #define INIT_SKIPLIST_UNIQ(var)                { }
 #define INIT_SKIPLIST_NONUNIQ(var)     { }
@@ -840,7 +846,7 @@ macro_pure size_t prefix ## _count(const struct prefix##_head *h)              \
 {                                                                              \
        return h->sh.count;                                                    \
 }                                                                              \
-/* ... */
+MACRO_REQUIRE_SEMICOLON() /* end */
 
 #define PREDECL_SKIPLIST_UNIQ(prefix)                                          \
        _PREDECL_SKIPLIST(prefix)
@@ -862,8 +868,8 @@ macro_inline const type *prefix ## _const_find(const struct prefix##_head *h,  \
 TYPESAFE_FIND(prefix, type)                                                    \
                                                                                \
 _DECLARE_SKIPLIST(prefix, type, field,                                         \
-               prefix ## __cmp, prefix ## __cmp)                              \
-/* ... */
+               prefix ## __cmp, prefix ## __cmp);                             \
+MACRO_REQUIRE_SEMICOLON() /* end */
 
 #define PREDECL_SKIPLIST_NONUNIQ(prefix)                                       \
        _PREDECL_SKIPLIST(prefix)
@@ -890,8 +896,8 @@ macro_inline int prefix ## __cmp_uq(const struct sskip_item *a,                \
 }                                                                              \
                                                                                \
 _DECLARE_SKIPLIST(prefix, type, field,                                         \
-               prefix ## __cmp, prefix ## __cmp_uq)                           \
-/* ... */
+               prefix ## __cmp, prefix ## __cmp_uq);                          \
+MACRO_REQUIRE_SEMICOLON() /* end */
 
 
 extern struct sskip_item *typesafe_skiplist_add(struct sskip_head *head,
index 0631e836f619c083d43f7a5b174421202a974da1..565c49fd59a1802cbc4a2e1b7976b8dc656f37bb 100644 (file)
@@ -23,8 +23,8 @@
 #include "vector.h"
 #include "memory.h"
 
-DEFINE_MTYPE_STATIC(LIB, VECTOR, "Vector")
-DEFINE_MTYPE_STATIC(LIB, VECTOR_INDEX, "Vector index")
+DEFINE_MTYPE_STATIC(LIB, VECTOR, "Vector");
+DEFINE_MTYPE_STATIC(LIB, VECTOR_INDEX, "Vector index");
 
 /* Initialize vector : allocate memory and return vector. */
 vector vector_init(unsigned int size)
index 0a91f4bc8653de5a76fa536525eb66b0c3d069af..dff041cbc77a3e5c95e78f8dfd18e204a0ee824d 100644 (file)
--- a/lib/vrf.c
+++ b/lib/vrf.c
 /* default VRF name value used when VRF backend is not NETNS */
 #define VRF_DEFAULT_NAME_INTERNAL "default"
 
-DEFINE_MTYPE_STATIC(LIB, VRF, "VRF")
-DEFINE_MTYPE_STATIC(LIB, VRF_BITMAP, "VRF bit-map")
+DEFINE_MTYPE_STATIC(LIB, VRF, "VRF");
+DEFINE_MTYPE_STATIC(LIB, VRF_BITMAP, "VRF bit-map");
 
-DEFINE_QOBJ_TYPE(vrf)
+DEFINE_QOBJ_TYPE(vrf);
 
 static __inline int vrf_id_compare(const struct vrf *, const struct vrf *);
 static __inline int vrf_name_compare(const struct vrf *, const struct vrf *);
index 333d68ce96a154edb2c20e33ce5b7439a95d94a5..6cdb52244dcd9a0992b5847809950b9bcf052f60 100644 (file)
--- a/lib/vrf.h
+++ b/lib/vrf.h
@@ -95,13 +95,13 @@ struct vrf {
        /* Back pointer to namespace context */
        void *ns_ctxt;
 
-       QOBJ_FIELDS
+       QOBJ_FIELDS;
 };
 RB_HEAD(vrf_id_head, vrf);
 RB_PROTOTYPE(vrf_id_head, vrf, id_entry, vrf_id_compare)
 RB_HEAD(vrf_name_head, vrf);
 RB_PROTOTYPE(vrf_name_head, vrf, name_entry, vrf_name_compare)
-DECLARE_QOBJ_TYPE(vrf)
+DECLARE_QOBJ_TYPE(vrf);
 
 /* Allow VRF with netns as backend */
 enum vrf_backend_type {
index 4cefb5e80c3b32e0965aef0e0716777fdae9cbd9..d44cc904c5765114cddd94d89008c7c936b620ac 100644 (file)
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -56,9 +56,9 @@
 #include "lib/vty_clippy.c"
 #endif
 
-DEFINE_MTYPE_STATIC(LIB, VTY, "VTY")
-DEFINE_MTYPE_STATIC(LIB, VTY_OUT_BUF, "VTY output buffer")
-DEFINE_MTYPE_STATIC(LIB, VTY_HIST, "VTY history")
+DEFINE_MTYPE_STATIC(LIB, VTY, "VTY");
+DEFINE_MTYPE_STATIC(LIB, VTY_OUT_BUF, "VTY output buffer");
+DEFINE_MTYPE_STATIC(LIB, VTY_HIST, "VTY history");
 
 /* Vty events */
 enum event {
index 5bdd6292f90b521f235d8d718aad2494bfb15683..1a0469b25620736846d2c25ea1316b5c47717df4 100644 (file)
@@ -24,8 +24,8 @@
 #include "wheel.h"
 #include "log.h"
 
-DEFINE_MTYPE_STATIC(LIB, TIMER_WHEEL, "Timer Wheel")
-DEFINE_MTYPE_STATIC(LIB, TIMER_WHEEL_LIST, "Timer Wheel Slot List")
+DEFINE_MTYPE_STATIC(LIB, TIMER_WHEEL, "Timer Wheel");
+DEFINE_MTYPE_STATIC(LIB, TIMER_WHEEL_LIST, "Timer Wheel Slot List");
 
 static int debug_timer_wheel = 0;
 
index 8eabdf52e76362442e0e8abe3cd4a9f748bbbbc8..2a8326c056d5db34e2f7bc62a8c2646ccbbe25d2 100644 (file)
@@ -28,9 +28,9 @@
 #include "command.h"
 #include "log.h"
 
-DEFINE_MTYPE(LIB, WORK_QUEUE, "Work queue")
-DEFINE_MTYPE_STATIC(LIB, WORK_QUEUE_ITEM, "Work queue item")
-DEFINE_MTYPE_STATIC(LIB, WORK_QUEUE_NAME, "Work queue name string")
+DEFINE_MTYPE(LIB, WORK_QUEUE, "Work queue");
+DEFINE_MTYPE_STATIC(LIB, WORK_QUEUE_ITEM, "Work queue item");
+DEFINE_MTYPE_STATIC(LIB, WORK_QUEUE_NAME, "Work queue name string");
 
 /* master list of work_queues */
 static struct list _work_queues;
index 7c610f5dd6b5e51d7c0fe8e118d5537fbb9aeb44..b076ed0d28ae67c0d28d4adcb93cb6de6aef85e9 100644 (file)
@@ -30,7 +30,7 @@
 extern "C" {
 #endif
 
-DECLARE_MTYPE(WORK_QUEUE)
+DECLARE_MTYPE(WORK_QUEUE);
 
 /* Hold time for the initial schedule of a queue run, in  millisec */
 #define WORK_QUEUE_DEFAULT_HOLD 50
index 40efe51363143f2bc3f93a2b599bb5e1f872744a..a41f91a2289f322cd5d3656acb63c75054fce1ba 100644 (file)
@@ -93,8 +93,6 @@ static void xref_add_one(const struct xref *xref)
                q = memrchr(filename, '/', p - filename);
                if (q)
                        filename = q + 1;
-               else
-                       filename = p + 1;
        }
 
        SHA256_Init(&sha);
index b3243fa058daa2ea6498d1030e9cf3139c17e101..b1cb172b410d3e260a535a70ce9b03c43b7b0549 100644 (file)
@@ -162,7 +162,7 @@ extern const struct xref * const __stop_xref_array[1] DSO_LOCAL;
                xref_block_add(&_xref_block);                                  \
        }                                                                      \
        asm(XREF_NOTE);                                                        \
-       /* end */
+       MACRO_REQUIRE_SEMICOLON() /* end */
 
 /* the following blurb emits an ELF note indicating start and end of the xref
  * array in the binary.  This is technically the "correct" entry point for
index 383dc9f5eba634a3d28c753776008bd628197f0e..df3b07fb090cb81cbfac29e8102e80e05c6e727d 100644 (file)
@@ -27,8 +27,8 @@
 
 #include <libyang/user_types.h>
 
-DEFINE_MTYPE_STATIC(LIB, YANG_MODULE, "YANG module")
-DEFINE_MTYPE_STATIC(LIB, YANG_DATA, "YANG data structure")
+DEFINE_MTYPE_STATIC(LIB, YANG_MODULE, "YANG module");
+DEFINE_MTYPE_STATIC(LIB, YANG_DATA, "YANG data structure");
 
 /* libyang container. */
 struct ly_ctx *ly_native_ctx;
index 1f64675d6a410bbf3584d23b276b03b7d25c8d22..5b1d96f24c64e3701335a19a35b8997919d10062 100644 (file)
@@ -26,9 +26,9 @@
 #include "yang_translator.h"
 #include "frrstr.h"
 
-DEFINE_MTYPE_STATIC(LIB, YANG_TRANSLATOR, "YANG Translator")
-DEFINE_MTYPE_STATIC(LIB, YANG_TRANSLATOR_MODULE, "YANG Translator Module")
-DEFINE_MTYPE_STATIC(LIB, YANG_TRANSLATOR_MAPPING, "YANG Translator Mapping")
+DEFINE_MTYPE_STATIC(LIB, YANG_TRANSLATOR, "YANG Translator");
+DEFINE_MTYPE_STATIC(LIB, YANG_TRANSLATOR_MODULE, "YANG Translator Module");
+DEFINE_MTYPE_STATIC(LIB, YANG_TRANSLATOR_MAPPING, "YANG Translator Mapping");
 
 /* Generate the yang_translators tree. */
 static inline int yang_translator_compare(const struct yang_translator *a,
index e6b254ee8d43e62d128c158e272dbde9894335bc..527282c4f283e289925135a35a0d1a593683d131 100644 (file)
@@ -28,14 +28,7 @@ extern void _zlog_assert_failed(const char *assertion, const char *file,
        __attribute__((noreturn));
 
 #undef __ASSERT_FUNCTION
-
-#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
 #define __ASSERT_FUNCTION    __func__
-#elif defined(__GNUC__)
-#define __ASSERT_FUNCTION    __FUNCTION__
-#else
-#define __ASSERT_FUNCTION    NULL
-#endif
 
 #define zassert(EX)                                                            \
        ((void)((EX) ? 0 : (_zlog_assert_failed(#EX, __FILE__, __LINE__,       \
index c5e844933c90a43e5f98eb611a66d87985b5fcac..c78937c1ec3b3cd141d0f065fe205df27e0cd13b 100644 (file)
@@ -42,8 +42,8 @@
 #include "srte.h"
 #include "printfrr.h"
 
-DEFINE_MTYPE_STATIC(LIB, ZCLIENT, "Zclient")
-DEFINE_MTYPE_STATIC(LIB, REDIST_INST, "Redistribution instance IDs")
+DEFINE_MTYPE_STATIC(LIB, ZCLIENT, "Zclient");
+DEFINE_MTYPE_STATIC(LIB, REDIST_INST, "Redistribution instance IDs");
 
 /* Zebra client events. */
 enum event { ZCLIENT_SCHEDULE, ZCLIENT_READ, ZCLIENT_CONNECT };
index ded44ac63669f91ecaaf64ff62fe3af0637ea8de..5c3d91ba74bca34aefb5871f3863e4583294e19b 100644 (file)
 
 /* misc include group */
 #include <stdarg.h>
-#if !(defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L)
-/* Not C99; do we need to define va_copy? */
-#ifndef va_copy
-#ifdef __va_copy
-#define va_copy(DST,SRC) __va_copy(DST,SRC)
-#else
-/* Now we are desperate; this should work on many typical platforms.
-   But this is slightly dangerous, because the standard does not require
-   va_copy to be a macro. */
-#define va_copy(DST,SRC) memcpy(&(DST), &(SRC), sizeof(va_list))
-#warning "Not C99 and no va_copy macro available, falling back to memcpy"
-#endif /* __va_copy */
-#endif /* !va_copy */
-#endif /* !C99 */
-
 
 #ifdef HAVE_LCAPS
 #include <sys/capability.h>
index 51509e24f4d4429615d500f005f4df9d3e096190..f54670932830b8f90202e1a7b06ae532051bc205 100644 (file)
 #include "zlog.h"
 #include "libfrr_trace.h"
 
-DEFINE_MTYPE_STATIC(LIB, LOG_MESSAGE,  "log message")
-DEFINE_MTYPE_STATIC(LIB, LOG_TLSBUF,   "log thread-local buffer")
+DEFINE_MTYPE_STATIC(LIB, LOG_MESSAGE,  "log message");
+DEFINE_MTYPE_STATIC(LIB, LOG_TLSBUF,   "log thread-local buffer");
 
 DEFINE_HOOK(zlog_init, (const char *progname, const char *protoname,
                        unsigned short instance, uid_t uid, gid_t gid),
-                      (progname, protoname, instance, uid, gid))
-DEFINE_KOOH(zlog_fini, (), ())
+                      (progname, protoname, instance, uid, gid));
+DEFINE_KOOH(zlog_fini, (), ());
 DEFINE_HOOK(zlog_aux_init, (const char *prefix, int prio_min),
-                          (prefix, prio_min))
+                          (prefix, prio_min));
 
 char zlog_prefix[128];
 size_t zlog_prefixsz;
 int zlog_tmpdirfd = -1;
 
+static atomic_bool zlog_ec = true, zlog_xid = true;
+
 /* these are kept around because logging is initialized (and directories
  * & files created) before zprivs code switches to the FRR user;  therefore
  * we need to chown() things so we don't get permission errors later when
@@ -530,12 +532,54 @@ const char *zlog_msg_text(struct zlog_msg *msg, size_t *textlen)
 {
        if (!msg->text) {
                va_list args;
+               bool do_xid, do_ec;
+               size_t need = 0, hdrlen;
+               struct fbuf fb = {
+                       .buf = msg->stackbuf,
+                       .pos = msg->stackbuf,
+                       .len = msg->stackbufsz,
+               };
+
+               do_ec = atomic_load_explicit(&zlog_ec, memory_order_relaxed);
+               do_xid = atomic_load_explicit(&zlog_xid, memory_order_relaxed);
+
+               if (msg->xref && do_xid && msg->xref->xref.xrefdata->uid[0]) {
+                       need += bputch(&fb, '[');
+                       need += bputs(&fb, msg->xref->xref.xrefdata->uid);
+                       need += bputch(&fb, ']');
+               }
+               if (msg->xref && do_ec && msg->xref->ec)
+                       need += bprintfrr(&fb, "[EC %u]", msg->xref->ec);
+               if (need)
+                       need += bputch(&fb, ' ');
+
+               hdrlen = need;
+               assert(hdrlen < msg->stackbufsz);
 
                va_copy(args, msg->args);
-               msg->text = vasnprintfrr(MTYPE_LOG_MESSAGE, msg->stackbuf,
-                                        msg->stackbufsz, msg->fmt, args);
-               msg->textlen = strlen(msg->text);
+               need += vbprintfrr(&fb, msg->fmt, args);
                va_end(args);
+
+               msg->textlen = need;
+               need += bputch(&fb, '\0');
+
+               if (need <= msg->stackbufsz)
+                       msg->text = msg->stackbuf;
+               else {
+                       msg->text = XMALLOC(MTYPE_LOG_MESSAGE, need);
+
+                       memcpy(msg->text, msg->stackbuf, hdrlen);
+
+                       fb.buf = msg->text;
+                       fb.len = need;
+                       fb.pos = msg->text + hdrlen;
+
+                       va_copy(args, msg->args);
+                       vbprintfrr(&fb, msg->fmt, args);
+                       va_end(args);
+
+                       bputch(&fb, '\0');
+               }
        }
        if (textlen)
                *textlen = msg->textlen;
@@ -619,6 +663,26 @@ size_t zlog_msg_ts(struct zlog_msg *msg, char *out, size_t outsz,
        }
 }
 
+void zlog_set_prefix_ec(bool enable)
+{
+       atomic_store_explicit(&zlog_ec, enable, memory_order_relaxed);
+}
+
+bool zlog_get_prefix_ec(void)
+{
+       return atomic_load_explicit(&zlog_ec, memory_order_relaxed);
+}
+
+void zlog_set_prefix_xid(bool enable)
+{
+       atomic_store_explicit(&zlog_xid, enable, memory_order_relaxed);
+}
+
+bool zlog_get_prefix_xid(void)
+{
+       return atomic_load_explicit(&zlog_xid, memory_order_relaxed);
+}
+
 /* setup functions */
 
 struct zlog_target *zlog_target_clone(struct memtype *mt,
index 4fdb47bb9520822c92256382319374c2d96b6f25..66d8f1e5d73f2eb22e22a3f54aed125fd6efb91e 100644 (file)
@@ -85,31 +85,6 @@ static inline void zlog_ref(const struct xref_logmsg *xref,
        va_end(ap);
 }
 
-#define _zlog_ref(prio, msg, ...)                                              \
-       do {                                                                   \
-               static struct xrefdata _xrefdata = {                           \
-                       .xref = NULL,                                          \
-                       .uid = {},                                             \
-                       .hashstr = (msg),                                      \
-                       .hashu32 = {(prio), 0},                                \
-               };                                                             \
-               static const struct xref_logmsg _xref __attribute__(           \
-                       (used)) = {                                            \
-                       .xref = XREF_INIT(XREFT_LOGMSG, &_xrefdata, __func__), \
-                       .fmtstring = (msg),                                    \
-                       .priority = (prio),                                    \
-                       .args = (#__VA_ARGS__),                                \
-               };                                                             \
-               XREF_LINK(_xref.xref);                                         \
-               zlog_ref(&_xref, (msg), ##__VA_ARGS__);                        \
-       } while (0)
-
-#define zlog_err(...)    _zlog_ref(LOG_ERR, __VA_ARGS__)
-#define zlog_warn(...)   _zlog_ref(LOG_WARNING, __VA_ARGS__)
-#define zlog_info(...)   _zlog_ref(LOG_INFO, __VA_ARGS__)
-#define zlog_notice(...) _zlog_ref(LOG_NOTICE, __VA_ARGS__)
-#define zlog_debug(...)  _zlog_ref(LOG_DEBUG, __VA_ARGS__)
-
 #define _zlog_ecref(ec_, prio, msg, ...)                                       \
        do {                                                                   \
                static struct xrefdata _xrefdata = {                           \
@@ -127,18 +102,22 @@ static inline void zlog_ref(const struct xref_logmsg *xref,
                        .args = (#__VA_ARGS__),                                \
                };                                                             \
                XREF_LINK(_xref.xref);                                         \
-               zlog_ref(&_xref, "[EC %u] " msg, ec_, ##__VA_ARGS__);          \
+               zlog_ref(&_xref, (msg), ##__VA_ARGS__);                        \
        } while (0)
 
+#define zlog_err(...)    _zlog_ecref(0, LOG_ERR, __VA_ARGS__)
+#define zlog_warn(...)   _zlog_ecref(0, LOG_WARNING, __VA_ARGS__)
+#define zlog_info(...)   _zlog_ecref(0, LOG_INFO, __VA_ARGS__)
+#define zlog_notice(...) _zlog_ecref(0, LOG_NOTICE, __VA_ARGS__)
+#define zlog_debug(...)  _zlog_ecref(0, LOG_DEBUG, __VA_ARGS__)
+
 #define flog_err(ferr_id, format, ...)                                         \
        _zlog_ecref(ferr_id, LOG_ERR, format, ## __VA_ARGS__)
 #define flog_warn(ferr_id, format, ...)                                        \
        _zlog_ecref(ferr_id, LOG_WARNING, format, ## __VA_ARGS__)
 
 #define flog_err_sys(ferr_id, format, ...)                                     \
-       flog_err(ferr_id, format, ##__VA_ARGS__)
-#define flog(priority, ferr_id, format, ...)                                   \
-       zlog(priority, "[EC %u] " format, ferr_id, ##__VA_ARGS__)
+       _zlog_ecref(ferr_id, LOG_ERR, format, ## __VA_ARGS__)
 
 extern void zlog_sigsafe(const char *text, size_t len);
 
@@ -203,7 +182,7 @@ extern size_t zlog_msg_ts(struct zlog_msg *msg, char *out, size_t outsz,
  * additional options.  It MUST be the first field in that larger struct.
  */
 
-PREDECL_ATOMLIST(zlog_targets)
+PREDECL_ATOMLIST(zlog_targets);
 struct zlog_target {
        struct zlog_targets_item head;
 
@@ -247,17 +226,22 @@ extern void zlog_init(const char *progname, const char *protoname,
                      unsigned short instance, uid_t uid, gid_t gid);
 DECLARE_HOOK(zlog_init, (const char *progname, const char *protoname,
                         unsigned short instance, uid_t uid, gid_t gid),
-                       (progname, protoname, instance, uid, gid))
+                       (progname, protoname, instance, uid, gid));
 
 extern void zlog_fini(void);
-DECLARE_KOOH(zlog_fini, (), ())
+DECLARE_KOOH(zlog_fini, (), ());
+
+extern void zlog_set_prefix_ec(bool enable);
+extern bool zlog_get_prefix_ec(void);
+extern void zlog_set_prefix_xid(bool enable);
+extern bool zlog_get_prefix_xid(void);
 
 /* for tools & test programs, i.e. anything not a daemon.
  * (no cleanup needed at exit)
  */
 extern void zlog_aux_init(const char *prefix, int prio_min);
 DECLARE_HOOK(zlog_aux_init, (const char *prefix, int prio_min),
-                           (prefix, prio_min))
+                           (prefix, prio_min));
 
 extern void zlog_startup_end(void);
 
index 8f4c2a46a8e432725d3d997a8ed81df86a9d555d..f258a8fbbddacf8b2eedb8c8b5bfbb83eca62f2d 100644 (file)
  * absolute end.
  */
 
-DECLARE_MGROUP(LOG)
-DEFINE_MGROUP_ACTIVEATEXIT(LOG, "logging subsystem")
+DECLARE_MGROUP(LOG);
+DEFINE_MGROUP_ACTIVEATEXIT(LOG, "logging subsystem");
 
-DEFINE_MTYPE_STATIC(LOG, LOG_FD,        "log file target")
-DEFINE_MTYPE_STATIC(LOG, LOG_FD_NAME,   "log file name")
-DEFINE_MTYPE_STATIC(LOG, LOG_FD_ROTATE, "log file rotate helper")
-DEFINE_MTYPE_STATIC(LOG, LOG_SYSL,      "syslog target")
+DEFINE_MTYPE_STATIC(LOG, LOG_FD,        "log file target");
+DEFINE_MTYPE_STATIC(LOG, LOG_FD_NAME,   "log file name");
+DEFINE_MTYPE_STATIC(LOG, LOG_FD_ROTATE, "log file rotate helper");
+DEFINE_MTYPE_STATIC(LOG, LOG_SYSL,      "syslog target");
 
 struct zlt_fd {
        struct zlog_target zt;
index d383ad5c6d6a5061370800bb1dc89b7a334c0638..b7872d9870a5472e2c757f3639dd3204fc763151 100644 (file)
@@ -219,7 +219,7 @@ for flag in $ax_pthread_flags; do
         # functions on Solaris that doesn't have a non-functional libc stub.
         # We try pthread_create on general principles.
         AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>
-                        static void routine(void *a) { a = 0; }
+                        static void routine(void *a) { if (a) a = 0; }
                         static void *start_routine(void *a) { return a; }],
                        [pthread_t th; pthread_attr_t attr;
                         pthread_create(&th, 0, start_routine, 0);
index db4bac79162cd5b1cf59dafc3222e064ef5e1a8d..e9428fa90a0e9fbb1aab5ce8236fa45b0cccdce9 100644 (file)
 
 extern unsigned int debug_flags;
 
-#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
-
 #define debugf(level, ...)                                                     \
        do {                                                                   \
                if (unlikely(debug_flags & level))                             \
                        zlog_debug(__VA_ARGS__);                               \
        } while (0)
-
-#elif defined __GNUC__
-
-#define debugf(level, _args...)                                                \
-       do {                                                                   \
-               if (unlikely(debug_flags & level))                             \
-                       zlog_debug(_args);                                     \
-       } while (0)
-
-#else
-
-static inline void debugf(int level, const char *format, ...)
-{
-}
-
-#endif
index cb298b1a09ab8c1fcafb066ef19aee40673a7532..4de8e220ced03467f957a8efb9d732eedc6a64be 100644 (file)
@@ -15,8 +15,8 @@
 
 #include "netlink.h"
 
-DEFINE_MTYPE_STATIC(NHRPD, NHRP_CACHE, "NHRP cache entry")
-DEFINE_MTYPE_STATIC(NHRPD, NHRP_CACHE_CONFIG, "NHRP cache config entry")
+DEFINE_MTYPE_STATIC(NHRPD, NHRP_CACHE, "NHRP cache entry");
+DEFINE_MTYPE_STATIC(NHRPD, NHRP_CACHE_CONFIG, "NHRP cache config entry");
 
 unsigned long nhrp_cache_counts[NHRP_CACHE_NUM_TYPES];
 
index f86dbe3d29d84eb9ba1c96a772d28e7a92661380..a64708d88ee89197c69c6a97126b414d74851be7 100644 (file)
@@ -21,7 +21,7 @@
 #include "os.h"
 #include "netlink.h"
 
-DEFINE_MTYPE_STATIC(NHRPD, NHRP_IF, "NHRP interface")
+DEFINE_MTYPE_STATIC(NHRPD, NHRP_IF, "NHRP interface");
 
 static void nhrp_interface_update_cache_config(struct interface *ifp,
                                               bool available,
@@ -464,16 +464,22 @@ void nhrp_interface_set_protection(struct interface *ifp, const char *profile,
 {
        struct nhrp_interface *nifp = ifp->info;
 
-       if (nifp->ipsec_profile)
+       if (nifp->ipsec_profile) {
+               vici_terminate_vc_by_profile_name(nifp->ipsec_profile);
+               nhrp_vc_reset();
                free(nifp->ipsec_profile);
+       }
        nifp->ipsec_profile = profile ? strdup(profile) : NULL;
 
-       if (nifp->ipsec_fallback_profile)
+       if (nifp->ipsec_fallback_profile) {
+               vici_terminate_vc_by_profile_name(nifp->ipsec_fallback_profile);
+               nhrp_vc_reset();
                free(nifp->ipsec_fallback_profile);
+       }
        nifp->ipsec_fallback_profile =
                fallback_profile ? strdup(fallback_profile) : NULL;
 
-       notifier_call(&nifp->notifier_list, NOTIFY_INTERFACE_ADDRESS_CHANGED);
+       notifier_call(&nifp->notifier_list, NOTIFY_INTERFACE_IPSEC_CHANGED);
 }
 
 void nhrp_interface_set_source(struct interface *ifp, const char *ifname)
index 49a4900bf8833bfd93fec64d7a7bfcd9adebd62d..5c819017f499911ee2edd247ae17b6ece80ccbd5 100644 (file)
@@ -29,7 +29,7 @@
 #include "netlink.h"
 #include "nhrp_errors.h"
 
-DEFINE_MGROUP(NHRPD, "NHRP")
+DEFINE_MGROUP(NHRPD, "NHRP");
 
 unsigned int debug_flags = 0;
 
@@ -128,7 +128,8 @@ FRR_DAEMON_INFO(nhrpd, NHRP, .vty_port = NHRP_VTY_PORT,
                .signals = sighandlers, .n_signals = array_size(sighandlers),
 
                .privs = &nhrpd_privs, .yang_modules = nhrpd_yang_modules,
-               .n_yang_modules = array_size(nhrpd_yang_modules), )
+               .n_yang_modules = array_size(nhrpd_yang_modules),
+);
 
 int main(int argc, char **argv)
 {
index 9ed03098ac1afe016d7337faa8ce84cba8698dd1..1689facbcfcaf3ed3be9a8721d7518d6cf18a2f4 100644 (file)
@@ -14,8 +14,8 @@
 #include "nhrpd.h"
 #include "nhrp_protocol.h"
 
-DEFINE_MTYPE_STATIC(NHRPD, NHRP_NHS, "NHRP next hop server")
-DEFINE_MTYPE_STATIC(NHRPD, NHRP_REGISTRATION, "NHRP registration entries")
+DEFINE_MTYPE_STATIC(NHRPD, NHRP_NHS, "NHRP next hop server");
+DEFINE_MTYPE_STATIC(NHRPD, NHRP_REGISTRATION, "NHRP registration entries");
 
 static int nhrp_nhs_resolve(struct thread *t);
 static int nhrp_reg_send_req(struct thread *t);
@@ -116,8 +116,20 @@ static int nhrp_reg_timeout(struct thread *t)
        }
 
        r->timeout <<= 1;
-       if (r->timeout > 64)
+       if (r->timeout > 64) {
+               /* If registration fails repeatedly, this may be because the
+                * IPSec connection is not working. Close the connection so it
+                * can be re-established correctly
+                */
+               if (r->peer && r->peer->vc && r->peer->vc->ike_uniqueid) {
+                       debugf(NHRP_DEBUG_COMMON,
+                              "Terminating IPSec Connection for %d",
+                              r->peer->vc->ike_uniqueid);
+                       vici_terminate_vc_by_ike_id(r->peer->vc->ike_uniqueid);
+                       r->peer->vc->ike_uniqueid = 0;
+               }
                r->timeout = 2;
+       }
        thread_add_timer_msec(master, nhrp_reg_send_req, r, 10, &r->t_register);
 
        return 0;
index 5e9929adeb78ca154f12146f5e1d5b9dec89e502..af352c68ee0cc6409f9da6d65950cc025a36d44e 100644 (file)
@@ -22,7 +22,7 @@
 #include "nhrp_protocol.h"
 #include "os.h"
 
-DEFINE_MTYPE_STATIC(NHRPD, NHRP_PEER, "NHRP peer entry")
+DEFINE_MTYPE_STATIC(NHRPD, NHRP_PEER, "NHRP peer entry");
 
 struct ipv6hdr {
        uint8_t priority_version;
@@ -147,6 +147,10 @@ static void nhrp_peer_ifp_notify(struct notifier_block *n, unsigned long cmd)
        case NOTIFY_INTERFACE_ADDRESS_CHANGED:
                notifier_call(&p->notifier_list, NOTIFY_PEER_IFCONFIG_CHANGED);
                break;
+       case NOTIFY_INTERFACE_IPSEC_CHANGED:
+               __nhrp_peer_check(p);
+               notifier_call(&p->notifier_list, NOTIFY_PEER_IFCONFIG_CHANGED);
+               break;
        case NOTIFY_INTERFACE_MTU_CHANGED:
                notifier_call(&p->notifier_list, NOTIFY_PEER_MTU_CHANGED);
                break;
index 737772dbc76e46ff6b0c04e4de5accb07463e05e..7a4c57b5d43fd367e7a1096f31578c77ed6afd5a 100644 (file)
@@ -18,7 +18,7 @@
 #include "log.h"
 #include "zclient.h"
 
-DEFINE_MTYPE_STATIC(NHRPD, NHRP_ROUTE, "NHRP routing entry")
+DEFINE_MTYPE_STATIC(NHRPD, NHRP_ROUTE, "NHRP routing entry");
 
 static struct zclient *zclient;
 static struct route_table *zebra_rib[AFI_MAX];
index ef3be82ca95a58c37e819ecc77dee9206349f06f..8ce19cd4a3a27cf2c5636060f17fda34a8b8163b 100644 (file)
@@ -18,7 +18,7 @@
 #include "log.h"
 #include "nhrp_protocol.h"
 
-DEFINE_MTYPE_STATIC(NHRPD, NHRP_SHORTCUT, "NHRP shortcut")
+DEFINE_MTYPE_STATIC(NHRPD, NHRP_SHORTCUT, "NHRP shortcut");
 
 static struct route_table *shortcut_rib[AFI_MAX];
 
index d538163e90fd16fa44042d4e38399a8797405e36..b3b657f3fada9ea6172e8f9490977b370385a8f5 100644 (file)
@@ -17,7 +17,7 @@
 #include "nhrpd.h"
 #include "os.h"
 
-DEFINE_MTYPE_STATIC(NHRPD, NHRP_VC, "NHRP virtual connection")
+DEFINE_MTYPE_STATIC(NHRPD, NHRP_VC, "NHRP virtual connection");
 
 struct child_sa {
        uint32_t id;
index a36d0c445db8412c215577f92383a03063cdcb86..9c8c293b9e26fd6aa442cc332b34f3028d207315 100644 (file)
@@ -18,7 +18,7 @@
 #include "memory.h"
 #include "resolver.h"
 
-DECLARE_MGROUP(NHRPD)
+DECLARE_MGROUP(NHRPD);
 
 #define NHRPD_DEFAULT_HOLDTIME 7200
 
@@ -105,6 +105,7 @@ enum nhrp_notify_type {
        NOTIFY_INTERFACE_ADDRESS_CHANGED,
        NOTIFY_INTERFACE_NBMA_CHANGED,
        NOTIFY_INTERFACE_MTU_CHANGED,
+       NOTIFY_INTERFACE_IPSEC_CHANGED,
 
        NOTIFY_VC_IPSEC_CHANGED,
        NOTIFY_VC_IPSEC_UPDATE_NBMA,
@@ -125,6 +126,7 @@ enum nhrp_notify_type {
 struct nhrp_vc {
        struct notifier_list notifier_list;
        uint32_t ipsec;
+       uint32_t ike_uniqueid;
        uint8_t updating;
        uint8_t abort_migration;
 
@@ -399,6 +401,8 @@ void nhrp_vc_reset(void);
 
 void vici_init(void);
 void vici_terminate(void);
+void vici_terminate_vc_by_profile_name(char *profile_name);
+void vici_terminate_vc_by_ike_id(unsigned int ike_id);
 void vici_request_vc(const char *profile, union sockunion *src,
                     union sockunion *dst, int prio);
 
index 86554f53dc3a0748500cfc7f023325b0ad5fc5c3..9b117ddf0d91bfa1aac01748c5191d43f8b43f80 100644 (file)
@@ -200,6 +200,7 @@ static void parse_sa_message(struct vici_message_ctx *ctx,
                                                nhrp_vc_ipsec_updown(
                                                        sactx->child_uniqueid,
                                                        vc);
+                                       vc->ike_uniqueid = sactx->ike_uniqueid;
                                }
                        } else {
                                nhrp_vc_ipsec_updown(sactx->child_uniqueid, 0);
@@ -521,6 +522,26 @@ void vici_terminate(void)
 {
 }
 
+void vici_terminate_vc_by_profile_name(char *profile_name)
+{
+       struct vici_conn *vici = &vici_connection;
+
+       debugf(NHRP_DEBUG_VICI, "Terminate profile = %s", profile_name);
+       vici_submit_request(vici, "terminate", VICI_KEY_VALUE, "ike",
+                   strlen(profile_name), profile_name, VICI_END);
+}
+
+void vici_terminate_vc_by_ike_id(unsigned int ike_id)
+{
+       struct vici_conn *vici = &vici_connection;
+       char ike_id_str[10];
+
+       snprintf(ike_id_str, sizeof(ike_id_str), "%d", ike_id);
+       debugf(NHRP_DEBUG_VICI, "Terminate ike_id_str = %s", ike_id_str);
+       vici_submit_request(vici, "terminate", VICI_KEY_VALUE, "ike-id",
+                   strlen(ike_id_str), ike_id_str, VICI_END);
+}
+
 void vici_request_vc(const char *profile, union sockunion *src,
                     union sockunion *dst, int prio)
 {
index 7f1475cc69e1a2eb19f49e73f27534951b2c92fb..a78d827ea59073265a43f89cb3ca1f4e2d12a463 100644 (file)
@@ -21,7 +21,7 @@
 
 #define ERRNO_IO_RETRY(EN) (((EN) == EAGAIN) || ((EN) == EWOULDBLOCK) || ((EN) == EINTR))
 
-DEFINE_MTYPE_STATIC(NHRPD, ZBUF_DATA, "NHRPD zbuf data")
+DEFINE_MTYPE_STATIC(NHRPD, ZBUF_DATA, "NHRPD zbuf data");
 
 struct zbuf *zbuf_alloc(size_t size)
 {
index cf33069c9f42c28db0e3f3139ddc69bb24a801df..6bf61b4804b0981c43311331c4757d7c32d7e55f 100644 (file)
@@ -46,7 +46,8 @@
 #include "ospf6d.h"
 #include "lib/json.h"
 
-DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_PLISTNAME, "Prefix list name")
+DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_AREA,      "OSPF6 area");
+DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_PLISTNAME, "Prefix list name");
 
 int ospf6_area_cmp(void *va, void *vb)
 {
index beca6b9690838984b551a43ba10e3f2671efc6cc..3497b2665699ceeb6e070800e0f13515f2c3b572 100644 (file)
 #include "ospf6d.h"
 #include "lib/json.h"
 
+DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_EXTERNAL_INFO, "OSPF6 ext. info");
+DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_DIST_ARGS,     "OSPF6 Distribute arguments");
+DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_REDISTRIBUTE, "OSPF6 Redistribute arguments");
+
 static void ospf6_asbr_redistribute_set(int type, vrf_id_t vrf_id);
 static void ospf6_asbr_redistribute_unset(struct ospf6 *ospf6,
                                          struct ospf6_redist *red, int type);
@@ -1106,7 +1110,7 @@ void ospf6_asbr_remove_externals_from_area(struct ospf6_area *oa)
        struct listnode *node, *nnode;
        struct ospf6_area *area;
        struct ospf6 *ospf6 = oa->ospf6;
-
+       const struct route_node *iterend;
 
        /* skip if router is in other non-stub areas */
        for (ALL_LIST_ELEMENTS(ospf6->area_list, node, nnode, area))
@@ -1114,9 +1118,12 @@ void ospf6_asbr_remove_externals_from_area(struct ospf6_area *oa)
                        return;
 
        /* if router is only in a stub area then purge AS-External LSAs */
-       for (ALL_LSDB(oa->ospf6->lsdb, lsa, lsanext)) {
+       iterend = ospf6_lsdb_head(ospf6->lsdb, 0, 0, 0, &lsa);
+       while (lsa != NULL) {
+               lsanext = ospf6_lsdb_next(iterend, lsa);
                if (ntohs(lsa->header->type) == OSPF6_LSTYPE_AS_EXTERNAL)
                        ospf6_lsdb_remove(lsa, ospf6->lsdb);
+               lsa = lsanext;
        }
 }
 
index a5d9138743a684c6bae5590c56babe73e83375a1..158b8dc483d017c7438a90efe35b0fdad280a405 100644 (file)
 #include "ospf6_zebra.h"
 #include "lib/json.h"
 
-DEFINE_MTYPE_STATIC(OSPF6D, CFG_PLIST_NAME, "configured prefix list names")
-DEFINE_QOBJ_TYPE(ospf6_interface)
+DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_IF,       "OSPF6 interface");
+DEFINE_MTYPE_STATIC(OSPF6D, CFG_PLIST_NAME, "configured prefix list names");
+DEFINE_QOBJ_TYPE(ospf6_interface);
 DEFINE_HOOK(ospf6_interface_change,
            (struct ospf6_interface * oi, int state, int old_state),
-           (oi, state, old_state))
+           (oi, state, old_state));
 
 unsigned char conf_debug_ospf6_interface = 0;
 
@@ -1449,6 +1450,12 @@ DEFUN (show_ipv6_ospf6_interface_ifname_prefix,
                return CMD_WARNING;
        }
 
+       if (CHECK_FLAG(oi->flag, OSPF6_INTERFACE_DISABLE)) {
+               vty_out(vty, "Interface %s not attached to area\n",
+                       argv[idx_ifname]->arg);
+               return CMD_WARNING;
+       }
+
        ospf6_route_table_show(vty, idx_prefix, argc, argv, oi->route_connected,
                               uj);
 
@@ -1482,7 +1489,7 @@ DEFUN (show_ipv6_ospf6_interface_prefix,
 
        FOR_ALL_INTERFACES (vrf, ifp) {
                oi = (struct ospf6_interface *)ifp->info;
-               if (oi == NULL)
+               if (oi == NULL || CHECK_FLAG(oi->flag, OSPF6_INTERFACE_DISABLE))
                        continue;
 
                ospf6_route_table_show(vty, idx_prefix, argc, argv,
index 6e4692920cba9b825bb3c736bcbc9b8444fad7a6..2a5a9ba4a2da1981b03f29fc55c2ede2a49ec7b6 100644 (file)
@@ -134,9 +134,9 @@ struct ospf6_interface {
        uint32_t ls_ack_out;
        uint32_t discarded;
 
-       QOBJ_FIELDS
+       QOBJ_FIELDS;
 };
-DECLARE_QOBJ_TYPE(ospf6_interface)
+DECLARE_QOBJ_TYPE(ospf6_interface);
 
 /* interface state */
 #define OSPF6_INTERFACE_NONE             0
@@ -199,6 +199,6 @@ extern void install_element_ospf6_debug_interface(void);
 
 DECLARE_HOOK(ospf6_interface_change,
             (struct ospf6_interface * oi, int state, int old_state),
-            (oi, state, old_state))
+            (oi, state, old_state));
 
 #endif /* OSPF6_INTERFACE_H */
index e1c3b4038c0d543b78f9ef4d5004112d08cc0578..f2a933d8780da08a419ffb24db846b73cd8ed880 100644 (file)
 #include "ospf6_flood.h"
 #include "ospf6d.h"
 
+DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_LSA,         "OSPF6 LSA");
+DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_LSA_HEADER,  "OSPF6 LSA header");
+DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_LSA_SUMMARY, "OSPF6 LSA summary");
+
 vector ospf6_lsa_handler_vector;
 
 struct ospf6 *ospf6_get_by_lsdb(struct ospf6_lsa *lsa)
@@ -657,27 +661,29 @@ void ospf6_lsa_show(struct vty *vty, struct ospf6_lsa *lsa,
                vty_out(vty, "\n");
 }
 
+struct ospf6_lsa *ospf6_lsa_alloc(size_t lsa_length)
+{
+       struct ospf6_lsa *lsa;
+
+       lsa = XCALLOC(MTYPE_OSPF6_LSA, sizeof(struct ospf6_lsa));
+       lsa->header = XMALLOC(MTYPE_OSPF6_LSA_HEADER, lsa_length);
+
+       return lsa;
+}
+
 /* OSPFv3 LSA creation/deletion function */
 struct ospf6_lsa *ospf6_lsa_create(struct ospf6_lsa_header *header)
 {
        struct ospf6_lsa *lsa = NULL;
-       struct ospf6_lsa_header *new_header = NULL;
        uint16_t lsa_size = 0;
 
        /* size of the entire LSA */
        lsa_size = ntohs(header->length); /* XXX vulnerable */
 
-       /* allocate memory for this LSA */
-       new_header = XMALLOC(MTYPE_OSPF6_LSA_HEADER, lsa_size);
+       lsa = ospf6_lsa_alloc(lsa_size);
 
        /* copy LSA from original header */
-       memcpy(new_header, header, lsa_size);
-
-       /* LSA information structure */
-       /* allocate memory */
-       lsa = XCALLOC(MTYPE_OSPF6_LSA, sizeof(struct ospf6_lsa));
-
-       lsa->header = new_header;
+       memcpy(lsa->header, header, lsa_size);
 
        /* dump string */
        ospf6_lsa_printbuf(lsa, lsa->name, sizeof(lsa->name));
@@ -691,20 +697,11 @@ struct ospf6_lsa *ospf6_lsa_create(struct ospf6_lsa_header *header)
 struct ospf6_lsa *ospf6_lsa_create_headeronly(struct ospf6_lsa_header *header)
 {
        struct ospf6_lsa *lsa = NULL;
-       struct ospf6_lsa_header *new_header = NULL;
 
-       /* allocate memory for this LSA */
-       new_header = XMALLOC(MTYPE_OSPF6_LSA_HEADER,
-                            sizeof(struct ospf6_lsa_header));
+       lsa = ospf6_lsa_alloc(sizeof(struct ospf6_lsa_header));
 
-       /* copy LSA from original header */
-       memcpy(new_header, header, sizeof(struct ospf6_lsa_header));
-
-       /* LSA information structure */
-       /* allocate memory */
-       lsa = XCALLOC(MTYPE_OSPF6_LSA, sizeof(struct ospf6_lsa));
+       memcpy(lsa->header, header, sizeof(struct ospf6_lsa_header));
 
-       lsa->header = new_header;
        SET_FLAG(lsa->flag, OSPF6_LSA_HEADERONLY);
 
        /* dump string */
index 7fa9c5fe40153370c50821c7c1707d6ca68e492c..c4d0290c0c1639b2c11acf149e926d7cc5ad5f3c 100644 (file)
@@ -217,6 +217,7 @@ extern void ospf6_lsa_show_internal(struct vty *vty, struct ospf6_lsa *lsa,
 extern void ospf6_lsa_show(struct vty *vty, struct ospf6_lsa *lsa,
                           json_object *json, bool use_json);
 
+extern struct ospf6_lsa *ospf6_lsa_alloc(size_t lsa_length);
 extern struct ospf6_lsa *ospf6_lsa_create(struct ospf6_lsa_header *header);
 extern struct ospf6_lsa *
 ospf6_lsa_create_headeronly(struct ospf6_lsa_header *header);
index 9636e1a230f110091ca1f594822cae138e5bdf5d..18f121e3a2bc4f6405081bd09ac87b17f6df4ddd 100644 (file)
@@ -34,6 +34,8 @@
 #include "ospf6d.h"
 #include "bitfield.h"
 
+DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_LSDB, "OSPF6 LSA database");
+
 struct ospf6_lsdb *ospf6_lsdb_create(void *data)
 {
        struct ospf6_lsdb *lsdb;
index 69424f4b46cb4f9710cd0c139bc77f6b8a78101c..c601693a7e4167c7697247e44fbcc87bfee2865f 100644 (file)
@@ -182,7 +182,8 @@ FRR_DAEMON_INFO(ospf6d, OSPF6, .vty_port = OSPF6_VTY_PORT,
                .n_signals = array_size(ospf6_signals),
 
                .privs = &ospf6d_privs, .yang_modules = ospf6d_yang_modules,
-               .n_yang_modules = array_size(ospf6d_yang_modules), )
+               .n_yang_modules = array_size(ospf6d_yang_modules),
+);
 
 /* Main routine of ospf6d. Treatment of argument and starting ospf finite
    state machine is handled here. */
diff --git a/ospf6d/ospf6_memory.c b/ospf6d/ospf6_memory.c
deleted file mode 100644 (file)
index 6585fc1..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/* ospf6d memory type definitions
- *
- * Copyright (C) 2015  David Lamparter
- *
- * This file is part of Quagga.
- *
- * Quagga 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.
- *
- * Quagga 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
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "ospf6_memory.h"
-
-DEFINE_MGROUP(OSPF6D, "ospf6d")
-DEFINE_MTYPE(OSPF6D, OSPF6_TOP, "OSPF6 top")
-DEFINE_MTYPE(OSPF6D, OSPF6_AREA, "OSPF6 area")
-DEFINE_MTYPE(OSPF6D, OSPF6_IF, "OSPF6 interface")
-DEFINE_MTYPE(OSPF6D, OSPF6_NEIGHBOR, "OSPF6 neighbor")
-DEFINE_MTYPE(OSPF6D, OSPF6_ROUTE, "OSPF6 route")
-DEFINE_MTYPE(OSPF6D, OSPF6_PREFIX, "OSPF6 prefix")
-DEFINE_MTYPE(OSPF6D, OSPF6_MESSAGE, "OSPF6 message")
-DEFINE_MTYPE(OSPF6D, OSPF6_LSA, "OSPF6 LSA")
-DEFINE_MTYPE(OSPF6D, OSPF6_LSA_HEADER, "OSPF6 LSA header")
-DEFINE_MTYPE(OSPF6D, OSPF6_LSA_SUMMARY, "OSPF6 LSA summary")
-DEFINE_MTYPE(OSPF6D, OSPF6_LSDB, "OSPF6 LSA database")
-DEFINE_MTYPE(OSPF6D, OSPF6_VERTEX, "OSPF6 vertex")
-DEFINE_MTYPE(OSPF6D, OSPF6_SPFTREE, "OSPF6 SPF tree")
-DEFINE_MTYPE(OSPF6D, OSPF6_NEXTHOP, "OSPF6 nexthop")
-DEFINE_MTYPE(OSPF6D, OSPF6_EXTERNAL_INFO, "OSPF6 ext. info")
-DEFINE_MTYPE(OSPF6D, OSPF6_PATH, "OSPF6 Path")
-DEFINE_MTYPE(OSPF6D, OSPF6_DIST_ARGS, "OSPF6 Distribute arguments")
-DEFINE_MTYPE(OSPF6D, OSPF6_OTHER, "OSPF6 other")
-DEFINE_MTYPE(OSPF6D, OSPF6_REDISTRIBUTE, "OSPF6 Redistribute arguments")
diff --git a/ospf6d/ospf6_memory.h b/ospf6d/ospf6_memory.h
deleted file mode 100644 (file)
index 57f0abd..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/* ospf6d memory type declarations
- *
- * Copyright (C) 2015  David Lamparter
- *
- * This file is part of Quagga.
- *
- * Quagga 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.
- *
- * Quagga 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 _QUAGGA_OSPF6_MEMORY_H
-#define _QUAGGA_OSPF6_MEMORY_H
-
-#include "memory.h"
-
-DECLARE_MGROUP(OSPF6D)
-DECLARE_MTYPE(OSPF6_TOP)
-DECLARE_MTYPE(OSPF6_AREA)
-DECLARE_MTYPE(OSPF6_IF)
-DECLARE_MTYPE(OSPF6_NEIGHBOR)
-DECLARE_MTYPE(OSPF6_ROUTE)
-DECLARE_MTYPE(OSPF6_PREFIX)
-DECLARE_MTYPE(OSPF6_MESSAGE)
-DECLARE_MTYPE(OSPF6_LSA)
-DECLARE_MTYPE(OSPF6_LSA_HEADER)
-DECLARE_MTYPE(OSPF6_LSA_SUMMARY)
-DECLARE_MTYPE(OSPF6_LSDB)
-DECLARE_MTYPE(OSPF6_VERTEX)
-DECLARE_MTYPE(OSPF6_SPFTREE)
-DECLARE_MTYPE(OSPF6_NEXTHOP)
-DECLARE_MTYPE(OSPF6_EXTERNAL_INFO)
-DECLARE_MTYPE(OSPF6_PATH)
-DECLARE_MTYPE(OSPF6_DIST_ARGS)
-DECLARE_MTYPE(OSPF6_REDISTRIBUTE)
-DECLARE_MTYPE(OSPF6_OTHER)
-
-#endif /* _QUAGGA_OSPF6_MEMORY_H */
index 160f012d780a4ec54764f9997d6ea0fffff73b00..7aedd3df45a624c41f2a559b0a38a139f7ffa473 100644 (file)
@@ -49,6 +49,8 @@
 
 #include <netinet/ip6.h>
 
+DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_MESSAGE, "OSPF6 message");
+
 unsigned char conf_debug_ospf6_message[6] = {0x03, 0, 0, 0, 0, 0};
 static const struct message ospf6_message_type_str[] = {
        {OSPF6_MESSAGE_TYPE_HELLO, "Hello"},
@@ -1829,7 +1831,9 @@ int ospf6_dbdesc_send(struct thread *thread)
                        /* MTU check */
                        if (p - sendbuf + sizeof(struct ospf6_lsa_header)
                            > ospf6_packet_max(on->ospf6_if)) {
-                               ospf6_lsdb_lsa_unlock(lsa);
+                               ospf6_lsa_unlock(lsa);
+                               if (lsanext)
+                                       ospf6_lsa_unlock(lsanext);
                                break;
                        }
                        memcpy(p, lsa->header, sizeof(struct ospf6_lsa_header));
@@ -1876,7 +1880,9 @@ int ospf6_dbdesc_send_newone(struct thread *thread)
 
                if (size + sizeof(struct ospf6_lsa_header)
                    > ospf6_packet_max(on->ospf6_if)) {
-                       ospf6_lsdb_lsa_unlock(lsa);
+                       ospf6_lsa_unlock(lsa);
+                       if (lsanext)
+                               ospf6_lsa_unlock(lsanext);
                        break;
                }
 
@@ -1935,7 +1941,9 @@ int ospf6_lsreq_send(struct thread *thread)
                /* MTU check */
                if (p - sendbuf + sizeof(struct ospf6_lsreq_entry)
                    > ospf6_packet_max(on->ospf6_if)) {
-                       ospf6_lsdb_lsa_unlock(lsa);
+                       ospf6_lsa_unlock(lsa);
+                       if (lsanext)
+                               ospf6_lsa_unlock(lsanext);
                        break;
                }
 
@@ -2396,7 +2404,9 @@ int ospf6_lsack_send_interface(struct thread *thread)
                        thread_add_event(master, ospf6_lsack_send_interface, oi,
                                         0, &oi->thread_send_lsack);
 
-                       ospf6_lsdb_lsa_unlock(lsa);
+                       ospf6_lsa_unlock(lsa);
+                       if (lsanext)
+                               ospf6_lsa_unlock(lsanext);
                        break;
                }
 
index 7a1b96c2b3b8f7cb5f959be241b4d1938d7cc6b6..485bde4b7b77ce8d62ab5e7fedb1c16251198909 100644 (file)
 #include "ospf6_zebra.h"
 #include "lib/json.h"
 
+DEFINE_MTYPE(OSPF6D, OSPF6_NEIGHBOR, "OSPF6 neighbor");
+
 DEFINE_HOOK(ospf6_neighbor_change,
            (struct ospf6_neighbor * on, int state, int next_state),
-           (on, state, next_state))
+           (on, state, next_state));
 
 unsigned char conf_debug_ospf6_neighbor = 0;
 
index 94300ff2bae24154a5aa1e732755e0aff3764913..f45b3405076aacd127a5de379794ca1c1d07956a 100644 (file)
@@ -166,6 +166,6 @@ extern void install_element_ospf6_debug_neighbor(void);
 
 DECLARE_HOOK(ospf6_neighbor_change,
             (struct ospf6_neighbor * on, int state, int next_state),
-            (on, state, next_state))
+            (on, state, next_state));
 
 #endif /* OSPF6_NEIGHBOR_H */
index b77f968179d811702df64b1b606917f6f23f60b3..9770dd0444be8a5b27ff1c02c7112c78b8ac3d91 100644 (file)
 #include "ospf6d.h"
 #include "ospf6_zebra.h"
 
+DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_ROUTE,   "OSPF6 route");
+DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_NEXTHOP, "OSPF6 nexthop");
+DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_PATH,    "OSPF6 Path");
+
 unsigned char conf_debug_ospf6_route = 0;
 
 static char *ospf6_route_table_name(struct ospf6_route_table *table)
index 51a3bff2a38685ccf83418a60a19d09a343b7c09..b9d413c3df7d1f8fa209d94bf2509c9451641ab9 100644 (file)
@@ -1418,4 +1418,5 @@ static int ospf6_snmp_module_init(void)
 
 FRR_MODULE_SETUP(.name = "ospf6d_snmp", .version = FRR_VERSION,
                 .description = "ospf6d AgentX SNMP module",
-                .init = ospf6_snmp_module_init, )
+                .init = ospf6_snmp_module_init,
+);
index 121e846843540ec01eae6d4ddbbc2de8f74e745e..7652d71c59d52ed52e7050dca9bc14a674cf254f 100644 (file)
@@ -43,6 +43,8 @@
 #include "ospf6d.h"
 #include "ospf6_abr.h"
 
+DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_VERTEX, "OSPF6 vertex");
+
 unsigned char conf_debug_ospf6_spf = 0;
 
 static void ospf6_spf_copy_nexthops_to_route(struct ospf6_route *rt,
@@ -86,7 +88,7 @@ static int ospf6_vertex_cmp(const struct ospf6_vertex *va,
        return 0;
 }
 DECLARE_SKIPLIST_NONUNIQ(vertex_pqueue, struct ospf6_vertex, pqi,
-               ospf6_vertex_cmp)
+               ospf6_vertex_cmp);
 
 static int ospf6_vertex_id_cmp(void *a, void *b)
 {
@@ -1021,13 +1023,8 @@ struct ospf6_lsa *ospf6_create_single_router_lsa(struct ospf6_area *area,
                return NULL;
        }
 
-       /* Allocate memory for this LSA */
-       new_header = XMALLOC(MTYPE_OSPF6_LSA_HEADER, total_lsa_length);
-
-       /* LSA information structure */
-       lsa = XCALLOC(MTYPE_OSPF6_LSA, sizeof(struct ospf6_lsa));
-
-       lsa->header = (struct ospf6_lsa_header *)new_header;
+       lsa = ospf6_lsa_alloc(total_lsa_length);
+       new_header = (uint8_t *)lsa->header;
 
        lsa->lsdb = area->temp_router_lsa_lsdb;
 
index 36e2b2791225e9672ecc2256231a9e6f34cbda17..523b318d5bbeaf15797dcd412e0fde2ed18ba446 100644 (file)
@@ -35,7 +35,7 @@ extern unsigned char conf_debug_ospf6_spf;
 #define IS_OSPF6_DEBUG_SPF(level)                                              \
        (conf_debug_ospf6_spf & OSPF6_DEBUG_SPF_##level)
 
-PREDECL_SKIPLIST_NONUNIQ(vertex_pqueue)
+PREDECL_SKIPLIST_NONUNIQ(vertex_pqueue);
 /* Transit Vertex */
 struct ospf6_vertex {
        /* type of this vertex */
index 3f72ec828e274824e88ee5602c622f01bf859776..a38f1cbc4500a6e0240cc4213572daf771003483 100644 (file)
 #include "ospf6d.h"
 #include "lib/json.h"
 
-DEFINE_QOBJ_TYPE(ospf6)
+DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_TOP, "OSPF6 top");
+
+DEFINE_QOBJ_TYPE(ospf6);
 
 FRR_CFG_DEFAULT_BOOL(OSPF6_LOG_ADJACENCY_CHANGES,
        { .val_bool = true, .match_profile = "datacenter", },
        { .val_bool = false },
-)
+);
 
 /* global ospf6d variable */
 static struct ospf6_master ospf6_master;
@@ -809,7 +811,8 @@ DEFUN (no_ospf6_interface_area,
 
        /* Verify Area */
        if (oi->area == NULL) {
-               vty_out(vty, "No such Area-ID: %s\n", argv[idx_ipv4]->arg);
+               vty_out(vty, "%s not attached to area %s\n",
+                       oi->interface->name, oi->area->name);
                return CMD_SUCCESS;
        }
 
@@ -830,7 +833,6 @@ DEFUN (no_ospf6_interface_area,
                UNSET_FLAG(oa->flag, OSPF6_AREA_ENABLE);
                ospf6_abr_disable_area(oa);
        }
-       ospf6_interface_delete(oi);
 
        return CMD_SUCCESS;
 }
index 75dff86cd70da16bf24e41dbd09729d26800f649..7980659e68d2681b024b86d61853c4161c64cfb8 100644 (file)
@@ -132,9 +132,9 @@ struct ospf6 {
         */
        uint16_t max_multipath;
 
-       QOBJ_FIELDS
+       QOBJ_FIELDS;
 };
-DECLARE_QOBJ_TYPE(ospf6)
+DECLARE_QOBJ_TYPE(ospf6);
 
 #define OSPF6_DISABLED    0x01
 #define OSPF6_STUB_ROUTER 0x02
index 9b9453ce24ff8846807e8a685177bc8e00a5e56b..8d5e0f0a393a5cb9e1bcb3cd40100931da1ac206 100644 (file)
@@ -42,7 +42,7 @@
 #include "ospf6_area.h"
 #include "lib/json.h"
 
-DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_DISTANCE, "OSPF6 distance")
+DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_DISTANCE, "OSPF6 distance");
 
 unsigned char conf_debug_ospf6_zebra = 0;
 
index 8d9c85fd08288de5f7167e59e6eba6c3230cfde6..91d427c78c5a04b9f524bbae9dfb817aa5b06b20 100644 (file)
@@ -46,6 +46,8 @@
 #include "ospf6_bfd.h"
 #include "lib/json.h"
 
+DEFINE_MGROUP(OSPF6D, "ospf6d");
+
 struct route_node *route_prev(struct route_node *node)
 {
        struct route_node *end;
index d85ff40f3254bd2d00c4acfa5cd99b5240e3f761..3f9461c7f0be8b65d82e654336a11a2c28ac0d33 100644 (file)
@@ -23,8 +23,9 @@
 
 #include "libospf.h"
 #include "thread.h"
+#include "memory.h"
 
-#include "ospf6_memory.h"
+DECLARE_MGROUP(OSPF6D);
 
 /* global variables */
 extern struct thread_master *master;
index ec6e59353343f1cc9412822cb2ebb417462a16fb..82d880cca868a1b84bc6c9ebe213d49130f90dd1 100644 (file)
@@ -40,7 +40,6 @@ ospf6d_libospf6_a_SOURCES = \
        ospf6d/ospf6_intra.c \
        ospf6d/ospf6_lsa.c \
        ospf6d/ospf6_lsdb.c \
-       ospf6d/ospf6_memory.c \
        ospf6d/ospf6_message.c \
        ospf6d/ospf6_neighbor.c \
        ospf6d/ospf6_network.c \
@@ -62,7 +61,6 @@ noinst_HEADERS += \
        ospf6d/ospf6_intra.h \
        ospf6d/ospf6_lsa.h \
        ospf6d/ospf6_lsdb.h \
-       ospf6d/ospf6_memory.h \
        ospf6d/ospf6_message.h \
        ospf6d/ospf6_neighbor.h \
        ospf6d/ospf6_network.h \
@@ -80,6 +78,6 @@ ospf6d_ospf6d_SOURCES = \
        # end
 
 ospf6d_ospf6d_snmp_la_SOURCES = ospf6d/ospf6_snmp.c
-ospf6d_ospf6d_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu99
+ospf6d_ospf6d_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu11
 ospf6d_ospf6d_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
 ospf6d_ospf6d_snmp_la_LIBADD = lib/libfrrsnmp.la
index 1b9b66d7453fb2b2f7930d769602cacf5ffbeb2e..29f1c0807db47618833837a2f0d98e1ac252c88b 100644 (file)
 #include "ospfd/ospf_dump_api.c"
 #include "ospfd/ospf_api.c"
 
-XREF_SETUP()
+XREF_SETUP();
 
-DEFINE_MGROUP(OSPFCLIENT, "libospfapiclient")
-DEFINE_MTYPE_STATIC(OSPFCLIENT, OSPF_APICLIENT, "OSPF-API client")
+DEFINE_MGROUP(OSPFCLIENT, "libospfapiclient");
+DEFINE_MTYPE_STATIC(OSPFCLIENT, OSPF_APICLIENT, "OSPF-API client");
 
 /* Backlog for listen */
 #define BACKLOG 5
index a9bc9069d20f3f509281deafa3781389aef8ae39..b202cd01f12958407a82a312d05c6597d43dc284 100644 (file)
@@ -23,6 +23,7 @@
 #include <zebra.h>
 
 #include "command.h"
+#include "json.h"
 #include "linklist.h"
 #include "memory.h"
 #include "prefix.h"
 #include "ospf_dump.h"
 #include "ospf_vty.h"
 
-extern struct zclient *zclient;
-
-/*
- * ospf_bfd_info_free - Free BFD info structure
- */
-void ospf_bfd_info_free(void **bfd_info)
-{
-       bfd_info_free((struct bfd_info **)bfd_info);
-}
-
-/*
- * ospf_bfd_reg_dereg_nbr - Register/Deregister a neighbor with BFD through
- *                          zebra for starting/stopping the monitoring of
- *                          the neighbor rechahability.
- */
-static void ospf_bfd_reg_dereg_nbr(struct ospf_neighbor *nbr, int command)
-{
-       struct ospf_interface *oi = nbr->oi;
-       struct interface *ifp = oi->ifp;
-       struct ospf_if_params *params;
-       struct bfd_info *bfd_info;
-       int cbit;
-
-       /* Check if BFD is enabled */
-       params = IF_DEF_PARAMS(ifp);
-
-       /* Check if BFD is enabled */
-       if (!params->bfd_info)
-               return;
-       bfd_info = (struct bfd_info *)params->bfd_info;
-
-       if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE))
-               zlog_debug("%s nbr (%pI4) with BFD. OSPF vrf %s",
-                          bfd_get_command_dbg_str(command),
-                          &nbr->src,
-                          ospf_vrf_id_to_name(oi->ospf->vrf_id));
-
-       cbit = CHECK_FLAG(bfd_info->flags, BFD_FLAG_BFD_CBIT_ON);
-
-       bfd_peer_sendmsg(zclient, bfd_info, AF_INET, &nbr->src, NULL, ifp->name,
-                        0, 0, cbit, command, 0, oi->ospf->vrf_id);
-}
+DEFINE_MTYPE_STATIC(OSPFD, BFD_CONFIG, "BFD configuration data");
 
 /*
  * ospf_bfd_trigger_event - Neighbor is registered/deregistered with BFD when
@@ -94,293 +54,155 @@ static void ospf_bfd_reg_dereg_nbr(struct ospf_neighbor *nbr, int command)
 void ospf_bfd_trigger_event(struct ospf_neighbor *nbr, int old_state, int state)
 {
        if ((old_state < NSM_TwoWay) && (state >= NSM_TwoWay))
-               ospf_bfd_reg_dereg_nbr(nbr, ZEBRA_BFD_DEST_REGISTER);
+               bfd_sess_install(nbr->bfd_session);
        else if ((old_state >= NSM_TwoWay) && (state < NSM_TwoWay))
-               ospf_bfd_reg_dereg_nbr(nbr, ZEBRA_BFD_DEST_DEREGISTER);
+               bfd_sess_uninstall(nbr->bfd_session);
 }
 
-/*
- * ospf_bfd_reg_dereg_all_nbr - Register/Deregister all neighbors associated
- *                              with a interface with BFD through
- *                              zebra for starting/stopping the monitoring of
- *                              the neighbor rechahability.
- */
-static int ospf_bfd_reg_dereg_all_nbr(struct interface *ifp, int command)
+static void ospf_bfd_session_change(struct bfd_session_params *bsp,
+                                   const struct bfd_session_status *bss,
+                                   void *arg)
 {
-       struct ospf_interface *oi;
-       struct route_table *nbrs;
-       struct ospf_neighbor *nbr;
-       struct route_node *irn;
-       struct route_node *nrn;
-
-       for (irn = route_top(IF_OIFS(ifp)); irn; irn = route_next(irn)) {
-               if ((oi = irn->info) == NULL)
-                       continue;
+       struct ospf_neighbor *nbr = arg;
 
-               if ((nbrs = oi->nbrs) == NULL)
-                       continue;
-
-               for (nrn = route_top(nbrs); nrn; nrn = route_next(nrn)) {
-                       if ((nbr = nrn->info) == NULL || nbr == oi->nbr_self)
-                               continue;
-
-                       if (command != ZEBRA_BFD_DEST_DEREGISTER)
-                               ospf_bfd_info_nbr_create(oi, nbr);
-                       else
-                               bfd_info_free(
-                                       (struct bfd_info **)&nbr->bfd_info);
-
-                       if (nbr->state < NSM_TwoWay)
-                               continue;
+       /* BFD peer went down. */
+       if (bss->state == BFD_STATUS_DOWN
+           && bss->previous_state == BFD_STATUS_UP) {
+               if (IS_DEBUG_OSPF(bfd, BFD_LIB))
+                       zlog_debug("%s: NSM[%s:%pI4]: BFD Down", __func__,
+                                  IF_NAME(nbr->oi), &nbr->address.u.prefix4);
 
-                       ospf_bfd_reg_dereg_nbr(nbr, command);
-               }
+               OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_InactivityTimer);
        }
 
-       return 0;
+       /* BFD peer went up. */
+       if (bss->state == BSS_UP && bss->previous_state == BSS_DOWN)
+               if (IS_DEBUG_OSPF(bfd, BFD_LIB))
+                       zlog_debug("%s: NSM[%s:%pI4]: BFD Up", __func__,
+                                  IF_NAME(nbr->oi), &nbr->address.u.prefix4);
 }
 
-/*
- * ospf_bfd_nbr_replay - Replay all the neighbors that have BFD enabled
- *                       to zebra
- */
-static int ospf_bfd_nbr_replay(ZAPI_CALLBACK_ARGS)
+void ospf_neighbor_bfd_apply(struct ospf_neighbor *nbr)
 {
-       struct listnode *inode, *node, *onode;
-       struct ospf *ospf;
-       struct ospf_interface *oi;
-       struct route_table *nbrs;
-       struct route_node *rn;
-       struct ospf_neighbor *nbr;
-       struct ospf_if_params *params;
+       struct ospf_interface *oi = nbr->oi;
+       struct ospf_if_params *oip = IF_DEF_PARAMS(oi->ifp);
 
-       if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE)) {
-               zlog_debug("Zebra: BFD Dest replay request");
+       /* BFD configuration was removed. */
+       if (oip->bfd_config == NULL) {
+               bfd_sess_free(&nbr->bfd_session);
+               return;
        }
 
-       /* Send the client registration */
-       bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, vrf_id);
-
-       /* Replay the neighbor, if BFD is enabled in OSPF */
-       for (ALL_LIST_ELEMENTS(om->ospf, node, onode, ospf)) {
-               for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, inode, oi)) {
-                       if ((nbrs = oi->nbrs) == NULL)
-                               continue;
-
-                       params = IF_DEF_PARAMS(oi->ifp);
-                       if (!params->bfd_info)
-                               continue;
-
-                       for (rn = route_top(nbrs); rn; rn = route_next(rn)) {
-                               if ((nbr = rn->info) == NULL
-                                   || nbr == oi->nbr_self)
-                                       continue;
+       /* New BFD session. */
+       if (nbr->bfd_session == NULL) {
+               nbr->bfd_session = bfd_sess_new(ospf_bfd_session_change, nbr);
+               bfd_sess_set_ipv4_addrs(nbr->bfd_session, NULL, &nbr->src);
+               bfd_sess_set_interface(nbr->bfd_session, oi->ifp->name);
+               bfd_sess_set_vrf(nbr->bfd_session, oi->ospf->vrf_id);
+               bfd_sess_enable(nbr->bfd_session, true);
+       }
 
-                               if (nbr->state < NSM_TwoWay)
-                                       continue;
+       /* Set new configuration. */
+       bfd_sess_set_timers(nbr->bfd_session,
+                           oip->bfd_config->detection_multiplier,
+                           oip->bfd_config->min_rx, oip->bfd_config->min_tx);
+       bfd_sess_set_profile(nbr->bfd_session, oip->bfd_config->profile);
 
-                               if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE))
-                                       zlog_debug("Replaying nbr (%pI4) to BFD",
-                                                  &nbr->src);
+       /* Don't start sessions on down OSPF sessions. */
+       if (nbr->state < NSM_TwoWay)
+               return;
 
-                               ospf_bfd_reg_dereg_nbr(nbr,
-                                                      ZEBRA_BFD_DEST_UPDATE);
-                       }
-               }
-       }
-       return 0;
+       bfd_sess_install(nbr->bfd_session);
 }
 
-/*
- * ospf_bfd_interface_dest_update - Find the neighbor for which the BFD status
- *                                  has changed and bring down the neighbor
- *                                  connectivity if the BFD status changed to
- *                                  down.
- */
-static int ospf_bfd_interface_dest_update(ZAPI_CALLBACK_ARGS)
+static void ospf_interface_bfd_apply(struct interface *ifp)
 {
-       struct interface *ifp;
        struct ospf_interface *oi;
-       struct ospf_if_params *params;
-       struct ospf_neighbor *nbr = NULL;
-       struct route_node *node;
-       struct route_node *n_node;
-       struct prefix p, src_p;
-       int status;
-       int old_status;
-       struct bfd_info *bfd_info;
-       struct timeval tv;
-
-       ifp = bfd_get_peer_info(zclient->ibuf, &p, &src_p, &status, NULL,
-                               vrf_id);
-
-       if ((ifp == NULL) || (p.family != AF_INET))
-               return 0;
-
-       if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE))
-               zlog_debug("Zebra: interface %s bfd destination %pFX %s",
-                          ifp->name, &p, bfd_get_status_str(status));
-
-       params = IF_DEF_PARAMS(ifp);
-       if (!params->bfd_info)
-               return 0;
-
-       for (node = route_top(IF_OIFS(ifp)); node; node = route_next(node)) {
-               if ((oi = node->info) == NULL)
-                       continue;
-
-               /* walk the neighbor list for point-to-point network */
-               if (oi->type == OSPF_IFTYPE_POINTOPOINT) {
-                       for (n_node = route_top(oi->nbrs); n_node;
-                               n_node = route_next(n_node)) {
-                               nbr = n_node->info;
-                               if (nbr) {
-                                       /* skip myself */
-                                       if (nbr == oi->nbr_self) {
-                                               nbr = NULL;
-                                               continue;
-                                       }
-
-                                       /* Found the matching neighbor */
-                                       if (nbr->src.s_addr ==
-                                               p.u.prefix4.s_addr)
-                                               break;
-                               }
-                       }
-               } else {
-                       nbr = ospf_nbr_lookup_by_addr(oi->nbrs, &p.u.prefix4);
-               }
+       struct route_table *nbrs;
+       struct ospf_neighbor *nbr;
+       struct route_node *irn;
+       struct route_node *nrn;
 
-               if (!nbr || !nbr->bfd_info)
+       /* Iterate over all interfaces and set neighbors BFD session. */
+       for (irn = route_top(IF_OIFS(ifp)); irn; irn = route_next(irn)) {
+               if ((oi = irn->info) == NULL)
                        continue;
-
-               bfd_info = (struct bfd_info *)nbr->bfd_info;
-               if (bfd_info->status == status)
+               if ((nbrs = oi->nbrs) == NULL)
                        continue;
+               for (nrn = route_top(nbrs); nrn; nrn = route_next(nrn)) {
+                       if ((nbr = nrn->info) == NULL || nbr == oi->nbr_self)
+                               continue;
 
-               old_status = bfd_info->status;
-               BFD_SET_CLIENT_STATUS(bfd_info->status, status);
-               monotime(&tv);
-               bfd_info->last_update = tv.tv_sec;
-
-               if ((status == BFD_STATUS_DOWN)
-                   && (old_status == BFD_STATUS_UP)) {
-                       if (IS_DEBUG_OSPF(nsm, NSM_EVENTS))
-                               zlog_debug("NSM[%s:%pI4]: BFD Down",
-                                          IF_NAME(nbr->oi),
-                                          &nbr->address.u.prefix4);
-
-                       OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_InactivityTimer);
-               }
-               if ((status == BFD_STATUS_UP)
-                   && (old_status == BFD_STATUS_DOWN)) {
-                       if (IS_DEBUG_OSPF(nsm, NSM_EVENTS))
-                               zlog_debug("NSM[%s:%pI4]: BFD Up",
-                                          IF_NAME(nbr->oi),
-                                          &nbr->address.u.prefix4);
+                       ospf_neighbor_bfd_apply(nbr);
                }
        }
-
-       return 0;
 }
 
-/*
- * ospf_bfd_info_nbr_create - Create/update BFD information for a neighbor.
- */
-void ospf_bfd_info_nbr_create(struct ospf_interface *oi,
-                             struct ospf_neighbor *nbr)
+static void ospf_interface_enable_bfd(struct interface *ifp)
 {
-       struct bfd_info *oi_bfd_info;
-       struct bfd_info *nbr_bfd_info;
-       struct interface *ifp = oi->ifp;
-       struct ospf_if_params *params;
-
-       /* Check if BFD is enabled */
-       params = IF_DEF_PARAMS(ifp);
+       struct ospf_if_params *oip = IF_DEF_PARAMS(ifp);
 
-       /* Check if BFD is enabled */
-       if (!params->bfd_info)
+       if (oip->bfd_config)
                return;
 
-       oi_bfd_info = (struct bfd_info *)params->bfd_info;
-       if (!nbr->bfd_info)
-               nbr->bfd_info = bfd_info_create();
+       /* Allocate memory for configurations and set defaults. */
+       oip->bfd_config = XCALLOC(MTYPE_BFD_CONFIG, sizeof(*oip->bfd_config));
+       oip->bfd_config->detection_multiplier = BFD_DEF_DETECT_MULT;
+       oip->bfd_config->min_rx = BFD_DEF_MIN_RX;
+       oip->bfd_config->min_tx = BFD_DEF_MIN_TX;
+}
 
-       nbr_bfd_info = (struct bfd_info *)nbr->bfd_info;
-       nbr_bfd_info->detect_mult = oi_bfd_info->detect_mult;
-       nbr_bfd_info->desired_min_tx = oi_bfd_info->desired_min_tx;
-       nbr_bfd_info->required_min_rx = oi_bfd_info->required_min_rx;
+void ospf_interface_disable_bfd(struct interface *ifp,
+                               struct ospf_if_params *oip)
+{
+       XFREE(MTYPE_BFD_CONFIG, oip->bfd_config);
+       ospf_interface_bfd_apply(ifp);
 }
 
 /*
  * ospf_bfd_write_config - Write the interface BFD configuration.
  */
-void ospf_bfd_write_config(struct vty *vty, struct ospf_if_params *params)
-
+void ospf_bfd_write_config(struct vty *vty, const struct ospf_if_params *params
+                          __attribute__((unused)))
 {
 #if HAVE_BFDD == 0
-       struct bfd_info *bfd_info;
-#endif /* ! HAVE_BFDD */
-
-       if (!params->bfd_info)
-               return;
-
-#if HAVE_BFDD == 0
-       bfd_info = (struct bfd_info *)params->bfd_info;
-
        if (CHECK_FLAG(bfd_info->flags, BFD_FLAG_PARAM_CFG))
-               vty_out(vty, " ip ospf bfd %d %d %d\n", bfd_info->detect_mult,
-                       bfd_info->required_min_rx, bfd_info->desired_min_tx);
+               vty_out(vty, " ip ospf bfd %d %d %d\n",
+                       params->bfd_config->detection_multiplier,
+                       params->bfd_config->min_rx, params->bfd_config->min_tx);
        else
 #endif /* ! HAVE_BFDD */
                vty_out(vty, " ip ospf bfd\n");
-}
 
-/*
- * ospf_bfd_show_info - Show BFD info structure
- */
-void ospf_bfd_show_info(struct vty *vty, void *bfd_info, json_object *json_obj,
-                       bool use_json, int param_only)
-{
-       if (param_only)
-               bfd_show_param(vty, (struct bfd_info *)bfd_info, 1, 0, use_json,
-                              json_obj);
-       else
-               bfd_show_info(vty, (struct bfd_info *)bfd_info, 0, 1, use_json,
-                             json_obj);
+       if (params->bfd_config->profile[0])
+               vty_out(vty, " ip ospf bfd profile %s\n",
+                       params->bfd_config->profile);
 }
 
-/*
- * ospf_bfd_interface_show - Show the interface BFD configuration.
- */
-void ospf_bfd_interface_show(struct vty *vty, struct interface *ifp,
-                            json_object *json_interface_sub, bool use_json)
+void ospf_interface_bfd_show(struct vty *vty, const struct interface *ifp,
+                            struct json_object *json)
 {
-       struct ospf_if_params *params;
-
-       params = IF_DEF_PARAMS(ifp);
+       struct ospf_if_params *params = IF_DEF_PARAMS(ifp);
+       struct bfd_configuration *bfd_config = params->bfd_config;
+       struct json_object *json_bfd;
 
-       ospf_bfd_show_info(vty, params->bfd_info, json_interface_sub, use_json,
-                          1);
-}
-
-/*
- * ospf_bfd_if_param_set - Set the configured BFD paramter values for
- *                         interface.
- */
-static void ospf_bfd_if_param_set(struct interface *ifp, uint32_t min_rx,
-                                 uint32_t min_tx, uint8_t detect_mult,
-                                 int defaults)
-{
-       struct ospf_if_params *params;
-       int command = 0;
-
-       params = IF_DEF_PARAMS(ifp);
+       if (bfd_config == NULL)
+               return;
 
-       bfd_set_param((struct bfd_info **)&(params->bfd_info), min_rx, min_tx,
-                     detect_mult, NULL, defaults, &command);
-       if (command)
-               ospf_bfd_reg_dereg_all_nbr(ifp, command);
+       if (json) {
+               json_bfd = json_object_new_object();
+               json_object_int_add(json_bfd, "detectionMultiplier",
+                                   bfd_config->detection_multiplier);
+               json_object_int_add(json_bfd, "rxMinInterval",
+                                   bfd_config->min_rx);
+               json_object_int_add(json_bfd, "txMinInterval",
+                                   bfd_config->min_tx);
+               json_object_object_add(json, "peerBfdInfo", json_bfd);
+       } else
+               vty_out(vty,
+                       "  BFD: Detect Multiplier: %d, Min Rx interval: %d, Min Tx interval: %d\n",
+                       bfd_config->detection_multiplier, bfd_config->min_rx,
+                       bfd_config->min_tx);
 }
 
 DEFUN (ip_ospf_bfd,
@@ -391,17 +213,8 @@ DEFUN (ip_ospf_bfd,
        "Enables BFD support\n")
 {
        VTY_DECLVAR_CONTEXT(interface, ifp);
-       struct ospf_if_params *params;
-       struct bfd_info *bfd_info;
-
-       assert(ifp);
-       params = IF_DEF_PARAMS(ifp);
-       bfd_info = params->bfd_info;
-
-       if (!bfd_info || !CHECK_FLAG(bfd_info->flags, BFD_FLAG_PARAM_CFG))
-               ospf_bfd_if_param_set(ifp, BFD_DEF_MIN_RX, BFD_DEF_MIN_TX,
-                                     BFD_DEF_DETECT_MULT, 1);
-
+       ospf_interface_enable_bfd(ifp);
+       ospf_interface_bfd_apply(ifp);
        return CMD_SUCCESS;
 }
 
@@ -421,23 +234,63 @@ DEFUN(
        "Desired min transmit interval\n")
 {
        VTY_DECLVAR_CONTEXT(interface, ifp);
+       struct ospf_if_params *params;
        int idx_number = 3;
        int idx_number_2 = 4;
        int idx_number_3 = 5;
-       uint32_t rx_val;
-       uint32_t tx_val;
-       uint8_t dm_val;
-       int ret;
 
-       assert(ifp);
+       ospf_interface_enable_bfd(ifp);
+
+       params = IF_DEF_PARAMS(ifp);
+       params->bfd_config->detection_multiplier =
+               strtol(argv[idx_number]->arg, NULL, 10);
+       params->bfd_config->min_rx = strtol(argv[idx_number_2]->arg, NULL, 10);
+       params->bfd_config->min_tx = strtol(argv[idx_number_3]->arg, NULL, 10);
+
+       ospf_interface_bfd_apply(ifp);
+
+       return CMD_SUCCESS;
+}
 
-       if ((ret = bfd_validate_param(
-                    vty, argv[idx_number]->arg, argv[idx_number_2]->arg,
-                    argv[idx_number_3]->arg, &dm_val, &rx_val, &tx_val))
-           != CMD_SUCCESS)
-               return ret;
+DEFUN (ip_ospf_bfd_prof,
+       ip_ospf_bfd_prof_cmd,
+       "ip ospf bfd profile BFDPROF",
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Enables BFD support\n"
+       BFD_PROFILE_STR
+       BFD_PROFILE_NAME_STR)
+{
+       VTY_DECLVAR_CONTEXT(interface, ifp);
+       struct ospf_if_params *params;
+       int idx_prof = 4;
 
-       ospf_bfd_if_param_set(ifp, rx_val, tx_val, dm_val, 0);
+       ospf_interface_enable_bfd(ifp);
+       params = IF_DEF_PARAMS(ifp);
+       strlcpy(params->bfd_config->profile, argv[idx_prof]->arg,
+               sizeof(params->bfd_config->profile));
+       ospf_interface_bfd_apply(ifp);
+
+       return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_ospf_bfd_prof,
+       no_ip_ospf_bfd_prof_cmd,
+       "no ip ospf bfd profile [BFDPROF]",
+       NO_STR
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Enables BFD support\n"
+       BFD_PROFILE_STR
+       BFD_PROFILE_NAME_STR)
+{
+       VTY_DECLVAR_CONTEXT(interface, ifp);
+       struct ospf_if_params *params;
+
+       ospf_interface_enable_bfd(ifp);
+       params = IF_DEF_PARAMS(ifp);
+       params->bfd_config->profile[0] = 0;
+       ospf_interface_bfd_apply(ifp);
 
        return CMD_SUCCESS;
 }
@@ -461,29 +314,18 @@ DEFUN (no_ip_ospf_bfd,
 )
 {
        VTY_DECLVAR_CONTEXT(interface, ifp);
-       struct ospf_if_params *params;
-
-       assert(ifp);
-
-       params = IF_DEF_PARAMS(ifp);
-       if (params->bfd_info) {
-               ospf_bfd_reg_dereg_all_nbr(ifp, ZEBRA_BFD_DEST_DEREGISTER);
-               bfd_info_free(&(params->bfd_info));
-       }
-
+       ospf_interface_disable_bfd(ifp, IF_DEF_PARAMS(ifp));
        return CMD_SUCCESS;
 }
 
-void ospf_bfd_init(void)
+void ospf_bfd_init(struct thread_master *tm)
 {
-       bfd_gbl_init();
-
-       /* Initialize BFD client functions */
-       zclient->interface_bfd_dest_update = ospf_bfd_interface_dest_update;
-       zclient->bfd_dest_replay = ospf_bfd_nbr_replay;
+       bfd_protocol_integration_init(zclient, tm);
 
        /* Install BFD command */
        install_element(INTERFACE_NODE, &ip_ospf_bfd_cmd);
        install_element(INTERFACE_NODE, &ip_ospf_bfd_param_cmd);
+       install_element(INTERFACE_NODE, &ip_ospf_bfd_prof_cmd);
+       install_element(INTERFACE_NODE, &no_ip_ospf_bfd_prof_cmd);
        install_element(INTERFACE_NODE, &no_ip_ospf_bfd_cmd);
 }
index 74385d326852f3d02c3460f5bc17fd084f8e3a5a..9393c839f501c69698f37e955c43c81095302f54 100644 (file)
 #ifndef _ZEBRA_OSPF_BFD_H
 #define _ZEBRA_OSPF_BFD_H
 
+#include "ospfd/ospf_interface.h"
 #include "json.h"
 
-extern void ospf_bfd_init(void);
+extern void ospf_bfd_init(struct thread_master *tm);
 
 extern void ospf_bfd_write_config(struct vty *vty,
-                                 struct ospf_if_params *params);
+                                 const struct ospf_if_params *params);
 
 extern void ospf_bfd_trigger_event(struct ospf_neighbor *nbr, int old_state,
                                   int state);
 
-extern void ospf_bfd_interface_show(struct vty *vty, struct interface *ifp,
-                                   json_object *json_interface_sub,
-                                   bool use_json);
-
-extern void ospf_bfd_info_nbr_create(struct ospf_interface *oi,
-                                    struct ospf_neighbor *nbr);
+/**
+ * Legacy information: it is the peers who actually have this information
+ * and the protocol should not need to know about timers.
+ */
+extern void ospf_interface_bfd_show(struct vty *vty,
+                                   const struct interface *ifp,
+                                   struct json_object *json);
 
-extern void ospf_bfd_show_info(struct vty *vty, void *bfd_info,
-                              json_object *json_obj, bool use_json,
-                              int param_only);
+/**
+ * Disables interface BFD configuration and remove settings from all peers.
+ */
+extern void ospf_interface_disable_bfd(struct interface *ifp,
+                                      struct ospf_if_params *oip);
 
-extern void ospf_bfd_info_free(void **bfd_info);
+/**
+ * Create/update BFD session for this OSPF neighbor.
+ */
+extern void ospf_neighbor_bfd_apply(struct ospf_neighbor *nbr);
 
 #endif /* _ZEBRA_OSPF_BFD_H */
index 19829d4546f0af66533db1941ebfa712a09f6e5a..2442f2e781c73030e00d47f3bd37e1490caea057 100644 (file)
@@ -21,6 +21,7 @@
 
 #include <zebra.h>
 
+#include "lib/bfd.h"
 #include "monotime.h"
 #include "linklist.h"
 #include "thread.h"
@@ -60,6 +61,7 @@ unsigned long conf_debug_ospf_ti_lfa = 0;
 unsigned long conf_debug_ospf_defaultinfo = 0;
 unsigned long conf_debug_ospf_ldp_sync = 0;
 unsigned long conf_debug_ospf_gr = 0;
+unsigned long conf_debug_ospf_bfd;
 
 /* Enable debug option variables -- valid only session. */
 unsigned long term_debug_ospf_packet[5] = {0, 0, 0, 0, 0};
@@ -76,6 +78,7 @@ unsigned long term_debug_ospf_ti_lfa = 0;
 unsigned long term_debug_ospf_defaultinfo;
 unsigned long term_debug_ospf_ldp_sync;
 unsigned long term_debug_ospf_gr = 0;
+unsigned long term_debug_ospf_bfd;
 
 const char *ospf_redist_string(unsigned int route_type)
 {
@@ -1563,6 +1566,31 @@ DEFPY (debug_ospf_gr,
        return CMD_SUCCESS;
 }
 
+DEFPY(debug_ospf_bfd, debug_ospf_bfd_cmd,
+      "[no] debug ospf bfd",
+      NO_STR
+      DEBUG_STR
+      OSPF_STR
+      "Bidirection Forwarding Detection\n")
+{
+       if (vty->node == CONFIG_NODE) {
+               if (no) {
+                       bfd_protocol_integration_set_debug(false);
+                       CONF_DEBUG_OFF(bfd, BFD_LIB);
+               } else {
+                       bfd_protocol_integration_set_debug(true);
+                       CONF_DEBUG_ON(bfd, BFD_LIB);
+               }
+       }
+
+       if (no)
+               TERM_DEBUG_OFF(bfd, BFD_LIB);
+       else
+               TERM_DEBUG_ON(bfd, BFD_LIB);
+
+       return CMD_SUCCESS;
+}
+
 DEFUN (no_debug_ospf,
        no_debug_ospf_cmd,
        "no debug ospf",
@@ -1594,6 +1622,10 @@ DEFUN (no_debug_ospf,
                DEBUG_OFF(defaultinfo, DEFAULTINFO);
                DEBUG_OFF(ldp_sync, LDP_SYNC);
 
+               /* BFD debugging is two parts: OSPF and library. */
+               DEBUG_OFF(bfd, BFD_LIB);
+               bfd_protocol_integration_set_debug(false);
+
                for (i = 0; i < 5; i++)
                        DEBUG_PACKET_OFF(i, flag);
        }
@@ -1621,6 +1653,7 @@ DEFUN (no_debug_ospf,
        TERM_DEBUG_OFF(zebra, ZEBRA_REDISTRIBUTE);
        TERM_DEBUG_OFF(defaultinfo, DEFAULTINFO);
        TERM_DEBUG_OFF(ldp_sync, LDP_SYNC);
+       TERM_DEBUG_OFF(bfd, BFD_LIB);
 
        return CMD_SUCCESS;
 }
@@ -1730,6 +1763,10 @@ static int show_debugging_ospf_common(struct vty *vty)
        if (IS_DEBUG_OSPF(gr, GR_HELPER) == OSPF_DEBUG_GR_HELPER)
                vty_out(vty, "  OSPF Graceful Restart Helper debugging is on\n");
 
+       if (IS_DEBUG_OSPF(bfd, BFD_LIB) == OSPF_DEBUG_BFD_LIB)
+               vty_out(vty,
+                       "  OSPF BFD integration library debugging is on\n");
+
        vty_out(vty, "\n");
 
        return CMD_SUCCESS;
@@ -1917,6 +1954,11 @@ static int config_write_debug(struct vty *vty)
                write = 1;
        }
 
+       if (IS_CONF_DEBUG_OSPF(bfd, BFD_LIB) == OSPF_DEBUG_BFD_LIB) {
+               vty_out(vty, "debug ospf%s bfd\n", str);
+               write = 1;
+       }
+
        return write;
 }
 
@@ -1949,6 +1991,7 @@ void ospf_debug_init(void)
        install_element(ENABLE_NODE, &no_debug_ospf_default_info_cmd);
        install_element(ENABLE_NODE, &no_debug_ospf_ldp_sync_cmd);
        install_element(ENABLE_NODE, &debug_ospf_gr_cmd);
+       install_element(ENABLE_NODE, &debug_ospf_bfd_cmd);
 
        install_element(ENABLE_NODE, &show_debugging_ospf_instance_cmd);
        install_element(ENABLE_NODE, &debug_ospf_packet_cmd);
@@ -1992,6 +2035,7 @@ void ospf_debug_init(void)
        install_element(CONFIG_NODE, &no_debug_ospf_default_info_cmd);
        install_element(CONFIG_NODE, &no_debug_ospf_ldp_sync_cmd);
        install_element(CONFIG_NODE, &debug_ospf_gr_cmd);
+       install_element(CONFIG_NODE, &debug_ospf_bfd_cmd);
 
        install_element(CONFIG_NODE, &debug_ospf_instance_nsm_cmd);
        install_element(CONFIG_NODE, &debug_ospf_instance_lsa_cmd);
index c4c560666367d6b3db9ae5d931c89bd9eda523c8..b1c1d02a5115472766c906e281a5af92932c2456 100644 (file)
@@ -67,6 +67,8 @@
 #define OSPF_DEBUG_GR_HELPER 0x01
 #define OSPF_DEBUG_GR 0x03
 
+#define OSPF_DEBUG_BFD_LIB 0x01
+
 /* Macro for setting debug option. */
 #define CONF_DEBUG_PACKET_ON(a, b)         conf_debug_ospf_packet[a] |= (b)
 #define CONF_DEBUG_PACKET_OFF(a, b)        conf_debug_ospf_packet[a] &= ~(b)
@@ -140,6 +142,7 @@ extern unsigned long term_debug_ospf_ti_lfa;
 extern unsigned long term_debug_ospf_defaultinfo;
 extern unsigned long term_debug_ospf_ldp_sync;
 extern unsigned long term_debug_ospf_gr;
+extern unsigned long term_debug_ospf_bfd;
 
 /* Message Strings. */
 extern char *ospf_lsa_type_str[];
index 51599ccc8a350f5a9ef5a779e2e90b3816b3252b..d494f0fbce5dacb271fec9d51c60a8b86f2b5946 100644 (file)
@@ -35,6 +35,7 @@
 #include "ldp_sync.h"
 
 #include "ospfd/ospfd.h"
+#include "ospfd/ospf_bfd.h"
 #include "ospfd/ospf_spf.h"
 #include "ospfd/ospf_interface.h"
 #include "ospfd/ospf_ism.h"
 #include "ospfd/ospf_dump.h"
 #include "ospfd/ospf_ldp_sync.h"
 
-DEFINE_QOBJ_TYPE(ospf_interface)
-DEFINE_HOOK(ospf_vl_add, (struct ospf_vl_data * vd), (vd))
-DEFINE_HOOK(ospf_vl_delete, (struct ospf_vl_data * vd), (vd))
-DEFINE_HOOK(ospf_if_update, (struct interface * ifp), (ifp))
-DEFINE_HOOK(ospf_if_delete, (struct interface * ifp), (ifp))
+DEFINE_QOBJ_TYPE(ospf_interface);
+DEFINE_HOOK(ospf_vl_add, (struct ospf_vl_data * vd), (vd));
+DEFINE_HOOK(ospf_vl_delete, (struct ospf_vl_data * vd), (vd));
+DEFINE_HOOK(ospf_if_update, (struct interface * ifp), (ifp));
+DEFINE_HOOK(ospf_if_delete, (struct interface * ifp), (ifp));
 
 int ospf_interface_neighbor_count(struct ospf_interface *oi)
 {
@@ -545,10 +546,11 @@ static struct ospf_if_params *ospf_new_if_params(void)
        return oip;
 }
 
-void ospf_del_if_params(struct ospf_if_params *oip)
+static void ospf_del_if_params(struct interface *ifp,
+                              struct ospf_if_params *oip)
 {
        list_delete(&oip->auth_crypt);
-       bfd_info_free(&(oip->bfd_info));
+       ospf_interface_disable_bfd(ifp, oip);
        ldp_sync_info_free(&(oip->ldp_sync_info));
        XFREE(MTYPE_OSPF_IF_PARAMS, oip);
 }
@@ -582,7 +584,7 @@ void ospf_free_if_params(struct interface *ifp, struct in_addr addr)
            && !OSPF_IF_PARAM_CONFIGURED(oip, auth_type)
            && !OSPF_IF_PARAM_CONFIGURED(oip, if_area)
            && listcount(oip->auth_crypt) == 0) {
-               ospf_del_if_params(oip);
+               ospf_del_if_params(ifp, oip);
                rn->info = NULL;
                route_unlock_node(rn);
        }
@@ -696,10 +698,10 @@ static int ospf_if_delete_hook(struct interface *ifp)
 
        for (rn = route_top(IF_OIFS_PARAMS(ifp)); rn; rn = route_next(rn))
                if (rn->info)
-                       ospf_del_if_params(rn->info);
+                       ospf_del_if_params(ifp, rn->info);
        route_table_finish(IF_OIFS_PARAMS(ifp));
 
-       ospf_del_if_params((struct ospf_if_params *)IF_DEF_PARAMS(ifp));
+       ospf_del_if_params(ifp, IF_DEF_PARAMS(ifp));
        XFREE(MTYPE_OSPF_IF_INFO, ifp->info);
 
        return rc;
index bf59af16c2cd2f063fd921d564f2b983ad9d20c3..a9534f543d53a5845eceee76ca6573b50320dde2 100644 (file)
@@ -22,6 +22,7 @@
 #ifndef _ZEBRA_OSPF_INTERFACE_H
 #define _ZEBRA_OSPF_INTERFACE_H
 
+#include "lib/bfd.h"
 #include "qobj.h"
 #include "hook.h"
 #include "ospfd/ospf_packet.h"
@@ -104,7 +105,16 @@ struct ospf_if_params {
        uint32_t network_lsa_seqnum; /* Network LSA seqnum */
 
        /* BFD configuration */
-       struct bfd_info *bfd_info;
+       struct bfd_configuration {
+               /** BFD session detection multiplier. */
+               uint8_t detection_multiplier;
+               /** BFD session minimum required receive interval. */
+               uint32_t min_rx;
+               /** BFD session minimum required transmission interval. */
+               uint32_t min_tx;
+               /** BFD profile. */
+               char profile[BFD_PROFILE_NAME_LEN];
+       } *bfd_config;
 
        /* MPLS LDP-IGP Sync configuration */
        struct ldp_sync_info *ldp_sync_info;
@@ -252,9 +262,9 @@ struct ospf_interface {
 
        uint32_t full_nbrs;
 
-       QOBJ_FIELDS
+       QOBJ_FIELDS;
 };
-DECLARE_QOBJ_TYPE(ospf_interface)
+DECLARE_QOBJ_TYPE(ospf_interface);
 
 /* Prototypes. */
 extern char *ospf_if_name(struct ospf_interface *);
@@ -285,7 +295,6 @@ extern struct ospf_if_params *ospf_lookup_if_params(struct interface *,
                                                    struct in_addr);
 extern struct ospf_if_params *ospf_get_if_params(struct interface *,
                                                 struct in_addr);
-extern void ospf_del_if_params(struct ospf_if_params *);
 extern void ospf_free_if_params(struct interface *, struct in_addr);
 extern void ospf_if_update_params(struct interface *, struct in_addr);
 
@@ -329,10 +338,10 @@ extern void ospf_if_set_multicast(struct ospf_interface *);
 
 extern void ospf_if_interface(struct interface *ifp);
 
-DECLARE_HOOK(ospf_vl_add, (struct ospf_vl_data * vd), (vd))
-DECLARE_HOOK(ospf_vl_delete, (struct ospf_vl_data * vd), (vd))
+DECLARE_HOOK(ospf_vl_add, (struct ospf_vl_data * vd), (vd));
+DECLARE_HOOK(ospf_vl_delete, (struct ospf_vl_data * vd), (vd));
 
-DECLARE_HOOK(ospf_if_update, (struct interface * ifp), (ifp))
-DECLARE_HOOK(ospf_if_delete, (struct interface * ifp), (ifp))
+DECLARE_HOOK(ospf_if_update, (struct interface * ifp), (ifp));
+DECLARE_HOOK(ospf_if_delete, (struct interface * ifp), (ifp));
 
 #endif /* _ZEBRA_OSPF_INTERFACE_H */
index 36e97f877906de225d4369006fa559c5886e0e4d..1850d946b8691ec7bcf8a3b915536ecca66cffa2 100644 (file)
@@ -45,7 +45,7 @@
 
 DEFINE_HOOK(ospf_ism_change,
            (struct ospf_interface * oi, int state, int oldstate),
-           (oi, state, oldstate))
+           (oi, state, oldstate));
 
 /* elect DR and BDR. Refer to RFC2319 section 9.4 */
 static struct ospf_neighbor *ospf_dr_election_sub(struct list *routers)
index c41ba6c843e6e7f5cf068f43f71c23d0ede14d12..5d0f95aed1ab320d4afe60d3f58705a8e0727802 100644 (file)
@@ -97,6 +97,6 @@ extern int ospf_dr_election(struct ospf_interface *oi);
 
 DECLARE_HOOK(ospf_ism_change,
             (struct ospf_interface * oi, int state, int oldstate),
-            (oi, state, oldstate))
+            (oi, state, oldstate));
 
 #endif /* _ZEBRA_OSPF_ISM_H */
index 6a90dbff115a274d29528d18993efc42951287d2..d23dea0ca1506f1d472f0b76bce71327781267a2 100644 (file)
@@ -22,6 +22,7 @@
 #include <zebra.h>
 
 #include <lib/version.h>
+#include "bfd.h"
 #include "getopt.h"
 #include "thread.h"
 #include "prefix.h"
@@ -98,6 +99,7 @@ static void sighup(void)
 static void sigint(void)
 {
        zlog_notice("Terminating on signal");
+       bfd_protocol_integration_set_shutdown(true);
        ospf_terminate();
        exit(0);
 }
@@ -141,7 +143,8 @@ FRR_DAEMON_INFO(ospfd, OSPF, .vty_port = OSPF_VTY_PORT,
                .signals = ospf_signals, .n_signals = array_size(ospf_signals),
 
                .privs = &ospfd_privs, .yang_modules = ospfd_yang_modules,
-               .n_yang_modules = array_size(ospfd_yang_modules), )
+               .n_yang_modules = array_size(ospfd_yang_modules),
+);
 
 /* OSPFd main routine. */
 int main(int argc, char **argv)
@@ -213,7 +216,7 @@ int main(int argc, char **argv)
        ospf_vty_clear_init();
 
        /* OSPF BFD init */
-       ospf_bfd_init();
+       ospf_bfd_init(master);
 
        /* OSPF LDP IGP Sync init */
        ospf_ldp_sync_init();
index f4fb68cbdfb0a2438b77e08147a225e891148a92..28384438923f46de2a8de24d39e34f545bf07949 100644 (file)
 
 #include "ospf_memory.h"
 
-DEFINE_MGROUP(OSPFD, "ospfd")
-DEFINE_MTYPE(OSPFD, OSPF_TOP, "OSPF top")
-DEFINE_MTYPE(OSPFD, OSPF_AREA, "OSPF area")
-DEFINE_MTYPE(OSPFD, OSPF_AREA_RANGE, "OSPF area range")
-DEFINE_MTYPE(OSPFD, OSPF_NETWORK, "OSPF network")
-DEFINE_MTYPE(OSPFD, OSPF_NEIGHBOR_STATIC, "OSPF static nbr")
-DEFINE_MTYPE(OSPFD, OSPF_IF, "OSPF interface")
-DEFINE_MTYPE(OSPFD, OSPF_NEIGHBOR, "OSPF neighbor")
-DEFINE_MTYPE(OSPFD, OSPF_ROUTE, "OSPF route")
-DEFINE_MTYPE(OSPFD, OSPF_TMP, "OSPF tmp mem")
-DEFINE_MTYPE(OSPFD, OSPF_LSA, "OSPF LSA")
-DEFINE_MTYPE(OSPFD, OSPF_LSA_DATA, "OSPF LSA data")
-DEFINE_MTYPE(OSPFD, OSPF_LSDB, "OSPF LSDB")
-DEFINE_MTYPE(OSPFD, OSPF_PACKET, "OSPF packet")
-DEFINE_MTYPE(OSPFD, OSPF_FIFO, "OSPF FIFO queue")
-DEFINE_MTYPE(OSPFD, OSPF_VERTEX, "OSPF vertex")
-DEFINE_MTYPE(OSPFD, OSPF_VERTEX_PARENT, "OSPF vertex parent")
-DEFINE_MTYPE(OSPFD, OSPF_NEXTHOP, "OSPF nexthop")
-DEFINE_MTYPE(OSPFD, OSPF_PATH, "OSPF path")
-DEFINE_MTYPE(OSPFD, OSPF_VL_DATA, "OSPF VL data")
-DEFINE_MTYPE(OSPFD, OSPF_CRYPT_KEY, "OSPF crypt key")
-DEFINE_MTYPE(OSPFD, OSPF_EXTERNAL_INFO, "OSPF ext. info")
-DEFINE_MTYPE(OSPFD, OSPF_DISTANCE, "OSPF distance")
-DEFINE_MTYPE(OSPFD, OSPF_IF_INFO, "OSPF if info")
-DEFINE_MTYPE(OSPFD, OSPF_IF_PARAMS, "OSPF if params")
-DEFINE_MTYPE(OSPFD, OSPF_MESSAGE, "OSPF message")
-DEFINE_MTYPE(OSPFD, OSPF_MPLS_TE, "OSPF MPLS parameters")
-DEFINE_MTYPE(OSPFD, OSPF_ROUTER_INFO, "OSPF Router Info parameters")
-DEFINE_MTYPE(OSPFD, OSPF_PCE_PARAMS, "OSPF PCE parameters")
-DEFINE_MTYPE(OSPFD, OSPF_EXT_PARAMS, "OSPF Extended parameters")
-DEFINE_MTYPE(OSPFD, OSPF_SR_PARAMS, "OSPF Segment Routing parameters")
-DEFINE_MTYPE(OSPFD, OSPF_GR_HELPER, "OSPF Graceful Restart Helper")
-DEFINE_MTYPE(OSPFD, OSPF_EXTERNAL_RT_AGGR, "OSPF External Route Summarisation")
-DEFINE_MTYPE(OSPFD, OSPF_P_SPACE, "OSPF TI-LFA P-Space")
-DEFINE_MTYPE(OSPFD, OSPF_Q_SPACE, "OSPF TI-LFA Q-Space")
+DEFINE_MGROUP(OSPFD, "ospfd");
+DEFINE_MTYPE(OSPFD, OSPF_TOP, "OSPF top");
+DEFINE_MTYPE(OSPFD, OSPF_AREA, "OSPF area");
+DEFINE_MTYPE(OSPFD, OSPF_AREA_RANGE, "OSPF area range");
+DEFINE_MTYPE(OSPFD, OSPF_NETWORK, "OSPF network");
+DEFINE_MTYPE(OSPFD, OSPF_NEIGHBOR_STATIC, "OSPF static nbr");
+DEFINE_MTYPE(OSPFD, OSPF_IF, "OSPF interface");
+DEFINE_MTYPE(OSPFD, OSPF_NEIGHBOR, "OSPF neighbor");
+DEFINE_MTYPE(OSPFD, OSPF_ROUTE, "OSPF route");
+DEFINE_MTYPE(OSPFD, OSPF_TMP, "OSPF tmp mem");
+DEFINE_MTYPE(OSPFD, OSPF_LSA, "OSPF LSA");
+DEFINE_MTYPE(OSPFD, OSPF_LSA_DATA, "OSPF LSA data");
+DEFINE_MTYPE(OSPFD, OSPF_LSDB, "OSPF LSDB");
+DEFINE_MTYPE(OSPFD, OSPF_PACKET, "OSPF packet");
+DEFINE_MTYPE(OSPFD, OSPF_FIFO, "OSPF FIFO queue");
+DEFINE_MTYPE(OSPFD, OSPF_VERTEX, "OSPF vertex");
+DEFINE_MTYPE(OSPFD, OSPF_VERTEX_PARENT, "OSPF vertex parent");
+DEFINE_MTYPE(OSPFD, OSPF_NEXTHOP, "OSPF nexthop");
+DEFINE_MTYPE(OSPFD, OSPF_PATH, "OSPF path");
+DEFINE_MTYPE(OSPFD, OSPF_VL_DATA, "OSPF VL data");
+DEFINE_MTYPE(OSPFD, OSPF_CRYPT_KEY, "OSPF crypt key");
+DEFINE_MTYPE(OSPFD, OSPF_EXTERNAL_INFO, "OSPF ext. info");
+DEFINE_MTYPE(OSPFD, OSPF_DISTANCE, "OSPF distance");
+DEFINE_MTYPE(OSPFD, OSPF_IF_INFO, "OSPF if info");
+DEFINE_MTYPE(OSPFD, OSPF_IF_PARAMS, "OSPF if params");
+DEFINE_MTYPE(OSPFD, OSPF_MESSAGE, "OSPF message");
+DEFINE_MTYPE(OSPFD, OSPF_MPLS_TE, "OSPF MPLS parameters");
+DEFINE_MTYPE(OSPFD, OSPF_ROUTER_INFO, "OSPF Router Info parameters");
+DEFINE_MTYPE(OSPFD, OSPF_PCE_PARAMS, "OSPF PCE parameters");
+DEFINE_MTYPE(OSPFD, OSPF_EXT_PARAMS, "OSPF Extended parameters");
+DEFINE_MTYPE(OSPFD, OSPF_SR_PARAMS, "OSPF Segment Routing parameters");
+DEFINE_MTYPE(OSPFD, OSPF_GR_HELPER, "OSPF Graceful Restart Helper");
+DEFINE_MTYPE(OSPFD, OSPF_EXTERNAL_RT_AGGR, "OSPF External Route Summarisation");
+DEFINE_MTYPE(OSPFD, OSPF_P_SPACE, "OSPF TI-LFA P-Space");
+DEFINE_MTYPE(OSPFD, OSPF_Q_SPACE, "OSPF TI-LFA Q-Space");
index 42bc8d7b77751c6b3996adc13c6a02edc467c9c8..9bd0a844af8159990834658bc3512f23cc2c725b 100644 (file)
 
 #include "memory.h"
 
-DECLARE_MGROUP(OSPFD)
-DECLARE_MTYPE(OSPF_TOP)
-DECLARE_MTYPE(OSPF_AREA)
-DECLARE_MTYPE(OSPF_AREA_RANGE)
-DECLARE_MTYPE(OSPF_NETWORK)
-DECLARE_MTYPE(OSPF_NEIGHBOR_STATIC)
-DECLARE_MTYPE(OSPF_IF)
-DECLARE_MTYPE(OSPF_NEIGHBOR)
-DECLARE_MTYPE(OSPF_ROUTE)
-DECLARE_MTYPE(OSPF_TMP)
-DECLARE_MTYPE(OSPF_LSA)
-DECLARE_MTYPE(OSPF_LSA_DATA)
-DECLARE_MTYPE(OSPF_LSDB)
-DECLARE_MTYPE(OSPF_PACKET)
-DECLARE_MTYPE(OSPF_FIFO)
-DECLARE_MTYPE(OSPF_VERTEX)
-DECLARE_MTYPE(OSPF_VERTEX_PARENT)
-DECLARE_MTYPE(OSPF_NEXTHOP)
-DECLARE_MTYPE(OSPF_PATH)
-DECLARE_MTYPE(OSPF_VL_DATA)
-DECLARE_MTYPE(OSPF_CRYPT_KEY)
-DECLARE_MTYPE(OSPF_EXTERNAL_INFO)
-DECLARE_MTYPE(OSPF_DISTANCE)
-DECLARE_MTYPE(OSPF_IF_INFO)
-DECLARE_MTYPE(OSPF_IF_PARAMS)
-DECLARE_MTYPE(OSPF_MESSAGE)
-DECLARE_MTYPE(OSPF_MPLS_TE)
-DECLARE_MTYPE(OSPF_ROUTER_INFO)
-DECLARE_MTYPE(OSPF_PCE_PARAMS)
-DECLARE_MTYPE(OSPF_SR_PARAMS)
-DECLARE_MTYPE(OSPF_EXT_PARAMS)
-DECLARE_MTYPE(OSPF_GR_HELPER)
-DECLARE_MTYPE(OSPF_EXTERNAL_RT_AGGR)
-DECLARE_MTYPE(OSPF_P_SPACE)
-DECLARE_MTYPE(OSPF_Q_SPACE)
+DECLARE_MGROUP(OSPFD);
+DECLARE_MTYPE(OSPF_TOP);
+DECLARE_MTYPE(OSPF_AREA);
+DECLARE_MTYPE(OSPF_AREA_RANGE);
+DECLARE_MTYPE(OSPF_NETWORK);
+DECLARE_MTYPE(OSPF_NEIGHBOR_STATIC);
+DECLARE_MTYPE(OSPF_IF);
+DECLARE_MTYPE(OSPF_NEIGHBOR);
+DECLARE_MTYPE(OSPF_ROUTE);
+DECLARE_MTYPE(OSPF_TMP);
+DECLARE_MTYPE(OSPF_LSA);
+DECLARE_MTYPE(OSPF_LSA_DATA);
+DECLARE_MTYPE(OSPF_LSDB);
+DECLARE_MTYPE(OSPF_PACKET);
+DECLARE_MTYPE(OSPF_FIFO);
+DECLARE_MTYPE(OSPF_VERTEX);
+DECLARE_MTYPE(OSPF_VERTEX_PARENT);
+DECLARE_MTYPE(OSPF_NEXTHOP);
+DECLARE_MTYPE(OSPF_PATH);
+DECLARE_MTYPE(OSPF_VL_DATA);
+DECLARE_MTYPE(OSPF_CRYPT_KEY);
+DECLARE_MTYPE(OSPF_EXTERNAL_INFO);
+DECLARE_MTYPE(OSPF_DISTANCE);
+DECLARE_MTYPE(OSPF_IF_INFO);
+DECLARE_MTYPE(OSPF_IF_PARAMS);
+DECLARE_MTYPE(OSPF_MESSAGE);
+DECLARE_MTYPE(OSPF_MPLS_TE);
+DECLARE_MTYPE(OSPF_ROUTER_INFO);
+DECLARE_MTYPE(OSPF_PCE_PARAMS);
+DECLARE_MTYPE(OSPF_SR_PARAMS);
+DECLARE_MTYPE(OSPF_EXT_PARAMS);
+DECLARE_MTYPE(OSPF_GR_HELPER);
+DECLARE_MTYPE(OSPF_EXTERNAL_RT_AGGR);
+DECLARE_MTYPE(OSPF_P_SPACE);
+DECLARE_MTYPE(OSPF_Q_SPACE);
 
 #endif /* _QUAGGA_OSPF_MEMORY_H */
index 2fa43923ab3c5cbe4bfdaeaba58ce9d853a06867..a1b35b2fcd2bd912fc99fc16c3ef4d681373505f 100644 (file)
@@ -21,6 +21,7 @@
 
 #include <zebra.h>
 
+#include "lib/bfd.h"
 #include "linklist.h"
 #include "prefix.h"
 #include "memory.h"
@@ -99,8 +100,6 @@ struct ospf_neighbor *ospf_nbr_new(struct ospf_interface *oi)
 
        nbr->crypt_seqnum = 0;
 
-       ospf_bfd_info_nbr_create(oi, nbr);
-
        /* Initialize GR Helper info*/
        nbr->gr_helper_info.recvd_grace_period = 0;
        nbr->gr_helper_info.actual_grace_period = 0;
@@ -149,7 +148,7 @@ void ospf_nbr_free(struct ospf_neighbor *nbr)
        /* Cancel all events. */ /* Thread lookup cost would be negligible. */
        thread_cancel_event(master, nbr);
 
-       ospf_bfd_info_free(&nbr->bfd_info);
+       bfd_sess_free(&nbr->bfd_session);
 
        OSPF_NSM_TIMER_OFF(nbr->gr_helper_info.t_grace_timer);
 
@@ -458,6 +457,9 @@ static struct ospf_neighbor *ospf_nbr_add(struct ospf_interface *oi,
        if (ntohs(ospfh->auth_type) == OSPF_AUTH_CRYPTOGRAPHIC)
                nbr->crypt_seqnum = ospfh->u.crypt.crypt_seqnum;
 
+       /* Configure BFD if interface has it. */
+       ospf_neighbor_bfd_apply(nbr);
+
        if (IS_DEBUG_OSPF_EVENT)
                zlog_debug("NSM[%s:%pI4]: start", IF_NAME(oi),
                           &nbr->router_id);
index 758693e28948fd79f72c07e807d550c66c2984c1..2ce6d6755c9dbb5920bab606cc3575b564b03b40 100644 (file)
@@ -88,7 +88,7 @@ struct ospf_neighbor {
        uint32_t state_change;           /* NSM state change counter       */
 
        /* BFD information */
-       void *bfd_info;
+       struct bfd_session_params *bfd_session;
 
        /* ospf graceful restart HELPER info */
        struct ospf_helper_info gr_helper_info;
index 26e7855e8c86e910ca696154841e7e75744c3389..006c4888aeb654c8ed54febf58f82b666d5f1033 100644 (file)
@@ -53,7 +53,7 @@
 
 DEFINE_HOOK(ospf_nsm_change,
            (struct ospf_neighbor * on, int state, int oldstate),
-           (on, state, oldstate))
+           (on, state, oldstate));
 
 static void nsm_clear_adj(struct ospf_neighbor *);
 
@@ -761,7 +761,8 @@ static void nsm_change_state(struct ospf_neighbor *nbr, int state)
        if (state == NSM_Down)
                nbr->crypt_seqnum = 0;
 
-       ospf_bfd_trigger_event(nbr, old_state, state);
+       if (nbr->bfd_session)
+               ospf_bfd_trigger_event(nbr, old_state, state);
 
        /* Preserve old status? */
 }
index 24cf05009ce231b4caaba777c6988fa3f77450b4..e8573c6301a5b863ae129c4915b72b275c0002de 100644 (file)
@@ -78,6 +78,6 @@ extern void ospf_db_summary_clear(struct ospf_neighbor *);
 extern int nsm_should_adj(struct ospf_neighbor *nbr);
 DECLARE_HOOK(ospf_nsm_change,
             (struct ospf_neighbor * on, int state, int oldstate),
-            (on, state, oldstate))
+            (on, state, oldstate));
 
 #endif /* _ZEBRA_OSPF_NSM_H */
index 3939b5479f13b3302c1ae1789ca120ad3685bdab..ae9ab48d4a262a2c54f8e2919462d0972131e212 100644 (file)
@@ -56,9 +56,9 @@
 #include "ospfd/ospf_ext.h"
 #include "ospfd/ospf_errors.h"
 
-DEFINE_MTYPE_STATIC(OSPFD, OSPF_OPAQUE_FUNCTAB, "OSPF opaque function table")
-DEFINE_MTYPE_STATIC(OSPFD, OPAQUE_INFO_PER_TYPE, "OSPF opaque per-type info")
-DEFINE_MTYPE_STATIC(OSPFD, OPAQUE_INFO_PER_ID, "OSPF opaque per-ID info")
+DEFINE_MTYPE_STATIC(OSPFD, OSPF_OPAQUE_FUNCTAB, "OSPF opaque function table");
+DEFINE_MTYPE_STATIC(OSPFD, OPAQUE_INFO_PER_TYPE, "OSPF opaque per-type info");
+DEFINE_MTYPE_STATIC(OSPFD, OPAQUE_INFO_PER_ID, "OSPF opaque per-ID info");
 
 /*------------------------------------------------------------------------*
  * Followings are initialize/terminate functions for Opaque-LSAs handling.
index 3f4ca44b0504b187fc481bf933d5074cb35366ab..8418bbf2b948ef5c6262393ddbfdc6022a841e5e 100644 (file)
@@ -2565,4 +2565,5 @@ static int ospf_snmp_module_init(void)
 
 FRR_MODULE_SETUP(.name = "ospfd_snmp", .version = FRR_VERSION,
                 .description = "ospfd AgentX SNMP module",
-                .init = ospf_snmp_module_init, )
+                .init = ospf_snmp_module_init,
+);
index 6cd6a47098fe82f85a5a2ef75138387f67d009fd..1e0814764bb5bc3ee583d25bf8faeda96a02255e 100644 (file)
@@ -89,7 +89,7 @@ static int vertex_cmp(const struct vertex *v1, const struct vertex *v2)
        }
        return 0;
 }
-DECLARE_SKIPLIST_NONUNIQ(vertex_pqueue, struct vertex, pqi, vertex_cmp)
+DECLARE_SKIPLIST_NONUNIQ(vertex_pqueue, struct vertex, pqi, vertex_cmp);
 
 static void lsdb_clean_stat(struct ospf_lsdb *lsdb)
 {
index 66555be4b705ffd22916254aba104ae0fe962de0..835caab288ea945f90cb377c7f60a48ae04db68b 100644 (file)
@@ -33,7 +33,7 @@
 
 /* The "root" is the node running the SPF calculation */
 
-PREDECL_SKIPLIST_NONUNIQ(vertex_pqueue)
+PREDECL_SKIPLIST_NONUNIQ(vertex_pqueue);
 /* A router or network in an area */
 struct vertex {
        struct vertex_pqueue_item pqi;
index 4a0186bfb917ab4bbb76d9b602bf583a3d85faf2..59b3b624e3903f016130172c440aec9b2c394a62 100644 (file)
@@ -37,9 +37,9 @@
 
 
 DECLARE_RBTREE_UNIQ(p_spaces, struct p_space, p_spaces_item,
-                   p_spaces_compare_func)
+                   p_spaces_compare_func);
 DECLARE_RBTREE_UNIQ(q_spaces, struct q_space, q_spaces_item,
-                   q_spaces_compare_func)
+                   q_spaces_compare_func);
 
 static void
 ospf_ti_lfa_generate_p_space(struct ospf_area *area, struct vertex *child,
index 2ff59ccf49b0a4acfe29748a83a6fb2dddcde415..e6835ffc72060bec936a9629847585d1e521251e 100644 (file)
@@ -60,7 +60,7 @@
 FRR_CFG_DEFAULT_BOOL(OSPF_LOG_ADJACENCY_CHANGES,
        { .val_bool = true, .match_profile = "datacenter", },
        { .val_bool = false },
-)
+);
 
 static const char *const ospf_network_type_str[] = {
        "Null", "POINTOPOINT", "BROADCAST", "NBMA", "POINTOMULTIPOINT",
@@ -3776,7 +3776,8 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf,
                                "  Neighbor Count is %d, Adjacent neighbor count is %d\n",
                                ospf_nbr_count(oi, 0),
                                ospf_nbr_count(oi, NSM_Full));
-               ospf_bfd_interface_show(vty, ifp, json_interface_sub, use_json);
+
+               ospf_interface_bfd_show(vty, ifp, json_interface_sub);
 
                /* OSPF Authentication information */
                ospf_interface_auth_show(vty, oi, json_interface_sub, use_json);
@@ -5282,7 +5283,7 @@ static void show_ip_ospf_neighbor_detail_sub(struct vty *vty,
                                                 .helper_exit_reason));
        }
 
-       ospf_bfd_show_info(vty, nbr->bfd_info, json_neigh, use_json, 0);
+       bfd_sess_show(vty, json_neigh, nbr->bfd_session);
 
        if (use_json)
                json_object_array_add(json_neigh_array, json_neigh);
@@ -7109,14 +7110,14 @@ DEFUN (show_ip_ospf_database_max,
        return ret;
 }
 
-DEFUN (show_ip_ospf_instance_database,
-       show_ip_ospf_instance_database_cmd,
-       "show ip ospf [{(1-65535)|vrf NAME}] database [<asbr-summary|external|network|router|summary|nssa-external|opaque-link|opaque-area|opaque-as> [A.B.C.D [<self-originate|adv-router A.B.C.D>]]] [json]",
+ALIAS (show_ip_ospf_database_max,
+       show_ip_ospf_database_cmd,
+       "show ip ospf [vrf <NAME|all>] database [<asbr-summary|external|network|router|summary|nssa-external|opaque-link|opaque-area|opaque-as> [A.B.C.D [<self-originate|adv-router A.B.C.D>]]] [json]",
        SHOW_STR
        IP_STR
        "OSPF information\n"
-       "Instance ID\n"
        VRF_CMD_HELP_STR
+       "All VRFs\n"
        "Database summary\n"
         OSPF_LSA_TYPES_DESC
        "Link State ID (as an IP address)\n"
@@ -7124,78 +7125,6 @@ DEFUN (show_ip_ospf_instance_database,
        "Advertising Router link states\n"
        "Advertising Router (as an IP address)\n"
        JSON_STR)
-{
-       struct ospf *ospf;
-       unsigned short instance = 0;
-       struct listnode *node = NULL;
-       char *vrf_name = NULL;
-       bool all_vrf = false;
-       int ret = CMD_SUCCESS;
-       int inst = 0;
-       int idx = 0;
-       uint8_t use_vrf = 0;
-       bool uj = use_json(argc, argv);
-       json_object *json = NULL;
-
-       if (uj)
-               json = json_object_new_object();
-
-       if (argv_find(argv, argc, "(1-65535)", &idx)) {
-               instance = strtoul(argv[idx]->arg, NULL, 10);
-               if (instance != ospf_instance)
-                       return CMD_NOT_MY_INSTANCE;
-
-               ospf = ospf_lookup_instance(instance);
-               if (!ospf || !ospf->oi_running)
-                       return CMD_SUCCESS;
-
-               return (show_ip_ospf_database_common(
-                       vty, ospf, idx ? 1 : 0, argc, argv, use_vrf, json, uj));
-       } else if (argv_find(argv, argc, "vrf", &idx)) {
-               vrf_name = argv[++idx]->arg;
-               all_vrf = strmatch(vrf_name, "all");
-       }
-
-       if (vrf_name) {
-               use_vrf = 1;
-               if (all_vrf) {
-                       for (ALL_LIST_ELEMENTS_RO(om->ospf, node, ospf)) {
-                               if (!ospf->oi_running)
-                                       continue;
-                               ret = (show_ip_ospf_database_common(
-                                       vty, ospf, idx ? 2 : 0, argc, argv,
-                                       use_vrf, json, uj));
-                       }
-               } else {
-                       ospf = ospf_lookup_by_inst_name(inst, vrf_name);
-                       if ((ospf == NULL) || !ospf->oi_running) {
-                               vty_out(vty, "%% OSPF instance not found\n");
-                               return CMD_SUCCESS;
-                       }
-
-                       ret = (show_ip_ospf_database_common(
-                               vty, ospf, idx ? 2 : 0, argc, argv, use_vrf,
-                               json, uj));
-               }
-       } else {
-               /* Display default ospf (instance 0) info */
-               ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
-               if (ospf == NULL || !ospf->oi_running) {
-                       vty_out(vty, "%% OSPF instance not found\n");
-                       return CMD_SUCCESS;
-               }
-
-               ret = (show_ip_ospf_database_common(vty, ospf, 0, argc, argv,
-                                                   use_vrf, json, uj));
-       }
-
-       if (uj) {
-               vty_out(vty, "%s\n", json_object_to_json_string(json));
-               json_object_free(json);
-       }
-
-       return ret;
-}
 
 DEFUN (show_ip_ospf_instance_database_max,
        show_ip_ospf_instance_database_max_cmd,
@@ -7238,6 +7167,20 @@ DEFUN (show_ip_ospf_instance_database_max,
        return CMD_SUCCESS;
 }
 
+ALIAS (show_ip_ospf_instance_database_max,
+       show_ip_ospf_instance_database_cmd,
+       "show ip ospf (1-65535) database [<asbr-summary|external|network|router|summary|nssa-external|opaque-link|opaque-area|opaque-as> [A.B.C.D [<self-originate|adv-router A.B.C.D>]]] [json]",
+       SHOW_STR
+       IP_STR
+       "OSPF information\n"
+       "Instance ID\n"
+       "Database summary\n"
+        OSPF_LSA_TYPES_DESC
+       "Link State ID (as an IP address)\n"
+       "Self-originated link states\n"
+       "Advertising Router link states\n"
+       "Advertising Router (as an IP address)\n"
+       JSON_STR)
 
 static int show_ip_ospf_database_type_adv_router_common(struct vty *vty,
                                                        struct ospf *ospf,
@@ -7327,14 +7270,14 @@ static int show_ip_ospf_database_type_adv_router_common(struct vty *vty,
        return CMD_SUCCESS;
 }
 
-DEFUN (show_ip_ospf_instance_database_type_adv_router,
-       show_ip_ospf_instance_database_type_adv_router_cmd,
-       "show ip ospf [{(1-65535)|vrf NAME}] database <asbr-summary|external|network|router|summary|nssa-external|opaque-link|opaque-area|opaque-as> <adv-router A.B.C.D|self-originate> [json]",
+DEFUN (show_ip_ospf_database_type_adv_router,
+       show_ip_ospf_database_type_adv_router_cmd,
+       "show ip ospf [vrf <NAME|all>] database <asbr-summary|external|network|router|summary|nssa-external|opaque-link|opaque-area|opaque-as> <adv-router A.B.C.D|self-originate> [json]",
        SHOW_STR
        IP_STR
        "OSPF information\n"
-       "Instance ID\n"
        VRF_CMD_HELP_STR
+       "All VRFs\n"
        "Database summary\n"
        OSPF_LSA_TYPES_DESC
        "Advertising Router link states\n"
@@ -7343,7 +7286,6 @@ DEFUN (show_ip_ospf_instance_database_type_adv_router,
        JSON_STR)
 {
        struct ospf *ospf = NULL;
-       unsigned short instance = 0;
        struct listnode *node = NULL;
        char *vrf_name = NULL;
        bool all_vrf = false;
@@ -7357,19 +7299,6 @@ DEFUN (show_ip_ospf_instance_database_type_adv_router,
        if (uj)
                json = json_object_new_object();
 
-       if (argv_find(argv, argc, "(1-65535)", &idx)) {
-               instance = strtoul(argv[idx]->arg, NULL, 10);
-               if (instance != ospf_instance)
-                       return CMD_NOT_MY_INSTANCE;
-
-               ospf = ospf_lookup_instance(instance);
-               if (!ospf || !ospf->oi_running)
-                       return CMD_SUCCESS;
-
-               return (show_ip_ospf_database_type_adv_router_common(
-                       vty, ospf, idx ? 1 : 0, argc, argv, use_vrf, json, uj));
-       }
-
        OSPF_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
 
        if (vrf_name) {
@@ -7416,8 +7345,50 @@ DEFUN (show_ip_ospf_instance_database_type_adv_router,
        }
 
        return ret;
-       /*return (show_ip_ospf_database_type_adv_router_common(
-               vty, ospf, idx ? 1 : 0, argc, argv));*/
+}
+
+DEFUN (show_ip_ospf_instance_database_type_adv_router,
+       show_ip_ospf_instance_database_type_adv_router_cmd,
+       "show ip ospf (1-65535) database <asbr-summary|external|network|router|summary|nssa-external|opaque-link|opaque-area|opaque-as> <adv-router A.B.C.D|self-originate> [json]",
+       SHOW_STR
+       IP_STR
+       "OSPF information\n"
+       "Instance ID\n"
+       "Database summary\n"
+       OSPF_LSA_TYPES_DESC
+       "Advertising Router link states\n"
+       "Advertising Router (as an IP address)\n"
+       "Self-originated link states\n"
+       JSON_STR)
+{
+       int idx_number = 3;
+       struct ospf *ospf;
+       unsigned short instance = 0;
+       bool uj = use_json(argc, argv);
+       json_object *json = NULL;
+
+       if (uj)
+               json = json_object_new_object();
+
+       instance = strtoul(argv[idx_number]->arg, NULL, 10);
+       if (instance != ospf_instance)
+               return CMD_NOT_MY_INSTANCE;
+
+       ospf = ospf_lookup_instance(instance);
+       if (!ospf || !ospf->oi_running)
+               return CMD_SUCCESS;
+
+       show_ip_ospf_database_type_adv_router_common(vty, ospf, 1, argc, argv,
+                                                    0, json, uj);
+
+       if (uj) {
+               vty_out(vty, "%s\n",
+                       json_object_to_json_string_ext(
+                               json, JSON_C_TO_STRING_PRETTY));
+               json_object_free(json);
+       }
+
+       return CMD_SUCCESS;
 }
 
 DEFUN (ip_ospf_authentication_args,
@@ -11716,7 +11687,7 @@ static int config_write_interface_one(struct vty *vty, struct vrf *vrf)
                        }
 
                        /* bfd  print. */
-                       if (params && params->bfd_info)
+                       if (params && params->bfd_config)
                                ospf_bfd_write_config(vty, params);
 
                        /* MTU ignore print. */
@@ -12375,8 +12346,10 @@ void ospf_vty_show_init(void)
        install_element(VIEW_NODE, &show_ip_ospf_instance_cmd);
 
        /* "show ip ospf database" commands. */
+       install_element(VIEW_NODE, &show_ip_ospf_database_cmd);
        install_element(VIEW_NODE, &show_ip_ospf_database_max_cmd);
-
+       install_element(VIEW_NODE,
+                       &show_ip_ospf_database_type_adv_router_cmd);
        install_element(VIEW_NODE,
                        &show_ip_ospf_instance_database_type_adv_router_cmd);
        install_element(VIEW_NODE, &show_ip_ospf_instance_database_cmd);
index a2fbd01ab8a127afb8acc089494151230817d54b..56b2f8d6603964c4e602defe17ca5516cb9afc95 100644 (file)
@@ -53,9 +53,9 @@
 #include "ospfd/ospf_sr.h"
 #include "ospfd/ospf_ldp_sync.h"
 
-DEFINE_MTYPE_STATIC(OSPFD, OSPF_EXTERNAL, "OSPF External route table")
-DEFINE_MTYPE_STATIC(OSPFD, OSPF_REDISTRIBUTE, "OSPF Redistriute")
-DEFINE_MTYPE_STATIC(OSPFD, OSPF_DIST_ARGS, "OSPF Distribute arguments")
+DEFINE_MTYPE_STATIC(OSPFD, OSPF_EXTERNAL, "OSPF External route table");
+DEFINE_MTYPE_STATIC(OSPFD, OSPF_REDISTRIBUTE, "OSPF Redistriute");
+DEFINE_MTYPE_STATIC(OSPFD, OSPF_DIST_ARGS, "OSPF Distribute arguments");
 
 
 /* Zebra structure to hold current status. */
index 9590a9c73bdf6ab74ce49022b0ecee42673691e7..9856e601305fc42d562c85feb55c77d780af5886 100644 (file)
@@ -42,6 +42,7 @@
 #include "ldp_sync.h"
 
 #include "ospfd/ospfd.h"
+#include "ospfd/ospf_bfd.h"
 #include "ospfd/ospf_network.h"
 #include "ospfd/ospf_interface.h"
 #include "ospfd/ospf_ism.h"
@@ -62,7 +63,7 @@
 #include "ospfd/ospf_gr_helper.h"
 
 
-DEFINE_QOBJ_TYPE(ospf)
+DEFINE_QOBJ_TYPE(ospf);
 
 /* OSPF process wide configuration. */
 static struct ospf_master ospf_master;
@@ -111,7 +112,7 @@ int q_spaces_compare_func(const struct q_space *a, const struct q_space *b)
 }
 
 DECLARE_RBTREE_UNIQ(p_spaces, struct p_space, p_spaces_item,
-                   p_spaces_compare_func)
+                   p_spaces_compare_func);
 
 void ospf_process_refresh_data(struct ospf *ospf, bool reset)
 {
@@ -1931,6 +1932,9 @@ static void ospf_nbr_nbma_add(struct ospf_nbr_nbma *nbr_nbma,
 
                nbr_nbma->nbr = nbr;
 
+               /* Configure BFD if interface has it. */
+               ospf_neighbor_bfd_apply(nbr);
+
                OSPF_NSM_EVENT_EXECUTE(nbr, NSM_Start);
        }
 }
index 5148bf555c01643fc03536ce86177ae36d58b8cd..5d64ee9ba21fa1da21a102297f6e9fe840a4f5c1 100644 (file)
@@ -386,9 +386,9 @@ struct ospf {
        bool ti_lfa_enabled;
        enum protection_type ti_lfa_protection_type;
 
-       QOBJ_FIELDS
+       QOBJ_FIELDS;
 };
-DECLARE_QOBJ_TYPE(ospf)
+DECLARE_QOBJ_TYPE(ospf);
 
 enum ospf_ti_lfa_p_q_space_adjacency {
        OSPF_TI_LFA_P_Q_SPACE_ADJACENT,
@@ -424,7 +424,7 @@ struct protected_resource {
        struct in_addr router_id;
 };
 
-PREDECL_RBTREE_UNIQ(q_spaces)
+PREDECL_RBTREE_UNIQ(q_spaces);
 struct q_space {
        struct vertex *root;
        struct list *vertex_list;
@@ -436,7 +436,7 @@ struct q_space {
        struct q_spaces_item q_spaces_item;
 };
 
-PREDECL_RBTREE_UNIQ(p_spaces)
+PREDECL_RBTREE_UNIQ(p_spaces);
 struct p_space {
        struct vertex *root;
        struct protected_resource *protected_resource;
index 28d58452df547602a0417d9570ea8d4c07241e23..25ddef358f860905c1c6458dbd5274f78eea04a2 100644 (file)
@@ -113,7 +113,7 @@ 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
-ospfd_ospfd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu99
+ospfd_ospfd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu11
 ospfd_ospfd_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
 ospfd_ospfd_snmp_la_LIBADD = lib/libfrrsnmp.la
 
index 8beb428135f59cafdbd85b37c76daac63985bbc1..cf14aa8c61689e4a3d3e5d2189805f96677bf34f 100644 (file)
@@ -20,6 +20,7 @@
 #include <math.h>
 #include <zebra.h>
 
+#include "memory.h"
 #include "log.h"
 #include "command.h"
 #include "mpls.h"
@@ -28,7 +29,6 @@
 
 #include "pathd/pathd.h"
 #include "pathd/path_nb.h"
-#include "pathd/path_memory.h"
 #ifndef VTYSH_EXTRACT_PL
 #include "pathd/path_cli_clippy.c"
 #endif
@@ -46,7 +46,7 @@ static int config_write_traffic_eng(struct vty *vty);
 static int config_write_segment_lists(struct vty *vty);
 static int config_write_sr_policies(struct vty *vty);
 
-DEFINE_MTYPE_STATIC(PATHD, PATH_CLI, "Client")
+DEFINE_MTYPE_STATIC(PATHD, PATH_CLI, "Client");
 
 /* Vty node structures. */
 static struct cmd_node segment_routing_node = {
index 8b7d4aba4863d35c9c8cd6a7b292e853593202bf..f54ab736c4b948da317e5f75beadd4a649976a81 100644 (file)
@@ -114,7 +114,8 @@ FRR_DAEMON_INFO(pathd, PATH, .vty_port = PATH_VTY_PORT,
                .signals = path_signals, .n_signals = array_size(path_signals),
 
                .privs = &pathd_privs, .yang_modules = pathd_yang_modules,
-               .n_yang_modules = array_size(pathd_yang_modules), )
+               .n_yang_modules = array_size(pathd_yang_modules),
+);
 
 int main(int argc, char **argv, char **envp)
 {
diff --git a/pathd/path_memory.c b/pathd/path_memory.c
deleted file mode 100644 (file)
index ad4904a..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2020  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 <zebra.h>
-
-#include <memory.h>
-
-#include "pathd/path_memory.h"
-
-DEFINE_MGROUP(PATHD, "pathd")
diff --git a/pathd/path_memory.h b/pathd/path_memory.h
deleted file mode 100644 (file)
index e2f6787..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2020  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
- */
-
-#ifndef _FRR_PATH_MEMORY_H_
-#define _FRR_PATH_MEMORY_H_
-
-#include "memory.h"
-
-DECLARE_MGROUP(PATHD)
-
-#endif /* _FRR_PATH_MEMORY_H_ */
index 2f9ff4f0f0028adbdaf8c95f31a0458c8bb4f4b5..d6cd48ecdb207322ee1f388c5a6d489a30aa8060 100644 (file)
@@ -17,8 +17,9 @@
  */
 
 #include <zebra.h>
-#include <pcep_utils_counters.h>
+#include "pceplib/pcep_utils_counters.h"
 
+#include "memory.h"
 #include "log.h"
 #include "command.h"
 #include "libfrr.h"
 
 #include "pathd/pathd.h"
 #include "pathd/path_errors.h"
-#include "pathd/path_pcep_memory.h"
 #include "pathd/path_pcep.h"
 #include "pathd/path_pcep_cli.h"
 #include "pathd/path_pcep_controller.h"
 #include "pathd/path_pcep_lib.h"
 #include "pathd/path_pcep_config.h"
 
+DEFINE_MTYPE(PATHD, PCEP, "PCEP module");
 
 /*
  * Globals.
@@ -215,29 +216,10 @@ int pcep_main_event_update_candidate(struct path *path)
 
        ret = path_pcep_config_update_path(path);
        if (ret != PATH_NB_ERR && path->srp_id != 0) {
-               /* ODL and Cisco requires the first reported
-                * LSP to have a DOWN status, the later status changes
-                * will be comunicated through hook calls.
-                */
-               enum pcep_lsp_operational_status real_status;
                if ((resp = path_pcep_config_get_path(&path->nbkey))) {
                        resp->srp_id = path->srp_id;
-                       real_status = resp->status;
-                       resp->status = PCEP_LSP_OPERATIONAL_DOWN;
-                       pcep_ctrl_send_report(pcep_g->fpt, path->pcc_id, resp);
-                       /* If the update did not have any effect and the real
-                        * status is not DOWN, we need to send a second report
-                        * so the PCE is aware of the real status. This is due
-                        * to the fact that NO notification will be received
-                        * if the update did not apply any changes */
-                       if ((ret == PATH_NB_NO_CHANGE)
-                           && (real_status != PCEP_LSP_OPERATIONAL_DOWN)) {
-                               resp->status = real_status;
-                               resp->srp_id = 0;
-                               pcep_ctrl_send_report(pcep_g->fpt, path->pcc_id,
-                                                     resp);
-                       }
-                       pcep_free_path(resp);
+                       pcep_ctrl_send_report(pcep_g->fpt, path->pcc_id, resp,
+                                             ret == PATH_NB_NO_CHANGE);
                }
        }
        return ret;
@@ -336,4 +318,5 @@ int pcep_module_init(void)
 
 FRR_MODULE_SETUP(.name = "frr_pathd_pcep", .version = FRR_VERSION,
                 .description = "FRR pathd PCEP module",
-                .init = pcep_module_init)
+                .init = pcep_module_init,
+);
index 1896c265c1b04fd175d20d69f3d9c2ef7c88d60d..654d089cbc01bb2559e0be121af78885b1ef669a 100644 (file)
 #include <stdbool.h>
 #include <debug.h>
 #include <netinet/tcp.h>
-#include <pcep_utils_logging.h>
-#include <pcep_pcc_api.h>
+#include "memory.h"
+#include "pceplib/pcep_utils_logging.h"
+#include "pceplib/pcep_pcc_api.h"
 #include "mpls.h"
 #include "pathd/pathd.h"
-#include "pathd/path_pcep_memory.h"
+
+DECLARE_MTYPE(PCEP);
 
 #define PCEP_DEFAULT_PORT 4189
 #define MAX_PCC 32
index add3391f22903b49bf214dbbe253929b4ff0d952..14404b1d088233d35940a83a9f01d8821321a4d4 100644 (file)
@@ -18,8 +18,8 @@
  */
 
 #include <zebra.h>
-#include <pcep_utils_counters.h>
-#include <pcep_session_logic.h>
+#include "pceplib/pcep_utils_counters.h"
+#include "pceplib/pcep_session_logic.h"
 
 #include "log.h"
 #include "command.h"
@@ -33,7 +33,6 @@
 
 #include "pathd/pathd.h"
 #include "pathd/path_errors.h"
-#include "pathd/path_pcep_memory.h"
 #include "pathd/path_pcep.h"
 #include "pathd/path_pcep_cli.h"
 #include "pathd/path_pcep_controller.h"
@@ -321,8 +320,9 @@ pcep_cli_merge_pcep_pce_config_options(struct pce_opts_cli *pce_opts_cli)
                                default_pcep_config_group_opts_g.tcp_md5_auth;
                }
        }
-       strncpy(pce_opts_cli->pce_opts.config_opts.tcp_md5_auth,
-               tcp_md5_auth_str, TCP_MD5SIG_MAXKEYLEN);
+       strlcpy(pce_opts_cli->pce_opts.config_opts.tcp_md5_auth,
+               tcp_md5_auth_str,
+               sizeof(pce_opts_cli->pce_opts.config_opts.tcp_md5_auth));
 
        struct ipaddr *source_ip =
                &pce_opts_cli->pce_config_group_opts.source_ip;
@@ -525,8 +525,9 @@ static int path_pcep_cli_show_srte_pcep_counters(struct vty *vty)
        tm_info = localtime(&group->start_time);
        strftime(tm_buffer, sizeof(tm_buffer), "%Y-%m-%d %H:%M:%S", tm_info);
 
-       vty_out(vty, "PCEP counters since %s (%luh %lum %lus):\n", tm_buffer,
-               diff_time / 3600, (diff_time / 60) % 60, diff_time % 60);
+       vty_out(vty, "PCEP counters since %s (%uh %um %us):\n", tm_buffer,
+               (uint32_t)(diff_time / 3600), (uint32_t)((diff_time / 60) % 60),
+               (uint32_t)(diff_time % 60));
 
        /* Prepare table. */
        tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
@@ -815,7 +816,8 @@ static int path_pcep_cli_peer_tcp_md5_auth(struct vty *vty,
                return CMD_ERR_NO_MATCH;
        }
 
-       strncpy(pce_config->tcp_md5_auth, tcp_md5_auth, TCP_MD5SIG_MAXKEYLEN);
+       strlcpy(pce_config->tcp_md5_auth, tcp_md5_auth,
+               sizeof(pce_config->tcp_md5_auth));
 
        return CMD_SUCCESS;
 }
@@ -1043,7 +1045,7 @@ static int path_pcep_cli_pcc_pcc_peer(struct vty *vty, const char *peer_name,
                XMALLOC(MTYPE_PCEP, sizeof(struct pcc_opts));
        memcpy(&pcc_opts_copy->addr,
               &pce_opts_cli->pce_opts.config_opts.source_ip,
-              sizeof(struct pcc_opts));
+              sizeof(pcc_opts_copy->addr));
        pcc_opts_copy->msd = pcc_msd_g;
        pcc_opts_copy->port = pce_opts_cli->pce_opts.config_opts.source_port;
        if (pcep_ctrl_update_pcc_options(pcep_g->fpt, pcc_opts_copy)) {
@@ -1220,8 +1222,9 @@ static void print_pcep_session(struct vty *vty, struct pce_opts *pce_opts,
                        localtime_r(&current_time, &lt);
                        gmtime_r(&session->time_connected, &lt);
                        vty_out(vty,
-                               " Connected for %ld seconds, since %d-%02d-%02d %02d:%02d:%02d UTC\n",
-                               (current_time - session->time_connected),
+                               " Connected for %u seconds, since %d-%02d-%02d %02d:%02d:%02d UTC\n",
+                               (uint32_t)(current_time
+                                          - session->time_connected),
                                lt.tm_year + 1900, lt.tm_mon + 1, lt.tm_mday,
                                lt.tm_hour, lt.tm_min, lt.tm_sec);
                }
index 989223ebc3f8a5f7c7d54a0da2fdbabb9fbfa5b2..107475bec9e0c5daf0bb4e9499ef19ae8fedeca1 100644 (file)
@@ -19,7 +19,7 @@
 #include <northbound.h>
 #include <yang.h>
 #include <printfrr.h>
-#include <pcep-objects.h>
+#include "pceplib/pcep_msg_objects.h"
 #include "pathd/pathd.h"
 #include "pathd/path_pcep.h"
 #include "pathd/path_pcep_config.h"
@@ -45,14 +45,13 @@ status_int_to_ext(enum srte_policy_status status);
 static enum pcep_sr_subobj_nai pcep_nai_type(enum srte_segment_nai_type type);
 static enum srte_segment_nai_type srte_nai_type(enum pcep_sr_subobj_nai type);
 
-static int path_pcep_config_lookup_cb(struct thread *t)
+void path_pcep_refine_path(struct path *path)
 {
-       struct path *path = THREAD_ARG(t);
        struct srte_candidate *candidate = lookup_candidate(&path->nbkey);
        struct srte_lsp *lsp;
 
        if (candidate == NULL)
-               return 0;
+               return;
 
        lsp = candidate->lsp;
 
@@ -65,16 +64,6 @@ static int path_pcep_config_lookup_cb(struct thread *t)
        if ((path->update_origin == SRTE_ORIGIN_UNDEFINED)
            && (lsp->segment_list != NULL))
                path->update_origin = lsp->segment_list->protocol_origin;
-
-       return 0;
-}
-
-void path_pcep_config_lookup(struct path *path)
-{
-       /*
-        * Configuration access is strictly done via the main thread
-        */
-       thread_execute(master, path_pcep_config_lookup_cb, path, 0);
 }
 
 struct path *path_pcep_config_get_path(struct lsp_nb_key *key)
@@ -346,9 +335,11 @@ int path_pcep_config_update_path(struct path *path)
        SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
 
        for (metric = path->first_metric; metric != NULL; metric = metric->next)
-               srte_lsp_set_metric(candidate->lsp, metric->type, metric->value,
-                                   metric->enforce, metric->is_bound,
-                                   metric->is_computed);
+               srte_lsp_set_metric(
+                       candidate->lsp,
+                       (enum srte_candidate_metric_type)metric->type,
+                       metric->value, metric->enforce, metric->is_bound,
+                       metric->is_computed);
 
        if (path->has_bandwidth)
                srte_lsp_set_bandwidth(candidate->lsp, path->bandwidth,
index de29ab29c156cbb53aa28b61acf49feae96d16ef..223dd10c82097a6e00fb417b28c48946ab368a11 100644 (file)
 typedef int (*path_list_cb_t)(struct path *path, void *arg);
 
 /* Lookup the candidate path and fill up the missing path attributes like name
-   and type. Used for path generated from PCEP message received from the PCE
-   so they contains more information about the candidate path. If no matching
-   policy or candidate path is found, nothing is changed */
-void path_pcep_config_lookup(struct path *path);
+ * and type. Used for path generated from PCEP message received from the PCE
+ * so they contains more information about the candidate path. If no matching
+ * policy or candidate path is found, nothing is changed.
+ * MUST BE CALLED FROM THE MAIN THREAD */
+void path_pcep_refine_path(struct path *path);
 struct path *path_pcep_config_get_path(struct lsp_nb_key *key);
 void path_pcep_config_list_path(path_list_cb_t cb, void *arg);
 int path_pcep_config_update_path(struct path *path);
index f4871a4d8dfc79aa51a9ca8f52f803618455ed75..db7d2b55a585599627255173d3ce047e4855b3cf 100644 (file)
@@ -55,7 +55,9 @@ enum pcep_ctrl_event_type {
        EV_SYNC_PATH,
        EV_SYNC_DONE,
        EV_PCEPLIB_EVENT,
-       EV_RESET_PCC_SESSION
+       EV_RESET_PCC_SESSION,
+       EV_SEND_REPORT,
+       EV_PATH_REFINED
 };
 
 struct pcep_ctrl_event_data {
@@ -73,18 +75,20 @@ struct pcep_main_event_data {
        void *payload;
 };
 
-/* Synchronous call arguments */
-
-struct get_counters_args {
+struct pcep_refine_path_event_data {
        struct ctrl_state *ctrl_state;
        int pcc_id;
-       struct counters_group *counters;
+       pcep_refine_callback_t continue_lsp_update_handler;
+       struct path *path;
+       void *payload;
 };
 
-struct send_report_args {
+/* Synchronous call arguments */
+
+struct get_counters_args {
        struct ctrl_state *ctrl_state;
        int pcc_id;
-       struct path *path;
+       struct counters_group *counters;
 };
 
 struct get_pcep_session_args {
@@ -95,13 +99,10 @@ struct get_pcep_session_args {
 
 /* Internal Functions Called From Main Thread */
 static int pcep_ctrl_halt_cb(struct frr_pthread *fpt, void **res);
+static int pcep_refine_path_event_cb(struct thread *thread);
 
 /* Internal Functions Called From Controller Thread */
 static int pcep_thread_finish_event_handler(struct thread *thread);
-static int pcep_thread_get_counters_callback(struct thread *t);
-static int pcep_thread_send_report_callback(struct thread *t);
-static int pcep_thread_get_pcep_session_callback(struct thread *t);
-static int pcep_thread_get_pcc_info_callback(struct thread *t);
 
 /* Controller Thread Timer Handler */
 static int schedule_thread_timer(struct ctrl_state *ctrl_state, int pcc_id,
@@ -148,6 +149,9 @@ static int pcep_thread_event_sync_done(struct ctrl_state *ctrl_state,
 static int pcep_thread_event_pathd_event(struct ctrl_state *ctrl_state,
                                         enum pcep_pathd_event_type type,
                                         struct path *path);
+static void
+pcep_thread_path_refined_event(struct ctrl_state *ctrl_state,
+                              struct pcep_refine_path_event_data *data);
 
 /* Main Thread Event Handler */
 static int send_to_main(struct ctrl_state *ctrl_state, int pcc_id,
@@ -280,48 +284,50 @@ struct counters_group *pcep_ctrl_get_counters(struct frr_pthread *fpt,
                                              int pcc_id)
 {
        struct ctrl_state *ctrl_state = get_ctrl_state(fpt);
-       struct get_counters_args args = {
-               .ctrl_state = ctrl_state, .pcc_id = pcc_id, .counters = NULL};
-       thread_execute(ctrl_state->self, pcep_thread_get_counters_callback,
-                      &args, 0);
-       return args.counters;
+       struct counters_group *counters = NULL;
+       struct pcc_state *pcc_state;
+       pcc_state = pcep_pcc_get_pcc_by_id(ctrl_state->pcc, pcc_id);
+       if (pcc_state) {
+               counters = pcep_lib_copy_counters(pcc_state->sess);
+       }
+       return counters;
 }
 
 pcep_session *pcep_ctrl_get_pcep_session(struct frr_pthread *fpt, int pcc_id)
 {
        struct ctrl_state *ctrl_state = get_ctrl_state(fpt);
-       struct get_pcep_session_args args = {.ctrl_state = ctrl_state,
-                                            .pcc_id = pcc_id,
-                                            .pcep_session = NULL};
-       thread_execute(ctrl_state->self, pcep_thread_get_pcep_session_callback,
-                      &args, 0);
-       return args.pcep_session;
+       struct pcc_state *pcc_state;
+       pcep_session *session = NULL;
+
+       pcc_state = pcep_pcc_get_pcc_by_id(ctrl_state->pcc, pcc_id);
+       if (pcc_state) {
+               session = pcep_lib_copy_pcep_session(pcc_state->sess);
+       }
+       return session;
 }
 
 struct pcep_pcc_info *pcep_ctrl_get_pcc_info(struct frr_pthread *fpt,
                                             const char *pce_name)
 {
        struct ctrl_state *ctrl_state = get_ctrl_state(fpt);
-       struct pcep_pcc_info *args = XCALLOC(MTYPE_PCEP, sizeof(*args));
-       args->ctrl_state = ctrl_state;
-       strncpy(args->pce_name, pce_name, sizeof(args->pce_name));
-       thread_execute(ctrl_state->self, pcep_thread_get_pcc_info_callback,
-                      args, 0);
+       struct pcep_pcc_info *pcc_info = XCALLOC(MTYPE_PCEP, sizeof(*pcc_info));
+       if( pcc_info && ctrl_state){
+               strlcpy(pcc_info->pce_name, pce_name, sizeof(pcc_info->pce_name));
+               pcep_pcc_copy_pcc_info(ctrl_state->pcc, pcc_info);
+       }
 
-       return args;
+       return pcc_info;
 }
 
-void pcep_ctrl_send_report(struct frr_pthread *fpt, int pcc_id,
-                          struct path *path)
+int pcep_ctrl_send_report(struct frr_pthread *fpt, int pcc_id,
+                         struct path *path, bool is_stable)
 {
-       /* Sends a report stynchronously */
        struct ctrl_state *ctrl_state = get_ctrl_state(fpt);
-       struct send_report_args args = {
-               .ctrl_state = ctrl_state, .pcc_id = pcc_id, .path = path};
-       thread_execute(ctrl_state->self, pcep_thread_send_report_callback,
-                      &args, 0);
+       return send_to_thread(ctrl_state, pcc_id, EV_SEND_REPORT, is_stable,
+                             path);
 }
 
+
 /* ------------ Internal Functions Called from Main Thread ------------ */
 
 int pcep_ctrl_halt_cb(struct frr_pthread *fpt, void **res)
@@ -333,6 +339,20 @@ int pcep_ctrl_halt_cb(struct frr_pthread *fpt, void **res)
        return 0;
 }
 
+int pcep_refine_path_event_cb(struct thread *thread)
+{
+       struct pcep_refine_path_event_data *data = THREAD_ARG(thread);
+       assert(data != NULL);
+       struct ctrl_state *ctrl_state = data->ctrl_state;
+       struct path *path = data->path;
+       assert(path != NULL);
+       int pcc_id = data->pcc_id;
+
+
+       path_pcep_refine_path(path);
+       return send_to_thread(ctrl_state, pcc_id, EV_PATH_REFINED, 0, data);
+}
+
 
 /* ------------ API Functions Called From Controller Thread ------------ */
 
@@ -442,6 +462,41 @@ int pcep_thread_pcc_count(struct ctrl_state *ctrl_state)
        return ctrl_state->pcc_count;
 }
 
+int pcep_thread_refine_path(struct ctrl_state *ctrl_state, int pcc_id,
+                           pcep_refine_callback_t cb, struct path *path,
+                           void *payload)
+{
+       struct pcep_refine_path_event_data *data;
+
+       data = XCALLOC(MTYPE_PCEP, sizeof(*data));
+       data->ctrl_state = ctrl_state;
+       data->path = path;
+       data->pcc_id = pcc_id;
+       data->continue_lsp_update_handler = cb;
+       data->payload = payload;
+
+       thread_add_event(ctrl_state->main, pcep_refine_path_event_cb,
+                        (void *)data, 0, NULL);
+       return 0;
+}
+
+void pcep_thread_path_refined_event(struct ctrl_state *ctrl_state,
+                                   struct pcep_refine_path_event_data *data)
+{
+       assert(data != NULL);
+       int pcc_id = data->pcc_id;
+       pcep_refine_callback_t continue_lsp_update_handler = data->continue_lsp_update_handler;
+       assert(continue_lsp_update_handler != NULL);
+       struct path *path = data->path;
+       void *payload = data->payload;
+       struct pcc_state *pcc_state = NULL;
+       XFREE(MTYPE_PCEP, data);
+
+       pcc_state = pcep_pcc_get_pcc_by_id(ctrl_state->pcc, pcc_id);
+       continue_lsp_update_handler(ctrl_state, pcc_state, path, payload);
+}
+
+
 /* ------------ Internal Functions Called From Controller Thread ------------ */
 
 int pcep_thread_finish_event_handler(struct thread *thread)
@@ -467,78 +522,6 @@ int pcep_thread_finish_event_handler(struct thread *thread)
        return 0;
 }
 
-int pcep_thread_get_counters_callback(struct thread *t)
-{
-       struct get_counters_args *args = THREAD_ARG(t);
-       assert(args != NULL);
-       struct ctrl_state *ctrl_state = args->ctrl_state;
-       assert(ctrl_state != NULL);
-       struct pcc_state *pcc_state;
-
-       pcc_state = pcep_pcc_get_pcc_by_id(ctrl_state->pcc, args->pcc_id);
-       if (pcc_state) {
-               args->counters = pcep_lib_copy_counters(pcc_state->sess);
-       } else {
-               args->counters = NULL;
-       }
-
-       return 0;
-}
-
-int pcep_thread_send_report_callback(struct thread *t)
-{
-       struct send_report_args *args = THREAD_ARG(t);
-       assert(args != NULL);
-       struct ctrl_state *ctrl_state = args->ctrl_state;
-       assert(ctrl_state != NULL);
-       struct pcc_state *pcc_state;
-
-       if (args->pcc_id == 0) {
-               for (int i = 0; i < MAX_PCC; i++) {
-                       if (ctrl_state->pcc[i]) {
-                               pcep_pcc_send_report(ctrl_state,
-                                                    ctrl_state->pcc[i],
-                                                    args->path);
-                       }
-               }
-       } else {
-               pcc_state =
-                       pcep_pcc_get_pcc_by_id(ctrl_state->pcc, args->pcc_id);
-               pcep_pcc_send_report(ctrl_state, pcc_state, args->path);
-       }
-
-       return 0;
-}
-
-int pcep_thread_get_pcep_session_callback(struct thread *t)
-{
-       struct get_pcep_session_args *args = THREAD_ARG(t);
-       assert(args != NULL);
-       struct ctrl_state *ctrl_state = args->ctrl_state;
-       assert(ctrl_state != NULL);
-       struct pcc_state *pcc_state;
-
-       pcc_state = pcep_pcc_get_pcc_by_id(ctrl_state->pcc, args->pcc_id);
-       if (pcc_state) {
-               args->pcep_session =
-                       pcep_lib_copy_pcep_session(pcc_state->sess);
-       }
-
-       return 0;
-}
-
-int pcep_thread_get_pcc_info_callback(struct thread *t)
-{
-       struct pcep_pcc_info *args = THREAD_ARG(t);
-       assert(args != NULL);
-       struct ctrl_state *ctrl_state = args->ctrl_state;
-       assert(ctrl_state != NULL);
-
-       pcep_pcc_copy_pcc_info(ctrl_state->pcc, args);
-
-       return 0;
-}
-
 /* ------------ Controller Thread Timer Handler ------------ */
 
 int schedule_thread_timer_with_cb(struct ctrl_state *ctrl_state, int pcc_id,
@@ -752,11 +735,14 @@ int pcep_thread_event_handler(struct thread *thread)
        /* Possible sub-type values */
        enum pcep_pathd_event_type path_event_type = PCEP_PATH_UNDEFINED;
 
-       /* Possible payload values */
+       /* Possible payload values, maybe an union would be better... */
        struct path *path = NULL;
        struct pcc_opts *pcc_opts = NULL;
        struct pce_opts *pce_opts = NULL;
        struct pcc_state *pcc_state = NULL;
+       struct pcep_refine_path_event_data *refine_data = NULL;
+
+       struct path *path_copy = NULL;
 
        switch (type) {
        case EV_UPDATE_PCC_OPTS:
@@ -808,6 +794,30 @@ int pcep_thread_event_handler(struct thread *thread)
                                  (const char *)payload);
                }
                break;
+       case EV_SEND_REPORT:
+               assert(payload != NULL);
+               path = (struct path *)payload;
+               if (pcc_id == 0) {
+                       for (int i = 0; i < MAX_PCC; i++) {
+                               if (ctrl_state->pcc[i]) {
+                                       path_copy = pcep_copy_path(path);
+                                       pcep_pcc_send_report(
+                                               ctrl_state, ctrl_state->pcc[i],
+                                               path_copy, (bool)sub_type);
+                               }
+                       }
+               } else {
+                       pcc_state =
+                               pcep_pcc_get_pcc_by_id(ctrl_state->pcc, pcc_id);
+                       pcep_pcc_send_report(ctrl_state, pcc_state, path,
+                                            (bool)sub_type);
+               }
+               break;
+       case EV_PATH_REFINED:
+               assert(payload != NULL);
+               refine_data = (struct pcep_refine_path_event_data *)payload;
+               pcep_thread_path_refined_event(ctrl_state, refine_data);
+               break;
        default:
                flog_warn(EC_PATH_PCEP_RECOVERABLE_INTERNAL_ERROR,
                          "Unexpected event received in controller thread: %u",
@@ -984,6 +994,7 @@ int pcep_main_event_handler(struct thread *thread)
 
 
 /* ------------ Helper functions ------------ */
+
 void set_ctrl_state(struct frr_pthread *fpt, struct ctrl_state *ctrl_state)
 {
        assert(fpt != NULL);
index f6eaa0ca2afaf95033ef61b725d19c5318ba02f1..1b7c3a4c72a5d83b22c51aa3c87c597e72921c5f 100644 (file)
 
 #include "pathd/path_pcep.h"
 
+struct ctrl_state;
+struct pcc_state;
 
 enum pcep_main_event_type {
        PCEP_MAIN_EVENT_UNDEFINED = 0,
        PCEP_MAIN_EVENT_START_SYNC,
        PCEP_MAIN_EVENT_UPDATE_CANDIDATE,
-       PCEP_MAIN_EVENT_REMOVE_CANDIDATE_LSP
+       PCEP_MAIN_EVENT_REMOVE_CANDIDATE_LSP,
 };
 
 typedef int (*pcep_main_event_handler_t)(enum pcep_main_event_type type,
                                         int pcc_id, void *payload);
+typedef void (*pcep_refine_callback_t)(struct ctrl_state *ctrl_state,
+                                      struct pcc_state *pcc_state,
+                                      struct path *path, void *payload);
 
 enum pcep_pathd_event_type {
        PCEP_PATH_UNDEFINED = 0,
@@ -124,10 +129,13 @@ pcep_session *pcep_ctrl_get_pcep_session(struct frr_pthread *fpt, int pcc_id);
 struct pcep_pcc_info *pcep_ctrl_get_pcc_info(struct frr_pthread *fpt,
                                             const char *pce_name);
 
-/* Synchronously send a report, the caller is responsible to free the path,
- * If `pcc_id` is `0` the report is sent by all PCCs */
-void pcep_ctrl_send_report(struct frr_pthread *fpt, int pcc_id,
-                          struct path *path);
+/* Asynchronously send a report. The caller is giving away the path structure,
+ * it shouldn't be allocated on the stack. If `pcc_id` is `0` the report is
+ * sent by all PCCs.  The parameter is_stable is used to hint wether the status
+ * will soon change, this is used to ensure all report updates are sent even
+ * when missing status update events */
+int pcep_ctrl_send_report(struct frr_pthread *fpt, int pcc_id,
+                         struct path *path, bool is_stable);
 
 /* Functions called from the controller thread */
 void pcep_thread_start_sync(struct ctrl_state *ctrl_state, int pcc_id);
@@ -162,5 +170,9 @@ int pcep_thread_send_ctrl_event(void *fpt, void *payload,
                                pcep_ctrl_thread_callback cb);
 int pcep_thread_pcep_event(struct thread *thread);
 int pcep_thread_pcc_count(struct ctrl_state *ctrl_state);
+/* Called by the PCC to refine a path in the main thread */
+int pcep_thread_refine_path(struct ctrl_state *ctrl_state, int pcc_id,
+                           pcep_refine_callback_t cb, struct path *path,
+                           void *payload);
 
 #endif // _PATH_PCEP_CONTROLLER_H_
index bcaadfe4d855757f8a5fde37526e00b593051a81..d222371bbb3925d8ba605cbebc92e27a0649762e 100644 (file)
@@ -636,8 +636,8 @@ const char *pcep_message_type_name(enum pcep_message_types pcep_message_type)
                return "UPDATE";
        case PCEP_TYPE_INITIATE:
                return "INITIATE";
-       case PCEP_TYPE_UNKOWN_MSG:
-               return "UNKOWN_MSG";
+       case PCEP_TYPE_START_TLS:
+               return "START_TLS";
        default:
                return "UNKNOWN";
        }
@@ -1288,7 +1288,7 @@ void _format_path_hop(int ps, struct path_hop *hop)
                                     &hop->nai.remote_addr.ipaddr_v6);
                        break;
                case PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY:
-                       PATHD_FORMAT("%*sNAI: %pI4(%u)/%pI4(%u)\n", ps, "",
+                       PATHD_FORMAT("%*sNAI: %pI6(%u)/%pI6(%u)\n", ps, "",
                                     &hop->nai.local_addr.ipaddr_v6,
                                     hop->nai.local_iface,
                                     &hop->nai.remote_addr.ipaddr_v6,
index 68b29ab6579d4ddbafa050a34c1b25c088a9b6d5..5a504e4e1a9d743d7ad224d39c249653d7396922 100644 (file)
@@ -20,8 +20,8 @@
 #define _PATH_PCEP_DEBUG_H_
 
 #include "pathd/path_debug.h"
-#include <pcep_pcc_api.h>
-#include <pcep-objects.h>
+#include "pceplib/pcep_pcc_api.h"
+#include "pceplib/pcep_msg_objects.h"
 #include "pathd/path_pcep.h"
 #include "pathd/path_pcep_controller.h"
 #include "pathd/path_pcep_pcc.h"
index bb6bfb133641453504476963997d4be939bb3f48..e9d699de47137a906c95e7543da4ad2ba4a22ba0 100644 (file)
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+#include <zebra.h>
+
+#include "memory.h"
+
 #include <debug.h>
-#include <pcep_utils_counters.h>
-#include <pcep_timers.h>
+#include "pceplib/pcep_utils_counters.h"
+#include "pceplib/pcep_timers.h"
 #include "pathd/path_errors.h"
-#include "pathd/path_memory.h"
 #include "pathd/path_pcep.h"
 #include "pathd/path_pcep_lib.h"
 #include "pathd/path_pcep_debug.h"
-#include "pathd/path_pcep_memory.h"
+
+DEFINE_MTYPE_STATIC(PATHD, PCEPLIB_INFRA,    "PCEPlib Infrastructure");
+DEFINE_MTYPE_STATIC(PATHD, PCEPLIB_MESSAGES, "PCEPlib PCEP Messages");
 
 #define CLASS_TYPE(CLASS, TYPE) (((CLASS) << 16) | (TYPE))
 #define DEFAULT_LSAP_SETUP_PRIO 4
@@ -176,11 +181,11 @@ pcep_lib_connect(struct ipaddr *src_addr, int src_port, struct ipaddr *dst_addr,
        /* TODO when available in the pceplib, set it here
         pcep_options->state_timeout_inteval_seconds;*/
 
-       if (pcep_options->tcp_md5_auth != NULL
-           && pcep_options->tcp_md5_auth[0] != '\0') {
+       if (pcep_options->tcp_md5_auth[0] != '\0') {
                config->is_tcp_auth_md5 = true;
-               strncpy(config->tcp_authentication_str,
-                       pcep_options->tcp_md5_auth, TCP_MD5SIG_MAXKEYLEN);
+               strlcpy(config->tcp_authentication_str,
+                       pcep_options->tcp_md5_auth,
+                       sizeof(config->tcp_authentication_str));
        } else {
                config->is_tcp_auth_md5 = false;
        }
index 3bea28432d6a1de1eb0d293d7e900282d19470db..3f34edcb3fbc7df051a1f736b19519b7becf81a4 100644 (file)
@@ -20,7 +20,7 @@
 #define _PATH_PCEP_LIB_H_
 
 #include <stdbool.h>
-#include <pcep_pcc_api.h>
+#include "pceplib/pcep_pcc_api.h"
 #include "frr_pthread.h"
 #include "pathd/path_pcep.h"
 
diff --git a/pathd/path_pcep_memory.c b/pathd/path_pcep_memory.c
deleted file mode 100644 (file)
index 8f60809..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2020  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 <zebra.h>
-
-#include <memory.h>
-
-#include "pathd/path_pcep_memory.h"
-
-DEFINE_MTYPE(PATHD, PCEP, "PCEP module")
-DEFINE_MTYPE(PATHD, PCEPLIB_INFRA, "PCEPlib Infrastructure")
-DEFINE_MTYPE(PATHD, PCEPLIB_MESSAGES, "PCEPlib PCEP Messages")
diff --git a/pathd/path_pcep_memory.h b/pathd/path_pcep_memory.h
deleted file mode 100644 (file)
index 05c5e2d..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2020  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
- */
-
-#ifndef _FRR_PATH_PCEP_MEMORY_H_
-#define _FRR_PATH_PCEP_MEMORY_H_
-
-#include "pathd/path_memory.h"
-
-DECLARE_MTYPE(PCEP)
-DECLARE_MTYPE(PCEPLIB_INFRA)
-DECLARE_MTYPE(PCEPLIB_MESSAGES)
-
-#endif /* _FRR_PATH_PCEP_MEMORY_H_ */
index c1f60edd22a49d274f392fc1170d417f349c884f..a2c1e7cd4cef0363f781780dc6c6136d8a66c852 100644 (file)
@@ -41,7 +41,6 @@
 #include "pathd/pathd.h"
 #include "pathd/path_zebra.h"
 #include "pathd/path_errors.h"
-#include "pathd/path_pcep_memory.h"
 #include "pathd/path_pcep.h"
 #include "pathd/path_pcep_controller.h"
 #include "pathd/path_pcep_lib.h"
@@ -55,6 +54,7 @@
 #define MAX_ERROR_MSG_SIZE 256
 #define MAX_COMPREQ_TRIES 3
 
+pthread_mutex_t g_pcc_info_mtx = PTHREAD_MUTEX_INITIALIZER;
 
 /* PCEP Event Handler */
 static void handle_pcep_open(struct ctrl_state *ctrl_state,
@@ -63,12 +63,15 @@ static void handle_pcep_open(struct ctrl_state *ctrl_state,
 static void handle_pcep_message(struct ctrl_state *ctrl_state,
                                struct pcc_state *pcc_state,
                                struct pcep_message *msg);
+static void handle_pcep_lsp_initiate(struct ctrl_state *ctrl_state,
+                                    struct pcc_state *pcc_state,
+                                    struct pcep_message *msg);
 static void handle_pcep_lsp_update(struct ctrl_state *ctrl_state,
                                   struct pcc_state *pcc_state,
                                   struct pcep_message *msg);
-static void handle_pcep_lsp_initiate(struct ctrl_state *ctrl_state,
+static void continue_pcep_lsp_update(struct ctrl_state *ctrl_state,
                                     struct pcc_state *pcc_state,
-                                    struct pcep_message *msg);
+                                    struct path *path, void *payload);
 static void handle_pcep_comp_reply(struct ctrl_state *ctrl_state,
                                   struct pcc_state *pcc_state,
                                   struct pcep_message *msg);
@@ -143,10 +146,10 @@ static uint32_t req_map_hash(const struct req_map_data *e);
 
 /* Data Structure Declarations */
 DECLARE_HASH(plspid_map, struct plspid_map_data, mi, plspid_map_cmp,
-            plspid_map_hash)
+            plspid_map_hash);
 DECLARE_HASH(nbkey_map, struct nbkey_map_data, mi, nbkey_map_cmp,
-            nbkey_map_hash)
-DECLARE_HASH(req_map, struct req_map_data, mi, req_map_cmp, req_map_hash)
+            nbkey_map_hash);
+DECLARE_HASH(req_map, struct req_map_data, mi, req_map_cmp, req_map_hash);
 
 static inline int req_entry_compare(const struct req_entry *a,
                                    const struct req_entry *b)
@@ -344,9 +347,6 @@ void pcep_pcc_reconnect(struct ctrl_state *ctrl_state,
 
 int pcep_pcc_enable(struct ctrl_state *ctrl_state, struct pcc_state *pcc_state)
 {
-       char pcc_buff[40];
-       char pce_buff[40];
-
        assert(pcc_state->status == PCEP_PCC_DISCONNECTED);
        assert(pcc_state->sess == NULL);
 
@@ -362,17 +362,14 @@ int pcep_pcc_enable(struct ctrl_state *ctrl_state, struct pcc_state *pcc_state)
        if (!CHECK_FLAG(pcc_state->flags, F_PCC_STATE_HAS_IPV4)) {
                if (pcc_state->retry_count < OTHER_FAMILY_MAX_RETRIES) {
                        flog_warn(EC_PATH_PCEP_MISSING_SOURCE_ADDRESS,
-                                 "skipping connection to PCE %s:%d due to "
-                                 "missing PCC IPv4 address",
-                                 ipaddr2str(&pcc_state->pce_opts->addr,
-                                            pce_buff, sizeof(pce_buff)),
+                                 "skipping connection to PCE %pIA:%d due to missing PCC IPv4 address",
+                                 &pcc_state->pce_opts->addr,
                                  pcc_state->pce_opts->port);
                        schedule_reconnect(ctrl_state, pcc_state);
                        return 0;
                } else {
                        flog_warn(EC_PATH_PCEP_MISSING_SOURCE_ADDRESS,
-                                 "missing IPv4 PCC address, IPv4 candidate "
-                                 "paths will be ignored");
+                                 "missing IPv4 PCC address, IPv4 candidate paths will be ignored");
                }
        }
 
@@ -381,17 +378,14 @@ int pcep_pcc_enable(struct ctrl_state *ctrl_state, struct pcc_state *pcc_state)
        if (!CHECK_FLAG(pcc_state->flags, F_PCC_STATE_HAS_IPV6)) {
                if (pcc_state->retry_count < OTHER_FAMILY_MAX_RETRIES) {
                        flog_warn(EC_PATH_PCEP_MISSING_SOURCE_ADDRESS,
-                                 "skipping connection to PCE %s:%d due to "
-                                 "missing PCC IPv6 address",
-                                 ipaddr2str(&pcc_state->pce_opts->addr,
-                                            pce_buff, sizeof(pce_buff)),
+                                 "skipping connection to PCE %pIA:%d due to missing PCC IPv6 address",
+                                 &pcc_state->pce_opts->addr,
                                  pcc_state->pce_opts->port);
                        schedule_reconnect(ctrl_state, pcc_state);
                        return 0;
                } else {
                        flog_warn(EC_PATH_PCEP_MISSING_SOURCE_ADDRESS,
-                                 "missing IPv6 PCC address, IPv6 candidate "
-                                 "paths will be ignored");
+                                 "missing IPv6 PCC address, IPv6 candidate paths will be ignored");
                }
        }
 
@@ -399,10 +393,8 @@ int pcep_pcc_enable(struct ctrl_state *ctrl_state, struct pcc_state *pcc_state)
         * have been spent, we still need the one for the transport familly */
        if (pcc_state->pcc_addr_tr.ipa_type == IPADDR_NONE) {
                flog_warn(EC_PATH_PCEP_MISSING_SOURCE_ADDRESS,
-                         "skipping connection to PCE %s:%d due to missing "
-                         "PCC address",
-                         ipaddr2str(&pcc_state->pce_opts->addr, pce_buff,
-                                    sizeof(pce_buff)),
+                         "skipping connection to PCE %pIA:%d due to missing PCC address",
+                         &pcc_state->pce_opts->addr,
                          pcc_state->pce_opts->port);
                schedule_reconnect(ctrl_state, pcc_state);
                return 0;
@@ -416,12 +408,10 @@ int pcep_pcc_enable(struct ctrl_state *ctrl_state, struct pcc_state *pcc_state)
 
        if (pcc_state->sess == NULL) {
                flog_warn(EC_PATH_PCEP_LIB_CONNECT,
-                         "failed to connect to PCE %s:%d from %s:%d",
-                         ipaddr2str(&pcc_state->pce_opts->addr, pce_buff,
-                                    sizeof(pce_buff)),
+                         "failed to connect to PCE %pIA:%d from %pIA:%d",
+                         &pcc_state->pce_opts->addr,
                          pcc_state->pce_opts->port,
-                         ipaddr2str(&pcc_state->pcc_addr_tr, pcc_buff,
-                                    sizeof(pcc_buff)),
+                         &pcc_state->pcc_addr_tr,
                          pcc_state->pcc_opts->port);
                schedule_reconnect(ctrl_state, pcc_state);
                return 0;
@@ -494,8 +484,7 @@ void pcep_pcc_sync_path(struct ctrl_state *ctrl_state,
                        send_report(pcc_state, path);
                } else {
                        PCEP_DEBUG(
-                               "%s Skipping %s candidate path %s "
-                               "synchronization",
+                               "%s Skipping %s candidate path %s synchronization",
                                pcc_state->tag,
                                ipaddr_type_name(&path->nbkey.endpoint),
                                path->name);
@@ -543,23 +532,43 @@ void pcep_pcc_sync_done(struct ctrl_state *ctrl_state,
 }
 
 void pcep_pcc_send_report(struct ctrl_state *ctrl_state,
-                         struct pcc_state *pcc_state, struct path *path)
+                         struct pcc_state *pcc_state, struct path *path,
+                         bool is_stable)
 {
-       if (pcc_state->status != PCEP_PCC_OPERATING)
+       if ((pcc_state->status != PCEP_PCC_OPERATING)
+           || (!pcc_state->caps.is_stateful)) {
+               pcep_free_path(path);
                return;
+       }
 
-       if (pcc_state->caps.is_stateful) {
-               PCEP_DEBUG("%s Send report for candidate path %s",
-                          pcc_state->tag, path->name);
+       PCEP_DEBUG("%s Send report for candidate path %s", pcc_state->tag,
+                  path->name);
+
+       /* ODL and Cisco requires the first reported
+        * LSP to have a DOWN status, the later status changes
+        * will be comunicated through hook calls.
+        */
+       enum pcep_lsp_operational_status real_status = path->status;
+       path->status = PCEP_LSP_OPERATIONAL_DOWN;
+       send_report(pcc_state, path);
+
+       /* If no update is expected and the real status wasn't down, we need to
+        * send a second report with the real status */
+       if (is_stable && (real_status != PCEP_LSP_OPERATIONAL_DOWN)) {
+               path->srp_id = 0;
+               path->status = real_status;
                send_report(pcc_state, path);
        }
+
+       pcep_free_path(path);
 }
 
+
 /* ------------ Timeout handler ------------ */
 
 void pcep_pcc_timeout_handler(struct ctrl_state *ctrl_state,
                              struct pcc_state *pcc_state,
-                             enum pcep_ctrl_timer_type type, void *param)
+                             enum pcep_ctrl_timeout_type type, void *param)
 {
        struct req_entry *req;
 
@@ -926,6 +935,7 @@ int pcep_pcc_calculate_best_pce(struct pcc_state **pcc)
 
        // Changed of state so ...
        if (step_0_best != best_pce) {
+               pthread_mutex_lock(&g_pcc_info_mtx);
                // Calculate previous
                previous_best_pce = step_0_best;
                // Clean state
@@ -970,6 +980,7 @@ int pcep_pcc_calculate_best_pce(struct pcc_state **pcc)
                                }
                        }
                }
+               pthread_mutex_unlock(&g_pcc_info_mtx);
        }
 
        return ((best_pce == -1) ? 0 : pcc[best_pce]->id);
@@ -1094,18 +1105,24 @@ void pcep_pcc_copy_pcc_info(struct pcc_state **pcc,
        }
 
        pcc_info->ctrl_state = NULL;
-       pcc_info->msd = pcc_state->pcc_opts->msd;
-       pcc_info->pcc_port = pcc_state->pcc_opts->port;
+       if(pcc_state->pcc_opts){
+               pcc_info->msd = pcc_state->pcc_opts->msd;
+               pcc_info->pcc_port = pcc_state->pcc_opts->port;
+       }
        pcc_info->next_plspid = pcc_state->next_plspid;
        pcc_info->next_reqid = pcc_state->next_reqid;
        pcc_info->status = pcc_state->status;
        pcc_info->pcc_id = pcc_state->id;
+       pthread_mutex_lock(&g_pcc_info_mtx);
        pcc_info->is_best_multi_pce = pcc_state->is_best;
        pcc_info->previous_best = pcc_state->previous_best;
+       pthread_mutex_unlock(&g_pcc_info_mtx);
        pcc_info->precedence =
                pcc_state->pce_opts ? pcc_state->pce_opts->precedence : 0;
-       memcpy(&pcc_info->pcc_addr, &pcc_state->pcc_addr_tr,
-              sizeof(struct ipaddr));
+       if(pcc_state->pcc_addr_tr.ipa_type != IPADDR_NONE){
+               memcpy(&pcc_info->pcc_addr, &pcc_state->pcc_addr_tr,
+                      sizeof(struct ipaddr));
+       }
 }
 
 
@@ -1154,12 +1171,19 @@ void handle_pcep_lsp_update(struct ctrl_state *ctrl_state,
                            struct pcc_state *pcc_state,
                            struct pcep_message *msg)
 {
-       char err[MAX_ERROR_MSG_SIZE] = "";
        struct path *path;
        path = pcep_lib_parse_path(msg);
        lookup_nbkey(pcc_state, path);
-       /* TODO: Investigate if this is safe to do in the controller thread */
-       path_pcep_config_lookup(path);
+       pcep_thread_refine_path(ctrl_state, pcc_state->id,
+                               &continue_pcep_lsp_update, path, NULL);
+}
+
+void continue_pcep_lsp_update(struct ctrl_state *ctrl_state,
+                             struct pcc_state *pcc_state, struct path *path,
+                             void *payload)
+{
+       char err[MAX_ERROR_MSG_SIZE] = {0};
+
        specialize_incoming_path(pcc_state, path);
        PCEP_DEBUG("%s Received LSP update", pcc_state->tag);
        PCEP_DEBUG_PATH("%s", format_path(path));
@@ -1204,8 +1228,7 @@ void handle_pcep_comp_reply(struct ctrl_state *ctrl_state,
                 * the connection if more that a given rate.
                 */
                PCEP_DEBUG(
-                       "%s Received computation reply for unknown request "
-                       "%d",
+                       "%s Received computation reply for unknown request %d",
                        pcc_state->tag, path->req_id);
                PCEP_DEBUG_PATH("%s", format_path(path));
                send_pcep_error(pcc_state, PCEP_ERRT_UNKNOWN_REQ_REF,
@@ -1309,13 +1332,13 @@ void select_transport_address(struct pcc_state *pcc_state)
         * address */
        if (IS_IPADDR_V4(&pcc_state->pce_opts->addr)) {
                if (CHECK_FLAG(pcc_state->flags, F_PCC_STATE_HAS_IPV4)) {
-                       taddr->ipa_type = IPADDR_V4;
                        taddr->ipaddr_v4 = pcc_state->pcc_addr_v4;
+                       taddr->ipa_type = IPADDR_V4;
                }
        } else {
                if (CHECK_FLAG(pcc_state->flags, F_PCC_STATE_HAS_IPV6)) {
-                       taddr->ipa_type = IPADDR_V6;
                        taddr->ipaddr_v6 = pcc_state->pcc_addr_v6;
+                       taddr->ipa_type = IPADDR_V6;
                }
        }
 }
@@ -1535,7 +1558,6 @@ void send_comp_request(struct ctrl_state *ctrl_state,
        assert(lookup_reqid(pcc_state, req->path) == req->path->req_id);
 
        int timeout;
-       char buff[40];
        struct pcep_message *msg;
 
        if (!pcc_state->is_best) {
@@ -1546,10 +1568,9 @@ void send_comp_request(struct ctrl_state *ctrl_state,
        specialize_outgoing_path(pcc_state, req->path);
 
        PCEP_DEBUG(
-               "%s Sending computation request %d for path %s to %s (retry %d)",
+               "%s Sending computation request %d for path %s to %pIA (retry %d)",
                pcc_state->tag, req->path->req_id, req->path->name,
-               ipaddr2str(&req->path->nbkey.endpoint, buff, sizeof(buff)),
-               req->retry_count);
+               &req->path->nbkey.endpoint, req->retry_count);
        PCEP_DEBUG_PATH("%s Computation request path %s: %s", pcc_state->tag,
                        req->path->name, format_path(req->path));
 
@@ -1582,7 +1603,6 @@ void cancel_comp_requests(struct ctrl_state *ctrl_state,
 void cancel_comp_request(struct ctrl_state *ctrl_state,
                         struct pcc_state *pcc_state, struct req_entry *req)
 {
-       char buff[40];
        struct pcep_message *msg;
 
        if (req->was_sent) {
@@ -1592,10 +1612,9 @@ void cancel_comp_request(struct ctrl_state *ctrl_state,
        }
 
        PCEP_DEBUG(
-               "%s Canceling computation request %d for path %s to %s (retry %d)",
+               "%s Canceling computation request %d for path %s to %pIA (retry %d)",
                pcc_state->tag, req->path->req_id, req->path->name,
-               ipaddr2str(&req->path->nbkey.endpoint, buff, sizeof(buff)),
-               req->retry_count);
+               &req->path->nbkey.endpoint, req->retry_count);
        PCEP_DEBUG_PATH("%s Canceled computation request path %s: %s",
                        pcc_state->tag, req->path->name,
                        format_path(req->path));
index a466d92d507102681e5fbdcf0b0b2b01850f163c..ceac6f32781013c169103a3bcb3cc63bf0678b96 100644 (file)
@@ -30,9 +30,9 @@ enum pcc_status {
        PCEP_PCC_OPERATING
 };
 
-PREDECL_HASH(plspid_map)
-PREDECL_HASH(nbkey_map)
-PREDECL_HASH(req_map)
+PREDECL_HASH(plspid_map);
+PREDECL_HASH(nbkey_map);
+PREDECL_HASH(req_map);
 
 struct plspid_map_data {
        struct plspid_map_item mi;
@@ -113,13 +113,18 @@ void pcep_pcc_pathd_event_handler(struct ctrl_state *ctrl_state,
                                  struct path *path);
 void pcep_pcc_timeout_handler(struct ctrl_state *ctrl_state,
                              struct pcc_state *pcc_state,
-                             enum pcep_ctrl_timer_type type, void *param);
+                             enum pcep_ctrl_timeout_type type, void *param);
 void pcep_pcc_sync_path(struct ctrl_state *ctrl_state,
                        struct pcc_state *pcc_state, struct path *path);
 void pcep_pcc_sync_done(struct ctrl_state *ctrl_state,
                        struct pcc_state *pcc_state);
+/* Send a report explicitly. When doing so the PCC may send multiple reports
+ * due to expectations from vendors for the first report to be with a DOWN
+ * status. The parameter is_stable is used for that purpose as a hint wheter
+ * to expect an update for the report */
 void pcep_pcc_send_report(struct ctrl_state *ctrl_state,
-                         struct pcc_state *pcc_state, struct path *path);
+                         struct pcc_state *pcc_state, struct path *path,
+                         bool is_stable);
 int pcep_pcc_multi_pce_sync_path(struct ctrl_state *ctrl_state, int pcc_id,
                                 struct pcc_state **pcc_state_list);
 int pcep_pcc_multi_pce_remove_pcc(struct ctrl_state *ctrl_state,
index e2c7c957280e430c39e992d466d2b2c565878b48..ae8218631584d7b8ec9cbf188d8e0ce530e1dc27 100644 (file)
 #include "network.h"
 
 #include "pathd/pathd.h"
-#include "pathd/path_memory.h"
 #include "pathd/path_zebra.h"
 #include "pathd/path_debug.h"
 
 #define HOOK_DELAY 3
 
-DEFINE_MTYPE_STATIC(PATHD, PATH_SEGMENT_LIST, "Segment List")
-DEFINE_MTYPE_STATIC(PATHD, PATH_SR_POLICY, "SR Policy")
-DEFINE_MTYPE_STATIC(PATHD, PATH_SR_CANDIDATE, "SR Policy candidate path")
+DEFINE_MGROUP(PATHD, "pathd");
+
+DEFINE_MTYPE_STATIC(PATHD, PATH_SEGMENT_LIST, "Segment List");
+DEFINE_MTYPE_STATIC(PATHD, PATH_SR_POLICY, "SR Policy");
+DEFINE_MTYPE_STATIC(PATHD, PATH_SR_CANDIDATE, "SR Policy candidate path");
 
 DEFINE_HOOK(pathd_candidate_created, (struct srte_candidate * candidate),
-           (candidate))
+           (candidate));
 DEFINE_HOOK(pathd_candidate_updated, (struct srte_candidate * candidate),
-           (candidate))
+           (candidate));
 DEFINE_HOOK(pathd_candidate_removed, (struct srte_candidate * candidate),
-           (candidate))
+           (candidate));
 
 static void trigger_pathd_candidate_created(struct srte_candidate *candidate);
 static int trigger_pathd_candidate_created_timer(struct thread *thread);
@@ -624,8 +625,7 @@ void srte_candidate_set_metric(struct srte_candidate *candidate,
        char endpoint[46];
        ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
        zlog_debug(
-               "SR-TE(%s, %u): candidate %s %sconfig metric %s (%u) set to %f "
-               "(is-bound: %s; is_computed: %s)",
+               "SR-TE(%s, %u): candidate %s %sconfig metric %s (%u) set to %f (is-bound: %s; is_computed: %s)",
                endpoint, policy->color, candidate->name,
                required ? "required " : "", srte_candidate_metric_name(type),
                type, value, is_bound ? "true" : "false",
@@ -659,8 +659,7 @@ void srte_lsp_set_metric(struct srte_lsp *lsp,
        char endpoint[46];
        ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
        zlog_debug(
-               "SR-TE(%s, %u): candidate %s %slsp metric %s (%u) set to %f "
-               "(is-bound: %s; is_computed: %s)",
+               "SR-TE(%s, %u): candidate %s %slsp metric %s (%u) set to %f (is-bound: %s; is_computed: %s)",
                endpoint, policy->color, candidate->name,
                required ? "required " : "", srte_candidate_metric_name(type),
                type, value, is_bound ? "true" : "false",
@@ -981,8 +980,7 @@ void srte_candidate_unset_segment_list(const char *originator, bool force)
                        if (segment_list->protocol_origin
                            == SRTE_ORIGIN_LOCAL) {
                                zlog_warn(
-                                       "Cannot unset segment list %s because it "
-                                       "was created locally",
+                                       "Cannot unset segment list %s because it was created locally",
                                        segment_list->name);
                                continue;
                        }
index 4879239db88f1e2b71ec78736390170638a1fd67..9c4d256ceff27f5328a3e88004728f8cbe4d2c0e 100644 (file)
 #ifndef _FRR_PATHD_H_
 #define _FRR_PATHD_H_
 
+#include "lib/memory.h"
 #include "lib/mpls.h"
 #include "lib/ipaddr.h"
 #include "lib/srte.h"
 #include "lib/hook.h"
 
+DECLARE_MGROUP(PATHD);
+
 enum srte_protocol_origin {
        SRTE_ORIGIN_UNDEFINED = 0,
        SRTE_ORIGIN_PCEP = 1,
@@ -338,11 +341,11 @@ RB_HEAD(srte_policy_head, srte_policy);
 RB_PROTOTYPE(srte_policy_head, srte_policy, entry, srte_policy_compare)
 
 DECLARE_HOOK(pathd_candidate_created, (struct srte_candidate * candidate),
-            (candidate))
+            (candidate));
 DECLARE_HOOK(pathd_candidate_updated, (struct srte_candidate * candidate),
-            (candidate))
+            (candidate));
 DECLARE_HOOK(pathd_candidate_removed, (struct srte_candidate * candidate),
-            (candidate))
+            (candidate));
 
 extern struct srte_segment_list_head srte_segment_lists;
 extern struct srte_policy_head srte_policies;
index 520a8c696a9299235c071f81dbd10667ecf02952..b4501214bfe8ec4905b3d5876e41510987137b89 100644 (file)
@@ -11,7 +11,7 @@ vtysh_daemons += pathd
 # TODO add man page
 #man8 += $(MANBUILD)/pathd.8
 
-if HAVE_PATHD_PCEP
+if PATHD_PCEP
 vtysh_scan += $(top_srcdir)/pathd/path_pcep_cli.c
 module_LTLIBRARIES += pathd/pathd_pcep.la
 endif
@@ -23,7 +23,6 @@ pathd_libpath_a_SOURCES = \
        pathd/path_debug.c \
        pathd/path_errors.c \
        pathd/path_main.c \
-       pathd/path_memory.c \
        pathd/path_nb.c \
        pathd/path_nb_config.c \
        pathd/path_nb_state.c \
@@ -39,14 +38,12 @@ clippy_scan += \
 noinst_HEADERS += \
        pathd/path_debug.h \
        pathd/path_errors.h \
-       pathd/path_memory.h \
        pathd/path_nb.h \
        pathd/path_pcep.h \
        pathd/path_pcep_cli.h \
        pathd/path_pcep_controller.h \
        pathd/path_pcep_debug.h \
        pathd/path_pcep_lib.h \
-       pathd/path_pcep_memory.h \
        pathd/path_pcep_config.h \
        pathd/path_pcep_pcc.h \
        pathd/path_zebra.h \
@@ -65,10 +62,18 @@ pathd_pathd_pcep_la_SOURCES = \
        pathd/path_pcep_controller.c \
        pathd/path_pcep_debug.c \
        pathd/path_pcep_lib.c \
-       pathd/path_pcep_memory.c \
        pathd/path_pcep_config.c \
        pathd/path_pcep_pcc.c \
        # end
+
+if PATHD_PCEP
+pathd_pathd_pcep_la_CPPFLAGS = -I./pceplib $(AM_CPPFLAGS)
+pathd_pathd_pcep_la_LIBADD = pceplib/libpcep_pcc.la
+else
+pathd_pathd_pcep_la_CPPFLAGS = $(AM_CPPFLAGS)
+pathd_pathd_pcep_la_LIBADD =
+endif
+
+
 pathd_pathd_pcep_la_CFLAGS = $(WERROR)
 pathd_pathd_pcep_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
-pathd_pathd_pcep_la_LIBADD = @PATHD_PCEP_LIBS@
index 01c52f24e53c95cc7e36361f7061c030fd1ba04d..1badaf95bddf0a8bd25d71304fab4a89819e3b04 100644 (file)
@@ -131,7 +131,8 @@ FRR_DAEMON_INFO(pbrd, PBR, .vty_port = PBR_VTY_PORT,
                .privs = &pbr_privs,
 
                .yang_modules = pbrd_yang_modules,
-               .n_yang_modules = array_size(pbrd_yang_modules), )
+               .n_yang_modules = array_size(pbrd_yang_modules),
+);
 
 int main(int argc, char **argv, char **envp)
 {
index 5b851988f64ab0dfd2f23ee351bd4dbebeea186f..053b7363a30964ff0b49aaa9f5fa320b90cf2c00 100644 (file)
@@ -37,9 +37,9 @@
 #include "pbr_debug.h"
 #include "pbr_vrf.h"
 
-DEFINE_MTYPE_STATIC(PBRD, PBR_MAP, "PBR Map")
-DEFINE_MTYPE_STATIC(PBRD, PBR_MAP_SEQNO, "PBR Map Sequence")
-DEFINE_MTYPE_STATIC(PBRD, PBR_MAP_INTERFACE, "PBR Map Interface")
+DEFINE_MTYPE_STATIC(PBRD, PBR_MAP, "PBR Map");
+DEFINE_MTYPE_STATIC(PBRD, PBR_MAP_SEQNO, "PBR Map Sequence");
+DEFINE_MTYPE_STATIC(PBRD, PBR_MAP_INTERFACE, "PBR Map Interface");
 
 static uint32_t pbr_map_sequence_unique;
 
@@ -51,7 +51,7 @@ RB_GENERATE(pbr_map_entry_head, pbr_map, pbr_map_entry, pbr_map_compare)
 
 struct pbr_map_entry_head pbr_maps = RB_INITIALIZER(&pbr_maps);
 
-DEFINE_QOBJ_TYPE(pbr_map_sequence)
+DEFINE_QOBJ_TYPE(pbr_map_sequence);
 
 static inline int pbr_map_compare(const struct pbr_map *pbrmap1,
                                  const struct pbr_map *pbrmap2)
index ad2db146b7e6309da5aa20b05e3d2af9d9caee7c..caeadb064413837f35f3e1837edfb2450aa6ec07 100644 (file)
@@ -149,10 +149,10 @@ struct pbr_map_sequence {
 #define PBR_MAP_INVALID_VRF              (1 << 5)
        uint64_t reason;
 
-       QOBJ_FIELDS
+       QOBJ_FIELDS;
 };
 
-DECLARE_QOBJ_TYPE(pbr_map_sequence)
+DECLARE_QOBJ_TYPE(pbr_map_sequence);
 
 extern struct pbr_map_entry_head pbr_maps;
 
index febe406ca75ae7fca6cfca46b9db4c64b772878c..5531d41935f9b422bb8105eb28e750e17ae51a22 100644 (file)
@@ -24,4 +24,4 @@
 #include "pbrd/pbr_memory.h"
 
 
-DEFINE_MGROUP(PBRD, "pbrd")
+DEFINE_MGROUP(PBRD, "pbrd");
index a87d519099c9a4ca0afd1d0906a334ad305bd652..eb13d5d9d1d57eab36ebe6e460096ad57106ca4c 100644 (file)
@@ -19,6 +19,6 @@
  */
 #ifndef __PBR_MEMORY_H__
 
-DECLARE_MGROUP(PBRD)
+DECLARE_MGROUP(PBRD);
 
 #endif
index ba9ad97ab8689c015b9cd030e9f5671c9aac28b0..e127999b0b22c298842bf057d894bc333609ac9a 100644 (file)
@@ -35,7 +35,7 @@
 #include "pbrd/pbr_memory.h"
 #include "pbrd/pbr_debug.h"
 
-DEFINE_MTYPE_STATIC(PBRD, PBR_NHG, "PBR Nexthop Groups")
+DEFINE_MTYPE_STATIC(PBRD, PBR_NHG, "PBR Nexthop Groups");
 
 struct hash *pbr_nhg_hash;
 static struct hash *pbr_nhrc_hash;
index 3284607406d09d481b192c61239ad82aa1c10936..1b69e23ce391259891f454b2ce17e702e9b8c0c1 100644 (file)
@@ -28,7 +28,7 @@
 #include "pbr_nht.h"
 #include "pbr_zebra.h"
 
-DEFINE_MTYPE_STATIC(PBRD, PBR_MAP_VRF, "PBR Map VRF")
+DEFINE_MTYPE_STATIC(PBRD, PBR_MAP_VRF, "PBR Map VRF");
 
 static struct pbr_vrf *pbr_vrf_alloc(void)
 {
index 467bbc8f72ca45dfaa015617652a416d52a9a20c..4b73e13c27f463b8da96f03ebdab2575e2a95c5d 100644 (file)
@@ -41,7 +41,7 @@
 #include "pbr_debug.h"
 #include "pbr_vrf.h"
 
-DEFINE_MTYPE_STATIC(PBRD, PBR_INTERFACE, "PBR Interface")
+DEFINE_MTYPE_STATIC(PBRD, PBR_INTERFACE, "PBR Interface");
 
 /* Zebra structure to hold current status. */
 struct zclient *zclient;
diff --git a/pceplib/.gitignore b/pceplib/.gitignore
new file mode 100644 (file)
index 0000000..5861f25
--- /dev/null
@@ -0,0 +1,14 @@
+pcep_pcc
+test/pcep_msg_tests
+test/pcep_pcc_api_tests
+test/pcep_session_logic_tests
+test/pcep_socket_comm_tests
+test/pcep_timers_tests
+test/pcep_utils_tests
+test/valgrind.pcep_msg_tests.log
+test/valgrind.pcep_pcc_api_tests.log
+test/valgrind.pcep_session_logic_tests.log
+test/valgrind.pcep_socket_comm_tests.log
+test/valgrind.pcep_timers_tests.log
+test/valgrind.pcep_utils_tests.log
+../test-driver
diff --git a/pceplib/pcep.h b/pceplib/pcep.h
new file mode 100644 (file)
index 0000000..278ab9d
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Javier Garcia <javier.garcia@voltanet.io>
+ *
+ */
+
+
+#ifndef PCEP_H_
+#define PCEP_H_
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#if defined(linux) || defined(GNU_LINUX)
+//#include <netinet/in.h>
+#define ipv6_u __in6_u
+#else
+// bsd family
+#define TCP_MD5SIG_MAXKEYLEN 80
+//#include <netinet/in.h>
+#define ipv6_u __u6_addr
+#ifdef __FreeBSD__
+#include <sys/endian.h>
+#else
+#include <endian.h>
+#endif /* __FreeBSD__ */
+#endif
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#endif
diff --git a/pceplib/pcep_msg_encoding.h b/pceplib/pcep_msg_encoding.h
new file mode 100644 (file)
index 0000000..d835b87
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+/*
+ * Definitions for encoding and decoding PCEP messages, objects, and TLVs.
+ */
+
+#ifndef PCEP_ENCODING_H
+#define PCEP_ENCODING_H
+
+#include <stdbool.h>
+
+#include "pcep_msg_messages.h"
+#include "pcep_msg_objects.h"
+#include "pcep_msg_tlvs.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct pcep_versioning {
+       bool draft_ietf_pce_segment_routing_07; /* If false, use draft16 */
+       /* As more draft versions are incorporated, add appropriate attributes
+        */
+};
+
+#define MESSAGE_HEADER_LENGTH 4
+#define PCEP_MESSAGE_LENGTH 65535
+#define OBJECT_HEADER_LENGTH 4
+#define OBJECT_RO_SUBOBJ_HEADER_LENGTH 2
+#define TLV_HEADER_LENGTH 4
+#define LENGTH_1WORD sizeof(uint32_t)
+#define LENGTH_2WORDS sizeof(uint32_t) * 2
+#define LENGTH_3WORDS sizeof(uint32_t) * 3
+#define LENGTH_4WORDS sizeof(uint32_t) * 4
+#define LENGTH_5WORDS sizeof(uint32_t) * 5
+#define LENGTH_6WORDS sizeof(uint32_t) * 6
+#define LENGTH_7WORDS sizeof(uint32_t) * 7
+#define LENGTH_8WORDS sizeof(uint32_t) * 8
+#define LENGTH_9WORDS sizeof(uint32_t) * 9
+#define LENGTH_10WORDS sizeof(uint32_t) * 10
+#define LENGTH_11WORDS sizeof(uint32_t) * 11
+#define LENGTH_12WORDS sizeof(uint32_t) * 12
+#define LENGTH_13WORDS sizeof(uint32_t) * 13
+
+/* When iterating sub-objects or TLVs, limit to 10 in case corrupt data is
+ * received */
+#define MAX_ITERATIONS 10
+
+struct pcep_versioning *create_default_pcep_versioning(void);
+void destroy_pcep_versioning(struct pcep_versioning *versioning);
+
+/*
+ * Message encoding / decoding functions
+ */
+
+/* Called before sending messages to encode the message to a byte buffer in
+ * Network byte order. This function will also encode all the objects and their
+ * TLVs in the message. The result will be stored in the encoded_message field
+ * in the pcep_message. Implemented in pcep-messages-encoding.c */
+void pcep_encode_message(struct pcep_message *message,
+                        struct pcep_versioning *versioning);
+
+/* Decode the message header and return the message length.
+ * Returns < 0 for invalid message headers. */
+int32_t pcep_decode_validate_msg_header(const uint8_t *msg_buf);
+
+/* Decode the entire message */
+struct pcep_message *pcep_decode_message(const uint8_t *message_buffer);
+
+
+/*
+ * Object encoding / decoding functions
+ */
+
+/* Implemented in pcep-objects-encoding.c
+ * Encode the object in struct pcep_object_header* into the uint8_t *buf,
+ * and return the encoded object_length. */
+uint16_t pcep_encode_object(struct pcep_object_header *object_hdr,
+                           struct pcep_versioning *versioning, uint8_t *buf);
+
+/* Implemented in pcep-objects-encoding.c
+ * Decode the object, including the TLVs (if any) and return the object.
+ * Returns object on success, NULL otherwise. */
+struct pcep_object_header *pcep_decode_object(const uint8_t *msg_buf);
+
+/* Internal util functions implemented in pcep-objects-encoding.c */
+void encode_ipv6(struct in6_addr *src_ipv6, uint32_t *dst);
+void decode_ipv6(const uint32_t *src, struct in6_addr *dst_ipv6);
+uint16_t normalize_pcep_tlv_length(uint16_t length);
+bool pcep_object_has_tlvs(struct pcep_object_header *object_hdr);
+uint16_t pcep_object_get_length_by_hdr(struct pcep_object_header *object_hdr);
+uint16_t pcep_object_get_length(enum pcep_object_classes object_class,
+                               enum pcep_object_types object_type);
+
+
+/*
+ * TLV encoding / decoding functions
+ */
+
+/* Implemented in pcep-tlv-encoding.c
+ * Encode the tlv in struct pcep_tlv_header* into the uint8_t *buf,
+ * and return the encoded tlv_length. */
+uint16_t pcep_encode_tlv(struct pcep_object_tlv_header *tlv_hdr,
+                        struct pcep_versioning *versioning, uint8_t *buf);
+
+/* Decode the TLV in tlv_buf and return a pointer to the object */
+struct pcep_object_tlv_header *pcep_decode_tlv(const uint8_t *tlv_buf);
+
+
+/*
+ * utils mainly for testing purposes
+ */
+bool validate_message_objects(struct pcep_message *msg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/pceplib/pcep_msg_messages.c b/pceplib/pcep_msg_messages.c
new file mode 100644 (file)
index 0000000..ec2a237
--- /dev/null
@@ -0,0 +1,308 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+/*
+ * This is the implementation of a High Level PCEP message API.
+ */
+
+#include <string.h>
+#include <arpa/inet.h>
+#include <stdarg.h>
+#include <unistd.h>
+
+#include "pcep_msg_encoding.h"
+#include "pcep_msg_messages.h"
+#include "pcep_msg_objects.h"
+#include "pcep_utils_double_linked_list.h"
+#include "pcep_utils_logging.h"
+#include "pcep_utils_memory.h"
+
+static struct pcep_message *
+pcep_msg_create_common_with_obj_list(enum pcep_message_types msg_type,
+                                    double_linked_list *obj_list)
+{
+       struct pcep_message *message =
+               pceplib_malloc(PCEPLIB_MESSAGES, sizeof(struct pcep_message));
+       memset(message, 0, sizeof(struct pcep_message));
+       message->msg_header = pceplib_malloc(
+               PCEPLIB_MESSAGES, sizeof(struct pcep_message_header));
+       memset(message->msg_header, 0, sizeof(struct pcep_message_header));
+       message->msg_header->type = msg_type;
+       message->msg_header->pcep_version = PCEP_MESSAGE_HEADER_VERSION;
+       message->obj_list = ((obj_list == NULL) ? dll_initialize() : obj_list);
+
+       return message;
+}
+
+static struct pcep_message *
+pcep_msg_create_common(enum pcep_message_types msg_type)
+{
+       return pcep_msg_create_common_with_obj_list(msg_type, NULL);
+}
+
+struct pcep_message *pcep_msg_create_open(uint8_t keepalive, uint8_t deadtimer,
+                                         uint8_t sid)
+{
+       struct pcep_message *message = pcep_msg_create_common(PCEP_TYPE_OPEN);
+       dll_append(message->obj_list,
+                  pcep_obj_create_open(keepalive, deadtimer, sid, NULL));
+
+       return message;
+}
+
+struct pcep_message *
+pcep_msg_create_open_with_tlvs(uint8_t keepalive, uint8_t deadtimer,
+                              uint8_t sid, double_linked_list *tlv_list)
+{
+       struct pcep_message *message = pcep_msg_create_common(PCEP_TYPE_OPEN);
+       dll_append(message->obj_list,
+                  pcep_obj_create_open(keepalive, deadtimer, sid, tlv_list));
+
+       return message;
+}
+
+
+struct pcep_message *
+pcep_msg_create_request(struct pcep_object_rp *rp,
+                       struct pcep_object_endpoints_ipv4 *endpoints,
+                       double_linked_list *object_list)
+{
+       if ((rp == NULL) || (endpoints == NULL)) {
+               return NULL;
+       }
+
+       struct pcep_message *message = pcep_msg_create_common_with_obj_list(
+               PCEP_TYPE_PCREQ, object_list);
+       dll_prepend(message->obj_list, endpoints);
+       dll_prepend(message->obj_list, rp);
+
+       return message;
+}
+
+struct pcep_message *
+pcep_msg_create_request_ipv6(struct pcep_object_rp *rp,
+                            struct pcep_object_endpoints_ipv6 *endpoints,
+                            double_linked_list *object_list)
+{
+       if ((rp == NULL) || (endpoints == NULL)) {
+               return NULL;
+       }
+
+       struct pcep_message *message = pcep_msg_create_common_with_obj_list(
+               PCEP_TYPE_PCREQ, object_list);
+       dll_prepend(message->obj_list, endpoints);
+       dll_prepend(message->obj_list, rp);
+
+       return message;
+}
+
+struct pcep_message *pcep_msg_create_reply(struct pcep_object_rp *rp,
+                                          double_linked_list *object_list)
+{
+       struct pcep_message *message = pcep_msg_create_common_with_obj_list(
+               PCEP_TYPE_PCREP, object_list);
+
+       if (rp != NULL) {
+               dll_prepend(message->obj_list, rp);
+       }
+
+       return message;
+}
+
+struct pcep_message *pcep_msg_create_close(uint8_t reason)
+{
+       struct pcep_message *message = pcep_msg_create_common(PCEP_TYPE_CLOSE);
+       dll_append(message->obj_list, pcep_obj_create_close(reason));
+
+       return message;
+}
+
+struct pcep_message *pcep_msg_create_error(uint8_t error_type,
+                                          uint8_t error_value)
+{
+       struct pcep_message *message = pcep_msg_create_common(PCEP_TYPE_ERROR);
+       dll_append(message->obj_list,
+                  pcep_obj_create_error(error_type, error_value));
+
+       return message;
+}
+
+struct pcep_message *
+pcep_msg_create_error_with_objects(uint8_t error_type, uint8_t error_value,
+                                  double_linked_list *object_list)
+{
+       struct pcep_message *message = pcep_msg_create_common_with_obj_list(
+               PCEP_TYPE_ERROR, object_list);
+       dll_prepend(message->obj_list,
+                   pcep_obj_create_error(error_type, error_value));
+
+       return message;
+}
+
+struct pcep_message *pcep_msg_create_keepalive()
+{
+       return (pcep_msg_create_common(PCEP_TYPE_KEEPALIVE));
+}
+
+struct pcep_message *
+pcep_msg_create_report(double_linked_list *state_report_object_list)
+{
+       return (state_report_object_list == NULL
+                       ? NULL
+                       : pcep_msg_create_common_with_obj_list(
+                               PCEP_TYPE_REPORT, state_report_object_list));
+}
+
+struct pcep_message *
+pcep_msg_create_update(double_linked_list *update_request_object_list)
+{
+       if (update_request_object_list == NULL) {
+               pcep_log(
+                       LOG_INFO,
+                       "%s: pcep_msg_create_update NULL update_request_object_list",
+                       __func__);
+               return NULL;
+       }
+
+       /* There must be at least 3 objects:
+        * These 3 are mandatory: SRP, LSP, and ERO. The ERO may be empty */
+       if (update_request_object_list->num_entries < 3) {
+               pcep_log(
+                       LOG_INFO,
+                       "%s: pcep_msg_create_update there must be at least 3 update objects",
+                       __func__);
+               return NULL;
+       }
+
+       double_linked_list_node *node = update_request_object_list->head;
+       struct pcep_object_header *obj_hdr =
+               (struct pcep_object_header *)node->data;
+
+       /* Check for the mandatory first SRP object */
+       if (obj_hdr->object_class != PCEP_OBJ_CLASS_SRP) {
+               /* If the SRP object is missing, the receiving PCC MUST send a
+                * PCErr message with Error-type=6 (Mandatory Object missing)
+                * and Error-value=10 (SRP object missing). */
+               pcep_log(
+                       LOG_INFO,
+                       "%s: pcep_msg_create_update missing mandatory first SRP object",
+                       __func__);
+               return NULL;
+       }
+
+       /* Check for the mandatory 2nd LSP object */
+       node = node->next_node;
+       obj_hdr = (struct pcep_object_header *)node->data;
+       if (obj_hdr->object_class != PCEP_OBJ_CLASS_LSP) {
+               /* If the LSP object is missing, the receiving PCC MUST send a
+                * PCErr message with Error-type=6 (Mandatory Object missing)
+                * and Error-value=8 (LSP object missing). */
+               pcep_log(
+                       LOG_INFO,
+                       "%s: pcep_msg_create_update missing mandatory second LSP object",
+                       __func__);
+               return NULL;
+       }
+
+       /* Check for the mandatory 3rd ERO object */
+       node = node->next_node;
+       obj_hdr = (struct pcep_object_header *)node->data;
+       if (obj_hdr->object_class != PCEP_OBJ_CLASS_ERO) {
+               /* If the ERO object is missing, the receiving PCC MUST send a
+                * PCErr message with Error-type=6 (Mandatory Object missing)
+                * and Error-value=9 (ERO object missing). */
+               pcep_log(
+                       LOG_INFO,
+                       "%s: pcep_msg_create_update missing mandatory third ERO object",
+                       __func__);
+               return NULL;
+       }
+
+       return (pcep_msg_create_common_with_obj_list(
+               PCEP_TYPE_UPDATE, update_request_object_list));
+}
+
+struct pcep_message *
+pcep_msg_create_initiate(double_linked_list *lsp_object_list)
+{
+       if (lsp_object_list == NULL) {
+               pcep_log(
+                       LOG_INFO,
+                       "%s: pcep_msg_create_initiate NULL update_request_object_list",
+                       __func__);
+               return NULL;
+       }
+
+       /* There must be at least 2 objects: SRP and LSP. */
+       if (lsp_object_list->num_entries < 2) {
+               pcep_log(
+                       LOG_INFO,
+                       "%s: pcep_msg_create_initiate there must be at least 2 objects",
+                       __func__);
+               return NULL;
+       }
+
+       double_linked_list_node *node = lsp_object_list->head;
+       struct pcep_object_header *obj_hdr =
+               (struct pcep_object_header *)node->data;
+
+       /* Check for the mandatory first SRP object */
+       if (obj_hdr->object_class != PCEP_OBJ_CLASS_SRP) {
+               pcep_log(
+                       LOG_INFO,
+                       "%s: pcep_msg_create_initiate missing mandatory first SRP object",
+                       __func__);
+               return NULL;
+       }
+
+       /* Check for the mandatory 2nd LSP object */
+       node = node->next_node;
+       obj_hdr = (struct pcep_object_header *)node->data;
+       if (obj_hdr->object_class != PCEP_OBJ_CLASS_LSP) {
+               pcep_log(
+                       LOG_INFO,
+                       "%s: pcep_msg_create_initiate missing mandatory second LSP object",
+                       __func__);
+               return NULL;
+       }
+
+       return (pcep_msg_create_common_with_obj_list(PCEP_TYPE_INITIATE,
+                                                    lsp_object_list));
+}
+
+struct pcep_message *pcep_msg_create_notify(struct pcep_object_notify *notify,
+                                           double_linked_list *object_list)
+{
+       if (notify == NULL) {
+               pcep_log(LOG_INFO,
+                        "%s: pcep_msg_create_notify NULL notify object",
+                        __func__);
+               return NULL;
+       }
+
+       struct pcep_message *message = pcep_msg_create_common_with_obj_list(
+               PCEP_TYPE_PCNOTF, object_list);
+       dll_prepend(message->obj_list, notify);
+
+       return message;
+}
diff --git a/pceplib/pcep_msg_messages.h b/pceplib/pcep_msg_messages.h
new file mode 100644 (file)
index 0000000..8542ea1
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ */
+
+
+/*
+ * This is a High Level PCEP message API.
+ */
+
+#ifndef PCEP_MESSAGES_H
+#define PCEP_MESSAGES_H
+
+#include <stdint.h>
+#include <netinet/in.h> /* struct in_addr */
+
+#include "pcep_utils_double_linked_list.h"
+#include "pcep_msg_objects.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum pcep_message_types {
+       PCEP_TYPE_OPEN = 1,
+       PCEP_TYPE_KEEPALIVE = 2,
+       PCEP_TYPE_PCREQ = 3,
+       PCEP_TYPE_PCREP = 4,
+       PCEP_TYPE_PCNOTF = 5,
+       PCEP_TYPE_ERROR = 6,
+       PCEP_TYPE_CLOSE = 7,
+       PCEP_TYPE_REPORT = 10,
+       PCEP_TYPE_UPDATE = 11,
+       PCEP_TYPE_INITIATE = 12,
+       PCEP_TYPE_START_TLS = 13,
+       PCEP_TYPE_MAX,
+};
+
+#define PCEP_MESSAGE_HEADER_VERSION 1
+
+struct pcep_message_header {
+       uint8_t pcep_version; /* Current version is 1. */
+       enum pcep_message_types
+               type; /* Defines message type:
+                        OPEN/KEEPALIVE/PCREQ/PCREP/PCNOTF/ERROR/CLOSE */
+};
+
+/* The obj_list is a double_linked_list of struct pcep_object_header pointers.
+ */
+struct pcep_message {
+       struct pcep_message_header *msg_header;
+       double_linked_list *obj_list;
+       uint8_t *encoded_message;
+       uint16_t encoded_message_length;
+};
+
+
+/*
+ * Regarding memory usage:
+ * When creating messages, any objects and tlvs passed into these APIs will be
+ * free'd when the pcep_message is free'd. That includes the
+ * double_linked_list's. So, just create the objects and TLVs, put them in their
+ * double_linked_list's, and everything will be managed internally. The message
+ * will be deleted by pcep_msg_free_message() or pcep_msg_free_message_list()
+ * which, in turn will call one of: pcep_obj_free_object() and
+ * pcep_obj_free_tlv(). For received messages, call pcep_msg_free_message() to
+ * free them.
+ */
+
+struct pcep_message *pcep_msg_create_open(uint8_t keepalive, uint8_t deadtimer,
+                                         uint8_t sid);
+struct pcep_message *
+pcep_msg_create_open_with_tlvs(uint8_t keepalive, uint8_t deadtimer,
+                              uint8_t sid, double_linked_list *tlv_list);
+struct pcep_message *
+pcep_msg_create_request(struct pcep_object_rp *rp,
+                       struct pcep_object_endpoints_ipv4 *endpoints,
+                       double_linked_list *object_list);
+struct pcep_message *
+pcep_msg_create_request_ipv6(struct pcep_object_rp *rp,
+                            struct pcep_object_endpoints_ipv6 *endpoints,
+                            double_linked_list *object_list);
+struct pcep_message *pcep_msg_create_reply(struct pcep_object_rp *rp,
+                                          double_linked_list *object_list);
+struct pcep_message *pcep_msg_create_close(uint8_t reason);
+struct pcep_message *pcep_msg_create_error(uint8_t error_type,
+                                          uint8_t error_value);
+struct pcep_message *pcep_msg_create_error_with_objects(
+       uint8_t error_type, uint8_t error_value,
+       double_linked_list *object_list); /* include the offending objects */
+struct pcep_message *pcep_msg_create_keepalive(void);
+struct pcep_message *pcep_msg_create_notify(struct pcep_object_notify *notify,
+                                           double_linked_list *object_list);
+
+/* Message defined in RFC 8231 section 6.1. Expecting double_linked_list of
+ * struct pcep_object_header* objects of type SRP, LSP, or path (ERO, Bandwidth,
+ * metrics, and RRO objects). */
+struct pcep_message *
+pcep_msg_create_report(double_linked_list *state_report_object_list);
+/* Message defined in RFC 8231. Expecting double_linked_list of at least 3
+ * struct pcep_object_header* objects of type SRP, LSP, and path (ERO and
+ * intended-attribute-list). The ERO must be present, but may be empty if
+ * the PCE cannot find a valid path for a delegated LSP. */
+struct pcep_message *
+pcep_msg_create_update(double_linked_list *update_request_object_list);
+/* Message defined in RFC 8281. Expecting double_linked_list of at least 2
+ * struct pcep_object_header* objects of type SRP and LSP for LSP deletion, and
+ * may also contain Endpoints, ERO and an attribute list for LSP creation. */
+struct pcep_message *
+pcep_msg_create_initiate(double_linked_list *lsp_object_list);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/pceplib/pcep_msg_messages_encoding.c b/pceplib/pcep_msg_messages_encoding.c
new file mode 100644 (file)
index 0000000..7c8e1b3
--- /dev/null
@@ -0,0 +1,359 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+/*
+ * Encoding and decoding for PCEP messages.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "pcep_msg_encoding.h"
+#include "pcep_msg_messages.h"
+#include "pcep_msg_objects.h"
+#include "pcep_msg_tools.h"
+#include "pcep_utils_logging.h"
+#include "pcep_utils_memory.h"
+
+#define ANY_OBJECT 0
+#define NO_OBJECT -1
+#define NUM_CHECKED_OBJECTS 4
+/* It wont compile with this definition:
+   static const int
+   MANDATORY_MESSAGE_OBJECT_CLASSES[PCEP_TYPE_INITIATE+1][NUM_CHECKED_OBJECTS]
+ */
+static const enum pcep_object_classes MANDATORY_MESSAGE_OBJECT_CLASSES[13][4] =
+       {
+               {NO_OBJECT, NO_OBJECT, NO_OBJECT,
+                NO_OBJECT}, /* unsupported message ID = 0 */
+               {PCEP_OBJ_CLASS_OPEN, NO_OBJECT, NO_OBJECT,
+                NO_OBJECT}, /* PCEP_TYPE_OPEN = 1 */
+               {NO_OBJECT, NO_OBJECT, NO_OBJECT,
+                NO_OBJECT}, /* PCEP_TYPE_KEEPALIVE = 2 */
+               {PCEP_OBJ_CLASS_RP, PCEP_OBJ_CLASS_ENDPOINTS, ANY_OBJECT,
+                ANY_OBJECT}, /* PCEP_TYPE_PCREQ = 3 */
+               {PCEP_OBJ_CLASS_RP, ANY_OBJECT, ANY_OBJECT,
+                ANY_OBJECT}, /* PCEP_TYPE_PCREP = 4 */
+               {PCEP_OBJ_CLASS_NOTF, ANY_OBJECT, ANY_OBJECT,
+                ANY_OBJECT}, /* PCEP_TYPE_PCNOTF = 5 */
+               {PCEP_OBJ_CLASS_ERROR, ANY_OBJECT, ANY_OBJECT,
+                ANY_OBJECT}, /* PCEP_TYPE_ERROR = 6 */
+               {PCEP_OBJ_CLASS_CLOSE, NO_OBJECT, NO_OBJECT,
+                NO_OBJECT}, /* PCEP_TYPE_CLOSE = 7 */
+               {NO_OBJECT, NO_OBJECT, NO_OBJECT,
+                NO_OBJECT}, /* unsupported message ID = 8 */
+               {NO_OBJECT, NO_OBJECT, NO_OBJECT,
+                NO_OBJECT}, /* unsupported message ID = 9 */
+               {PCEP_OBJ_CLASS_SRP, PCEP_OBJ_CLASS_LSP, ANY_OBJECT,
+                ANY_OBJECT}, /* PCEP_TYPE_REPORT = 10 */
+               {PCEP_OBJ_CLASS_SRP, PCEP_OBJ_CLASS_LSP, ANY_OBJECT,
+                ANY_OBJECT}, /* PCEP_TYPE_UPDATE = 11 */
+               {PCEP_OBJ_CLASS_SRP, PCEP_OBJ_CLASS_LSP, ANY_OBJECT,
+                ANY_OBJECT}, /* PCEP_TYPE_INITIATE = 12 */
+};
+
+/* PCEP Message Common Header, According to RFC 5440
+ *
+ *   0                   1                   2                   3
+ *   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  | Ver |  Flags  |  Message-Type |       Message-Length          |
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * Ver (Version - 3 bits):  PCEP version number. Current version is version 1.
+ *
+ * Flags (5 bits):  No flags are currently defined. Unassigned bits are
+ *    considered as reserved.  They MUST be set to zero on transmission
+ *    and MUST be ignored on receipt.
+ */
+void pcep_encode_message(struct pcep_message *message,
+                        struct pcep_versioning *versioning)
+{
+       if (message == NULL) {
+               return;
+       }
+
+       if (message->msg_header == NULL) {
+               return;
+       }
+
+       /* Internal buffer used for the entire message. Later, once the entire
+        * length is known, memory will be allocated and this buffer will be
+        * copied. */
+       uint8_t message_buffer[PCEP_MESSAGE_LENGTH] = {0};
+
+       /* Write the message header. The message header length will be
+        * written when the entire length is known. */
+       uint32_t message_length = MESSAGE_HEADER_LENGTH;
+       uint16_t net_order_length = 0;
+       message_buffer[0] = (message->msg_header->pcep_version << 5) & 0xf0;
+       message_buffer[1] = message->msg_header->type;
+
+       if (message->obj_list == NULL) {
+               net_order_length = htons(message_length);
+               memcpy(message_buffer + 2, &net_order_length,
+                      sizeof(net_order_length));
+               message->encoded_message =
+                       pceplib_malloc(PCEPLIB_MESSAGES, message_length);
+               memcpy(message->encoded_message, message_buffer,
+                      message_length);
+               message->encoded_message_length = message_length;
+
+               return;
+       }
+
+       /* Encode each of the objects */
+       double_linked_list_node *node = message->obj_list->head;
+       for (; node != NULL; node = node->next_node) {
+               message_length +=
+                       pcep_encode_object(node->data, versioning,
+                                          message_buffer + message_length);
+               if (message_length >= PCEP_MESSAGE_LENGTH) {
+                       message->encoded_message = NULL;
+                       message->encoded_message_length = 0;
+                       return;
+               }
+       }
+
+       net_order_length = htons(message_length);
+       memcpy(message_buffer + 2, &net_order_length, sizeof(net_order_length));
+       message->encoded_message =
+               pceplib_malloc(PCEPLIB_MESSAGES, message_length);
+       memcpy(message->encoded_message, message_buffer, message_length);
+       message->encoded_message_length = message_length;
+}
+
+/*
+ * Decoding functions
+ */
+
+/* Expecting Host byte ordered header */
+static bool validate_msg_header(uint8_t msg_version, uint8_t msg_flags,
+                               uint8_t msg_type, uint16_t msg_length)
+{
+       /* Invalid message if the length is less than the header
+        * size or if its not a multiple of 4 */
+       if (msg_length < MESSAGE_HEADER_LENGTH || (msg_length % 4) != 0) {
+               pcep_log(LOG_INFO,
+                        "%s: Invalid PCEP message header length [%d]",
+                        __func__, msg_length);
+               return false;
+       }
+
+       if (msg_version != PCEP_MESSAGE_HEADER_VERSION) {
+               pcep_log(
+                       LOG_INFO,
+                       "%s: Invalid PCEP message header version [0x%x] expected version [0x%x]",
+                       __func__, msg_version, PCEP_MESSAGE_HEADER_VERSION);
+               return false;
+       }
+
+       if (msg_flags != 0) {
+               pcep_log(LOG_INFO,
+                        "%s: Invalid PCEP message header flags [0x%x]",
+                        __func__, msg_flags);
+               return false;
+       }
+
+       switch (msg_type) {
+       /* Supported message types */
+       case PCEP_TYPE_OPEN:
+       case PCEP_TYPE_KEEPALIVE:
+       case PCEP_TYPE_PCREQ:
+       case PCEP_TYPE_PCREP:
+       case PCEP_TYPE_PCNOTF:
+       case PCEP_TYPE_ERROR:
+       case PCEP_TYPE_CLOSE:
+       case PCEP_TYPE_REPORT:
+       case PCEP_TYPE_UPDATE:
+       case PCEP_TYPE_INITIATE:
+               break;
+       default:
+               pcep_log(LOG_INFO, "%s: Invalid PCEP message header type [%d]",
+                        __func__, msg_type);
+               return false;
+               break;
+       }
+
+       return true;
+}
+
+/* Internal util function */
+static uint16_t pcep_decode_msg_header(const uint8_t *msg_buf,
+                                      uint8_t *msg_version, uint8_t *msg_flags,
+                                      uint8_t *msg_type)
+{
+       // Check RFC 5440 for version and flags position.
+       // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+       //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       //| Ver | Flags   | Message-Type  |  Message-Length               |
+       //+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       *msg_version = (msg_buf[0] >> 5) & 0x07;
+       *msg_flags = (msg_buf[0] & 0x1f);
+       *msg_type = msg_buf[1];
+       uint16_t host_order_length;
+       memcpy(&host_order_length, msg_buf + 2, sizeof(host_order_length));
+       return ntohs(host_order_length);
+}
+
+/* Decode the message header and return the message length */
+int32_t pcep_decode_validate_msg_header(const uint8_t *msg_buf)
+{
+       uint8_t msg_version;
+       uint8_t msg_flags;
+       uint8_t msg_type;
+       uint32_t msg_length;
+
+       msg_length = pcep_decode_msg_header(msg_buf, &msg_version, &msg_flags,
+                                           &msg_type);
+
+       return ((validate_msg_header(msg_version, msg_flags, msg_type,
+                                    msg_length)
+                == false)
+                       ? -1
+                       : (int32_t)msg_length);
+}
+
+bool validate_message_objects(struct pcep_message *msg)
+{
+       if (msg->msg_header->type >= PCEP_TYPE_START_TLS) {
+               pcep_log(
+                       LOG_INFO,
+                       "%s: Rejecting received message: Unknown message type [%d]",
+                       __func__, msg->msg_header->type);
+               return false;
+       }
+
+       const enum pcep_object_classes *object_classes =
+               MANDATORY_MESSAGE_OBJECT_CLASSES[msg->msg_header->type];
+       double_linked_list_node *node;
+       int index;
+       for (node = (msg->obj_list == NULL ? NULL : msg->obj_list->head),
+           index = 0;
+            index < NUM_CHECKED_OBJECTS;
+            index++, (node = (node == NULL ? NULL : node->next_node))) {
+               struct pcep_object_header *obj =
+                       ((node == NULL)
+                                ? NULL
+                                : (struct pcep_object_header *)node->data);
+
+               if ((int)object_classes[index] == NO_OBJECT) {
+                       if (node != NULL) {
+                               pcep_log(
+                                       LOG_INFO,
+                                       "%s: Rejecting received message: Unexpected object [%d] present",
+                                       __func__, obj->object_class);
+                               return false;
+                       }
+               } else if (object_classes[index] != ANY_OBJECT) {
+                       if (node == NULL) {
+                               pcep_log(
+                                       LOG_INFO,
+                                       "%s: Rejecting received message: Expecting object in position [%d], but none received",
+                                       __func__, index);
+                               return false;
+                       } else if (object_classes[index] != obj->object_class) {
+                               pcep_log(
+                                       LOG_INFO,
+                                       "%s: Rejecting received message: Unexpected Object Class received [%d]",
+                                       __func__, object_classes[index]);
+                               return false;
+                       }
+               }
+       }
+
+       return true;
+}
+
+struct pcep_message *pcep_decode_message(const uint8_t *msg_buf)
+{
+       uint8_t msg_version;
+       uint8_t msg_flags;
+       uint8_t msg_type;
+       uint16_t msg_length;
+
+       msg_length = pcep_decode_msg_header(msg_buf, &msg_version, &msg_flags,
+                                           &msg_type);
+       if (msg_length == 0) {
+               pcep_log(LOG_INFO, "%s: Discarding empty message", __func__);
+               return NULL;
+       }
+       if (msg_length >= PCEP_MESSAGE_LENGTH) {
+               pcep_log(LOG_INFO, "%s: Discarding message too big", __func__);
+               return NULL;
+       }
+
+       struct pcep_message *msg =
+               pceplib_calloc(PCEPLIB_MESSAGES, sizeof(struct pcep_message));
+
+       msg->msg_header = pceplib_malloc(PCEPLIB_MESSAGES,
+                                        sizeof(struct pcep_message_header));
+       msg->msg_header->pcep_version = msg_version;
+       msg->msg_header->type = msg_type;
+
+       msg->obj_list = dll_initialize();
+       msg->encoded_message = pceplib_malloc(PCEPLIB_MESSAGES, msg_length);
+       memcpy(msg->encoded_message, msg_buf, msg_length);
+       msg->encoded_message_length = msg_length;
+
+       uint16_t bytes_read = MESSAGE_HEADER_LENGTH;
+       while ((msg_length - bytes_read) >= OBJECT_HEADER_LENGTH) {
+               struct pcep_object_header *obj_hdr =
+                       pcep_decode_object(msg_buf + bytes_read);
+
+               if (obj_hdr == NULL) {
+                       pcep_log(LOG_INFO, "%s: Discarding invalid message",
+                                __func__);
+                       pcep_msg_free_message(msg);
+
+                       return NULL;
+               }
+
+               dll_append(msg->obj_list, obj_hdr);
+               bytes_read += obj_hdr->encoded_object_length;
+       }
+
+       if (validate_message_objects(msg) == false) {
+               pcep_log(LOG_INFO, "%s: Discarding invalid message", __func__);
+               pcep_msg_free_message(msg);
+
+               return NULL;
+       }
+
+       return msg;
+}
+
+struct pcep_versioning *create_default_pcep_versioning()
+{
+       struct pcep_versioning *versioning =
+               pceplib_malloc(PCEPLIB_INFRA, sizeof(struct pcep_versioning));
+       memset(versioning, 0, sizeof(struct pcep_versioning));
+
+       return versioning;
+}
+
+void destroy_pcep_versioning(struct pcep_versioning *versioning)
+{
+       pceplib_free(PCEPLIB_INFRA, versioning);
+}
diff --git a/pceplib/pcep_msg_object_error_types.c b/pceplib/pcep_msg_object_error_types.c
new file mode 100644 (file)
index 0000000..a4fd815
--- /dev/null
@@ -0,0 +1,389 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ */
+
+#include <stdlib.h>
+
+#include "pcep_msg_object_error_types.h"
+#include "pcep_utils_logging.h"
+
+/* All of these values were copied from:
+ *     https://www.iana.org/assignments/pcep/pcep.xhtml#pcep-error-object
+ * Which was last updated 2020-06-02 */
+
+static const char *error_type_strings[] = {
+       "Reserved",
+       "PCEP session establishment failure",
+       "Capability not supported",
+       "Unknown Object",
+       "Not supported object",
+       "Policy violation",
+       "Mandatory Object missing",
+       "Synchronized path computation request missing",
+       "Unknown request reference",
+       "Attempt to establish a second PCEP session",
+
+       "Reception of an invalid object", /* 10 */
+       "Unrecognized EXRS subobject",
+       "Diffserv-aware TE error",
+       "BRPC procedure completion failure",
+       "Unassigned 14",
+       "Global Concurrent Optimization Error",
+       "P2MP Capability Error",
+       "P2MP END-POINTS Error",
+       "P2MP Fragmentation Error",
+       "Invalid Operation",
+
+       "LSP State Synchronization Error", /* 20 */
+       "Invalid traffic engineering path setup type",
+       "Unassigned 22",
+       "Bad parameter value",
+       "LSP instantiation error",
+       "PCEP StartTLS failure",
+       "Association Error",
+       "WSON RWA Error",
+       "H-PCE Error",
+       "Path computation failure",
+       "Unassigned 30"};
+
+static const char *error_value_strings[MAX_ERROR_TYPE][MAX_ERROR_VALUE] = {
+
+       /* 0   Reserved */
+       {"Unassigned"},
+
+       /* 1   PCEP session establishment failure */
+       {
+               "Unassigned",
+               "reception of an invalid Open message or a non Open message.",
+               "no Open message received before the expiration of the OpenWait timer",
+               "unacceptable and non negotiable session characteristics",
+               "unacceptable but negotiable session characteristics",
+               "reception of a second Open message with still unacceptable session characteristics",
+               "reception of a PCErr message proposing unacceptable session characteristics",
+               "No Keepalive or PCErr message received before the expiration of the KeepWait timer",
+               "PCEP version not supported",
+       },
+
+       /* 2   Capability not supported */
+       {"Unassigned"},
+
+       /* 3   Unknown Object */
+       {
+               "Unassigned",
+               "Unrecognized object class",
+               "Unrecognized object Type",
+       },
+
+       /* 4   Not supported object */
+       {
+               "Unassigned",
+               "Not supported object class",
+               "Not supported object Type",
+               "Unassigned",
+               "Unsupported parameter",
+               "Unsupported network performance constraint",
+               "Bandwidth Object type 3 or 4 not supported",
+               "Unsupported endpoint type in END-POINTS Generalized Endpoint object type",
+               "Unsupported TLV present in END-POINTS Generalized Endpoint object type",
+               "Unsupported granularity in the RP object flags",
+       },
+
+       /* 5   Policy violation */
+       {
+               "Unassigned",
+               "C bit of the METRIC object set (request rejected)",
+               "O bit of the RP object cleared (request rejected)",
+               "objective function not allowed (request rejected)",
+               "OF bit of the RP object set (request rejected)",
+               "Global concurrent optimization not allowed",
+               "Monitoring message supported but rejected due to policy violation",
+               "P2MP Path computation is not allowed",
+               "Not allowed network performance constraint",
+       },
+
+       /* 6   Mandatory Object missing */
+       {
+               "Unassigned",
+               "RP object missing",
+               "RRO missing for a reoptimization request (R bit of the RP object set)",
+               "END-POINTS object missing",
+               "MONITORING object missing",
+               "Unassigned",
+               "Unassigned",
+               "Unassigned",
+               "LSP object missing",
+               "ERO object missing",
+               "SRP object missing",
+               "LSP-IDENTIFIERS TLV missing",
+               "LSP-DB-VERSION TLV missing",
+               "S2LS object missing",
+               "P2MP-LSP-IDENTIFIERS TLV missing",
+               "DISJOINTNESS-CONFIGURATION TLV missing",
+       },
+
+       /* 7   Synchronized path computation request missing */
+       {"Unassigned"},
+
+       /* 8   Unknown request reference */
+       {"Unassigned"},
+
+       /* 9   Attempt to establish a second PCEP session */
+       {"Unassigned"},
+
+       /* 10  Reception of an invalid object */
+       {
+               "Unassigned",
+               "reception of an object with P flag not set although the P-flag must be set according to this specification.",
+               "Bad label value",
+               "Unsupported number of SR-ERO subobjects",
+               "Bad label format",
+               "ERO mixes SR-ERO subobjects with other subobject types",
+               "Both SID and NAI are absent in the SR-ERO subobject",
+               "Both SID and NAI are absent in the SR-RRO subobject",
+               "SYMBOLIC-PATH-NAME TLV missing",
+               "MSD exceeds the default for the PCEP session",
+               "RRO mixes SR-RRO subobjects with other subobject types",
+               "Malformed object",
+               "Missing PCE-SR-CAPABILITY sub-TLV",
+               "Unsupported NAI Type in the SR-ERO/SR-RRO subobject",
+               "Unknown SID",
+               "NAI cannot be resolved to a SID",
+               "Could not find SRGB",
+               "SID index exceeds SRGB size",
+               "Could not find SRLB",
+               "SID index exceeds SRLB size",
+               "Inconsistent SIDs in SR-ERO / SR-RRO subobjects",
+               "MSD must be nonzero",
+               "Mismatch of O field in S2LS and LSP object",
+               "Incompatible OF codes in H-PCE",
+               "Bad Bandwidth Object type 3 (Generalized bandwidth) or 4 (Generalized bandwidth of existing TE-LSP for which a reoptimization is requested)",
+               "Unsupported LSP Protection Flags in PROTECTION-ATTRIBUTE TLV",
+               "Unsupported Secondary LSP Protection Flags in PROTECTION-ATTRIBUTE TLV",
+               "Unsupported Link Protection Type in PROTECTION-ATTRIBUTE TLV",
+               "LABEL-SET TLV present with 0 bit set but without R bit set in RP",
+               "Wrong LABEL-SET TLV present with 0 and L bit set",
+               "Wrong LABEL-SET with O bit set and wrong format",
+               "Missing GMPLS-CAPABILITY TLV",
+               "Incompatible OF code",
+       },
+
+       /* 11  Unrecognized EXRS subobject */
+       {"Unassigned"},
+
+       /* 12  Diffserv-aware TE error */
+       {
+               "Unassigned",
+               "Unsupported class-type",
+               "Invalid class-type",
+               "Class-Type and setup priority do not form a configured TE-class",
+       },
+
+       /* 13  BRPC procedure completion failure */
+       {
+               "Unassigned",
+               "BRPC procedure not supported by one or more PCEs along the domain path",
+       },
+
+       /* 14  Unassigned */
+       {"Unassigned"},
+
+       /* 15  Global Concurrent Optimization Error */
+       {
+               "Unassigned",
+               "Insufficient memory",
+               "Global concurrent optimization not supported",
+       },
+
+       /* 16  P2MP Capability Error */
+       {
+               "Unassigned",
+               "The PCE cannot satisfy the request due to insufficient memory",
+               "The PCE is not capable of P2MP computation",
+       },
+
+       /* 17  P2MP END-POINTS Error */
+       {
+               "Unassigned",
+               "The PCE cannot satisfy the request due to no END-POINTS with leaf type 2",
+               "The PCE cannot satisfy the request due to no END-POINTS with leaf type 3",
+               "The PCE cannot satisfy the request due to no END-POINTS with leaf type 4",
+               "The PCE cannot satisfy the request due to inconsistent END-POINTS",
+       },
+
+       /* 18  P2MP Fragmentation Error */
+       {
+               "Unassigned",
+               "Fragmented request failure",
+               "Fragmented Report failure",
+               "Fragmented Update failure",
+               "Fragmented Instantiation failure",
+       },
+
+       /* 19  Invalid Operation */
+       {
+               "Unassigned",
+               "Attempted LSP Update Request for a non-delegated LSP. The PCEP-ERROR object is followed by the LSP object that identifies the LSP.",
+               "Attempted LSP Update Request if the stateful PCE capability was not advertised.",
+               "Attempted LSP Update Request for an LSP identified by an unknown PLSP-ID.",
+               "Unassigned",
+               "Attempted LSP State Report if active stateful PCE capability was not advertised.",
+               "PCE-initiated LSP limit reached",
+               "Delegation for PCE-initiated LSP cannot be revoked",
+               "Non-zero PLSP-ID in LSP Initiate Request",
+               "LSP is not PCE initiated",
+               "PCE-initiated operation-frequency limit reached",
+               "Attempted LSP State Report for P2MP if stateful PCE capability for P2MP was not advertised",
+               "Attempted LSP Update Request for P2MP if active stateful PCE capability for P2MP was not advertised",
+               "Attempted LSP Instantiation Request for P2MP if stateful PCE instantiation capability for P2MP was not advertised",
+               "Auto-Bandwidth capability was not advertised",
+       },
+
+       /* 20  LSP State Synchronization Error */
+       {
+               "Unassigned",
+               "A PCE indicates to a PCC that it cannot process (an otherwise valid) LSP State Report. The PCEP- ERROR object is followed by the LSP object that identifies the LSP.",
+               "LSP-DB version mismatch.",
+               "Attempt to trigger synchronization before PCE trigger.",
+               "Attempt to trigger a synchronization when the PCE triggered synchronization capability has not been advertised.",
+               "A PCC indicates to a PCE that it cannot complete the State Synchronization.",
+               "Received an invalid LSP-DB Version Number.",
+               "Received an invalid Speaker Entity Identifier.",
+       },
+
+       /* 21  Invalid traffic engineering path setup type */
+       {
+               "Unassigned",
+               "Unsupported path setup type",
+               "Mismatched path setup type",
+       },
+
+       /* 22  Unassigned */
+       {"Unassigned"},
+
+       /* 23  Bad parameter value */
+       {
+               "Unassigned",
+               "SYMBOLIC-PATH-NAME in use",
+               "Speaker identity included for an LSP that is not PCE initiated",
+       },
+
+       /* 24  LSP instantiation error */
+       {
+               "Unassigned",
+               "Unacceptable instantiation parameters",
+               "Internal error",
+               "Signaling error",
+       },
+
+       /* 25  PCEP StartTLS failure */
+       {
+               "Unassigned",
+               "Reception of StartTLS after any PCEP exchange",
+               "Reception of any other message apart from StartTLS, Open, or PCErr",
+               "Failure, connection without TLS is not possible",
+               "Failure, connection without TLS is possible",
+               "No StartTLS message (nor PCErr/Open) before StartTLSWait timer expiry",
+       },
+
+       /* 26  Association Error */
+       {
+               "Unassigned",
+               "Association Type is not supported",
+               "Too many LSPs in the association group",
+               "Too many association groups",
+               "Association unknown",
+               "Operator-configured association information mismatch",
+               "Association information mismatch",
+               "Cannot join the association group",
+               "Association ID not in range",
+               "Tunnel ID or End points mismatch for Path Protection Association",
+               "Attempt to add another working/protection LSP for Path Protection Association",
+               "Protection type is not supported",
+       },
+
+       /* 27  WSON RWA Error */
+       {
+               "Unassigned",
+               "Insufficient Memory",
+               "RWA computation Not supported",
+               "Syntactical Encoding error",
+       },
+
+       /* 28  H-PCE Error */
+       {
+               "Unassigned",
+               "H-PCE Capability not advertised",
+               "Parent PCE Capability cannot be provided",
+       },
+
+       /* 29  Path computation failure */
+       {
+               "Unassigned",
+               "Unacceptable request message",
+               "Generalized bandwidth value not supported",
+               "Label Set constraint could not be met",
+               "Label constraint could not be met",
+       }
+
+       /* 30-255  Unassigned */
+};
+
+
+const char *get_error_type_str(enum pcep_error_type error_type)
+{
+       if (error_type < 0 || error_type >= MAX_ERROR_TYPE) {
+               pcep_log(
+                       LOG_DEBUG,
+                       "%s: get_error_type_str: error_type [%d] out of range [0..%d]",
+                       __func__, error_type, MAX_ERROR_TYPE);
+
+               return NULL;
+       }
+
+       return error_type_strings[error_type];
+}
+
+const char *get_error_value_str(enum pcep_error_type error_type,
+                               enum pcep_error_value error_value)
+{
+       if (error_type < 0 || error_type >= MAX_ERROR_TYPE) {
+               pcep_log(
+                       LOG_DEBUG,
+                       "%s: get_error_value_str: error_type [%d] out of range [0..%d]",
+                       __func__, error_type, MAX_ERROR_TYPE);
+
+               return NULL;
+       }
+
+       if (error_value < 0 || error_value >= MAX_ERROR_VALUE) {
+               pcep_log(
+                       LOG_DEBUG,
+                       "%s: get_error_value_str: error_value [%d] out of range [0..%d]",
+                       __func__, error_value, MAX_ERROR_VALUE);
+
+               return NULL;
+       }
+
+       if (error_value_strings[error_type][error_value] == NULL) {
+               return "Unassigned";
+       }
+
+       return error_value_strings[error_type][error_value];
+}
diff --git a/pceplib/pcep_msg_object_error_types.h b/pceplib/pcep_msg_object_error_types.h
new file mode 100644 (file)
index 0000000..d62cc7e
--- /dev/null
@@ -0,0 +1,284 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ */
+
+
+/*
+ * Error Object Type and Value definitions
+ */
+
+#ifndef PCEP_OBJECT_ERROR_TYPES_H
+#define PCEP_OBJECT_ERROR_TYPES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MAX_ERROR_TYPE 30
+#define MAX_ERROR_VALUE 255
+
+enum pcep_error_type {
+       PCEP_ERRT_SESSION_FAILURE = 1,
+       PCEP_ERRT_CAPABILITY_NOT_SUPPORTED = 2,
+       PCEP_ERRT_UNKNOW_OBJECT = 3,
+       PCEP_ERRT_NOT_SUPPORTED_OBJECT = 4,
+       PCEP_ERRT_POLICY_VIOLATION = 5,
+       PCEP_ERRT_MANDATORY_OBJECT_MISSING = 6,
+       PCEP_ERRT_SYNC_PC_REQ_MISSING = 7,
+       PCEP_ERRT_UNKNOWN_REQ_REF = 8,
+       PCEP_ERRT_ATTEMPT_TO_ESTABLISH_2ND_PCEP_SESSION = 9,
+       PCEP_ERRT_RECEPTION_OF_INV_OBJECT = 10,
+
+       PCEP_ERRT_UNRECOGNIZED_EXRS_SUBOBJ = 11,
+       PCEP_ERRT_DIFFSERV_AWARE_TE_ERROR = 12,
+       PCEP_ERRT_BRPC_PROC_COMPLETION_ERROR = 13,
+       PCEP_ERRT_UNASSIGNED14 = 14,
+       PCEP_ERRT_GLOBAL_CONCURRENT_ERROR = 15,
+       PCEP_ERRT_P2PMP_CAP_ERROR = 16,
+       PCEP_ERRT_P2P_ENDPOINTS_ERROR = 17,
+       PCEP_ERRT_P2P_FRAGMENTATION_ERROR = 18,
+       PCEP_ERRT_INVALID_OPERATION = 19,
+       PCEP_ERRT_LSP_STATE_SYNC_ERROR = 20,
+
+       PCEP_ERRT_INVALID_TE_PATH_SETUP_TYPE = 21,
+       PCEP_ERRT_UNASSIGNED22 = 22,
+       PCEP_ERRT_BAD_PARAMETER_VALUE = 23,
+       PCEP_ERRT_LSP_INSTANTIATE_ERROR = 24,
+       PCEP_ERRT_START_TLS_FAILURE = 25,
+       PCEP_ERRT_ASSOCIATION_ERROR = 26,
+       PCEP_ERRT_WSON_RWA_ERROR = 27,
+       PCEP_ERRT_H_PCE_ERROR = 28,
+       PCEP_ERRT_PATH_COMP_FAILURE = 29,
+       PCEP_ERRT_UNASSIGNED30 = 30 /* 30 - 255 Unassigned */
+};
+
+enum pcep_error_value {
+       /* Error Value for Error Types that do not use an Error Value:
+        * PCEP_ERRT_CAPABILITY_NOT_SUPPORTED=2
+        * PCEP_ERRT_SYNC_PC_REQ_MISSING=7
+        * PCEP_ERRT_UNKNOWN_REQ_REF=8
+        * PCEP_ERRT_ATTEMPT_TO_ESTABLISH_2ND_PCEP_SESSION=9
+        * PCEP_ERRT_UNRECOGNIZED_EXRS_SUBOBJ=11 */
+       PCEP_ERRV_UNASSIGNED = 0,
+
+       /* Error Values for PCEP_ERRT_SESSION_FAILURE=1 */
+       PCEP_ERRV_RECVD_INVALID_OPEN_MSG = 1,
+       PCEP_ERRV_OPENWAIT_TIMED_OUT = 2,
+       PCEP_ERRV_UNACCEPTABLE_OPEN_MSG_NO_NEG = 3,
+       PCEP_ERRV_UNACCEPTABLE_OPEN_MSG_NEG = 4,
+       PCEP_ERRV_RECVD_SECOND_OPEN_MSG_UNACCEPTABLE = 5,
+       PCEP_ERRV_RECVD_PCERR = 6,
+       PCEP_ERRV_KEEPALIVEWAIT_TIMED_OUT = 7,
+       PCEP_ERRV_PCEP_VERSION_NOT_SUPPORTED = 8,
+
+       /* Error Values for PCEP_ERRT_UNKNOW_OBJECT=3 */
+       PCEP_ERRV_UNREC_OBJECT_CLASS = 1,
+       PCEP_ERRV_UNREC_OBJECT_TYPE = 2,
+
+       /* Error Values for PCEP_ERRT_NOT_SUPPORTED_OBJECT=4 */
+       PCEP_ERRV_NOT_SUPPORTED_OBJECT_CLASS = 1,
+       PCEP_ERRV_NOT_SUPPORTED_OBJECT_TYPE = 2,
+       /* 3: Unassigned */
+       PCEP_ERRV_UNSUPPORTED_PARAM = 4,
+       PCEP_ERRV_UNSUPPORTED_NW_PERF_CONSTRAINT = 5,
+       PCEP_ERRV_NOT_SUPPORTED_BW_OBJECT_3_4 = 6,
+       PCEP_ERRV_UNSUPPORTED_ENDPOINT_TYPE = 7,
+       PCEP_ERRV_UNSUPPORTED_ENDPOINT_TLV = 8,
+       PCEP_ERRV_UNSUPPORTED_RP_FLAG_GRANULARITY = 9,
+
+       /* Error Values for PCEP_ERRT_POLICY_VIOLATION=5 */
+       PCEP_ERRV_C_BIT_SET_IN_METRIC_OBJECT = 1,
+       PCEP_ERRV_O_BIT_CLEARD_IN_RP_OBJECT = 2,
+       PCEP_ERRV_OBJECTIVE_FUNC_NOT_ALLOWED = 3,
+       PCEP_ERRV_RP_OF_BIT_SET = 4,
+       PCEP_ERRV_GLOBAL_CONCURRENCY_NOT_ALLOWED = 5,
+       PCEP_ERRV_MONITORING_MSG_REJECTED = 6,
+       PCEP_ERRV_P2MP_PATH_COMP_NOT_ALLOWED = 7,
+       PCEP_ERRV_UNALLOWED_NW_PERF_CONSTRAINT = 8,
+
+       /* Error Values for PCEP_ERRT_MANDATORY_OBJECT_MISSING=6 */
+       PCEP_ERRV_RP_OBJECT_MISSING = 1,
+       PCEP_ERRV_RRO_OBJECT_MISSING_FOR_REOP = 2,
+       PCEP_ERRV_EP_OBJECT_MISSING = 3,
+       PCEP_ERRV_MONITOR_OBJECT_MISSING = 4,
+       /* 5 - 7 Unassigned */
+       PCEP_ERRV_LSP_OBJECT_MISSING = 8,
+       PCEP_ERRV_ERO_OBJECT_MISSING = 9,
+       PCEP_ERRV_SRP_OBJECT_MISSING = 10,
+       PCEP_ERRV_LSP_ID_TLV_MISSING = 11,
+       PCEP_ERRV_LSP_DB_TLV_MISSING = 12,
+       PCEP_ERRV_S2LS_OBJECT_MISSING = 13,
+       PCEP_ERRV_P2MP_LSP_ID_TLV_MISSING = 14,
+       PCEP_ERRV_DISJOINTED_CONF_TLV_MISSING = 15,
+
+       /* Error Values for PCEP_ERRT_RECEPTION_OF_INV_OBJECT=10 */
+       PCEP_ERRV_P_FLAG_NOT_CORRECT_IN_OBJECT = 1,
+       PCEP_ERRV_BAD_LABEL_VALUE = 2,
+       PCEP_ERRV_UNSUPPORTED_NUM_SR_ERO_SUBOBJECTS = 3,
+       PCEP_ERRV_BAD_LABEL_FORMAT = 4,
+       PCEP_ERRV_ERO_SR_ERO_MIX = 5,
+       PCEP_ERRV_SR_ERO_SID_NAI_ABSENT = 6,
+       PCEP_ERRV_SR_RRO_SID_NAI_ABSENT = 7,
+       PCEP_ERRV_SYMBOLIC_PATH_NAME_TLV_MISSING = 8,
+       PCEP_ERRV_MSD_EXCEEDS_PCEP_SESSION_MAX = 9,
+
+       PCEP_ERRV_RRO_SR_RRO_MIX = 10,
+       PCEP_ERRV_MALFORMED_OBJECT = 11,
+       PCEP_ERRV_MISSING_PCE_SR_CAP_TLV = 12,
+       PCEP_ERRV_UNSUPPORTED_NAI = 13,
+       PCEP_ERRV_UNKNOWN_SID = 14,
+       PCEP_ERRV_CANNOT_RESOLVE_NAI_TO_SID = 15,
+       PCEP_ERRV_COULD_NOT_FIND_SRGB = 16,
+       PCEP_ERRV_SID_EXCEEDS_SRGB = 17,
+       PCEP_ERRV_COULD_NOT_FIND_SRLB = 18,
+       PCEP_ERRV_SID_EXCEEDS_SRLB = 19,
+
+       PCEP_ERRV_INCONSISTENT_SID = 20,
+       PCEP_ERRV_MSD_MUST_BE_NONZERO = 21,
+       PCEP_ERRV_MISMATCH_O_S2LS_LSP = 22,
+       PCEP_ERRV_INCOMPATIBLE_H_PCE_OF = 23,
+       PCEP_ERRV_BAD_BANDWIDTH_TYPE_3_4 = 24,
+       PCEP_ERRV_UNSUPPORTED_LSP_PROT_FLAGS = 25,
+       PCEP_ERRV_UNSUPPORTED_2ND_LSP_PROT_FLAGS = 26,
+       PCEP_ERRV_UNSUPPORTED_LINK_PROT_TYPE = 27,
+       PCEP_ERRV_LABEL_SET_TLV_NO_RP_R = 28,
+       PCEP_ERRV_WRONG_LABEL_SET_TLV_O_L_SET = 29,
+
+       PCEP_ERRV_WRONG_LABEL_SET_O_SET = 30,
+       PCEP_ERRV_MISSING_GMPLS_CAP_TLV = 31,
+       PCEP_ERRV_INCOMPATIBLE_OF_CODE = 32,
+
+       /* PCEP_ERRT_DIFFSERV_AWARE_TE_ERROR = 12 */
+       PCEP_ERRV_UNSUPPORTED_CLASS_TYPE = 1,
+       PCEP_ERRV_INVALID_CLASS_TYPE = 2,
+       PCEP_ERRV_CLASS_SETUP_TYPE_NOT_TE_CLASS = 3,
+
+       /* PCEP_ERRT_BRPC_PROC_COMPLETION_ERROR = 13 */
+       PCEP_ERRV_BRPC_PROC_NOT_SUPPORTED = 1,
+
+       /* PCEP_ERRT_UNASSIGNED14 = 14 */
+
+       /* PCEP_ERRT_GLOBAL_CONCURRENT_ERROR = 15 */
+       PCEP_ERRV_INSUFFICIENT_MEMORY = 1,
+       PCEP_ERRV_GLOBAL_CONCURRENT_OPT_NOT_SUPPORTED = 2,
+
+       /* PCEP_ERRT_P2PMP_CAP_ERROR = 16 */
+       PCEP_ERRV_PCE_INSUFFICIENT_MEMORY = 1,
+       PCEP_ERRV_PCE_NOT_CAPABLE_P2MP_COMP = 2,
+
+       /* PCEP_ERRT_P2P_ENDPOINTS_ERROR = 17 */
+       PCEP_ERRV_NO_EP_WITH_LEAF_TYPE2 = 1,
+       PCEP_ERRV_NO_EP_WITH_LEAF_TYPE3 = 2,
+       PCEP_ERRV_NO_EP_WITH_LEAF_TYPE4 = 3,
+       PCEP_ERRV_INCONSITENT_EP = 4,
+
+       /* PCEP_ERRT_P2P_FRAGMENTATION_ERROR = 18 */
+       PCEP_ERRV_FRAG_REQUEST_FAILURE = 1,
+       PCEP_ERRV_FRAG_REPORT_FAILURE = 2,
+       PCEP_ERRV_FRAG_UPDATE_FAILURE = 3,
+       PCEP_ERRV_FRAG_INSTANTIATION_FAILURE = 4,
+
+       /* Error Values for PCEP_ERRT_INVALID_OPERATION=19 */
+       PCEP_ERRV_LSP_UPDATE_FOR_NON_DELEGATED_LSP = 1,
+       PCEP_ERRV_LSP_UPDATE_NON_ADVERTISED_PCE = 2,
+       PCEP_ERRV_LSP_UPDATE_UNKNOWN_PLSP_ID = 3,
+       /* 4: unassigned */
+       PCEP_ERRV_LSP_REPORT_NON_ADVERTISED_PCE = 5,
+       PCEP_ERRV_PCE_INIT_LSP_LIMIT_REACHED = 6,
+       PCEP_ERRV_PCE_INIT_LSP_DELEGATION_CANT_REVOKE = 7,
+       PCEP_ERRV_LSP_INIT_NON_ZERO_PLSP_ID = 8,
+       PCEP_ERRV_LSP_NOT_PCE_INITIATED = 9,
+       PCEP_ERRV_PCE_INIT_OP_FREQ_LIMIT_REACHED = 10,
+       PCEP_ERRV_LSP_REPORT_P2MP_NOT_ADVERTISED = 11,
+       PCEP_ERRV_LSP_UPDATE_P2MP_NOT_ADVERTISED = 12,
+       PCEP_ERRV_LSP_INSTANTIATION_P2MP_NOT_ADVERTISED = 13,
+       PCEP_ERRV_AUTO_BW_CAP_NOT_ADVERTISED = 14,
+
+       /* Error Values for PCEP_ERRT_LSP_STATE_SYNC_ERROR=20 */
+       PCEP_ERRV_PCE_CANT_PROCESS_LSP_REPORT = 1,
+       PCEP_ERRV_LSP_DB_VERSION_MISMATCH = 2,
+       PCEP_ERRV_TRIGGER_ATTEMPT_BEFORE_PCE_TRIGGER = 3,
+       PCEP_ERRV_TRIGGER_ATTEMPT_NO_PCE_TRIGGER_CAP = 4,
+       PCEP_ERRV_PCC_CANT_COMPLETE_STATE_SYNC = 5,
+       PCEP_ERRV_INVALID_LSP_DB_VERSION_NUMBER = 6,
+       PCEP_ERRV_INVALID_SPEAKER_ENTITY_ID = 7,
+
+       /* PCEP_ERRT_INVALID_TE_PATH_SETUP_TYPE = 21 */
+       PCEP_ERRV_UNSUPPORTED_PATH_SETUP_TYPE = 1,
+       PCEP_ERRV_MISMATCHED_PATH_SETUP_TYPE = 2,
+
+       /* PCEP_ERRT_UNASSIGNED22 = 22 */
+
+       /* Error Values for PCEP_ERRT_BAD_PARAMETER_VALUE=23 */
+       PCEP_ERRV_SYMBOLIC_PATH_NAME_IN_USE = 1,
+       PCEP_ERRV_LSP_SPEAKER_ID_NOT_PCE_INITIATED = 2,
+
+       /* Error Values for PCEP_ERRT_LSP_INSTANTIATE_ERROR=24 */
+       PCEP_ERRV_UNACCEPTABLE_INSTANTIATE_ERROR = 1,
+       PCEP_ERRV_INTERNAL_ERROR = 2,
+       PCEP_ERRV_SIGNALLING_ERROR = 3,
+
+       /* PCEP_ERRT_START_TLS_FAILURE = 25 */
+       PCEP_ERRV_START_TLS_AFTER_PCEP_EXCHANGE = 1,
+       PCEP_ERRV_MSG_NOT_START_TLS_OPEN_ERROR = 2,
+       PCEP_ERRV_CONNECTION_WO_TLS_NOT_POSSIBLE = 3,
+       PCEP_ERRV_CONNECTION_WO_TLS_IS_POSSIBLE = 4,
+       PCEP_ERRV_NO_START_TLS_BEFORE_START_TLS_WAIT_TIMER = 5,
+
+       /* PCEP_ERRT_ASSOCIATION_ERROR = 26 */
+       PCEP_ERRV_ASSOC_TYPE_NOT_SUPPORTED = 1,
+       PCEP_ERRV_TOO_MANY_LSPS_IN_ASSOC_GRP = 2,
+       PCEP_ERRV_TOO_MANY_ASSOC_GROUPS = 3,
+       PCEP_ERRV_ASSOCIATION_UNKNOWN = 4,
+       PCEP_ERRV_OP_CONF_ASSOC_INFO_MISMATCH = 5,
+       PCEP_ERRV_ASSOC_INFO_MISMATCH = 6,
+       PCEP_ERRV_CANNOT_JOIN_ASSOC_GROUP = 7,
+       PCEP_ERRV_ASSOC_ID_NOT_IN_RANGE = 8,
+       PCEP_ERRV_TUNNEL_EP_MISMATCH_PATH_PROT_ASSOC = 9,
+       PCEP_ERRV_ATTEMPTED_ADD_LSP_PATH_PROT_ASSOC = 10,
+       PCEP_ERRV_PROTECTION_TYPE_NOT_SUPPORTED = 11,
+
+       /* PCEP_ERRT_WSON_RWA_ERROR = 27 */
+       PCEP_ERRV_RWA_INSUFFICIENT_MEMORY = 1,
+       PCEP_ERRV_RWA_COMP_NOT_SUPPORTED = 2,
+       PCEP_ERRV_SYNTAX_ENC_ERROR = 3,
+
+       /* PCEP_ERRT_H_PCE_ERROR = 28 */
+       PCEP_ERRV_H_PCE_CAP_NOT_ADVERTISED = 1,
+       PCEP_ERRV_PARENT_PCE_CAP_CANT_BE_PROVIDED = 2,
+
+       /* PCEP_ERRT_PATH_COMP_FAILURE = 29 */
+       PCEP_ERRV_UNACCEPTABLE_REQUEST_MSG = 1,
+       PCEP_ERRV_GENERALIZED_BW_VAL_NOT_SUPPORTED = 2,
+       PCEP_ERRV_LABEL_SET_CONSTRAINT_COULD_NOT_BE_MET = 3,
+       PCEP_ERRV_LABEL_CONSTRAINT_COULD_NOT_BE_MET = 4,
+
+};
+
+const char *get_error_type_str(enum pcep_error_type error_type);
+const char *get_error_value_str(enum pcep_error_type error_type,
+                               enum pcep_error_value error_value);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/pceplib/pcep_msg_objects.c b/pceplib/pcep_msg_objects.c
new file mode 100644 (file)
index 0000000..6c943dd
--- /dev/null
@@ -0,0 +1,854 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+/*
+ * This is the implementation of a High Level PCEP message object API.
+ */
+
+#include <string.h>
+#include <arpa/inet.h>
+#include <stdarg.h>
+#include <unistd.h>
+
+#include "pcep_msg_objects.h"
+#include "pcep_msg_tlvs.h"
+#include "pcep_utils_double_linked_list.h"
+#include "pcep_utils_logging.h"
+#include "pcep_utils_memory.h"
+
+/* Internal common function used to create a pcep_object and populate the header
+ */
+static struct pcep_object_header *pcep_obj_create_common_with_tlvs(
+       uint8_t obj_length, enum pcep_object_classes object_class,
+       enum pcep_object_types object_type, double_linked_list *tlv_list)
+{
+       uint8_t *buffer = pceplib_malloc(PCEPLIB_MESSAGES, obj_length);
+       memset(buffer, 0, obj_length);
+
+       /* The flag_p and flag_i flags will be set externally */
+       struct pcep_object_header *hdr = (struct pcep_object_header *)buffer;
+       hdr->object_class = object_class;
+       hdr->object_type = object_type;
+       hdr->tlv_list = tlv_list;
+
+       return hdr;
+}
+
+static struct pcep_object_header *
+pcep_obj_create_common(uint8_t obj_length,
+                      enum pcep_object_classes object_class,
+                      enum pcep_object_types object_type)
+{
+       return pcep_obj_create_common_with_tlvs(obj_length, object_class,
+                                               object_type, NULL);
+}
+
+struct pcep_object_open *pcep_obj_create_open(uint8_t keepalive,
+                                             uint8_t deadtimer, uint8_t sid,
+                                             double_linked_list *tlv_list)
+{
+       struct pcep_object_open *open =
+               (struct pcep_object_open *)pcep_obj_create_common_with_tlvs(
+                       sizeof(struct pcep_object_open), PCEP_OBJ_CLASS_OPEN,
+                       PCEP_OBJ_TYPE_OPEN, tlv_list);
+
+       open->open_version =
+               PCEP_OBJECT_OPEN_VERSION; /* PCEP version. Current version is 1
+                                            /No flags are currently defined. */
+       open->open_keepalive =
+               keepalive; /* Maximum period of time between two consecutive
+                             PCEP messages sent by the sender. */
+       open->open_deadtimer = deadtimer; /* Specifies the amount of time before
+                                            closing the session down. */
+       open->open_sid = sid; /* PCEP session number that identifies the current
+                                session. */
+
+       return open;
+}
+
+struct pcep_object_rp *pcep_obj_create_rp(uint8_t priority, bool flag_r,
+                                         bool flag_b, bool flag_s,
+                                         bool flag_of, uint32_t reqid,
+                                         double_linked_list *tlv_list)
+{
+       if (priority > OBJECT_RP_MAX_PRIORITY) {
+               pcep_log(
+                       LOG_INFO,
+                       "%s: Error creating RP object, invalid priority [%d], max priority [%d].",
+                       __func__, priority, OBJECT_RP_MAX_PRIORITY);
+               return NULL;
+       }
+
+       struct pcep_object_rp *obj =
+               (struct pcep_object_rp *)pcep_obj_create_common_with_tlvs(
+                       sizeof(struct pcep_object_rp), PCEP_OBJ_CLASS_RP,
+                       PCEP_OBJ_TYPE_RP, tlv_list);
+
+       obj->priority = priority;
+       obj->flag_reoptimization = flag_r;
+       obj->flag_bidirectional = flag_b;
+       obj->flag_strict = flag_s;
+       obj->flag_of = flag_of;
+       obj->request_id = reqid;
+
+       return obj;
+}
+
+struct pcep_object_notify *
+pcep_obj_create_notify(enum pcep_notification_types notification_type,
+                      enum pcep_notification_values notification_value)
+{
+       struct pcep_object_notify *obj =
+               (struct pcep_object_notify *)pcep_obj_create_common(
+                       sizeof(struct pcep_object_notify), PCEP_OBJ_CLASS_NOTF,
+                       PCEP_OBJ_TYPE_NOTF);
+
+       obj->notification_type = notification_type;
+       obj->notification_value = notification_value;
+
+       return obj;
+}
+
+struct pcep_object_nopath *
+pcep_obj_create_nopath(uint8_t ni, bool flag_c,
+                      enum pcep_nopath_tlv_err_codes error_code)
+{
+       struct pcep_object_tlv_nopath_vector *tlv =
+               pcep_tlv_create_nopath_vector(error_code);
+       double_linked_list *tlv_list = dll_initialize();
+       dll_append(tlv_list, tlv);
+
+       struct pcep_object_nopath *obj =
+               (struct pcep_object_nopath *)pcep_obj_create_common_with_tlvs(
+                       sizeof(struct pcep_object_nopath),
+                       PCEP_OBJ_CLASS_NOPATH, PCEP_OBJ_TYPE_NOPATH, tlv_list);
+
+       obj->ni = ni;
+       obj->flag_c = flag_c;
+       obj->err_code = error_code;
+
+       return obj;
+}
+
+struct pcep_object_association_ipv4 *
+pcep_obj_create_association_ipv4(bool r_flag, uint16_t association_type,
+                                uint16_t association_id, struct in_addr src)
+{
+       struct pcep_object_association_ipv4 *obj =
+               (struct pcep_object_association_ipv4 *)pcep_obj_create_common(
+                       sizeof(struct pcep_object_association_ipv4),
+                       PCEP_OBJ_CLASS_ASSOCIATION,
+                       PCEP_OBJ_TYPE_ASSOCIATION_IPV4);
+
+       obj->R_flag = r_flag;
+       obj->association_type = association_type;
+       obj->association_id = association_id;
+       obj->src = src;
+
+       return obj;
+}
+struct pcep_object_association_ipv6 *
+pcep_obj_create_association_ipv6(bool r_flag, uint16_t association_type,
+                                uint16_t association_id, struct in6_addr src)
+{
+       struct pcep_object_association_ipv6 *obj =
+               (struct pcep_object_association_ipv6 *)pcep_obj_create_common(
+                       sizeof(struct pcep_object_association_ipv6),
+                       PCEP_OBJ_CLASS_ASSOCIATION,
+                       PCEP_OBJ_TYPE_ASSOCIATION_IPV6);
+
+       obj->R_flag = r_flag;
+       obj->association_type = association_type;
+       obj->association_id = association_id;
+       obj->src = src;
+
+       return obj;
+}
+struct pcep_object_endpoints_ipv4 *
+pcep_obj_create_endpoint_ipv4(const struct in_addr *src_ipv4,
+                             const struct in_addr *dst_ipv4)
+{
+       if (src_ipv4 == NULL || dst_ipv4 == NULL) {
+               return NULL;
+       }
+
+       struct pcep_object_endpoints_ipv4 *obj =
+               (struct pcep_object_endpoints_ipv4 *)pcep_obj_create_common(
+                       sizeof(struct pcep_object_endpoints_ipv4),
+                       PCEP_OBJ_CLASS_ENDPOINTS, PCEP_OBJ_TYPE_ENDPOINT_IPV4);
+
+       obj->src_ipv4.s_addr = src_ipv4->s_addr;
+       obj->dst_ipv4.s_addr = dst_ipv4->s_addr;
+
+       return obj;
+}
+
+struct pcep_object_endpoints_ipv6 *
+pcep_obj_create_endpoint_ipv6(const struct in6_addr *src_ipv6,
+                             const struct in6_addr *dst_ipv6)
+{
+       if (src_ipv6 == NULL || dst_ipv6 == NULL) {
+               return NULL;
+       }
+
+       struct pcep_object_endpoints_ipv6 *obj =
+               (struct pcep_object_endpoints_ipv6 *)pcep_obj_create_common(
+                       sizeof(struct pcep_object_endpoints_ipv6),
+                       PCEP_OBJ_CLASS_ENDPOINTS, PCEP_OBJ_TYPE_ENDPOINT_IPV6);
+
+       memcpy(&obj->src_ipv6, src_ipv6, sizeof(struct in6_addr));
+       memcpy(&obj->dst_ipv6, dst_ipv6, sizeof(struct in6_addr));
+
+       return obj;
+}
+
+struct pcep_object_bandwidth *pcep_obj_create_bandwidth(float bandwidth)
+{
+       struct pcep_object_bandwidth *obj =
+               (struct pcep_object_bandwidth *)pcep_obj_create_common(
+                       sizeof(struct pcep_object_bandwidth),
+                       PCEP_OBJ_CLASS_BANDWIDTH, PCEP_OBJ_TYPE_BANDWIDTH_REQ);
+
+       obj->bandwidth = bandwidth;
+
+       return obj;
+}
+
+struct pcep_object_metric *pcep_obj_create_metric(enum pcep_metric_types type,
+                                                 bool flag_b, bool flag_c,
+                                                 float value)
+{
+       struct pcep_object_metric *obj =
+               (struct pcep_object_metric *)pcep_obj_create_common(
+                       sizeof(struct pcep_object_metric),
+                       PCEP_OBJ_CLASS_METRIC, PCEP_OBJ_TYPE_METRIC);
+
+       obj->flag_b = flag_b;
+       obj->flag_c = flag_c;
+       obj->type = type;
+       obj->value = value;
+
+       return obj;
+}
+
+struct pcep_object_lspa *
+pcep_obj_create_lspa(uint32_t exclude_any, uint32_t include_any,
+                    uint32_t include_all, uint8_t setup_priority,
+                    uint8_t holding_priority, bool flag_local_protection)
+{
+       struct pcep_object_lspa *obj =
+               (struct pcep_object_lspa *)pcep_obj_create_common(
+                       sizeof(struct pcep_object_lspa), PCEP_OBJ_CLASS_LSPA,
+                       PCEP_OBJ_TYPE_LSPA);
+
+       obj->lspa_exclude_any = exclude_any;
+       obj->lspa_include_any = include_any;
+       obj->lspa_include_all = include_all;
+       obj->setup_priority = setup_priority;
+       obj->holding_priority = holding_priority;
+       obj->flag_local_protection = flag_local_protection;
+
+       return obj;
+}
+
+struct pcep_object_svec *
+pcep_obj_create_svec(bool srlg, bool node, bool link,
+                    double_linked_list *request_id_list)
+{
+       if (request_id_list == NULL) {
+               return NULL;
+       }
+
+       struct pcep_object_svec *obj =
+               (struct pcep_object_svec *)pcep_obj_create_common(
+                       sizeof(struct pcep_object_svec), PCEP_OBJ_CLASS_SVEC,
+                       PCEP_OBJ_TYPE_SVEC);
+
+       obj->flag_srlg_diverse = srlg;
+       obj->flag_node_diverse = node;
+       obj->flag_link_diverse = link;
+       obj->request_id_list = request_id_list;
+
+       return obj;
+}
+
+struct pcep_object_error *
+pcep_obj_create_error(enum pcep_error_type error_type,
+                     enum pcep_error_value error_value)
+{
+       struct pcep_object_error *obj =
+               (struct pcep_object_error *)pcep_obj_create_common(
+                       sizeof(struct pcep_object_error), PCEP_OBJ_CLASS_ERROR,
+                       PCEP_OBJ_TYPE_ERROR);
+
+       obj->error_type = error_type;
+       obj->error_value = error_value;
+
+       return obj;
+}
+
+struct pcep_object_close *pcep_obj_create_close(enum pcep_close_reason reason)
+{
+       struct pcep_object_close *obj =
+               (struct pcep_object_close *)pcep_obj_create_common(
+                       sizeof(struct pcep_object_close), PCEP_OBJ_CLASS_CLOSE,
+                       PCEP_OBJ_TYPE_CLOSE);
+
+       obj->reason = reason;
+
+       return obj;
+}
+
+struct pcep_object_srp *pcep_obj_create_srp(bool lsp_remove,
+                                           uint32_t srp_id_number,
+                                           double_linked_list *tlv_list)
+{
+       struct pcep_object_srp *obj =
+               (struct pcep_object_srp *)pcep_obj_create_common_with_tlvs(
+                       sizeof(struct pcep_object_srp), PCEP_OBJ_CLASS_SRP,
+                       PCEP_OBJ_TYPE_SRP, tlv_list);
+
+       obj->flag_lsp_remove = lsp_remove;
+       obj->srp_id_number = srp_id_number;
+
+       return obj;
+}
+
+struct pcep_object_lsp *
+pcep_obj_create_lsp(uint32_t plsp_id, enum pcep_lsp_operational_status status,
+                   bool c_flag, bool a_flag, bool r_flag, bool s_flag,
+                   bool d_flag, double_linked_list *tlv_list)
+{
+       /* The plsp_id is only 20 bits */
+       if (plsp_id > MAX_PLSP_ID) {
+               pcep_log(
+                       LOG_INFO,
+                       "%s: pcep_obj_create_lsp invalid plsp_id [%d] max value [%d]",
+                       __func__, plsp_id, MAX_PLSP_ID);
+               return NULL;
+       }
+
+       /* The status is only 3 bits */
+       if (status > MAX_LSP_STATUS) {
+               pcep_log(
+                       LOG_INFO,
+                       "%s: pcep_obj_create_lsp invalid status [%d] max value [%d]",
+                       __func__, plsp_id, MAX_PLSP_ID);
+               return NULL;
+       }
+
+       struct pcep_object_lsp *obj =
+               (struct pcep_object_lsp *)pcep_obj_create_common_with_tlvs(
+                       sizeof(struct pcep_object_lsp), PCEP_OBJ_CLASS_LSP,
+                       PCEP_OBJ_TYPE_LSP, tlv_list);
+
+       obj->plsp_id = plsp_id;
+       obj->operational_status = status;
+       obj->flag_c = c_flag;
+       obj->flag_a = a_flag;
+       obj->flag_r = r_flag;
+       obj->flag_s = s_flag;
+       obj->flag_d = d_flag;
+
+       return obj;
+}
+
+struct pcep_object_vendor_info *
+pcep_obj_create_vendor_info(uint32_t enterprise_number,
+                           uint32_t enterprise_spec_info)
+{
+       struct pcep_object_vendor_info *obj =
+               (struct pcep_object_vendor_info *)pcep_obj_create_common(
+                       sizeof(struct pcep_object_vendor_info),
+                       PCEP_OBJ_CLASS_VENDOR_INFO, PCEP_OBJ_TYPE_VENDOR_INFO);
+
+       obj->enterprise_number = enterprise_number;
+       obj->enterprise_specific_info = enterprise_spec_info;
+
+       return obj;
+}
+
+struct pcep_object_inter_layer *
+pcep_obj_create_inter_layer(bool flag_i, bool flag_m, bool flag_t)
+{
+       struct pcep_object_inter_layer *obj =
+               (struct pcep_object_inter_layer *)pcep_obj_create_common(
+                       sizeof(struct pcep_object_inter_layer),
+                       PCEP_OBJ_CLASS_INTER_LAYER, PCEP_OBJ_TYPE_INTER_LAYER);
+
+       obj->flag_i = flag_i;
+       obj->flag_m = flag_m;
+       obj->flag_t = flag_t;
+
+       return obj;
+}
+
+struct pcep_object_switch_layer *
+pcep_obj_create_switch_layer(double_linked_list *switch_layer_rows)
+{
+       struct pcep_object_switch_layer *obj =
+               (struct pcep_object_switch_layer *)pcep_obj_create_common(
+                       sizeof(struct pcep_object_switch_layer),
+                       PCEP_OBJ_CLASS_SWITCH_LAYER,
+                       PCEP_OBJ_TYPE_SWITCH_LAYER);
+
+       obj->switch_layer_rows = switch_layer_rows;
+
+       return obj;
+}
+
+struct pcep_object_req_adap_cap *
+pcep_obj_create_req_adap_cap(enum pcep_switching_capability sw_cap,
+                            enum pcep_lsp_encoding_type encoding)
+{
+       struct pcep_object_req_adap_cap *obj =
+               (struct pcep_object_req_adap_cap *)pcep_obj_create_common(
+                       sizeof(struct pcep_object_req_adap_cap),
+                       PCEP_OBJ_CLASS_REQ_ADAP_CAP,
+                       PCEP_OBJ_TYPE_REQ_ADAP_CAP);
+
+       obj->switching_capability = sw_cap;
+       obj->encoding = encoding;
+
+       return obj;
+}
+
+struct pcep_object_server_indication *
+pcep_obj_create_server_indication(enum pcep_switching_capability sw_cap,
+                                 enum pcep_lsp_encoding_type encoding,
+                                 double_linked_list *tlv_list)
+{
+       struct pcep_object_server_indication *obj =
+               (struct pcep_object_server_indication *)
+                       pcep_obj_create_common_with_tlvs(
+                               sizeof(struct pcep_object_server_indication),
+                               PCEP_OBJ_CLASS_SERVER_IND,
+                               PCEP_OBJ_TYPE_SERVER_IND, tlv_list);
+
+       obj->switching_capability = sw_cap;
+       obj->encoding = encoding;
+
+       return obj;
+}
+
+struct pcep_object_objective_function *
+pcep_obj_create_objective_function(uint16_t of_code,
+                                  double_linked_list *tlv_list)
+{
+       struct pcep_object_objective_function *obj =
+               (struct pcep_object_objective_function *)
+                       pcep_obj_create_common_with_tlvs(
+                               sizeof(struct pcep_object_objective_function),
+                               PCEP_OBJ_CLASS_OF, PCEP_OBJ_TYPE_OF, tlv_list);
+
+       obj->of_code = of_code;
+
+       return obj;
+}
+
+/* Wrap a list of ro subobjects in a structure with an object header */
+struct pcep_object_ro *pcep_obj_create_ero(double_linked_list *ero_list)
+{
+       struct pcep_object_ro *ero =
+               (struct pcep_object_ro *)pcep_obj_create_common(
+                       sizeof(struct pcep_object_ro), PCEP_OBJ_CLASS_ERO,
+                       PCEP_OBJ_TYPE_ERO);
+       ero->sub_objects = ero_list;
+
+       return ero;
+}
+
+/* Wrap a list of ro subobjects in a structure with an object header */
+struct pcep_object_ro *pcep_obj_create_iro(double_linked_list *iro_list)
+{
+       struct pcep_object_ro *iro =
+               (struct pcep_object_ro *)pcep_obj_create_common(
+                       sizeof(struct pcep_object_ro), PCEP_OBJ_CLASS_IRO,
+                       PCEP_OBJ_TYPE_IRO);
+       iro->sub_objects = iro_list;
+
+       return iro;
+}
+
+/* Wrap a list of ro subobjects in a structure with an object header */
+struct pcep_object_ro *pcep_obj_create_rro(double_linked_list *rro_list)
+{
+       struct pcep_object_ro *rro =
+               (struct pcep_object_ro *)pcep_obj_create_common(
+                       sizeof(struct pcep_object_ro), PCEP_OBJ_CLASS_RRO,
+                       PCEP_OBJ_TYPE_RRO);
+       rro->sub_objects = rro_list;
+
+       return rro;
+}
+
+/*
+ * Route Object Sub-object creation functions
+ */
+
+static struct pcep_object_ro_subobj *
+pcep_obj_create_ro_subobj_common(uint8_t subobj_size,
+                                enum pcep_ro_subobj_types ro_subobj_type,
+                                bool flag_subobj_loose_hop)
+{
+       struct pcep_object_ro_subobj *ro_subobj =
+               pceplib_malloc(PCEPLIB_MESSAGES, subobj_size);
+       memset(ro_subobj, 0, subobj_size);
+       ro_subobj->flag_subobj_loose_hop = flag_subobj_loose_hop;
+       ro_subobj->ro_subobj_type = ro_subobj_type;
+
+       return ro_subobj;
+}
+
+struct pcep_ro_subobj_ipv4 *
+pcep_obj_create_ro_subobj_ipv4(bool loose_hop, const struct in_addr *rro_ipv4,
+                              uint8_t prefix_length, bool flag_local_prot)
+{
+       if (rro_ipv4 == NULL) {
+               return NULL;
+       }
+
+       struct pcep_ro_subobj_ipv4 *obj =
+               (struct pcep_ro_subobj_ipv4 *)pcep_obj_create_ro_subobj_common(
+                       sizeof(struct pcep_ro_subobj_ipv4), RO_SUBOBJ_TYPE_IPV4,
+                       loose_hop);
+       obj->ip_addr.s_addr = rro_ipv4->s_addr;
+       obj->prefix_length = prefix_length;
+       obj->flag_local_protection = flag_local_prot;
+
+       return obj;
+}
+
+struct pcep_ro_subobj_ipv6 *
+pcep_obj_create_ro_subobj_ipv6(bool loose_hop, const struct in6_addr *rro_ipv6,
+                              uint8_t prefix_length, bool flag_local_prot)
+{
+       if (rro_ipv6 == NULL) {
+               return NULL;
+       }
+
+       struct pcep_ro_subobj_ipv6 *obj =
+               (struct pcep_ro_subobj_ipv6 *)pcep_obj_create_ro_subobj_common(
+                       sizeof(struct pcep_ro_subobj_ipv6), RO_SUBOBJ_TYPE_IPV6,
+                       loose_hop);
+       obj->prefix_length = prefix_length;
+       obj->flag_local_protection = flag_local_prot;
+       memcpy(&obj->ip_addr, rro_ipv6, sizeof(struct in6_addr));
+
+       return obj;
+}
+
+struct pcep_ro_subobj_unnum *
+pcep_obj_create_ro_subobj_unnum(struct in_addr *router_id, uint32_t if_id)
+{
+       if (router_id == NULL) {
+               return NULL;
+       }
+
+       struct pcep_ro_subobj_unnum *obj =
+               (struct pcep_ro_subobj_unnum *)pcep_obj_create_ro_subobj_common(
+                       sizeof(struct pcep_ro_subobj_unnum),
+                       RO_SUBOBJ_TYPE_UNNUM, false);
+       obj->interface_id = if_id;
+       obj->router_id.s_addr = router_id->s_addr;
+
+       return obj;
+}
+
+struct pcep_ro_subobj_32label *
+pcep_obj_create_ro_subobj_32label(bool flag_global_label, uint8_t class_type,
+                                 uint32_t label)
+{
+       struct pcep_ro_subobj_32label *obj = (struct pcep_ro_subobj_32label *)
+               pcep_obj_create_ro_subobj_common(
+                       sizeof(struct pcep_ro_subobj_32label),
+                       RO_SUBOBJ_TYPE_LABEL, false);
+       obj->class_type = class_type;
+       obj->flag_global_label = flag_global_label;
+       obj->label = label;
+
+       return obj;
+}
+
+struct pcep_ro_subobj_asn *pcep_obj_create_ro_subobj_asn(uint16_t asn)
+{
+       struct pcep_ro_subobj_asn *obj =
+               (struct pcep_ro_subobj_asn *)pcep_obj_create_ro_subobj_common(
+                       sizeof(struct pcep_ro_subobj_asn), RO_SUBOBJ_TYPE_ASN,
+                       false);
+       obj->asn = asn;
+
+       return obj;
+}
+
+/* Internal util function to create pcep_ro_subobj_sr sub-objects */
+static struct pcep_ro_subobj_sr *
+pcep_obj_create_ro_subobj_sr_common(enum pcep_sr_subobj_nai nai_type,
+                                   bool loose_hop, bool f_flag, bool s_flag,
+                                   bool c_flag_in, bool m_flag_in)
+{
+       struct pcep_ro_subobj_sr *obj =
+               (struct pcep_ro_subobj_sr *)pcep_obj_create_ro_subobj_common(
+                       sizeof(struct pcep_ro_subobj_sr), RO_SUBOBJ_TYPE_SR,
+                       loose_hop);
+
+       /* Flag logic according to draft-ietf-pce-segment-routing-16 */
+       bool c_flag = c_flag_in;
+       bool m_flag = m_flag_in;
+       if (s_flag) {
+               c_flag = false;
+               m_flag = false;
+       }
+
+       if (m_flag == false) {
+               c_flag = false;
+       }
+
+       obj->nai_type = nai_type;
+       obj->flag_f = f_flag;
+       obj->flag_s = s_flag;
+       obj->flag_c = c_flag;
+       obj->flag_m = m_flag;
+
+       return obj;
+}
+
+struct pcep_ro_subobj_sr *pcep_obj_create_ro_subobj_sr_nonai(bool loose_hop,
+                                                            uint32_t sid,
+                                                            bool c_flag,
+                                                            bool m_flag)
+{
+       /* According to draft-ietf-pce-segment-routing-16#section-5.2.1
+        * If NT=0, the F bit MUST be 1, the S bit MUST be zero and the
+        * Length MUST be 8. */
+       struct pcep_ro_subobj_sr *obj = pcep_obj_create_ro_subobj_sr_common(
+               PCEP_SR_SUBOBJ_NAI_ABSENT, loose_hop, true, false, c_flag,
+               m_flag);
+       obj->sid = sid;
+
+       return obj;
+}
+
+struct pcep_ro_subobj_sr *
+pcep_obj_create_ro_subobj_sr_ipv4_node(bool loose_hop, bool sid_absent,
+                                      bool c_flag, bool m_flag, uint32_t sid,
+                                      struct in_addr *ipv4_node_id)
+{
+       if (ipv4_node_id == NULL) {
+               return NULL;
+       }
+
+       /* According to draft-ietf-pce-segment-routing-16#section-5.2.1
+        * If NT=1, the F bit MUST be zero.  If the S bit is 1, the Length
+        * MUST be 8, otherwise the Length MUST be 12 */
+       struct pcep_ro_subobj_sr *obj = pcep_obj_create_ro_subobj_sr_common(
+               PCEP_SR_SUBOBJ_NAI_IPV4_NODE, loose_hop, false, sid_absent,
+               c_flag, m_flag);
+
+       if (!sid_absent) {
+               obj->sid = sid;
+       }
+       obj->nai_list = dll_initialize();
+       /* Since the IP has to be stored in the list, copy it so the caller
+        * doesnt have any restrictions about the type of memory used externally
+        * for the IP. This memory will be freed with the object is freed. */
+       struct in_addr *ipv4_node_id_copy =
+               pceplib_malloc(PCEPLIB_MESSAGES, sizeof(struct in_addr));
+       ipv4_node_id_copy->s_addr = ipv4_node_id->s_addr;
+       dll_append(obj->nai_list, ipv4_node_id_copy);
+
+       return obj;
+}
+
+struct pcep_ro_subobj_sr *
+pcep_obj_create_ro_subobj_sr_ipv6_node(bool loose_hop, bool sid_absent,
+                                      bool c_flag, bool m_flag, uint32_t sid,
+                                      struct in6_addr *ipv6_node_id)
+{
+       if (ipv6_node_id == NULL) {
+               return NULL;
+       }
+
+       /* According to draft-ietf-pce-segment-routing-16#section-5.2.1
+        * If NT=2, the F bit MUST be zero.  If the S bit is 1, the Length
+        * MUST be 20, otherwise the Length MUST be 24. */
+       struct pcep_ro_subobj_sr *obj = pcep_obj_create_ro_subobj_sr_common(
+               PCEP_SR_SUBOBJ_NAI_IPV6_NODE, loose_hop, false, sid_absent,
+               c_flag, m_flag);
+
+       if (!sid_absent) {
+               obj->sid = sid;
+       }
+       obj->nai_list = dll_initialize();
+       struct in6_addr *ipv6_node_id_copy =
+               pceplib_malloc(PCEPLIB_MESSAGES, sizeof(struct in6_addr));
+       memcpy(ipv6_node_id_copy, ipv6_node_id, sizeof(struct in6_addr));
+       dll_append(obj->nai_list, ipv6_node_id_copy);
+
+       return obj;
+}
+
+struct pcep_ro_subobj_sr *pcep_obj_create_ro_subobj_sr_ipv4_adj(
+       bool loose_hop, bool sid_absent, bool c_flag, bool m_flag, uint32_t sid,
+       struct in_addr *local_ipv4, struct in_addr *remote_ipv4)
+{
+       if (local_ipv4 == NULL || remote_ipv4 == NULL) {
+               return NULL;
+       }
+
+       /* According to draft-ietf-pce-segment-routing-16#section-5.2.1
+        * If NT=3, the F bit MUST be zero.  If the S bit is 1, the Length
+        * MUST be 12, otherwise the Length MUST be 16 */
+       struct pcep_ro_subobj_sr *obj = pcep_obj_create_ro_subobj_sr_common(
+               PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY, loose_hop, false, sid_absent,
+               c_flag, m_flag);
+
+       if (!sid_absent) {
+               obj->sid = sid;
+       }
+       obj->nai_list = dll_initialize();
+       struct in_addr *local_ipv4_copy =
+               pceplib_malloc(PCEPLIB_MESSAGES, sizeof(struct in_addr));
+       struct in_addr *remote_ipv4_copy =
+               pceplib_malloc(PCEPLIB_MESSAGES, sizeof(struct in_addr));
+       local_ipv4_copy->s_addr = local_ipv4->s_addr;
+       remote_ipv4_copy->s_addr = remote_ipv4->s_addr;
+       dll_append(obj->nai_list, local_ipv4_copy);
+       dll_append(obj->nai_list, remote_ipv4_copy);
+
+       return obj;
+}
+
+struct pcep_ro_subobj_sr *pcep_obj_create_ro_subobj_sr_ipv6_adj(
+       bool loose_hop, bool sid_absent, bool c_flag, bool m_flag, uint32_t sid,
+       struct in6_addr *local_ipv6, struct in6_addr *remote_ipv6)
+{
+       if (local_ipv6 == NULL || remote_ipv6 == NULL) {
+               return NULL;
+       }
+
+       /* According to draft-ietf-pce-segment-routing-16#section-5.2.1
+        * If NT=4, the F bit MUST be zero.  If the S bit is 1, the Length
+        * MUST be 36, otherwise the Length MUST be 40 */
+       struct pcep_ro_subobj_sr *obj = pcep_obj_create_ro_subobj_sr_common(
+               PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY, loose_hop, false, sid_absent,
+               c_flag, m_flag);
+
+       if (!sid_absent) {
+               obj->sid = sid;
+       }
+       obj->nai_list = dll_initialize();
+       struct in6_addr *local_ipv6_copy =
+               pceplib_malloc(PCEPLIB_MESSAGES, sizeof(struct in6_addr));
+       struct in6_addr *remote_ipv6_copy =
+               pceplib_malloc(PCEPLIB_MESSAGES, sizeof(struct in6_addr));
+       memcpy(local_ipv6_copy, local_ipv6, sizeof(struct in6_addr));
+       memcpy(remote_ipv6_copy, remote_ipv6, sizeof(struct in6_addr));
+       dll_append(obj->nai_list, local_ipv6_copy);
+       dll_append(obj->nai_list, remote_ipv6_copy);
+
+       return obj;
+}
+
+struct pcep_ro_subobj_sr *pcep_obj_create_ro_subobj_sr_unnumbered_ipv4_adj(
+       bool loose_hop, bool sid_absent, bool c_flag, bool m_flag, uint32_t sid,
+       uint32_t local_node_id, uint32_t local_if_id, uint32_t remote_node_id,
+       uint32_t remote_if_id)
+{
+       /* According to draft-ietf-pce-segment-routing-16#section-5.2.1
+        * If NT=5, the F bit MUST be zero.  If the S bit is 1, the Length
+        * MUST be 20, otherwise the Length MUST be 24. */
+       struct pcep_ro_subobj_sr *obj = pcep_obj_create_ro_subobj_sr_common(
+               PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY, loose_hop, false,
+               sid_absent, c_flag, m_flag);
+
+       if (!sid_absent) {
+               obj->sid = sid;
+       }
+
+       obj->nai_list = dll_initialize();
+       uint32_t *local_node_id_copy =
+               pceplib_malloc(PCEPLIB_MESSAGES, sizeof(uint32_t));
+       *local_node_id_copy = local_node_id;
+       dll_append(obj->nai_list, local_node_id_copy);
+
+       uint32_t *local_if_id_copy =
+               pceplib_malloc(PCEPLIB_MESSAGES, sizeof(uint32_t));
+       *local_if_id_copy = local_if_id;
+       dll_append(obj->nai_list, local_if_id_copy);
+
+       uint32_t *remote_node_id_copy =
+               pceplib_malloc(PCEPLIB_MESSAGES, sizeof(uint32_t));
+       *remote_node_id_copy = remote_node_id;
+       dll_append(obj->nai_list, remote_node_id_copy);
+
+       uint32_t *remote_if_id_copy =
+               pceplib_malloc(PCEPLIB_MESSAGES, sizeof(uint32_t));
+       *remote_if_id_copy = remote_if_id;
+       dll_append(obj->nai_list, remote_if_id_copy);
+
+       return obj;
+}
+
+struct pcep_ro_subobj_sr *pcep_obj_create_ro_subobj_sr_linklocal_ipv6_adj(
+       bool loose_hop, bool sid_absent, bool c_flag, bool m_flag, uint32_t sid,
+       struct in6_addr *local_ipv6, uint32_t local_if_id,
+       struct in6_addr *remote_ipv6, uint32_t remote_if_id)
+{
+       if (local_ipv6 == NULL || remote_ipv6 == NULL) {
+               return NULL;
+       }
+
+       /* According to draft-ietf-pce-segment-routing-16#section-5.2.1
+        * If NT=6, the F bit MUST be zero.  If the S bit is 1, the Length
+        * MUST be 44, otherwise the Length MUST be 48 */
+       struct pcep_ro_subobj_sr *obj = pcep_obj_create_ro_subobj_sr_common(
+               PCEP_SR_SUBOBJ_NAI_LINK_LOCAL_IPV6_ADJACENCY, loose_hop, false,
+               sid_absent, c_flag, m_flag);
+
+       if (!sid_absent) {
+               obj->sid = sid;
+       }
+       obj->nai_list = dll_initialize();
+       struct in6_addr *local_ipv6_copy =
+               pceplib_malloc(PCEPLIB_MESSAGES, sizeof(struct in6_addr));
+       memcpy(local_ipv6_copy, local_ipv6, sizeof(struct in6_addr));
+       dll_append(obj->nai_list, local_ipv6_copy);
+
+       uint32_t *local_if_id_copy =
+               pceplib_malloc(PCEPLIB_MESSAGES, sizeof(uint32_t));
+       *local_if_id_copy = local_if_id;
+       dll_append(obj->nai_list, local_if_id_copy);
+
+       struct in6_addr *remote_ipv6_copy =
+               pceplib_malloc(PCEPLIB_MESSAGES, sizeof(struct in6_addr));
+       memcpy(remote_ipv6_copy, remote_ipv6, sizeof(struct in6_addr));
+       dll_append(obj->nai_list, remote_ipv6_copy);
+
+       uint32_t *remote_if_id_copy =
+               pceplib_malloc(PCEPLIB_MESSAGES, sizeof(uint32_t));
+       *remote_if_id_copy = remote_if_id;
+       dll_append(obj->nai_list, remote_if_id_copy);
+
+       return obj;
+}
diff --git a/pceplib/pcep_msg_objects.h b/pceplib/pcep_msg_objects.h
new file mode 100644 (file)
index 0000000..959a6f8
--- /dev/null
@@ -0,0 +1,741 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ */
+
+
+/*
+ * This is a High Level PCEP message object API.
+ */
+
+#ifndef PCEP_OBJECTS_H
+#define PCEP_OBJECTS_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "pcep.h"
+#include "pcep_utils_double_linked_list.h"
+#include "pcep_msg_object_error_types.h"
+#include "pcep_msg_tlvs.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Regarding memory usage:
+ * When creating objects, any objects passed into these APIs will be free'd when
+ * the enclosing pcep_message is free'd. That includes the double_linked_list's.
+ * So, just create the objects and TLVs, put them in their double_linked_list's,
+ * and everything will be managed internally. The enclosing message will be
+ * deleted by pcep_msg_free_message() or pcep_msg_free_message_list() which,
+ * in turn will call one of: pcep_obj_free_object() and pcep_obj_free_tlv().
+ * For received messages with objects, call pcep_msg_free_message() to free
+ * them.
+ */
+
+enum pcep_object_classes {
+       PCEP_OBJ_CLASS_OPEN = 1,
+       PCEP_OBJ_CLASS_RP = 2,
+       PCEP_OBJ_CLASS_NOPATH = 3,
+       PCEP_OBJ_CLASS_ENDPOINTS = 4,
+       PCEP_OBJ_CLASS_BANDWIDTH = 5,
+       PCEP_OBJ_CLASS_METRIC = 6,
+       PCEP_OBJ_CLASS_ERO = 7,
+       PCEP_OBJ_CLASS_RRO = 8,
+       PCEP_OBJ_CLASS_LSPA = 9,
+       PCEP_OBJ_CLASS_IRO = 10,
+       PCEP_OBJ_CLASS_SVEC = 11,
+       PCEP_OBJ_CLASS_NOTF = 12,
+       PCEP_OBJ_CLASS_ERROR = 13,
+       PCEP_OBJ_CLASS_CLOSE = 15,
+       PCEP_OBJ_CLASS_OF = 21,
+       PCEP_OBJ_CLASS_LSP = 32,
+       PCEP_OBJ_CLASS_SRP = 33,
+       PCEP_OBJ_CLASS_VENDOR_INFO = 34,
+       PCEP_OBJ_CLASS_INTER_LAYER = 36,  /* RFC 8282 */
+       PCEP_OBJ_CLASS_SWITCH_LAYER = 37, /* RFC 8282 */
+       PCEP_OBJ_CLASS_REQ_ADAP_CAP = 38, /* RFC 8282 */
+       PCEP_OBJ_CLASS_SERVER_IND = 39,   /* RFC 8282 */
+       PCEP_OBJ_CLASS_ASSOCIATION = 40, /*draft-ietf-pce-association-group-10*/
+       PCEP_OBJ_CLASS_MAX,
+};
+
+enum pcep_object_types {
+       PCEP_OBJ_TYPE_OPEN = 1,
+       PCEP_OBJ_TYPE_RP = 1,
+       PCEP_OBJ_TYPE_NOPATH = 1,
+       PCEP_OBJ_TYPE_ENDPOINT_IPV4 = 1,
+       PCEP_OBJ_TYPE_ENDPOINT_IPV6 = 2,
+       PCEP_OBJ_TYPE_BANDWIDTH_REQ = 1,
+       PCEP_OBJ_TYPE_BANDWIDTH_TELSP = 2,
+       PCEP_OBJ_TYPE_BANDWIDTH_CISCO =
+               5, /* IANA unassigned, but rcvd from Cisco PCE */
+       PCEP_OBJ_TYPE_SRP = 1,
+       PCEP_OBJ_TYPE_VENDOR_INFO = 1,
+       PCEP_OBJ_TYPE_LSP = 1,
+       PCEP_OBJ_TYPE_METRIC = 1,
+       PCEP_OBJ_TYPE_ERO = 1,
+       PCEP_OBJ_TYPE_RRO = 1,
+       PCEP_OBJ_TYPE_LSPA = 1,
+       PCEP_OBJ_TYPE_IRO = 1,
+       PCEP_OBJ_TYPE_SVEC = 1,
+       PCEP_OBJ_TYPE_NOTF = 1,
+       PCEP_OBJ_TYPE_ERROR = 1,
+       PCEP_OBJ_TYPE_CLOSE = 1,
+       PCEP_OBJ_TYPE_INTER_LAYER = 1,
+       PCEP_OBJ_TYPE_SWITCH_LAYER = 1,
+       PCEP_OBJ_TYPE_REQ_ADAP_CAP = 1,
+       PCEP_OBJ_TYPE_SERVER_IND = 1,
+       PCEP_OBJ_TYPE_ASSOCIATION_IPV4 =
+               1, /*draft-ietf-pce-association-group-10*/
+       PCEP_OBJ_TYPE_ASSOCIATION_IPV6 =
+               2, /*draft-ietf-pce-association-group-10*/
+       PCEP_OBJ_TYPE_OF = 1,
+       PCEP_OBJ_TYPE_MAX = 2,
+};
+
+#define OBJECT_HEADER_FLAG_I 0x01
+#define OBJECT_HEADER_FLAG_P 0x02
+
+/* The flag_p and flag_i arent set via the APIs, if they need to be set, just
+ * set them on the returned object once it has been created. */
+struct pcep_object_header {
+       enum pcep_object_classes object_class;
+       enum pcep_object_types object_type;
+       bool flag_p; /* PCC Processing rule bit: When set, the object MUST be
+                       taken into account, when cleared the object is optional.
+                     */
+       bool flag_i; /* PCE Ignore bit: indicates to a PCC whether or not an
+                       optional object was processed */
+       double_linked_list *tlv_list;
+       /* Pointer into encoded_message field from the pcep_message */
+       const uint8_t *encoded_object;
+       uint16_t encoded_object_length;
+};
+
+#define PCEP_OBJECT_OPEN_VERSION 1
+
+struct pcep_object_open {
+       struct pcep_object_header header;
+       uint8_t open_version;   /* PCEP version. Current version is 1 */
+       uint8_t open_keepalive; /* Maximum period of time between two
+                                  consecutive PCEP messages sent by the sender.
+                                */
+       uint8_t open_deadtimer; /* Specifies the amount of time before closing
+                                  the session down. */
+       uint8_t open_sid; /* PCEP session number that identifies the current
+                            session. */
+};
+
+#define OBJECT_RP_FLAG_R 0x08
+#define OBJECT_RP_FLAG_B 0x10
+#define OBJECT_RP_FLAG_O 0x20
+#define OBJECT_RP_FLAG_OF 0x80
+#define OBJECT_RP_MAX_PRIORITY 0x07
+
+struct pcep_object_rp {
+       struct pcep_object_header header;
+       uint8_t priority; /* 3 bit priority, max priority is 7 */
+       bool flag_reoptimization;
+       bool flag_bidirectional;
+       bool flag_strict;    /* when set, a loose path is acceptable */
+       bool flag_of;        /* Supply Objective Function on Response */
+       uint32_t request_id; /* The Request-id-number value combined with the
+                               source for PCC & PCE creates a uniquely number.
+                             */
+};
+
+enum pcep_notification_types {
+       PCEP_NOTIFY_TYPE_PENDING_REQUEST_CANCELLED = 1,
+       PCEP_NOTIFY_TYPE_PCE_OVERLOADED = 2
+};
+
+enum pcep_notification_values {
+       PCEP_NOTIFY_VALUE_PCC_CANCELLED_REQUEST = 1,
+       PCEP_NOTIFY_VALUE_PCE_CANCELLED_REQUEST = 2,
+       PCEP_NOTIFY_VALUE_PCE_CURRENTLY_OVERLOADED = 1,
+       PCEP_NOTIFY_VALUE_PCE_NO_LONGER_OVERLOADED = 2
+};
+
+struct pcep_object_notify {
+       struct pcep_object_header header;
+       enum pcep_notification_types notification_type;
+       enum pcep_notification_values notification_value;
+};
+
+enum pcep_association_type {
+       PCEP_ASSOCIATION_TYPE_PATH_PROTECTION_ASSOCIATION =
+               1, // iana unique value define as 2020-01-08!
+       PCEP_ASSOCIATION_TYPE_SR_POLICY_ASSOCIATION_TYPE =
+               65535 // TBD1  draft-barth-pce-segment-routing-policy-cp-04
+};
+#define OBJECT_ASSOCIATION_FLAG_R 0x01
+struct pcep_object_association_ipv4 { // draft-ietf-pce-association-group-10
+       struct pcep_object_header header;
+       bool R_flag;
+       uint16_t association_type;
+       uint16_t association_id;
+       struct in_addr src;
+};
+
+struct pcep_object_association_ipv6 { // draft-ietf-pce-association-group-10
+       struct pcep_object_header header;
+       bool R_flag;
+       uint16_t association_type;
+       uint16_t association_id;
+       struct in6_addr src;
+};
+
+
+enum pcep_nopath_nature_of_issue {
+       PCEP_NOPATH_NI_NO_PATH_FOUND = 0,
+       PCEP_NOPATH_NI_PCE_CHAIN_BROKEN = 1,
+};
+
+enum pcep_nopath_tlv_err_codes {
+       PCEP_NOPATH_TLV_ERR_NO_TLV = 0,
+       PCEP_NOPATH_TLV_ERR_PCE_UNAVAILABLE = 1,
+       PCEP_NOPATH_TLV_ERR_UNKNOWN_DST = 2,
+       PCEP_NOPATH_TLV_ERR_UNKNOWN_SRC = 3
+};
+
+#define OBJECT_NOPATH_FLAG_C 0x80
+
+struct pcep_object_nopath {
+       struct pcep_object_header header;
+       uint8_t ni; /* Nature of Issue, reports the nature of the issue that led
+                      to a negative reply */
+       bool flag_c; /* when set, indicates the unsatisfied constraints by
+                       including relevant PCEP objects. */
+       enum pcep_nopath_tlv_err_codes
+               err_code; /* When set other than 0, an appropriate TLV will be
+                            included */
+};
+
+struct pcep_object_endpoints_ipv4 {
+       struct pcep_object_header header;
+       struct in_addr src_ipv4;
+       struct in_addr dst_ipv4;
+};
+
+struct pcep_object_endpoints_ipv6 {
+       struct pcep_object_header header;
+       struct in6_addr src_ipv6;
+       struct in6_addr dst_ipv6;
+};
+
+/* PCEP floats are encoded according to:
+ *   https://en.wikipedia.org/wiki/IEEE_754-1985
+ * Luckily, this is the same encoding used by C */
+struct pcep_object_bandwidth {
+       struct pcep_object_header header;
+       float bandwidth;
+};
+
+enum pcep_metric_types {
+       /* RFC 5440 */
+       PCEP_METRIC_IGP = 1,
+       PCEP_METRIC_TE = 2,
+       PCEP_METRIC_HOP_COUNT = 3,
+       /* RFC 5541 */
+       PCEP_METRIC_AGGREGATE_BW = 4,
+       PCEP_METRIC_MOST_LOADED_LINK = 5,
+       PCEP_METRIC_CUMULATIVE_IGP = 6,
+       PCEP_METRIC_CUMULATIVE_TE = 7,
+       /* RFC 8306 */
+       PCEP_METRIC_P2MP_IGP = 8,
+       PCEP_METRIC_P2MP_TE = 9,
+       PCEP_METRIC_P2MP_HOP_COUNT = 10,
+       /* RFC 8864 */
+       PCEP_METRIC_SEGMENT_ID_DEPTH = 11,
+       /* RFC 8233 */
+       PCEP_METRIC_PATH_DELAY = 12,
+       PCEP_METRIC_PATH_DELAY_VARIATION = 13,
+       PCEP_METRIC_PATH_LOSS = 14,
+       PCEP_METRIC_P2MP_PATH_DELAY = 15,
+       PCEP_METRIC_P2MP_PATH_DELAY_VARIATION = 16,
+       PCEP_METRIC_P2MP_PATH_LOSS = 17,
+       /* RFC 8282 */
+       PCEP_METRIC_NUM_PATH_ADAPTATIONS = 18,
+       PCEP_METRIC_NUM_PATH_LAYERS = 19,
+       /* RFC 8685 */
+       PCEP_METRIC_DOMAIN_COUNT = 20,
+       PCEP_METRIC_BORDER_NODE_COUNT = 21,
+};
+
+#define OBJECT_METRIC_FLAC_B 0x01
+#define OBJECT_METRIC_FLAC_C 0x02
+
+/* PCEP floats are encoded according to:
+ *   https://en.wikipedia.org/wiki/IEEE_754-1985
+ * Luckily, this is the same encoding used by C */
+struct pcep_object_metric {
+       struct pcep_object_header header;
+       enum pcep_metric_types type;
+       bool flag_b; /* Bound flag */
+       bool flag_c; /* Computed metric */
+       float value; /* Metric value in 32 bits */
+};
+
+#define OBJECT_LSPA_FLAG_L 0x01
+
+struct pcep_object_lspa {
+       struct pcep_object_header header;
+       uint32_t lspa_exclude_any;
+       uint32_t lspa_include_any;
+       uint32_t lspa_include_all;
+       uint8_t setup_priority;
+       uint8_t holding_priority;
+       bool flag_local_protection; /* Local protection desired bit */
+};
+
+/* The SVEC object with some custom extensions. */
+#define OBJECT_SVEC_FLAG_L 0x01
+#define OBJECT_SVEC_FLAG_N 0x02
+#define OBJECT_SVEC_FLAG_S 0x04
+
+struct pcep_object_svec {
+       struct pcep_object_header header;
+       bool flag_link_diverse;
+       bool flag_node_diverse;
+       bool flag_srlg_diverse;
+       double_linked_list
+               *request_id_list; /* list of 32-bit request ID pointers */
+};
+
+struct pcep_object_error {
+       struct pcep_object_header header;
+       enum pcep_error_type error_type;
+       enum pcep_error_value error_value;
+};
+
+struct pcep_object_load_balancing {
+       struct pcep_object_header header;
+       uint8_t load_maxlsp;   /* Maximum number of TE LSPs in the set */
+       uint32_t load_minband; /* Specifies the minimum bandwidth of each
+                                 element */
+};
+
+enum pcep_close_reason {
+       PCEP_CLOSE_REASON_NO = 1,
+       PCEP_CLOSE_REASON_DEADTIMER = 2,
+       PCEP_CLOSE_REASON_FORMAT = 3,
+       PCEP_CLOSE_REASON_UNKNOWN_REQ = 4,
+       PCEP_CLOSE_REASON_UNREC_MSG = 5
+};
+
+struct pcep_object_close {
+       struct pcep_object_header header;
+       enum pcep_close_reason reason;
+};
+
+/* Stateful PCE Request Parameters RFC 8231, 8281 */
+
+#define OBJECT_SRP_FLAG_R 0x01
+
+struct pcep_object_srp {
+       struct pcep_object_header header;
+       bool flag_lsp_remove; /* RFC 8281 */
+       uint32_t srp_id_number;
+};
+
+/* Label Switched Path Object RFC 8231 */
+enum pcep_lsp_operational_status {
+       PCEP_LSP_OPERATIONAL_DOWN = 0,
+       PCEP_LSP_OPERATIONAL_UP = 1,
+       PCEP_LSP_OPERATIONAL_ACTIVE = 2,
+       PCEP_LSP_OPERATIONAL_GOING_DOWN = 3,
+       PCEP_LSP_OPERATIONAL_GOING_UP = 4,
+};
+
+#define MAX_PLSP_ID 0x000fffff /* The plsp_id is only 20 bits */
+#define MAX_LSP_STATUS 0x0007 /* The status is only 3 bits */
+#define OBJECT_LSP_FLAG_D 0x01
+#define OBJECT_LSP_FLAG_S 0x02
+#define OBJECT_LSP_FLAG_R 0x04
+#define OBJECT_LSP_FLAG_A 0x08
+#define OBJECT_LSP_FLAG_C 0x80
+
+struct pcep_object_lsp {
+       struct pcep_object_header header;
+       uint32_t plsp_id; /* plsp_id is 20 bits, must be <= MAX_PLSP_ID*/
+       enum pcep_lsp_operational_status operational_status; /* max 3 bits */
+       bool flag_d;
+       bool flag_s;
+       bool flag_r;
+       bool flag_a;
+       bool flag_c;
+};
+
+/* RFC 7470 */
+struct pcep_object_vendor_info {
+       struct pcep_object_header header;
+       uint32_t enterprise_number;
+       uint32_t enterprise_specific_info;
+};
+
+/* RFC 8282 */
+#define OBJECT_INTER_LAYER_FLAG_I 0x01
+#define OBJECT_INTER_LAYER_FLAG_M 0x02
+#define OBJECT_INTER_LAYER_FLAG_T 0x04
+
+struct pcep_object_inter_layer {
+       struct pcep_object_header header;
+       bool flag_i;
+       bool flag_m;
+       bool flag_t;
+};
+
+/* RFC 8282 */
+#define OBJECT_SWITCH_LAYER_FLAG_I 0x01
+enum pcep_lsp_encoding_type {
+       /* Values taken from RFC 3471 as suggested by RFC 8282 */
+       PCEP_LSP_ENC_PACKET = 1,
+       PCEP_LSP_ENC_ETHERNET = 2,
+       PCEP_LSP_ENC_PDH = 3,
+       PCEP_LSP_ENC_RESERVED4 = 4,
+       PCEP_LSP_ENC_SDH_SONET = 5,
+       PCEP_LSP_ENC_RESERVED6 = 6,
+       PCEP_LSP_ENC_DIG_WRAPPER = 7,
+       PCEP_LSP_ENC_LAMBDA = 8,
+       PCEP_LSP_ENC_FIBER = 9,
+       PCEP_LSP_ENC_RESERVED10 = 10,
+       PCEP_LSP_ENC_FIBER_CHAN = 11
+};
+
+enum pcep_switching_capability {
+       /* Switching capability values taken from RFC 4203/3471 as suggested by
+          RFC 8282 */
+       PCEP_SW_CAP_PSC1 = 1, /* Packet-Switch Capable-1 (PSC-1) */
+       PCEP_SW_CAP_PSC2 = 2,
+       PCEP_SW_CAP_PSC3 = 3,
+       PCEP_SW_CAP_PSC4 = 4,
+       PCEP_SW_CAP_L2SC = 51, /* Layer-2 Switch Capable */
+       PCEP_SW_CAP_TDM = 100, /* Time-Division-Multiplex Capable */
+       PCEP_SW_CAP_LSC = 150, /* Lambda-Switch Capable */
+       PCEP_SW_CAP_FSC = 200  /* Fiber-Switch Capable */
+};
+
+struct pcep_object_switch_layer_row {
+       enum pcep_lsp_encoding_type lsp_encoding_type;
+       enum pcep_switching_capability switching_type;
+       bool flag_i;
+};
+
+struct pcep_object_switch_layer {
+       struct pcep_object_header header;
+       double_linked_list
+               *switch_layer_rows; /* list of struct
+                                      pcep_object_switch_layer_row */
+};
+
+/* RFC 8282
+ * Requested Adaptation capability */
+
+struct pcep_object_req_adap_cap {
+       struct pcep_object_header header;
+       enum pcep_switching_capability switching_capability;
+       enum pcep_lsp_encoding_type encoding;
+};
+
+/* RFC 8282 */
+
+struct pcep_object_server_indication {
+       struct pcep_object_header header;
+       enum pcep_switching_capability switching_capability;
+       enum pcep_lsp_encoding_type encoding;
+       /* This object is identical to req_adap_cap, except it allows TLVs */
+};
+
+/* Objective Function Object: RFC 5541 */
+
+struct pcep_object_objective_function {
+       struct pcep_object_header header;
+       uint16_t of_code;
+};
+
+/*
+ * Common Route Object sub-object definitions
+ * used by ERO, IRO, and RRO
+ */
+
+/* Common Route Object sub-object types
+ * used by ERO, IRO, and RRO */
+enum pcep_ro_subobj_types {
+       RO_SUBOBJ_TYPE_IPV4 = 1,  /* RFC 3209 */
+       RO_SUBOBJ_TYPE_IPV6 = 2,  /* RFC 3209 */
+       RO_SUBOBJ_TYPE_LABEL = 3, /* RFC 3209 */
+       RO_SUBOBJ_TYPE_UNNUM = 4, /* RFC 3477 */
+       RO_SUBOBJ_TYPE_ASN = 32,  /* RFC 3209, Section 4.3.3.4 */
+       RO_SUBOBJ_TYPE_SR = 36, /* RFC 8408, draft-ietf-pce-segment-routing-16.
+                                  Type 5 for draft07 has been assigned to
+                                  something else. */
+       RO_SUBOBJ_UNKNOWN
+};
+
+struct pcep_object_ro {
+       struct pcep_object_header header;
+       double_linked_list
+               *sub_objects; /* list of struct pcep_object_ro_subobj */
+};
+
+struct pcep_object_ro_subobj {
+       bool flag_subobj_loose_hop; /* L subobj flag */
+       enum pcep_ro_subobj_types ro_subobj_type;
+};
+
+#define OBJECT_SUBOBJ_IP_FLAG_LOCAL_PROT 0x01
+
+struct pcep_ro_subobj_ipv4 {
+       struct pcep_object_ro_subobj ro_subobj;
+       struct in_addr ip_addr;
+       uint8_t prefix_length;
+       bool flag_local_protection;
+};
+
+struct pcep_ro_subobj_ipv6 {
+       struct pcep_object_ro_subobj ro_subobj;
+       struct in6_addr ip_addr;
+       uint8_t prefix_length;
+       bool flag_local_protection;
+};
+
+struct pcep_ro_subobj_unnum {
+       struct pcep_object_ro_subobj ro_subobj;
+       struct in_addr router_id;
+       uint32_t interface_id;
+};
+
+#define OBJECT_SUBOBJ_LABEL_FLAG_GLOGAL 0x01
+struct pcep_ro_subobj_32label {
+       struct pcep_object_ro_subobj ro_subobj;
+       bool flag_global_label;
+       uint8_t class_type; /* label class-type (generalized label = 2) */
+       uint32_t label;     /* label supported */
+};
+
+struct pcep_ro_subobj_asn {
+       struct pcep_object_ro_subobj ro_subobj;
+       uint16_t asn; /* Autonomous system number */
+};
+
+/* The SR ERO and SR RRO subojbects are the same, except
+ * the SR-RRO does not have the L flag in the Type field.
+ * Defined in draft-ietf-pce-segment-routing-16 */
+enum pcep_sr_subobj_nai {
+       PCEP_SR_SUBOBJ_NAI_ABSENT = 0,
+       PCEP_SR_SUBOBJ_NAI_IPV4_NODE = 1,
+       PCEP_SR_SUBOBJ_NAI_IPV6_NODE = 2,
+       PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY = 3,
+       PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY = 4,
+       PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY = 5,
+       PCEP_SR_SUBOBJ_NAI_LINK_LOCAL_IPV6_ADJACENCY = 6,
+       PCEP_SR_SUBOBJ_NAI_UNKNOWN
+};
+
+#define OBJECT_SUBOBJ_SR_FLAG_M 0x01
+#define OBJECT_SUBOBJ_SR_FLAG_C 0x02
+#define OBJECT_SUBOBJ_SR_FLAG_S 0x04
+#define OBJECT_SUBOBJ_SR_FLAG_F 0x08
+
+struct pcep_ro_subobj_sr {
+       struct pcep_object_ro_subobj ro_subobj;
+       enum pcep_sr_subobj_nai nai_type;
+       bool flag_f;
+       bool flag_s;
+       bool flag_c;
+       bool flag_m;
+
+       /* The SID and NAI are optional depending on the flags,
+        * and the NAI can be variable length */
+       uint32_t sid;
+       double_linked_list
+               *nai_list; /* double linked list of in_addr or in6_addr */
+};
+
+/* Macros to make a SID Label
+ *
+ * 0                   1                   2                   3
+   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Label
+   |                Label                  | TC  |S|       TTL     | Stack
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Entry
+ */
+#define ENCODE_SR_ERO_SID(label_20bits, tc_3bits, stack_bottom_bit, ttl_8bits) \
+       ((((label_20bits) << 12) & 0xfffff000)                                 \
+        | (((tc_3bits) << 9) & 0x00000e00)                                    \
+        | (((stack_bottom_bit) << 8) & 0x00000100) | ((ttl_8bits)&0xff))
+#define GET_SR_ERO_SID_LABEL(SID) ((SID & 0xfffff000) >> 12)
+#define GET_SR_ERO_SID_TC(SID) ((SID & 0x00000e00) >> 9)
+#define GET_SR_ERO_SID_S(SID) ((SID & 0x00000100) >> 8)
+#define GET_SR_ERO_SID_TTL(SID) ((SID & 0x000000ff))
+
+/*
+ * All created objects will be in Host byte order, except for IPs.
+ * All IP addresses are expected to be passed-in in Network byte order,
+ * and any objects received will have their IPs in Network byte order.
+ * The message containing the objects should be converted to Network byte order
+ * with pcep_encode_msg_header() before sending, which will also convert the
+ * Objects, TLVs, and sub-objects.
+ */
+
+struct pcep_object_open *pcep_obj_create_open(uint8_t keepalive,
+                                             uint8_t deadtimer, uint8_t sid,
+                                             double_linked_list *tlv_list);
+struct pcep_object_rp *pcep_obj_create_rp(uint8_t priority, bool flag_r,
+                                         bool flag_b, bool flag_s,
+                                         bool flag_of, uint32_t reqid,
+                                         double_linked_list *tlv_list);
+struct pcep_object_notify *
+pcep_obj_create_notify(enum pcep_notification_types notification_type,
+                      enum pcep_notification_values notification_value);
+struct pcep_object_nopath *
+pcep_obj_create_nopath(uint8_t ni, bool flag_c,
+                      enum pcep_nopath_tlv_err_codes error_code);
+struct pcep_object_association_ipv4 *
+pcep_obj_create_association_ipv4(bool r_flag, uint16_t association_type,
+                                uint16_t association_id, struct in_addr src);
+struct pcep_object_association_ipv6 *
+pcep_obj_create_association_ipv6(bool r_flag, uint16_t association_type,
+                                uint16_t association_id, struct in6_addr src);
+struct pcep_object_endpoints_ipv4 *
+pcep_obj_create_endpoint_ipv4(const struct in_addr *src_ipv4,
+                             const struct in_addr *dst_ipv4);
+struct pcep_object_endpoints_ipv6 *
+pcep_obj_create_endpoint_ipv6(const struct in6_addr *src_ipv6,
+                             const struct in6_addr *dst_ipv6);
+struct pcep_object_bandwidth *pcep_obj_create_bandwidth(float bandwidth);
+struct pcep_object_metric *pcep_obj_create_metric(enum pcep_metric_types type,
+                                                 bool flag_b, bool flag_c,
+                                                 float value);
+struct pcep_object_lspa *
+pcep_obj_create_lspa(uint32_t exclude_any, uint32_t include_any,
+                    uint32_t include_all, uint8_t setup_priority,
+                    uint8_t holding_priority, bool flag_local_protection);
+struct pcep_object_svec *
+pcep_obj_create_svec(bool srlg, bool node, bool link,
+                    double_linked_list *request_id_list);
+struct pcep_object_error *
+pcep_obj_create_error(enum pcep_error_type error_type,
+                     enum pcep_error_value error_value);
+struct pcep_object_close *pcep_obj_create_close(enum pcep_close_reason reason);
+struct pcep_object_srp *pcep_obj_create_srp(bool lsp_remove,
+                                           uint32_t srp_id_number,
+                                           double_linked_list *tlv_list);
+struct pcep_object_lsp *
+pcep_obj_create_lsp(uint32_t plsp_id, enum pcep_lsp_operational_status status,
+                   bool c_flag, bool a_flag, bool r_flag, bool s_flag,
+                   bool d_flag, double_linked_list *tlv_list);
+struct pcep_object_vendor_info *
+pcep_obj_create_vendor_info(uint32_t enterprise_number,
+                           uint32_t enterprise_spec_info);
+struct pcep_object_inter_layer *
+pcep_obj_create_inter_layer(bool flag_i, bool flag_m, bool flag_t);
+struct pcep_object_switch_layer *
+pcep_obj_create_switch_layer(double_linked_list *switch_layer_rows);
+struct pcep_object_req_adap_cap *
+pcep_obj_create_req_adap_cap(enum pcep_switching_capability sw_cap,
+                            enum pcep_lsp_encoding_type encoding);
+struct pcep_object_server_indication *
+pcep_obj_create_server_indication(enum pcep_switching_capability sw_cap,
+                                 enum pcep_lsp_encoding_type encoding,
+                                 double_linked_list *tlv_list);
+struct pcep_object_objective_function *
+pcep_obj_create_objective_function(uint16_t of_code,
+                                  double_linked_list *tlv_list);
+
+/* Route Object (Explicit ero, Reported rro, and Include iro) functions
+ * First, the sub-objects should be created and appended to a
+ * double_linked_list, then call one of these Route Object creation functions
+ * with the subobj list */
+struct pcep_object_ro *pcep_obj_create_ero(double_linked_list *ero_list);
+struct pcep_object_ro *pcep_obj_create_rro(double_linked_list *rro_list);
+struct pcep_object_ro *pcep_obj_create_iro(double_linked_list *iro_list);
+/* Route Object sub-object creation functions */
+struct pcep_ro_subobj_ipv4 *
+pcep_obj_create_ro_subobj_ipv4(bool loose_hop, const struct in_addr *ro_ipv4,
+                              uint8_t prefix_len, bool flag_local_prot);
+struct pcep_ro_subobj_ipv6 *
+pcep_obj_create_ro_subobj_ipv6(bool loose_hop, const struct in6_addr *ro_ipv6,
+                              uint8_t prefix_len, bool flag_local_prot);
+struct pcep_ro_subobj_unnum *
+pcep_obj_create_ro_subobj_unnum(struct in_addr *router_id, uint32_t if_id);
+struct pcep_ro_subobj_32label *
+pcep_obj_create_ro_subobj_32label(bool flag_global_label, uint8_t class_type,
+                                 uint32_t label);
+struct pcep_ro_subobj_asn *pcep_obj_create_ro_subobj_asn(uint16_t asn);
+
+/* SR ERO and SR RRO creation functions for different NAI (Node/Adj ID) types.
+ *  - The loose_hop is only used for sr ero and must always be false for sr rro.
+ *  - The NAI value will be set internally, depending on which function is used.
+ * m_flag:
+ *  - If this flag is true, the SID value represents an MPLS label stack
+ *    entry as specified in [RFC3032].  Otherwise, the SID value is an
+ *    administratively configured value which represents an index into
+ *    an MPLS label space (either SRGB or SRLB) per [RFC8402].
+ * c_flag:
+ *  - If the M flag and the C flag are both true, then the TC, S, and TTL
+ *    fields in the MPLS label stack entry are specified by the PCE.  However,
+ *    a PCC MAY choose to override these values according to its local policy
+ *    and MPLS forwarding rules.
+ *  - If the M flag is true but the C flag is false, then the TC, S, and TTL
+ *    fields MUST be ignored by the PCC.
+ *  - The PCC MUST set these fields according to its local policy and MPLS
+ *    forwarding rules.
+ *  - If the M flag is false then the C bit MUST be false. */
+struct pcep_ro_subobj_sr *pcep_obj_create_ro_subobj_sr_nonai(bool loose_hop,
+                                                            uint32_t sid,
+                                                            bool c_flag,
+                                                            bool m_flag);
+
+/* The ipv4_node_id will be copied internally */
+struct pcep_ro_subobj_sr *
+pcep_obj_create_ro_subobj_sr_ipv4_node(bool loose_hop, bool sid_absent,
+                                      bool c_flag, bool m_flag, uint32_t sid,
+                                      struct in_addr *ipv4_node_id);
+/* The ipv6_node_id will be copied internally */
+struct pcep_ro_subobj_sr *
+pcep_obj_create_ro_subobj_sr_ipv6_node(bool loose_hop, bool sid_absent,
+                                      bool c_flag, bool m_flag, uint32_t sid,
+                                      struct in6_addr *ipv6_node_id);
+/* The local_ipv4 and remote_ipv4 will be copied internally */
+struct pcep_ro_subobj_sr *pcep_obj_create_ro_subobj_sr_ipv4_adj(
+       bool loose_hop, bool sid_absent, bool c_flag, bool m_flag, uint32_t sid,
+       struct in_addr *local_ipv4, struct in_addr *remote_ipv4);
+/* The local_ipv6 and remote_ipv6 will be copied internally */
+struct pcep_ro_subobj_sr *pcep_obj_create_ro_subobj_sr_ipv6_adj(
+       bool loose_hop, bool sid_absent, bool c_flag, bool m_flag, uint32_t sid,
+       struct in6_addr *local_ipv6, struct in6_addr *remote_ipv6);
+struct pcep_ro_subobj_sr *pcep_obj_create_ro_subobj_sr_unnumbered_ipv4_adj(
+       bool loose_hop, bool sid_absent, bool c_flag, bool m_flag, uint32_t sid,
+       uint32_t local_node_id, uint32_t local_if_id, uint32_t remote_node_id,
+       uint32_t remote_if_id);
+/* The local_ipv6 and remote_ipv6 will be copied internally */
+struct pcep_ro_subobj_sr *pcep_obj_create_ro_subobj_sr_linklocal_ipv6_adj(
+       bool loose_hop, bool sid_absent, bool c_flag, bool m_flag, uint32_t sid,
+       struct in6_addr *local_ipv6, uint32_t local_if_id,
+       struct in6_addr *remote_ipv6, uint32_t remote_if_id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/pceplib/pcep_msg_objects_encoding.c b/pceplib/pcep_msg_objects_encoding.c
new file mode 100644 (file)
index 0000000..c4089ba
--- /dev/null
@@ -0,0 +1,1720 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+/*
+ * Encoding and decoding for PCEP Objects.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "pcep_msg_objects.h"
+#include "pcep_msg_encoding.h"
+#include "pcep_utils_logging.h"
+#include "pcep_utils_memory.h"
+
+void write_object_header(struct pcep_object_header *object_hdr,
+                        uint16_t object_length, uint8_t *buf);
+void pcep_decode_object_hdr(const uint8_t *obj_buf,
+                           struct pcep_object_header *obj_hdr);
+void set_ro_subobj_fields(struct pcep_object_ro_subobj *subobj, bool flag_l,
+                         uint8_t subobj_type);
+
+/*
+ * forward declarations for initialize_object_encoders()
+ */
+uint16_t pcep_encode_obj_open(struct pcep_object_header *obj,
+                             struct pcep_versioning *versioning, uint8_t *buf);
+uint16_t pcep_encode_obj_rp(struct pcep_object_header *obj,
+                           struct pcep_versioning *versioning, uint8_t *buf);
+uint16_t pcep_encode_obj_nopath(struct pcep_object_header *obj,
+                               struct pcep_versioning *versioning,
+                               uint8_t *buf);
+uint16_t pcep_encode_obj_endpoints(struct pcep_object_header *obj,
+                                  struct pcep_versioning *versioning,
+                                  uint8_t *buf);
+uint16_t pcep_encode_obj_association(struct pcep_object_header *obj,
+                                    struct pcep_versioning *versioning,
+                                    uint8_t *buf);
+uint16_t pcep_encode_obj_bandwidth(struct pcep_object_header *obj,
+                                  struct pcep_versioning *versioning,
+                                  uint8_t *buf);
+uint16_t pcep_encode_obj_metric(struct pcep_object_header *obj,
+                               struct pcep_versioning *versioning,
+                               uint8_t *buf);
+uint16_t pcep_encode_obj_ro(struct pcep_object_header *obj,
+                           struct pcep_versioning *versioning, uint8_t *buf);
+uint16_t pcep_encode_obj_lspa(struct pcep_object_header *obj,
+                             struct pcep_versioning *versioning, uint8_t *buf);
+uint16_t pcep_encode_obj_svec(struct pcep_object_header *obj,
+                             struct pcep_versioning *versioning, uint8_t *buf);
+uint16_t pcep_encode_obj_notify(struct pcep_object_header *obj,
+                               struct pcep_versioning *versioning,
+                               uint8_t *buf);
+uint16_t pcep_encode_obj_error(struct pcep_object_header *error,
+                              struct pcep_versioning *versioning,
+                              uint8_t *buf);
+uint16_t pcep_encode_obj_close(struct pcep_object_header *close,
+                              struct pcep_versioning *versioning,
+                              uint8_t *buf);
+uint16_t pcep_encode_obj_srp(struct pcep_object_header *obj,
+                            struct pcep_versioning *versioning, uint8_t *buf);
+uint16_t pcep_encode_obj_lsp(struct pcep_object_header *obj,
+                            struct pcep_versioning *versioning, uint8_t *buf);
+uint16_t pcep_encode_obj_vendor_info(struct pcep_object_header *obj,
+                                    struct pcep_versioning *versioning,
+                                    uint8_t *buf);
+uint16_t pcep_encode_obj_inter_layer(struct pcep_object_header *obj,
+                                    struct pcep_versioning *versioning,
+                                    uint8_t *buf);
+uint16_t pcep_encode_obj_switch_layer(struct pcep_object_header *obj,
+                                     struct pcep_versioning *versioning,
+                                     uint8_t *buf);
+uint16_t pcep_encode_obj_req_adap_cap(struct pcep_object_header *obj,
+                                     struct pcep_versioning *versioning,
+                                     uint8_t *buf);
+uint16_t pcep_encode_obj_server_ind(struct pcep_object_header *obj,
+                                   struct pcep_versioning *versioning,
+                                   uint8_t *buf);
+uint16_t pcep_encode_obj_objective_function(struct pcep_object_header *obj,
+                                           struct pcep_versioning *versioning,
+                                           uint8_t *buf);
+typedef uint16_t (*object_encoder_funcptr)(struct pcep_object_header *,
+                                          struct pcep_versioning *versioning,
+                                          uint8_t *buf);
+
+#define MAX_OBJECT_ENCODER_INDEX 64
+
+#define PCEP_ENCODERS_ARGS                                                     \
+       struct pcep_object_header *, struct pcep_versioning *versioning,       \
+               uint8_t *buf
+uint16_t (*const object_encoders[MAX_OBJECT_ENCODER_INDEX])(
+       PCEP_ENCODERS_ARGS) = {
+       [PCEP_OBJ_CLASS_OPEN] = pcep_encode_obj_open,
+       [PCEP_OBJ_CLASS_RP] = pcep_encode_obj_rp,
+       [PCEP_OBJ_CLASS_NOPATH] = pcep_encode_obj_nopath,
+       [PCEP_OBJ_CLASS_ENDPOINTS] = pcep_encode_obj_endpoints,
+       [PCEP_OBJ_CLASS_BANDWIDTH] = pcep_encode_obj_bandwidth,
+       [PCEP_OBJ_CLASS_METRIC] = pcep_encode_obj_metric,
+       [PCEP_OBJ_CLASS_ERO] = pcep_encode_obj_ro,
+       [PCEP_OBJ_CLASS_RRO] = pcep_encode_obj_ro,
+       [PCEP_OBJ_CLASS_LSPA] = pcep_encode_obj_lspa,
+       [PCEP_OBJ_CLASS_IRO] = pcep_encode_obj_ro,
+       [PCEP_OBJ_CLASS_SVEC] = pcep_encode_obj_svec,
+       [PCEP_OBJ_CLASS_NOTF] = pcep_encode_obj_notify,
+       [PCEP_OBJ_CLASS_ERROR] = pcep_encode_obj_error,
+       [PCEP_OBJ_CLASS_CLOSE] = pcep_encode_obj_close,
+       [PCEP_OBJ_CLASS_LSP] = pcep_encode_obj_lsp,
+       [PCEP_OBJ_CLASS_SRP] = pcep_encode_obj_srp,
+       [PCEP_OBJ_CLASS_ASSOCIATION] = pcep_encode_obj_association,
+       [PCEP_OBJ_CLASS_INTER_LAYER] = pcep_encode_obj_inter_layer,
+       [PCEP_OBJ_CLASS_SWITCH_LAYER] = pcep_encode_obj_switch_layer,
+       [PCEP_OBJ_CLASS_REQ_ADAP_CAP] = pcep_encode_obj_req_adap_cap,
+       [PCEP_OBJ_CLASS_SERVER_IND] = pcep_encode_obj_server_ind,
+       [PCEP_OBJ_CLASS_VENDOR_INFO] = pcep_encode_obj_vendor_info,
+       [PCEP_OBJ_CLASS_OF] = pcep_encode_obj_objective_function,
+};
+/*
+ * forward declarations for initialize_object_decoders()
+ */
+struct pcep_object_header *pcep_decode_obj_open(struct pcep_object_header *hdr,
+                                               const uint8_t *buf);
+struct pcep_object_header *pcep_decode_obj_rp(struct pcep_object_header *hdr,
+                                             const uint8_t *buf);
+struct pcep_object_header *
+pcep_decode_obj_nopath(struct pcep_object_header *hdr, const uint8_t *buf);
+struct pcep_object_header *
+pcep_decode_obj_endpoints(struct pcep_object_header *hdr, const uint8_t *buf);
+struct pcep_object_header *
+pcep_decode_obj_association(struct pcep_object_header *hdr, const uint8_t *buf);
+struct pcep_object_header *
+pcep_decode_obj_bandwidth(struct pcep_object_header *hdr, const uint8_t *buf);
+struct pcep_object_header *
+pcep_decode_obj_metric(struct pcep_object_header *hdr, const uint8_t *buf);
+struct pcep_object_header *pcep_decode_obj_ro(struct pcep_object_header *hdr,
+                                             const uint8_t *buf);
+struct pcep_object_header *pcep_decode_obj_lspa(struct pcep_object_header *hdr,
+                                               const uint8_t *buf);
+struct pcep_object_header *pcep_decode_obj_svec(struct pcep_object_header *hdr,
+                                               const uint8_t *buf);
+struct pcep_object_header *
+pcep_decode_obj_notify(struct pcep_object_header *hdr, const uint8_t *buf);
+struct pcep_object_header *pcep_decode_obj_error(struct pcep_object_header *hdr,
+                                                const uint8_t *buf);
+struct pcep_object_header *pcep_decode_obj_close(struct pcep_object_header *hdr,
+                                                const uint8_t *buf);
+struct pcep_object_header *pcep_decode_obj_srp(struct pcep_object_header *hdr,
+                                              const uint8_t *buf);
+struct pcep_object_header *pcep_decode_obj_lsp(struct pcep_object_header *hdr,
+                                              const uint8_t *buf);
+struct pcep_object_header *
+pcep_decode_obj_vendor_info(struct pcep_object_header *hdr, const uint8_t *buf);
+struct pcep_object_header *
+pcep_decode_obj_inter_layer(struct pcep_object_header *hdr, const uint8_t *buf);
+struct pcep_object_header *
+pcep_decode_obj_switch_layer(struct pcep_object_header *hdr,
+                            const uint8_t *buf);
+struct pcep_object_header *
+pcep_decode_obj_req_adap_cap(struct pcep_object_header *hdr,
+                            const uint8_t *buf);
+struct pcep_object_header *
+pcep_decode_obj_server_ind(struct pcep_object_header *hdr, const uint8_t *buf);
+struct pcep_object_header *
+pcep_decode_obj_objective_function(struct pcep_object_header *hdr,
+                                  const uint8_t *buf);
+typedef struct pcep_object_header *(*object_decoder_funcptr)(
+       struct pcep_object_header *, const uint8_t *buf);
+
+#define PCEP_DECODERS_ARGS struct pcep_object_header *, const uint8_t *buf
+
+struct pcep_object_header *(*const object_decoders[MAX_OBJECT_ENCODER_INDEX])(
+       PCEP_DECODERS_ARGS) = {
+       [PCEP_OBJ_CLASS_OPEN] = pcep_decode_obj_open,
+       [PCEP_OBJ_CLASS_RP] = pcep_decode_obj_rp,
+       [PCEP_OBJ_CLASS_NOPATH] = pcep_decode_obj_nopath,
+       [PCEP_OBJ_CLASS_ENDPOINTS] = pcep_decode_obj_endpoints,
+       [PCEP_OBJ_CLASS_BANDWIDTH] = pcep_decode_obj_bandwidth,
+       [PCEP_OBJ_CLASS_METRIC] = pcep_decode_obj_metric,
+       [PCEP_OBJ_CLASS_ERO] = pcep_decode_obj_ro,
+       [PCEP_OBJ_CLASS_RRO] = pcep_decode_obj_ro,
+       [PCEP_OBJ_CLASS_LSPA] = pcep_decode_obj_lspa,
+       [PCEP_OBJ_CLASS_IRO] = pcep_decode_obj_ro,
+       [PCEP_OBJ_CLASS_SVEC] = pcep_decode_obj_svec,
+       [PCEP_OBJ_CLASS_NOTF] = pcep_decode_obj_notify,
+       [PCEP_OBJ_CLASS_ERROR] = pcep_decode_obj_error,
+       [PCEP_OBJ_CLASS_CLOSE] = pcep_decode_obj_close,
+       [PCEP_OBJ_CLASS_LSP] = pcep_decode_obj_lsp,
+       [PCEP_OBJ_CLASS_SRP] = pcep_decode_obj_srp,
+       [PCEP_OBJ_CLASS_ASSOCIATION] = pcep_decode_obj_association,
+       [PCEP_OBJ_CLASS_INTER_LAYER] = pcep_decode_obj_inter_layer,
+       [PCEP_OBJ_CLASS_SWITCH_LAYER] = pcep_decode_obj_switch_layer,
+       [PCEP_OBJ_CLASS_REQ_ADAP_CAP] = pcep_decode_obj_req_adap_cap,
+       [PCEP_OBJ_CLASS_SERVER_IND] = pcep_decode_obj_server_ind,
+       [PCEP_OBJ_CLASS_VENDOR_INFO] = pcep_decode_obj_vendor_info,
+       [PCEP_OBJ_CLASS_OF] = pcep_decode_obj_objective_function,
+};
+
+/* Object lengths, including the Object Header.
+ * Used by pcep_object_get_length() and pcep_object_has_tlvs() */
+static uint8_t pcep_object_class_lengths[] = {
+       0,  /* Object class 0 unused */
+       8,  /* PCEP_OBJ_CLASS_OPEN = 1 */
+       12, /* PCEP_OBJ_CLASS_RP = 2 */
+       16, /* PCEP_OBJ_CLASS_NOPATH = 3, includes 8 for mandatory TLV */
+       0,  /* PCEP_OBJ_CLASS_ENDPOINTS = 4, could be ipv4 or ipv6, setting to 0
+            */
+       8,  /* PCEP_OBJ_CLASS_BANDWIDTH = 5 */
+       12, /* PCEP_OBJ_CLASS_METRIC = 6 */
+       0,  /* PCEP_OBJ_CLASS_ERO = 7, setting 0, ROs cannot have TLVs */
+       0,  /* PCEP_OBJ_CLASS_RRO = 8, setting 0, ROs cannot have TLVs */
+       20, /* PCEP_OBJ_CLASS_LSPA = 9 */
+       0,  /* PCEP_OBJ_CLASS_IRO = 10, setting 0, ROs cannot have TLVs */
+       0,  /* PCEP_OBJ_CLASS_SVEC = 11, SVECs cannot have TLVs */
+       8,  /* PCEP_OBJ_CLASS_NOTF = 12 */
+       8,  /* PCEP_OBJ_CLASS_ERROR = 13 */
+       0,  /* Object class 14 unused */
+       8,  /* PCEP_OBJ_CLASS_CLOSE = 15 */
+       0,  0, 0, 0, 0, /* Object classes 16 - 20 are not used */
+       8,              /* PCEP_OBJ_CLASS_OF = 21 */
+       0,  0, 0, 0, 0, /* Object classes 22 - 26 are not used */
+       0,  0, 0, 0, 0, /* Object classes 27 - 31 are not used */
+       8,              /* PCEP_OBJ_CLASS_LSP = 32 */
+       12,             /* PCEP_OBJ_CLASS_SRP = 33 */
+       12,             /* PCEP_OBJ_CLASS_VENDOR_INFO = 34 */
+       0,              /* Object class 35 unused */
+       0,              /* PCEP_OBJ_CLASS_INTER_LAYER = 36, cannot have TLVs */
+       0,              /* PCEP_OBJ_CLASS_SWITCH_LAYER = 37, cannot have TLVs */
+       0,              /* PCEP_OBJ_CLASS_REQ_ADAP_CAP = 38, cannot have TLVs*/
+       8,              /* PCEP_OBJ_CLASS_SERVER_IND = 39 */
+       0,              /* PCEP_OBJ_CLASS_ASSOCIATION = 40, cannot have TLVs */
+};
+
+/*
+ * The TLVs can have strange length values, since they do not include padding in
+ * the TLV header length, but that extra padding must be taken into account by
+ * the enclosing object by rounding up to the next 4 byte boundary.
+ * Example returned lengths:
+ *   normalize_length(4)  =  4, normalize_length(5)  =  8, normalize_length(6)
+ * =  8, normalize_length(7)  =  8, normalize_length(8)  =  8
+ * normalize_length(9)  = 12, normalize_length(10) = 12, normalize_length(11) =
+ * 12, normalize_length(12) = 12, normalize_length(13) = 13...
+ */
+uint16_t normalize_pcep_tlv_length(uint16_t length)
+{
+       return (length % 4 == 0) ? length : (length + (4 - (length % 4)));
+}
+
+/*
+ * Encoding functions
+ */
+uint16_t pcep_encode_object(struct pcep_object_header *object_hdr,
+                           struct pcep_versioning *versioning, uint8_t *buf)
+{
+
+       if (object_hdr->object_class >= MAX_OBJECT_ENCODER_INDEX) {
+               pcep_log(LOG_INFO,
+                        "%s: Cannot encode unknown Object class [%d]",
+                        __func__, object_hdr->object_class);
+               return 0;
+       }
+
+       object_encoder_funcptr obj_encoder =
+               object_encoders[object_hdr->object_class];
+       if (obj_encoder == NULL) {
+               pcep_log(LOG_INFO,
+                        "%s: No object encoder found for Object class [%d]",
+                        __func__, object_hdr->object_class);
+               return 0;
+       }
+
+       uint16_t object_length = OBJECT_HEADER_LENGTH
+                                + obj_encoder(object_hdr, versioning,
+                                              buf + OBJECT_HEADER_LENGTH);
+       double_linked_list_node *node =
+               (object_hdr->tlv_list == NULL ? NULL
+                                             : object_hdr->tlv_list->head);
+       for (; node != NULL; node = node->next_node) {
+               /* Returns the length of the TLV, including the TLV header */
+               object_length += pcep_encode_tlv(
+                       (struct pcep_object_tlv_header *)node->data, versioning,
+                       buf + object_length);
+       }
+       object_length = normalize_pcep_tlv_length(object_length);
+       write_object_header(object_hdr, object_length, buf);
+       object_hdr->encoded_object = buf;
+       object_hdr->encoded_object_length = object_length;
+
+       return object_length;
+}
+
+
+/* Object Header
+ *
+ *   0                   1                   2                   3
+ *   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  | Object-Class  |   OT  |Res|P|I|   Object Length (bytes)       |
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |                                                               |
+ *  //                        (Object body)                        //
+ *  |                                                               |
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ */
+
+void write_object_header(struct pcep_object_header *object_hdr,
+                        uint16_t object_length, uint8_t *buf)
+{
+       buf[0] = object_hdr->object_class;
+       buf[1] = ((object_hdr->object_type << 4)
+                 | (object_hdr->flag_p ? OBJECT_HEADER_FLAG_P : 0x00)
+                 | (object_hdr->flag_i ? OBJECT_HEADER_FLAG_I : 0x00));
+       uint16_t net_order_length = htons(object_length);
+       memcpy(buf + 2, &net_order_length, sizeof(net_order_length));
+}
+
+
+/*
+ * Functions to encode objects
+ * - they will be passed a pointer to a buffer to write the object body,
+ *   which is past the object header.
+ * - they should return the object body length, not including the object header
+ * length.
+ */
+
+uint16_t pcep_encode_obj_open(struct pcep_object_header *hdr,
+                             struct pcep_versioning *versioning,
+                             uint8_t *obj_body_buf)
+{
+       (void)versioning;
+       struct pcep_object_open *open = (struct pcep_object_open *)hdr;
+       obj_body_buf[0] = (open->open_version << 5) & 0xe0;
+       obj_body_buf[1] = open->open_keepalive;
+       obj_body_buf[2] = open->open_deadtimer;
+       obj_body_buf[3] = open->open_sid;
+
+       return LENGTH_1WORD;
+}
+
+uint16_t pcep_encode_obj_rp(struct pcep_object_header *hdr,
+                           struct pcep_versioning *versioning,
+                           uint8_t *obj_body_buf)
+{
+       (void)versioning;
+       struct pcep_object_rp *rp = (struct pcep_object_rp *)hdr;
+       obj_body_buf[3] = ((rp->flag_strict ? OBJECT_RP_FLAG_O : 0x00)
+                          | (rp->flag_bidirectional ? OBJECT_RP_FLAG_B : 0x00)
+                          | (rp->flag_reoptimization ? OBJECT_RP_FLAG_R : 0x00)
+                          | (rp->flag_of ? OBJECT_RP_FLAG_OF : 0x00)
+                          | (rp->priority & 0x07));
+       uint32_t *uint32_ptr = (uint32_t *)(obj_body_buf + 4);
+       *uint32_ptr = htonl(rp->request_id);
+
+       return LENGTH_2WORDS;
+}
+
+uint16_t pcep_encode_obj_notify(struct pcep_object_header *hdr,
+                               struct pcep_versioning *versioning,
+                               uint8_t *obj_body_buf)
+{
+       (void)versioning;
+       struct pcep_object_notify *notify = (struct pcep_object_notify *)hdr;
+       obj_body_buf[2] = notify->notification_type;
+       obj_body_buf[3] = notify->notification_value;
+
+       return LENGTH_1WORD;
+}
+
+uint16_t pcep_encode_obj_nopath(struct pcep_object_header *hdr,
+                               struct pcep_versioning *versioning,
+                               uint8_t *obj_body_buf)
+{
+       (void)versioning;
+       struct pcep_object_nopath *nopath = (struct pcep_object_nopath *)hdr;
+       obj_body_buf[0] = nopath->ni;
+       obj_body_buf[1] = ((nopath->flag_c) ? OBJECT_NOPATH_FLAG_C : 0x00);
+
+       return LENGTH_1WORD;
+}
+
+uint16_t pcep_encode_obj_association(struct pcep_object_header *hdr,
+                                    struct pcep_versioning *versioning,
+                                    uint8_t *obj_body_buf)
+{
+       (void)versioning;
+       uint16_t *uint16_ptr = (uint16_t *)obj_body_buf;
+       uint32_t *uint32_ptr = (uint32_t *)obj_body_buf;
+       if (hdr->object_type == PCEP_OBJ_TYPE_ASSOCIATION_IPV4) {
+               struct pcep_object_association_ipv4 *ipv4 =
+                       (struct pcep_object_association_ipv4 *)hdr;
+               obj_body_buf[3] =
+                       (ipv4->R_flag ? OBJECT_ASSOCIATION_FLAG_R : 0x00);
+               uint16_ptr[2] = htons(ipv4->association_type);
+               uint16_ptr[3] = htons(ipv4->association_id);
+               uint32_ptr[2] = ipv4->src.s_addr;
+
+               return LENGTH_3WORDS;
+       } else {
+               struct pcep_object_association_ipv6 *ipv6 =
+                       (struct pcep_object_association_ipv6 *)hdr;
+               obj_body_buf[3] =
+                       (ipv6->R_flag ? OBJECT_ASSOCIATION_FLAG_R : 0x00);
+               uint16_ptr[2] = htons(ipv6->association_type);
+               uint16_ptr[3] = htons(ipv6->association_id);
+               memcpy(uint32_ptr, &ipv6->src, sizeof(struct in6_addr));
+
+               return LENGTH_6WORDS;
+       }
+}
+
+uint16_t pcep_encode_obj_endpoints(struct pcep_object_header *hdr,
+                                  struct pcep_versioning *versioning,
+                                  uint8_t *obj_body_buf)
+{
+       (void)versioning;
+       uint32_t *uint32_ptr = (uint32_t *)obj_body_buf;
+       if (hdr->object_type == PCEP_OBJ_TYPE_ENDPOINT_IPV4) {
+               struct pcep_object_endpoints_ipv4 *ipv4 =
+                       (struct pcep_object_endpoints_ipv4 *)hdr;
+               uint32_ptr[0] = ipv4->src_ipv4.s_addr;
+               uint32_ptr[1] = ipv4->dst_ipv4.s_addr;
+
+               return LENGTH_2WORDS;
+       } else {
+               struct pcep_object_endpoints_ipv6 *ipv6 =
+                       (struct pcep_object_endpoints_ipv6 *)hdr;
+               memcpy(uint32_ptr, &ipv6->src_ipv6, sizeof(struct in6_addr));
+               memcpy(&uint32_ptr[4], &ipv6->dst_ipv6,
+                      sizeof(struct in6_addr));
+
+               return LENGTH_8WORDS;
+       }
+}
+
+uint16_t pcep_encode_obj_bandwidth(struct pcep_object_header *hdr,
+                                  struct pcep_versioning *versioning,
+                                  uint8_t *obj_body_buf)
+{
+       (void)versioning;
+       struct pcep_object_bandwidth *bandwidth =
+               (struct pcep_object_bandwidth *)hdr;
+       uint32_t *uint32_ptr = (uint32_t *)obj_body_buf;
+       /* Seems like the compiler doesnt correctly copy the float, so memcpy()
+        * it */
+       memcpy(uint32_ptr, &(bandwidth->bandwidth), sizeof(uint32_t));
+       *uint32_ptr = htonl(*uint32_ptr);
+
+       return LENGTH_1WORD;
+}
+
+uint16_t pcep_encode_obj_metric(struct pcep_object_header *hdr,
+                               struct pcep_versioning *versioning,
+                               uint8_t *obj_body_buf)
+{
+       (void)versioning;
+       struct pcep_object_metric *metric = (struct pcep_object_metric *)hdr;
+       obj_body_buf[2] = ((metric->flag_c ? OBJECT_METRIC_FLAC_C : 0x00)
+                          | (metric->flag_b ? OBJECT_METRIC_FLAC_B : 0x00));
+       obj_body_buf[3] = metric->type;
+       uint32_t *uint32_ptr = (uint32_t *)(obj_body_buf + 4);
+       /* Seems like the compiler doesnt correctly copy the float, so memcpy()
+        * it */
+       memcpy(uint32_ptr, &(metric->value), sizeof(uint32_t));
+       *uint32_ptr = htonl(*uint32_ptr);
+
+       return LENGTH_2WORDS;
+}
+
+uint16_t pcep_encode_obj_lspa(struct pcep_object_header *hdr,
+                             struct pcep_versioning *versioning,
+                             uint8_t *obj_body_buf)
+{
+       (void)versioning;
+       struct pcep_object_lspa *lspa = (struct pcep_object_lspa *)hdr;
+       uint32_t *uint32_ptr = (uint32_t *)obj_body_buf;
+       uint32_ptr[0] = htonl(lspa->lspa_exclude_any);
+       uint32_ptr[1] = htonl(lspa->lspa_include_any);
+       uint32_ptr[2] = htonl(lspa->lspa_include_all);
+       obj_body_buf[12] = lspa->setup_priority;
+       obj_body_buf[13] = lspa->holding_priority;
+       obj_body_buf[14] =
+               (lspa->flag_local_protection ? OBJECT_LSPA_FLAG_L : 0x00);
+
+       return LENGTH_4WORDS;
+}
+
+uint16_t pcep_encode_obj_svec(struct pcep_object_header *hdr,
+                             struct pcep_versioning *versioning,
+                             uint8_t *obj_body_buf)
+{
+       (void)versioning;
+       struct pcep_object_svec *svec = (struct pcep_object_svec *)hdr;
+       obj_body_buf[3] =
+               ((svec->flag_srlg_diverse ? OBJECT_SVEC_FLAG_S : 0x00)
+                | (svec->flag_node_diverse ? OBJECT_SVEC_FLAG_N : 0x00)
+                | (svec->flag_link_diverse ? OBJECT_SVEC_FLAG_L : 0x00));
+
+       if (svec->request_id_list == NULL) {
+               return LENGTH_1WORD;
+       }
+
+       int index = 1;
+       uint32_t *uint32_ptr = (uint32_t *)obj_body_buf;
+       double_linked_list_node *node = svec->request_id_list->head;
+       for (; node != NULL; node = node->next_node) {
+               uint32_ptr[index++] = htonl(*((uint32_t *)(node->data)));
+       }
+
+       return LENGTH_1WORD
+              + (svec->request_id_list->num_entries * sizeof(uint32_t));
+}
+
+uint16_t pcep_encode_obj_error(struct pcep_object_header *hdr,
+                              struct pcep_versioning *versioning,
+                              uint8_t *obj_body_buf)
+{
+       (void)versioning;
+       struct pcep_object_error *error = (struct pcep_object_error *)hdr;
+       obj_body_buf[2] = error->error_type;
+       obj_body_buf[3] = error->error_value;
+
+       return LENGTH_1WORD;
+}
+
+uint16_t pcep_encode_obj_close(struct pcep_object_header *hdr,
+                              struct pcep_versioning *versioning,
+                              uint8_t *obj_body_buf)
+{
+       (void)versioning;
+       struct pcep_object_close *close = (struct pcep_object_close *)hdr;
+       obj_body_buf[3] = close->reason;
+
+       return LENGTH_1WORD;
+}
+
+uint16_t pcep_encode_obj_srp(struct pcep_object_header *hdr,
+                            struct pcep_versioning *versioning,
+                            uint8_t *obj_body_buf)
+{
+       (void)versioning;
+       struct pcep_object_srp *srp = (struct pcep_object_srp *)hdr;
+       obj_body_buf[3] = (srp->flag_lsp_remove ? OBJECT_SRP_FLAG_R : 0x00);
+       uint32_t *uint32_ptr = (uint32_t *)(obj_body_buf + 4);
+       *uint32_ptr = htonl(srp->srp_id_number);
+
+       return LENGTH_2WORDS;
+}
+
+uint16_t pcep_encode_obj_lsp(struct pcep_object_header *hdr,
+                            struct pcep_versioning *versioning,
+                            uint8_t *obj_body_buf)
+{
+       (void)versioning;
+       struct pcep_object_lsp *lsp = (struct pcep_object_lsp *)hdr;
+       uint32_t *uint32_ptr = (uint32_t *)obj_body_buf;
+       uint32_ptr[0] = htonl((lsp->plsp_id << 12) & 0xfffff000);
+       obj_body_buf[3] = ((lsp->flag_c ? OBJECT_LSP_FLAG_C : 0x00)
+                          | ((lsp->operational_status << 4) & 0x70)
+                          | (lsp->flag_a ? OBJECT_LSP_FLAG_A : 0x00)
+                          | (lsp->flag_r ? OBJECT_LSP_FLAG_R : 0x00)
+                          | (lsp->flag_s ? OBJECT_LSP_FLAG_S : 0x00)
+                          | (lsp->flag_d ? OBJECT_LSP_FLAG_D : 0x00));
+
+       return LENGTH_1WORD;
+}
+
+uint16_t pcep_encode_obj_vendor_info(struct pcep_object_header *hdr,
+                                    struct pcep_versioning *versioning,
+                                    uint8_t *obj_body_buf)
+{
+       (void)versioning;
+       struct pcep_object_vendor_info *obj =
+               (struct pcep_object_vendor_info *)hdr;
+       uint32_t *uint32_ptr = (uint32_t *)obj_body_buf;
+       uint32_ptr[0] = htonl(obj->enterprise_number);
+       uint32_ptr[1] = htonl(obj->enterprise_specific_info);
+
+       return LENGTH_2WORDS;
+}
+
+uint16_t pcep_encode_obj_inter_layer(struct pcep_object_header *hdr,
+                                    struct pcep_versioning *versioning,
+                                    uint8_t *obj_body_buf)
+{
+       (void)versioning;
+       struct pcep_object_inter_layer *obj =
+               (struct pcep_object_inter_layer *)hdr;
+       obj_body_buf[3] = ((obj->flag_i ? OBJECT_INTER_LAYER_FLAG_I : 0x00)
+                          | (obj->flag_m ? OBJECT_INTER_LAYER_FLAG_M : 0x00)
+                          | (obj->flag_t ? OBJECT_INTER_LAYER_FLAG_T : 0x00));
+
+       return LENGTH_1WORD;
+}
+
+uint16_t pcep_encode_obj_switch_layer(struct pcep_object_header *hdr,
+                                     struct pcep_versioning *versioning,
+                                     uint8_t *obj_body_buf)
+{
+       (void)versioning;
+       struct pcep_object_switch_layer *obj =
+               (struct pcep_object_switch_layer *)hdr;
+       uint8_t buf_index = 0;
+
+       double_linked_list_node *node = obj->switch_layer_rows->head;
+       while (node != NULL) {
+               struct pcep_object_switch_layer_row *row = node->data;
+               if (row == NULL) {
+                       break;
+               }
+
+               obj_body_buf[buf_index] = row->lsp_encoding_type;
+               obj_body_buf[buf_index + 1] = row->switching_type;
+               obj_body_buf[buf_index + 3] =
+                       (row->flag_i ? OBJECT_SWITCH_LAYER_FLAG_I : 0x00);
+
+               buf_index += LENGTH_1WORD;
+       }
+
+       return buf_index;
+}
+
+uint16_t pcep_encode_obj_req_adap_cap(struct pcep_object_header *hdr,
+                                     struct pcep_versioning *versioning,
+                                     uint8_t *obj_body_buf)
+{
+       (void)versioning;
+       struct pcep_object_req_adap_cap *obj =
+               (struct pcep_object_req_adap_cap *)hdr;
+
+       obj_body_buf[0] = obj->switching_capability;
+       obj_body_buf[1] = obj->encoding;
+
+       return LENGTH_1WORD;
+}
+
+uint16_t pcep_encode_obj_server_ind(struct pcep_object_header *hdr,
+                                   struct pcep_versioning *versioning,
+                                   uint8_t *obj_body_buf)
+{
+       (void)versioning;
+       struct pcep_object_server_indication *obj =
+               (struct pcep_object_server_indication *)hdr;
+
+       obj_body_buf[0] = obj->switching_capability;
+       obj_body_buf[1] = obj->encoding;
+
+       return LENGTH_1WORD;
+}
+
+uint16_t pcep_encode_obj_objective_function(struct pcep_object_header *hdr,
+                                           struct pcep_versioning *versioning,
+                                           uint8_t *obj_body_buf)
+{
+       (void)versioning;
+       struct pcep_object_objective_function *obj =
+               (struct pcep_object_objective_function *)hdr;
+
+       uint16_t *uint16_ptr = (uint16_t *)obj_body_buf;
+       *uint16_ptr = htons(obj->of_code);
+
+       return LENGTH_1WORD;
+}
+
+uint16_t pcep_encode_obj_ro(struct pcep_object_header *hdr,
+                           struct pcep_versioning *versioning,
+                           uint8_t *obj_body_buf)
+{
+       (void)versioning;
+       struct pcep_object_ro *ro = (struct pcep_object_ro *)hdr;
+       if (ro == NULL || ro->sub_objects == NULL) {
+               return 0;
+       }
+
+       /* RO Subobject format
+        *
+        *  0                   1
+        *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+        *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-------------//----------------+
+        *  |L|    Type     |     Length    | (Subobject contents)          |
+        *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-------------//----------------+
+        */
+
+       uint16_t index = 0;
+       double_linked_list_node *node = ro->sub_objects->head;
+       for (; node != NULL; node = node->next_node) {
+               struct pcep_object_ro_subobj *ro_subobj = node->data;
+               obj_body_buf[index++] =
+                       ((ro_subobj->flag_subobj_loose_hop ? 0x80 : 0x00)
+                        | (ro_subobj->ro_subobj_type));
+               /* The length will be written below, depending on the subobj
+                * type */
+               uint8_t *length_ptr = &(obj_body_buf[index++]);
+               uint32_t *uint32_ptr = (uint32_t *)(obj_body_buf + index);
+
+               /* - The index has already been incremented past the header,
+                *   and now points to the ro_subobj body. Below it just needs
+                *   to be incremented past the body.
+                *
+                * - Each section below needs to write the total length,
+                *   including the 2 byte subobj header. */
+
+               switch (ro_subobj->ro_subobj_type) {
+               case RO_SUBOBJ_TYPE_IPV4: {
+                       struct pcep_ro_subobj_ipv4 *ipv4 =
+                               (struct pcep_ro_subobj_ipv4 *)ro_subobj;
+                       uint32_ptr[0] = ipv4->ip_addr.s_addr;
+                       index += LENGTH_1WORD;
+                       obj_body_buf[index++] = ipv4->prefix_length;
+                       obj_body_buf[index++] =
+                               (ipv4->flag_local_protection
+                                        ? OBJECT_SUBOBJ_IP_FLAG_LOCAL_PROT
+                                        : 0x00);
+                       *length_ptr = LENGTH_2WORDS;
+               } break;
+
+               case RO_SUBOBJ_TYPE_IPV6: {
+                       struct pcep_ro_subobj_ipv6 *ipv6 =
+                               (struct pcep_ro_subobj_ipv6 *)ro_subobj;
+                       encode_ipv6(&ipv6->ip_addr, uint32_ptr);
+                       index += LENGTH_4WORDS;
+                       obj_body_buf[index++] = ipv6->prefix_length;
+                       obj_body_buf[index++] =
+                               (ipv6->flag_local_protection
+                                        ? OBJECT_SUBOBJ_IP_FLAG_LOCAL_PROT
+                                        : 0x00);
+                       *length_ptr = LENGTH_5WORDS;
+               } break;
+
+               case RO_SUBOBJ_TYPE_LABEL: {
+                       struct pcep_ro_subobj_32label *label =
+                               (struct pcep_ro_subobj_32label *)ro_subobj;
+                       obj_body_buf[index++] =
+                               (label->flag_global_label
+                                        ? OBJECT_SUBOBJ_LABEL_FLAG_GLOGAL
+                                        : 0x00);
+                       obj_body_buf[index++] = label->class_type;
+                       uint32_ptr = (uint32_t *)(obj_body_buf + index);
+                       *uint32_ptr = htonl(label->label);
+                       *length_ptr = LENGTH_2WORDS;
+                       index += LENGTH_1WORD;
+               } break;
+
+               case RO_SUBOBJ_TYPE_UNNUM: {
+                       struct pcep_ro_subobj_unnum *unum =
+                               (struct pcep_ro_subobj_unnum *)ro_subobj;
+                       index += 2; /* increment past 2 reserved bytes */
+                       uint32_ptr = (uint32_t *)(obj_body_buf + index);
+                       uint32_ptr[0] = unum->router_id.s_addr;
+                       uint32_ptr[1] = htonl(unum->interface_id);
+                       *length_ptr = LENGTH_3WORDS;
+                       index += LENGTH_2WORDS;
+               } break;
+
+               case RO_SUBOBJ_TYPE_ASN: {
+                       struct pcep_ro_subobj_asn *asn =
+                               (struct pcep_ro_subobj_asn *)ro_subobj;
+                       uint16_t *uint16_ptr =
+                               (uint16_t *)(obj_body_buf + index);
+                       *uint16_ptr = htons(asn->asn);
+                       *length_ptr = LENGTH_1WORD;
+                       index += 2;
+               } break;
+
+               case RO_SUBOBJ_TYPE_SR: {
+                       /* SR-ERO subobject format
+                        *
+                        * 0                   1                   2 3 0 1 2 3 4
+                        * 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+                        * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+                        * |L|   Type=36   |     Length    |  NT   |     Flags
+                        * |F|S|C|M|
+                        * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+                        * |                         SID (optional) |
+                        * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+                        * //                   NAI (variable, optional) //
+                        * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+                        */
+
+                       struct pcep_ro_subobj_sr *sr_subobj =
+                               (struct pcep_ro_subobj_sr *)ro_subobj;
+                       obj_body_buf[index++] =
+                               ((sr_subobj->nai_type << 4) & 0xf0);
+                       obj_body_buf[index++] =
+                               ((sr_subobj->flag_f ? OBJECT_SUBOBJ_SR_FLAG_F
+                                                   : 0x00)
+                                | (sr_subobj->flag_s ? OBJECT_SUBOBJ_SR_FLAG_S
+                                                     : 0x00)
+                                | (sr_subobj->flag_c ? OBJECT_SUBOBJ_SR_FLAG_C
+                                                     : 0x00)
+                                | (sr_subobj->flag_m ? OBJECT_SUBOBJ_SR_FLAG_M
+                                                     : 0x00));
+                       uint32_ptr = (uint32_t *)(obj_body_buf + index);
+                       /* Start with LENGTH_1WORD for the SubObj HDR + NT +
+                        * Flags */
+                       uint8_t sr_base_length = LENGTH_1WORD;
+                       /* If the sid_absent flag is true, then dont convert the
+                        * sid */
+                       if (sr_subobj->flag_s == false) {
+                               uint32_ptr[0] = htonl(sr_subobj->sid);
+                               index += LENGTH_1WORD;
+                               uint32_ptr = (uint32_t *)(obj_body_buf + index);
+                               sr_base_length += LENGTH_1WORD;
+                       }
+
+                       /* The lengths below need to include:
+                        * - sr_base_length: set above to include SR SubObj Hdr
+                        * and the SID if present
+                        * - Number of bytes written to the NAI
+                        * The index will only be incremented below by the
+                        * number of bytes written to the NAI, since the RO SR
+                        * subobj header and the SID have already been written.
+                        */
+
+                       double_linked_list_node *nai_node =
+                               (sr_subobj->nai_list == NULL
+                                        ? NULL
+                                        : sr_subobj->nai_list->head);
+                       if (nai_node == NULL) {
+                               if (sr_subobj->nai_type
+                                   == PCEP_SR_SUBOBJ_NAI_ABSENT) {
+                                       *length_ptr = sr_base_length;
+                                       continue;
+                               } else {
+                                       return 0;
+                               }
+                       }
+                       switch (sr_subobj->nai_type) {
+                       case PCEP_SR_SUBOBJ_NAI_IPV4_NODE:
+                               uint32_ptr[0] =
+                                       ((struct in_addr *)nai_node->data)
+                                               ->s_addr;
+                               *length_ptr = sr_base_length + LENGTH_1WORD;
+                               index += LENGTH_1WORD;
+                               break;
+
+                       case PCEP_SR_SUBOBJ_NAI_IPV6_NODE:
+                               encode_ipv6((struct in6_addr *)nai_node->data,
+                                           uint32_ptr);
+                               *length_ptr = sr_base_length + LENGTH_4WORDS;
+                               index += LENGTH_4WORDS;
+                               break;
+
+                       case PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY:
+                               uint32_ptr[0] =
+                                       ((struct in_addr *)nai_node->data)
+                                               ->s_addr;
+                               nai_node = nai_node->next_node;
+                               uint32_ptr[1] =
+                                       ((struct in_addr *)nai_node->data)
+                                               ->s_addr;
+                               nai_node = nai_node->next_node;
+                               uint32_ptr[2] =
+                                       ((struct in_addr *)nai_node->data)
+                                               ->s_addr;
+                               nai_node = nai_node->next_node;
+                               uint32_ptr[3] =
+                                       ((struct in_addr *)nai_node->data)
+                                               ->s_addr;
+                               *length_ptr = sr_base_length + LENGTH_4WORDS;
+                               index += LENGTH_4WORDS;
+                               break;
+
+                       case PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY:
+                               uint32_ptr[0] =
+                                       ((struct in_addr *)nai_node->data)
+                                               ->s_addr;
+                               nai_node = nai_node->next_node;
+                               uint32_ptr[1] =
+                                       ((struct in_addr *)nai_node->data)
+                                               ->s_addr;
+                               *length_ptr = sr_base_length + LENGTH_2WORDS;
+                               index += LENGTH_2WORDS;
+                               break;
+
+                       case PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY:
+                               encode_ipv6((struct in6_addr *)nai_node->data,
+                                           uint32_ptr);
+                               nai_node = nai_node->next_node;
+                               encode_ipv6((struct in6_addr *)nai_node->data,
+                                           uint32_ptr + 4);
+                               *length_ptr = sr_base_length + LENGTH_8WORDS;
+                               index += LENGTH_8WORDS;
+                               break;
+
+                       case PCEP_SR_SUBOBJ_NAI_LINK_LOCAL_IPV6_ADJACENCY:
+                               encode_ipv6((struct in6_addr *)nai_node->data,
+                                           uint32_ptr);
+                               nai_node = nai_node->next_node;
+                               uint32_ptr[4] =
+                                       ((struct in_addr *)nai_node->data)
+                                               ->s_addr;
+                               nai_node = nai_node->next_node;
+                               encode_ipv6((struct in6_addr *)nai_node->data,
+                                           uint32_ptr + 5);
+                               nai_node = nai_node->next_node;
+                               uint32_ptr[9] =
+                                       ((struct in_addr *)nai_node->data)
+                                               ->s_addr;
+                               *length_ptr = sr_base_length + LENGTH_10WORDS;
+                               index += LENGTH_10WORDS;
+                               break;
+
+                       default:
+                               break;
+                       }
+               } break;
+
+               default:
+                       break;
+               }
+       }
+
+       return index;
+}
+
+void encode_ipv6(struct in6_addr *src_ipv6, uint32_t *dst)
+{
+       memcpy(dst, src_ipv6, sizeof(struct in6_addr));
+}
+
+/*
+ * Decoding functions.
+ */
+
+void pcep_decode_object_hdr(const uint8_t *obj_buf,
+                           struct pcep_object_header *obj_hdr)
+{
+       memset(obj_hdr, 0, sizeof(struct pcep_object_header));
+
+       obj_hdr->object_class = obj_buf[0];
+       obj_hdr->object_type = (obj_buf[1] >> 4) & 0x0f;
+       obj_hdr->flag_p = (obj_buf[1] & OBJECT_HEADER_FLAG_P);
+       obj_hdr->flag_i = (obj_buf[1] & OBJECT_HEADER_FLAG_I);
+       uint16_t net_order_length;
+       memcpy(&net_order_length, obj_buf + 2, sizeof(net_order_length));
+       obj_hdr->encoded_object_length = ntohs(net_order_length);
+       obj_hdr->encoded_object = obj_buf;
+}
+
+uint16_t pcep_object_get_length(enum pcep_object_classes object_class,
+                               enum pcep_object_types object_type)
+{
+       uint8_t object_length = pcep_object_class_lengths[object_class];
+       if (object_length == 0) {
+               if (object_class == PCEP_OBJ_CLASS_ENDPOINTS) {
+                       if (object_type == PCEP_OBJ_TYPE_ENDPOINT_IPV4) {
+                               return 12;
+                       } else if (object_type == PCEP_OBJ_TYPE_ENDPOINT_IPV6) {
+                               return 36;
+                       }
+               }
+
+               return 0;
+       }
+
+       return object_length;
+}
+
+uint16_t pcep_object_get_length_by_hdr(struct pcep_object_header *object_hdr)
+{
+       return (pcep_object_get_length(object_hdr->object_class,
+                                      object_hdr->object_type));
+}
+
+bool pcep_object_has_tlvs(struct pcep_object_header *object_hdr)
+{
+       uint8_t object_length = pcep_object_get_length_by_hdr(object_hdr);
+       if (object_length == 0) {
+               return false;
+       }
+
+       return (object_hdr->encoded_object_length - object_length) > 0;
+}
+
+struct pcep_object_header *pcep_decode_object(const uint8_t *obj_buf)
+{
+
+       struct pcep_object_header object_hdr;
+       /* Only initializes and decodes the Object Header: class, type, flags,
+        * and length */
+       pcep_decode_object_hdr(obj_buf, &object_hdr);
+
+       if (object_hdr.object_class >= MAX_OBJECT_ENCODER_INDEX) {
+               pcep_log(LOG_INFO,
+                        "%s: Cannot decode unknown Object class [%d]",
+                        __func__, object_hdr.object_class);
+               return NULL;
+       }
+
+       object_decoder_funcptr obj_decoder =
+               object_decoders[object_hdr.object_class];
+       if (obj_decoder == NULL) {
+               pcep_log(LOG_INFO,
+                        "%s: No object decoder found for Object class [%d]",
+                        __func__, object_hdr.object_class);
+               return NULL;
+       }
+
+       /* The object decoders will start decoding the object body, if
+        * anything from the header is needed, they have the object_hdr */
+       struct pcep_object_header *object =
+               obj_decoder(&object_hdr, obj_buf + OBJECT_HEADER_LENGTH);
+       if (object == NULL) {
+               pcep_log(LOG_INFO, "%s: Unable to decode Object class [%d].",
+                        __func__, object_hdr.object_class);
+               return NULL;
+       }
+
+       if (pcep_object_has_tlvs(&object_hdr)) {
+               object->tlv_list = dll_initialize();
+               int num_iterations = 0;
+               uint16_t tlv_index = pcep_object_get_length_by_hdr(&object_hdr);
+               while ((object->encoded_object_length - tlv_index) > 0
+                      && num_iterations++ < MAX_ITERATIONS) {
+                       struct pcep_object_tlv_header *tlv =
+                               pcep_decode_tlv(obj_buf + tlv_index);
+                       if (tlv == NULL) {
+                               /* TODO should we do anything else here ? */
+                               return object;
+                       }
+
+                       /* The TLV length does not include the TLV header */
+                       tlv_index += normalize_pcep_tlv_length(
+                               tlv->encoded_tlv_length + TLV_HEADER_LENGTH);
+                       dll_append(object->tlv_list, tlv);
+               }
+       }
+
+       return object;
+}
+
+static struct pcep_object_header *
+common_object_create(struct pcep_object_header *hdr, uint16_t new_obj_length)
+{
+       struct pcep_object_header *new_object =
+               pceplib_malloc(PCEPLIB_MESSAGES, new_obj_length);
+       memset(new_object, 0, new_obj_length);
+       memcpy(new_object, hdr, sizeof(struct pcep_object_header));
+
+       return new_object;
+}
+
+/*
+ * Decoders
+ */
+
+struct pcep_object_header *pcep_decode_obj_open(struct pcep_object_header *hdr,
+                                               const uint8_t *obj_buf)
+{
+       struct pcep_object_open *obj =
+               (struct pcep_object_open *)common_object_create(
+                       hdr, sizeof(struct pcep_object_open));
+
+       obj->open_version = (obj_buf[0] >> 5) & 0x07;
+       obj->open_keepalive = obj_buf[1];
+       obj->open_deadtimer = obj_buf[2];
+       obj->open_sid = obj_buf[3];
+
+       return (struct pcep_object_header *)obj;
+}
+
+struct pcep_object_header *pcep_decode_obj_rp(struct pcep_object_header *hdr,
+                                             const uint8_t *obj_buf)
+{
+       struct pcep_object_rp *obj =
+               (struct pcep_object_rp *)common_object_create(
+                       hdr, sizeof(struct pcep_object_rp));
+
+       obj->flag_reoptimization = (obj_buf[3] & OBJECT_RP_FLAG_R);
+       obj->flag_bidirectional = (obj_buf[3] & OBJECT_RP_FLAG_B);
+       obj->flag_strict = (obj_buf[3] & OBJECT_RP_FLAG_O);
+       obj->flag_of = (obj_buf[3] & OBJECT_RP_FLAG_OF);
+       obj->priority = (obj_buf[3] & 0x07);
+       obj->request_id = ntohl(*((uint32_t *)(obj_buf + 4)));
+
+       return (struct pcep_object_header *)obj;
+}
+
+struct pcep_object_header *
+pcep_decode_obj_notify(struct pcep_object_header *hdr, const uint8_t *obj_buf)
+{
+       struct pcep_object_notify *obj =
+               (struct pcep_object_notify *)common_object_create(
+                       hdr, sizeof(struct pcep_object_notify));
+
+       obj->notification_type = obj_buf[2];
+       obj->notification_value = obj_buf[3];
+
+       return (struct pcep_object_header *)obj;
+}
+
+struct pcep_object_header *
+pcep_decode_obj_nopath(struct pcep_object_header *hdr, const uint8_t *obj_buf)
+{
+       struct pcep_object_nopath *obj =
+               (struct pcep_object_nopath *)common_object_create(
+                       hdr, sizeof(struct pcep_object_nopath));
+
+       obj->ni = (obj_buf[0] >> 1);
+       obj->flag_c = (obj_buf[0] & OBJECT_NOPATH_FLAG_C);
+
+       return (struct pcep_object_header *)obj;
+}
+
+struct pcep_object_header *
+pcep_decode_obj_association(struct pcep_object_header *hdr,
+                           const uint8_t *obj_buf)
+{
+       uint16_t *uint16_ptr = (uint16_t *)obj_buf;
+       uint32_t *uint32_ptr = (uint32_t *)obj_buf;
+
+       if (hdr->object_type == PCEP_OBJ_TYPE_ASSOCIATION_IPV4) {
+               struct pcep_object_association_ipv4 *obj =
+                       (struct pcep_object_association_ipv4 *)
+                               common_object_create(
+                                       hdr,
+                                       sizeof(struct
+                                              pcep_object_association_ipv4));
+               obj->R_flag = (obj_buf[3] & OBJECT_ASSOCIATION_FLAG_R);
+               obj->association_type = ntohs(uint16_ptr[2]);
+               obj->association_id = ntohs(uint16_ptr[3]);
+               obj->src.s_addr = uint32_ptr[2];
+
+               return (struct pcep_object_header *)obj;
+       } else if (hdr->object_type == PCEP_OBJ_TYPE_ENDPOINT_IPV6) {
+               struct pcep_object_association_ipv6 *obj =
+                       (struct pcep_object_association_ipv6 *)
+                               common_object_create(
+                                       hdr,
+                                       sizeof(struct
+                                              pcep_object_association_ipv6));
+
+               obj->R_flag = (obj_buf[3] & OBJECT_ASSOCIATION_FLAG_R);
+               obj->association_type = ntohs(uint16_ptr[2]);
+               obj->association_id = ntohs(uint16_ptr[3]);
+               memcpy(&obj->src, &uint32_ptr[2], sizeof(struct in6_addr));
+
+               return (struct pcep_object_header *)obj;
+       }
+
+       return NULL;
+}
+struct pcep_object_header *
+pcep_decode_obj_endpoints(struct pcep_object_header *hdr,
+                         const uint8_t *obj_buf)
+{
+       uint32_t *uint32_ptr = (uint32_t *)obj_buf;
+
+       if (hdr->object_type == PCEP_OBJ_TYPE_ENDPOINT_IPV4) {
+               struct pcep_object_endpoints_ipv4 *obj =
+                       (struct pcep_object_endpoints_ipv4 *)
+                               common_object_create(
+                                       hdr,
+                                       sizeof(struct
+                                              pcep_object_endpoints_ipv4));
+               obj->src_ipv4.s_addr = uint32_ptr[0];
+               obj->dst_ipv4.s_addr = uint32_ptr[1];
+
+               return (struct pcep_object_header *)obj;
+       } else if (hdr->object_type == PCEP_OBJ_TYPE_ENDPOINT_IPV6) {
+               struct pcep_object_endpoints_ipv6 *obj =
+                       (struct pcep_object_endpoints_ipv6 *)
+                               common_object_create(
+                                       hdr,
+                                       sizeof(struct
+                                              pcep_object_endpoints_ipv6));
+
+               memcpy(&obj->src_ipv6, &uint32_ptr[0], sizeof(struct in6_addr));
+               memcpy(&obj->dst_ipv6, &uint32_ptr[4], sizeof(struct in6_addr));
+
+               return (struct pcep_object_header *)obj;
+       }
+
+       return NULL;
+}
+
+struct pcep_object_header *
+pcep_decode_obj_bandwidth(struct pcep_object_header *hdr,
+                         const uint8_t *obj_buf)
+{
+       struct pcep_object_bandwidth *obj =
+               (struct pcep_object_bandwidth *)common_object_create(
+                       hdr, sizeof(struct pcep_object_bandwidth));
+
+       uint32_t value = ntohl(*((uint32_t *)obj_buf));
+       /* Seems like the compiler doesnt correctly copy to the float, so
+        * memcpy() it */
+       memcpy(&obj->bandwidth, &value, sizeof(uint32_t));
+
+       return (struct pcep_object_header *)obj;
+}
+
+struct pcep_object_header *
+pcep_decode_obj_metric(struct pcep_object_header *hdr, const uint8_t *obj_buf)
+{
+       struct pcep_object_metric *obj =
+               (struct pcep_object_metric *)common_object_create(
+                       hdr, sizeof(struct pcep_object_metric));
+       obj->flag_b = (obj_buf[2] & OBJECT_METRIC_FLAC_B);
+       obj->flag_c = (obj_buf[2] & OBJECT_METRIC_FLAC_C);
+       obj->type = obj_buf[3];
+       uint32_t value = ntohl(*((uint32_t *)(obj_buf + 4)));
+       /* Seems like the compiler doesnt correctly copy to the float, so
+        * memcpy() it */
+       memcpy(&obj->value, &value, sizeof(uint32_t));
+
+       return (struct pcep_object_header *)obj;
+}
+
+struct pcep_object_header *pcep_decode_obj_lspa(struct pcep_object_header *hdr,
+                                               const uint8_t *obj_buf)
+{
+       struct pcep_object_lspa *obj =
+               (struct pcep_object_lspa *)common_object_create(
+                       hdr, sizeof(struct pcep_object_lspa));
+       uint32_t *uint32_ptr = (uint32_t *)obj_buf;
+
+       obj->lspa_exclude_any = ntohl(uint32_ptr[0]);
+       obj->lspa_include_any = ntohl(uint32_ptr[1]);
+       obj->lspa_include_all = ntohl(uint32_ptr[2]);
+       obj->setup_priority = obj_buf[12];
+       obj->holding_priority = obj_buf[13];
+       obj->flag_local_protection = (obj_buf[14] & OBJECT_LSPA_FLAG_L);
+
+       return (struct pcep_object_header *)obj;
+}
+
+struct pcep_object_header *pcep_decode_obj_svec(struct pcep_object_header *hdr,
+                                               const uint8_t *obj_buf)
+{
+       struct pcep_object_svec *obj =
+               (struct pcep_object_svec *)common_object_create(
+                       hdr, sizeof(struct pcep_object_svec));
+
+       obj->flag_link_diverse = (obj_buf[3] & OBJECT_SVEC_FLAG_L);
+       obj->flag_node_diverse = (obj_buf[3] & OBJECT_SVEC_FLAG_N);
+       obj->flag_srlg_diverse = (obj_buf[3] & OBJECT_SVEC_FLAG_S);
+
+       if (hdr->encoded_object_length > LENGTH_2WORDS) {
+               obj->request_id_list = dll_initialize();
+               uint16_t index = 1;
+               uint32_t *uint32_ptr = (uint32_t *)obj_buf;
+               for (;
+                    index < ((hdr->encoded_object_length - LENGTH_2WORDS) / 4);
+                    index++) {
+                       uint32_t *req_id_ptr = pceplib_malloc(PCEPLIB_MESSAGES,
+                                                             sizeof(uint32_t));
+                       *req_id_ptr = uint32_ptr[index];
+                       dll_append(obj->request_id_list, req_id_ptr);
+               }
+       }
+
+       return (struct pcep_object_header *)obj;
+}
+
+struct pcep_object_header *pcep_decode_obj_error(struct pcep_object_header *hdr,
+                                                const uint8_t *obj_buf)
+{
+       struct pcep_object_error *obj =
+               (struct pcep_object_error *)common_object_create(
+                       hdr, sizeof(struct pcep_object_error));
+
+       obj->error_type = obj_buf[2];
+       obj->error_value = obj_buf[3];
+
+       return (struct pcep_object_header *)obj;
+}
+
+struct pcep_object_header *pcep_decode_obj_close(struct pcep_object_header *hdr,
+                                                const uint8_t *obj_buf)
+{
+       struct pcep_object_close *obj =
+               (struct pcep_object_close *)common_object_create(
+                       hdr, sizeof(struct pcep_object_close));
+
+       obj->reason = obj_buf[3];
+
+       return (struct pcep_object_header *)obj;
+}
+
+struct pcep_object_header *pcep_decode_obj_srp(struct pcep_object_header *hdr,
+                                              const uint8_t *obj_buf)
+{
+       struct pcep_object_srp *obj =
+               (struct pcep_object_srp *)common_object_create(
+                       hdr, sizeof(struct pcep_object_srp));
+
+       obj->flag_lsp_remove = (obj_buf[3] & OBJECT_SRP_FLAG_R);
+       obj->srp_id_number = ntohl(*((uint32_t *)(obj_buf + 4)));
+
+       return (struct pcep_object_header *)obj;
+}
+
+struct pcep_object_header *pcep_decode_obj_lsp(struct pcep_object_header *hdr,
+                                              const uint8_t *obj_buf)
+{
+       struct pcep_object_lsp *obj =
+               (struct pcep_object_lsp *)common_object_create(
+                       hdr, sizeof(struct pcep_object_lsp));
+
+       obj->flag_d = (obj_buf[3] & OBJECT_LSP_FLAG_D);
+       obj->flag_s = (obj_buf[3] & OBJECT_LSP_FLAG_S);
+       obj->flag_r = (obj_buf[3] & OBJECT_LSP_FLAG_R);
+       obj->flag_a = (obj_buf[3] & OBJECT_LSP_FLAG_A);
+       obj->flag_c = (obj_buf[3] & OBJECT_LSP_FLAG_C);
+       obj->operational_status = ((obj_buf[3] >> 4) & 0x07);
+       obj->plsp_id = ((ntohl(*((uint32_t *)obj_buf)) >> 12) & 0x000fffff);
+
+       return (struct pcep_object_header *)obj;
+}
+
+struct pcep_object_header *
+pcep_decode_obj_vendor_info(struct pcep_object_header *hdr,
+                           const uint8_t *obj_buf)
+{
+       struct pcep_object_vendor_info *obj =
+               (struct pcep_object_vendor_info *)common_object_create(
+                       hdr, sizeof(struct pcep_object_vendor_info));
+       obj->enterprise_number = ntohl(*((uint32_t *)(obj_buf)));
+       obj->enterprise_specific_info = ntohl(*((uint32_t *)(obj_buf + 4)));
+
+       return (struct pcep_object_header *)obj;
+}
+
+struct pcep_object_header *
+pcep_decode_obj_inter_layer(struct pcep_object_header *hdr,
+                           const uint8_t *obj_buf)
+{
+       struct pcep_object_inter_layer *obj =
+               (struct pcep_object_inter_layer *)common_object_create(
+                       hdr, sizeof(struct pcep_object_inter_layer));
+       obj->flag_t = (obj_buf[3] & OBJECT_INTER_LAYER_FLAG_T);
+       obj->flag_m = (obj_buf[3] & OBJECT_INTER_LAYER_FLAG_M);
+       obj->flag_i = (obj_buf[3] & OBJECT_INTER_LAYER_FLAG_I);
+
+       return (struct pcep_object_header *)obj;
+}
+
+struct pcep_object_header *
+pcep_decode_obj_switch_layer(struct pcep_object_header *hdr,
+                            const uint8_t *obj_buf)
+{
+       struct pcep_object_switch_layer *obj =
+               (struct pcep_object_switch_layer *)common_object_create(
+                       hdr, sizeof(struct pcep_object_switch_layer));
+       obj->switch_layer_rows = dll_initialize();
+       int num_rows = ((hdr->encoded_object_length - 4) / 4);
+       uint8_t buf_index = 0;
+
+       int i = 0;
+       for (; i < num_rows; i++) {
+               struct pcep_object_switch_layer_row *row = pceplib_malloc(
+                       PCEPLIB_MESSAGES,
+                       sizeof(struct pcep_object_switch_layer_row));
+               row->lsp_encoding_type = obj_buf[buf_index];
+               row->switching_type = obj_buf[buf_index + 1];
+               row->flag_i =
+                       (obj_buf[buf_index + 3] & OBJECT_SWITCH_LAYER_FLAG_I);
+               dll_append(obj->switch_layer_rows, row);
+
+               buf_index += LENGTH_1WORD;
+       }
+
+       return (struct pcep_object_header *)obj;
+}
+
+struct pcep_object_header *
+pcep_decode_obj_req_adap_cap(struct pcep_object_header *hdr,
+                            const uint8_t *obj_buf)
+{
+       struct pcep_object_req_adap_cap *obj =
+               (struct pcep_object_req_adap_cap *)common_object_create(
+                       hdr, sizeof(struct pcep_object_req_adap_cap));
+
+       obj->switching_capability = obj_buf[0];
+       obj->encoding = obj_buf[1];
+
+       return (struct pcep_object_header *)obj;
+}
+
+struct pcep_object_header *
+pcep_decode_obj_server_ind(struct pcep_object_header *hdr,
+                          const uint8_t *obj_buf)
+{
+       struct pcep_object_server_indication *obj =
+               (struct pcep_object_server_indication *)common_object_create(
+                       hdr, sizeof(struct pcep_object_server_indication));
+
+       obj->switching_capability = obj_buf[0];
+       obj->encoding = obj_buf[1];
+
+       return (struct pcep_object_header *)obj;
+}
+
+struct pcep_object_header *
+pcep_decode_obj_objective_function(struct pcep_object_header *hdr,
+                                  const uint8_t *obj_buf)
+{
+       struct pcep_object_objective_function *obj =
+               (struct pcep_object_objective_function *)common_object_create(
+                       hdr, sizeof(struct pcep_object_objective_function));
+
+       uint16_t *uint16_ptr = (uint16_t *)obj_buf;
+       obj->of_code = ntohs(*uint16_ptr);
+
+       return (struct pcep_object_header *)obj;
+}
+
+void set_ro_subobj_fields(struct pcep_object_ro_subobj *subobj, bool flag_l,
+                         uint8_t subobj_type)
+{
+       subobj->flag_subobj_loose_hop = flag_l;
+       subobj->ro_subobj_type = subobj_type;
+}
+
+void decode_ipv6(const uint32_t *src, struct in6_addr *dst_ipv6)
+{
+       memcpy(dst_ipv6, src, sizeof(struct in6_addr));
+}
+struct pcep_object_header *pcep_decode_obj_ro(struct pcep_object_header *hdr,
+                                             const uint8_t *obj_buf)
+{
+       struct pcep_object_ro *obj =
+               (struct pcep_object_ro *)common_object_create(
+                       hdr, sizeof(struct pcep_object_ro));
+       obj->sub_objects = dll_initialize();
+
+       /* RO Subobject format
+        *
+        *  0                   1
+        *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+        *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-------------//----------------+
+        *  |L|    Type     |     Length    | (Subobject contents)          |
+        *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-------------//----------------+
+        */
+
+       uint16_t read_count = 0;
+       int num_sub_objects = 1;
+       uint32_t *uint32_ptr;
+       uint16_t obj_body_length =
+               hdr->encoded_object_length - OBJECT_HEADER_LENGTH;
+
+       while ((obj_body_length - read_count) > OBJECT_RO_SUBOBJ_HEADER_LENGTH
+              && num_sub_objects < MAX_ITERATIONS) {
+               num_sub_objects++;
+               /* Read the Sub-Object Header */
+               bool flag_l = (obj_buf[read_count] & 0x80);
+               uint8_t subobj_type = (obj_buf[read_count++] & 0x7f);
+               uint8_t subobj_length = obj_buf[read_count++];
+
+               if (subobj_length <= OBJECT_RO_SUBOBJ_HEADER_LENGTH) {
+                       pcep_log(LOG_INFO,
+                                "%s: Invalid ro subobj type [%d] length [%d]",
+                                __func__, subobj_type, subobj_length);
+                       pceplib_free(PCEPLIB_MESSAGES, obj);
+                       return NULL;
+               }
+
+               switch (subobj_type) {
+               case RO_SUBOBJ_TYPE_IPV4: {
+                       struct pcep_ro_subobj_ipv4 *ipv4 = pceplib_malloc(
+                               PCEPLIB_MESSAGES,
+                               sizeof(struct pcep_ro_subobj_ipv4));
+                       ipv4->ro_subobj.flag_subobj_loose_hop = flag_l;
+                       ipv4->ro_subobj.ro_subobj_type = subobj_type;
+                       uint32_ptr = (uint32_t *)(obj_buf + read_count);
+                       ipv4->ip_addr.s_addr = *uint32_ptr;
+                       read_count += LENGTH_1WORD;
+                       ipv4->prefix_length = obj_buf[read_count++];
+                       ipv4->flag_local_protection =
+                               (obj_buf[read_count++]
+                                & OBJECT_SUBOBJ_IP_FLAG_LOCAL_PROT);
+
+                       dll_append(obj->sub_objects, ipv4);
+               } break;
+
+               case RO_SUBOBJ_TYPE_IPV6: {
+                       struct pcep_ro_subobj_ipv6 *ipv6 = pceplib_malloc(
+                               PCEPLIB_MESSAGES,
+                               sizeof(struct pcep_ro_subobj_ipv6));
+                       ipv6->ro_subobj.flag_subobj_loose_hop = flag_l;
+                       ipv6->ro_subobj.ro_subobj_type = subobj_type;
+                       decode_ipv6((uint32_t *)obj_buf, &ipv6->ip_addr);
+                       read_count += LENGTH_4WORDS;
+                       ipv6->prefix_length = obj_buf[read_count++];
+                       ipv6->flag_local_protection =
+                               (obj_buf[read_count++]
+                                & OBJECT_SUBOBJ_IP_FLAG_LOCAL_PROT);
+
+                       dll_append(obj->sub_objects, ipv6);
+               } break;
+
+               case RO_SUBOBJ_TYPE_LABEL: {
+                       struct pcep_ro_subobj_32label *label = pceplib_malloc(
+                               PCEPLIB_MESSAGES,
+                               sizeof(struct pcep_ro_subobj_32label));
+                       label->ro_subobj.flag_subobj_loose_hop = flag_l;
+                       label->ro_subobj.ro_subobj_type = subobj_type;
+                       label->flag_global_label =
+                               (obj_buf[read_count++]
+                                & OBJECT_SUBOBJ_LABEL_FLAG_GLOGAL);
+                       label->class_type = obj_buf[read_count++];
+                       label->label = ntohl(obj_buf[read_count]);
+                       read_count += LENGTH_1WORD;
+
+                       dll_append(obj->sub_objects, label);
+               } break;
+
+               case RO_SUBOBJ_TYPE_UNNUM: {
+                       struct pcep_ro_subobj_unnum *unum = pceplib_malloc(
+                               PCEPLIB_MESSAGES,
+                               sizeof(struct pcep_ro_subobj_unnum));
+                       unum->ro_subobj.flag_subobj_loose_hop = flag_l;
+                       unum->ro_subobj.ro_subobj_type = subobj_type;
+                       set_ro_subobj_fields(
+                               (struct pcep_object_ro_subobj *)unum, flag_l,
+                               subobj_type);
+                       uint32_ptr = (uint32_t *)(obj_buf + read_count);
+                       unum->interface_id = ntohl(uint32_ptr[0]);
+                       unum->router_id.s_addr = uint32_ptr[1];
+                       read_count += 2;
+
+                       dll_append(obj->sub_objects, unum);
+               } break;
+
+               case RO_SUBOBJ_TYPE_ASN: {
+                       struct pcep_ro_subobj_asn *asn = pceplib_malloc(
+                               PCEPLIB_MESSAGES,
+                               sizeof(struct pcep_ro_subobj_asn));
+                       asn->ro_subobj.flag_subobj_loose_hop = flag_l;
+                       asn->ro_subobj.ro_subobj_type = subobj_type;
+                       uint16_t *uint16_ptr =
+                               (uint16_t *)(obj_buf + read_count);
+                       asn->asn = ntohs(*uint16_ptr);
+                       read_count += 2;
+
+                       dll_append(obj->sub_objects, asn);
+               } break;
+
+               case RO_SUBOBJ_TYPE_SR: {
+                       /* SR-ERO subobject format
+                        *
+                        * 0                   1                   2 3 0 1 2 3 4
+                        * 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+                        * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+                        * |L|   Type=36   |     Length    |  NT   |     Flags
+                        * |F|S|C|M|
+                        * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+                        * |                         SID (optional) |
+                        * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+                        * //                   NAI (variable, optional) //
+                        * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+                        */
+
+                       struct pcep_ro_subobj_sr *sr_subobj = pceplib_malloc(
+                               PCEPLIB_MESSAGES,
+                               sizeof(struct pcep_ro_subobj_sr));
+                       sr_subobj->ro_subobj.flag_subobj_loose_hop = flag_l;
+                       sr_subobj->ro_subobj.ro_subobj_type = subobj_type;
+                       dll_append(obj->sub_objects, sr_subobj);
+
+                       sr_subobj->nai_list = dll_initialize();
+                       sr_subobj->nai_type =
+                               ((obj_buf[read_count++] >> 4) & 0x0f);
+                       sr_subobj->flag_f =
+                               (obj_buf[read_count] & OBJECT_SUBOBJ_SR_FLAG_F);
+                       sr_subobj->flag_s =
+                               (obj_buf[read_count] & OBJECT_SUBOBJ_SR_FLAG_S);
+                       sr_subobj->flag_c =
+                               (obj_buf[read_count] & OBJECT_SUBOBJ_SR_FLAG_C);
+                       sr_subobj->flag_m =
+                               (obj_buf[read_count] & OBJECT_SUBOBJ_SR_FLAG_M);
+                       read_count++;
+
+                       /* If the sid_absent flag is true, then dont decode the
+                        * sid */
+                       uint32_ptr = (uint32_t *)(obj_buf + read_count);
+                       if (sr_subobj->flag_s == false) {
+                               sr_subobj->sid = ntohl(*uint32_ptr);
+                               read_count += LENGTH_1WORD;
+                               uint32_ptr += 1;
+                       }
+
+                       switch (sr_subobj->nai_type) {
+                       case PCEP_SR_SUBOBJ_NAI_IPV4_NODE: {
+                               struct in_addr *ipv4 =
+                                       pceplib_malloc(PCEPLIB_MESSAGES,
+                                                      sizeof(struct in_addr));
+                               ipv4->s_addr = *uint32_ptr;
+                               dll_append(sr_subobj->nai_list, ipv4);
+                               read_count += LENGTH_1WORD;
+                       } break;
+
+                       case PCEP_SR_SUBOBJ_NAI_IPV6_NODE: {
+                               struct in6_addr *ipv6 =
+                                       pceplib_malloc(PCEPLIB_MESSAGES,
+                                                      sizeof(struct in6_addr));
+                               decode_ipv6(uint32_ptr, ipv6);
+                               dll_append(sr_subobj->nai_list, ipv6);
+                               read_count += LENGTH_4WORDS;
+                       } break;
+
+                       case PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY: {
+                               struct in_addr *ipv4 =
+                                       pceplib_malloc(PCEPLIB_MESSAGES,
+                                                      sizeof(struct in_addr));
+                               ipv4->s_addr = uint32_ptr[0];
+                               dll_append(sr_subobj->nai_list, ipv4);
+
+                               ipv4 = pceplib_malloc(PCEPLIB_MESSAGES,
+                                                     sizeof(struct in_addr));
+                               ipv4->s_addr = uint32_ptr[1];
+                               dll_append(sr_subobj->nai_list, ipv4);
+
+                               ipv4 = pceplib_malloc(PCEPLIB_MESSAGES,
+                                                     sizeof(struct in_addr));
+                               ipv4->s_addr = uint32_ptr[2];
+                               dll_append(sr_subobj->nai_list, ipv4);
+
+                               ipv4 = pceplib_malloc(PCEPLIB_MESSAGES,
+                                                     sizeof(struct in_addr));
+                               ipv4->s_addr = uint32_ptr[3];
+                               dll_append(sr_subobj->nai_list, ipv4);
+
+                               read_count += LENGTH_4WORDS;
+                       } break;
+
+                       case PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY: {
+                               struct in_addr *ipv4 =
+                                       pceplib_malloc(PCEPLIB_MESSAGES,
+                                                      sizeof(struct in_addr));
+                               ipv4->s_addr = uint32_ptr[0];
+                               dll_append(sr_subobj->nai_list, ipv4);
+
+                               ipv4 = pceplib_malloc(PCEPLIB_MESSAGES,
+                                                     sizeof(struct in_addr));
+                               ipv4->s_addr = uint32_ptr[1];
+                               dll_append(sr_subobj->nai_list, ipv4);
+
+                               read_count += LENGTH_2WORDS;
+                       } break;
+
+                       case PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY: {
+                               struct in6_addr *ipv6 =
+                                       pceplib_malloc(PCEPLIB_MESSAGES,
+                                                      sizeof(struct in6_addr));
+                               decode_ipv6(uint32_ptr, ipv6);
+                               dll_append(sr_subobj->nai_list, ipv6);
+
+                               ipv6 = pceplib_malloc(PCEPLIB_MESSAGES,
+                                                     sizeof(struct in6_addr));
+                               decode_ipv6(uint32_ptr + 4, ipv6);
+                               dll_append(sr_subobj->nai_list, ipv6);
+
+                               read_count += LENGTH_8WORDS;
+                       } break;
+
+                       case PCEP_SR_SUBOBJ_NAI_LINK_LOCAL_IPV6_ADJACENCY: {
+                               struct in6_addr *ipv6 =
+                                       pceplib_malloc(PCEPLIB_MESSAGES,
+                                                      sizeof(struct in6_addr));
+                               decode_ipv6(uint32_ptr, ipv6);
+                               dll_append(sr_subobj->nai_list, ipv6);
+
+                               struct in_addr *ipv4 =
+                                       pceplib_malloc(PCEPLIB_MESSAGES,
+                                                      sizeof(struct in_addr));
+                               ipv4->s_addr = uint32_ptr[4];
+                               dll_append(sr_subobj->nai_list, ipv4);
+
+                               ipv6 = pceplib_malloc(PCEPLIB_MESSAGES,
+                                                     sizeof(struct in6_addr));
+                               decode_ipv6(uint32_ptr + 5, ipv6);
+                               dll_append(sr_subobj->nai_list, ipv6);
+
+                               ipv4 = pceplib_malloc(PCEPLIB_MESSAGES,
+                                                     sizeof(struct in_addr));
+                               ipv4->s_addr = uint32_ptr[9];
+                               dll_append(sr_subobj->nai_list, ipv4);
+
+                               read_count += LENGTH_10WORDS;
+                       } break;
+
+                       case PCEP_SR_SUBOBJ_NAI_ABSENT:
+                       default:
+                               break;
+                       }
+               } break;
+
+               default:
+                       pcep_log(
+                               LOG_INFO,
+                               "%s: pcep_decode_obj_ro skipping unrecognized sub-object type [%d]",
+                               __func__, subobj_type);
+                       read_count += subobj_length;
+                       break;
+               }
+       }
+
+       return (struct pcep_object_header *)obj;
+}
diff --git a/pceplib/pcep_msg_tlvs.c b/pceplib/pcep_msg_tlvs.c
new file mode 100644 (file)
index 0000000..9c84e71
--- /dev/null
@@ -0,0 +1,464 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+/*
+ * This is the implementation of a High Level PCEP message object TLV API.
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "pcep_msg_tlvs.h"
+#include "pcep_msg_encoding.h"
+#include "pcep_utils_memory.h"
+
+static struct pcep_object_tlv_header *
+pcep_tlv_common_create(enum pcep_object_tlv_types type, uint16_t size)
+{
+       struct pcep_object_tlv_header *tlv =
+               pceplib_malloc(PCEPLIB_MESSAGES, size);
+       memset(tlv, 0, size);
+       tlv->type = type;
+
+       return tlv;
+}
+
+/*
+ * Open Object TLVs
+ */
+
+struct pcep_object_tlv_stateful_pce_capability *
+pcep_tlv_create_stateful_pce_capability(
+       bool flag_u_lsp_update_capability, bool flag_s_include_db_version,
+       bool flag_i_lsp_instantiation_capability, bool flag_t_triggered_resync,
+       bool flag_d_delta_lsp_sync, bool flag_f_triggered_initial_sync)
+{
+       struct pcep_object_tlv_stateful_pce_capability *tlv =
+               (struct pcep_object_tlv_stateful_pce_capability *)
+                       pcep_tlv_common_create(
+                               PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY,
+                               sizeof(struct
+                                      pcep_object_tlv_stateful_pce_capability));
+       tlv->flag_u_lsp_update_capability = flag_u_lsp_update_capability;
+       tlv->flag_s_include_db_version = flag_s_include_db_version;
+       tlv->flag_i_lsp_instantiation_capability =
+               flag_i_lsp_instantiation_capability;
+       tlv->flag_t_triggered_resync = flag_t_triggered_resync;
+       tlv->flag_d_delta_lsp_sync = flag_d_delta_lsp_sync;
+       tlv->flag_f_triggered_initial_sync = flag_f_triggered_initial_sync;
+
+       return tlv;
+}
+
+struct pcep_object_tlv_lsp_db_version *
+pcep_tlv_create_lsp_db_version(uint64_t lsp_db_version)
+{
+       struct pcep_object_tlv_lsp_db_version *tlv =
+               (struct pcep_object_tlv_lsp_db_version *)pcep_tlv_common_create(
+                       PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION,
+                       sizeof(struct pcep_object_tlv_lsp_db_version));
+       tlv->lsp_db_version = lsp_db_version;
+
+       return tlv;
+}
+
+struct pcep_object_tlv_speaker_entity_identifier *
+pcep_tlv_create_speaker_entity_id(double_linked_list *speaker_entity_id_list)
+{
+       if (speaker_entity_id_list == NULL) {
+               return NULL;
+       }
+
+       if (speaker_entity_id_list->num_entries == 0) {
+               return NULL;
+       }
+
+       struct pcep_object_tlv_speaker_entity_identifier *tlv =
+               (struct pcep_object_tlv_speaker_entity_identifier *)
+                       pcep_tlv_common_create(
+                               PCEP_OBJ_TLV_TYPE_SPEAKER_ENTITY_ID,
+                               sizeof(struct
+                                      pcep_object_tlv_speaker_entity_identifier));
+       tlv->speaker_entity_id_list = speaker_entity_id_list;
+
+       return tlv;
+}
+
+struct pcep_object_tlv_path_setup_type *
+pcep_tlv_create_path_setup_type(uint8_t pst)
+{
+       struct pcep_object_tlv_path_setup_type *tlv =
+               (struct pcep_object_tlv_path_setup_type *)
+                       pcep_tlv_common_create(
+                               PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE,
+                               sizeof(struct pcep_object_tlv_path_setup_type));
+       tlv->path_setup_type = pst;
+
+       return tlv;
+}
+
+struct pcep_object_tlv_path_setup_type_capability *
+pcep_tlv_create_path_setup_type_capability(double_linked_list *pst_list,
+                                          double_linked_list *sub_tlv_list)
+{
+       if (pst_list == NULL) {
+               return NULL;
+       }
+
+       if (pst_list->num_entries == 0) {
+               return NULL;
+       }
+
+       struct pcep_object_tlv_path_setup_type_capability *tlv =
+               (struct pcep_object_tlv_path_setup_type_capability *)
+                       pcep_tlv_common_create(
+                               PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY,
+                               sizeof(struct
+                                      pcep_object_tlv_path_setup_type_capability));
+
+       tlv->pst_list = pst_list;
+       tlv->sub_tlv_list = sub_tlv_list;
+
+       return tlv;
+}
+
+struct pcep_object_tlv_sr_pce_capability *
+pcep_tlv_create_sr_pce_capability(bool flag_n, bool flag_x,
+                                 uint8_t max_sid_depth)
+{
+       struct pcep_object_tlv_sr_pce_capability *tlv =
+               (struct pcep_object_tlv_sr_pce_capability *)
+                       pcep_tlv_common_create(
+                               PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY,
+                               sizeof(struct
+                                      pcep_object_tlv_sr_pce_capability));
+       tlv->flag_n = flag_n;
+       tlv->flag_x = flag_x;
+       tlv->max_sid_depth = max_sid_depth;
+
+       return tlv;
+}
+
+struct pcep_object_tlv_of_list *
+pcep_tlv_create_of_list(double_linked_list *of_list)
+{
+       if (of_list == NULL) {
+               return NULL;
+       }
+
+       struct pcep_object_tlv_of_list *tlv =
+               (struct pcep_object_tlv_of_list *)pcep_tlv_common_create(
+                       PCEP_OBJ_TLV_TYPE_OBJECTIVE_FUNCTION_LIST,
+                       sizeof(struct pcep_object_tlv_of_list));
+
+       tlv->of_list = of_list;
+
+       return tlv;
+}
+
+/*
+ * LSP Object TLVs
+ */
+
+struct pcep_object_tlv_ipv4_lsp_identifier *
+pcep_tlv_create_ipv4_lsp_identifiers(struct in_addr *ipv4_tunnel_sender,
+                                    struct in_addr *ipv4_tunnel_endpoint,
+                                    uint16_t lsp_id, uint16_t tunnel_id,
+                                    struct in_addr *extended_tunnel_id)
+{
+       if (ipv4_tunnel_sender == NULL || ipv4_tunnel_endpoint == NULL) {
+               return NULL;
+       }
+
+       struct pcep_object_tlv_ipv4_lsp_identifier *tlv =
+               (struct pcep_object_tlv_ipv4_lsp_identifier *)
+                       pcep_tlv_common_create(
+                               PCEP_OBJ_TLV_TYPE_IPV4_LSP_IDENTIFIERS,
+                               sizeof(struct
+                                      pcep_object_tlv_ipv4_lsp_identifier));
+       tlv->ipv4_tunnel_sender.s_addr = ipv4_tunnel_sender->s_addr;
+       tlv->ipv4_tunnel_endpoint.s_addr = ipv4_tunnel_endpoint->s_addr;
+       tlv->lsp_id = lsp_id;
+       tlv->tunnel_id = tunnel_id;
+       tlv->extended_tunnel_id.s_addr =
+               (extended_tunnel_id == NULL ? INADDR_ANY
+                                           : extended_tunnel_id->s_addr);
+
+       return tlv;
+}
+
+struct pcep_object_tlv_ipv6_lsp_identifier *
+pcep_tlv_create_ipv6_lsp_identifiers(struct in6_addr *ipv6_tunnel_sender,
+                                    struct in6_addr *ipv6_tunnel_endpoint,
+                                    uint16_t lsp_id, uint16_t tunnel_id,
+                                    struct in6_addr *extended_tunnel_id)
+{
+       if (ipv6_tunnel_sender == NULL || ipv6_tunnel_endpoint == NULL) {
+               return NULL;
+       }
+
+       struct pcep_object_tlv_ipv6_lsp_identifier *tlv =
+               (struct pcep_object_tlv_ipv6_lsp_identifier *)
+                       pcep_tlv_common_create(
+                               PCEP_OBJ_TLV_TYPE_IPV6_LSP_IDENTIFIERS,
+                               sizeof(struct
+                                      pcep_object_tlv_ipv6_lsp_identifier));
+
+       memcpy(&tlv->ipv6_tunnel_sender, ipv6_tunnel_sender,
+              sizeof(struct in6_addr));
+
+       tlv->tunnel_id = tunnel_id;
+       tlv->lsp_id = lsp_id;
+
+       memcpy(&tlv->extended_tunnel_id, extended_tunnel_id,
+              sizeof(struct in6_addr));
+
+       memcpy(&tlv->ipv6_tunnel_endpoint, ipv6_tunnel_endpoint,
+              sizeof(struct in6_addr));
+
+       return tlv;
+}
+
+struct pcep_object_tlv_symbolic_path_name *
+pcep_tlv_create_symbolic_path_name(const char *symbolic_path_name,
+                                  uint16_t symbolic_path_name_length)
+{
+       /* symbolic_path_name_length should NOT include the null terminator and
+        * cannot be zero */
+       if (symbolic_path_name == NULL || symbolic_path_name_length == 0) {
+               return NULL;
+       }
+
+       struct pcep_object_tlv_symbolic_path_name *tlv =
+               (struct pcep_object_tlv_symbolic_path_name *)
+                       pcep_tlv_common_create(
+                               PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME,
+                               sizeof(struct
+                                      pcep_object_tlv_symbolic_path_name));
+
+       uint16_t length = (symbolic_path_name_length > MAX_SYMBOLIC_PATH_NAME)
+                                 ? MAX_SYMBOLIC_PATH_NAME
+                                 : symbolic_path_name_length;
+       memcpy(tlv->symbolic_path_name, symbolic_path_name, length);
+       tlv->symbolic_path_name_length = length;
+
+       return tlv;
+}
+
+struct pcep_object_tlv_lsp_error_code *
+pcep_tlv_create_lsp_error_code(enum pcep_tlv_lsp_error_codes lsp_error_code)
+{
+       struct pcep_object_tlv_lsp_error_code *tlv =
+               (struct pcep_object_tlv_lsp_error_code *)pcep_tlv_common_create(
+                       PCEP_OBJ_TLV_TYPE_LSP_ERROR_CODE,
+                       sizeof(struct pcep_object_tlv_lsp_error_code));
+       tlv->lsp_error_code = lsp_error_code;
+
+       return tlv;
+}
+
+struct pcep_object_tlv_rsvp_error_spec *
+pcep_tlv_create_rsvp_ipv4_error_spec(struct in_addr *error_node_ip,
+                                    uint8_t error_code, uint16_t error_value)
+{
+       if (error_node_ip == NULL) {
+               return NULL;
+       }
+
+       struct pcep_object_tlv_rsvp_error_spec *tlv =
+               (struct pcep_object_tlv_rsvp_error_spec *)
+                       pcep_tlv_common_create(
+                               PCEP_OBJ_TLV_TYPE_RSVP_ERROR_SPEC,
+                               sizeof(struct pcep_object_tlv_rsvp_error_spec));
+
+       tlv->c_type = RSVP_ERROR_SPEC_IPV4_CTYPE;
+       tlv->class_num = RSVP_ERROR_SPEC_CLASS_NUM;
+       tlv->error_code = error_code;
+       tlv->error_value = error_value;
+       tlv->error_spec_ip.ipv4_error_node_address.s_addr =
+               error_node_ip->s_addr;
+
+       return tlv;
+}
+
+struct pcep_object_tlv_rsvp_error_spec *
+pcep_tlv_create_rsvp_ipv6_error_spec(struct in6_addr *error_node_ip,
+                                    uint8_t error_code, uint16_t error_value)
+{
+       if (error_node_ip == NULL) {
+               return NULL;
+       }
+
+       struct pcep_object_tlv_rsvp_error_spec *tlv =
+               (struct pcep_object_tlv_rsvp_error_spec *)
+                       pcep_tlv_common_create(
+                               PCEP_OBJ_TLV_TYPE_RSVP_ERROR_SPEC,
+                               sizeof(struct pcep_object_tlv_rsvp_error_spec));
+
+       tlv->c_type = RSVP_ERROR_SPEC_IPV6_CTYPE;
+       tlv->class_num = RSVP_ERROR_SPEC_CLASS_NUM;
+       tlv->error_code = error_code;
+       tlv->error_value = error_value;
+       memcpy(&tlv->error_spec_ip, error_node_ip, sizeof(struct in6_addr));
+
+       return tlv;
+}
+
+struct pcep_object_tlv_nopath_vector *
+pcep_tlv_create_nopath_vector(uint32_t error_code)
+{
+       struct pcep_object_tlv_nopath_vector *tlv =
+               (struct pcep_object_tlv_nopath_vector *)pcep_tlv_common_create(
+                       PCEP_OBJ_TLV_TYPE_NO_PATH_VECTOR,
+                       sizeof(struct pcep_object_tlv_nopath_vector));
+
+       tlv->error_code = error_code;
+
+       return tlv;
+}
+
+struct pcep_object_tlv_vendor_info *
+pcep_tlv_create_vendor_info(uint32_t enterprise_number,
+                           uint32_t enterprise_specific_info)
+{
+       struct pcep_object_tlv_vendor_info *tlv =
+               (struct pcep_object_tlv_vendor_info *)pcep_tlv_common_create(
+                       PCEP_OBJ_TLV_TYPE_VENDOR_INFO,
+                       sizeof(struct pcep_object_tlv_vendor_info));
+
+       tlv->enterprise_number = enterprise_number;
+       tlv->enterprise_specific_info = enterprise_specific_info;
+
+       return tlv;
+}
+
+/*
+ * SRPAG (SR Association Group) TLVs
+ */
+
+struct pcep_object_tlv_srpag_pol_id *
+pcep_tlv_create_srpag_pol_id_ipv4(uint32_t color, struct in_addr *ipv4)
+{
+       struct pcep_object_tlv_srpag_pol_id *tlv =
+               (struct pcep_object_tlv_srpag_pol_id *)pcep_tlv_common_create(
+                       PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_ID,
+                       sizeof(struct pcep_object_tlv_srpag_pol_id));
+       tlv->color = color;
+       tlv->is_ipv4 = true;
+       memcpy(&tlv->end_point.ipv4.s_addr, ipv4, sizeof(struct in_addr));
+
+       return tlv;
+}
+
+struct pcep_object_tlv_srpag_pol_id *
+pcep_tlv_create_srpag_pol_id_ipv6(uint32_t color, struct in6_addr *ipv6)
+{
+       struct pcep_object_tlv_srpag_pol_id *tlv =
+               (struct pcep_object_tlv_srpag_pol_id *)pcep_tlv_common_create(
+                       PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_ID,
+                       sizeof(struct pcep_object_tlv_srpag_pol_id));
+       tlv->color = color;
+       tlv->is_ipv4 = false;
+       memcpy(&tlv->end_point.ipv6, ipv6, sizeof(struct in6_addr));
+
+       return tlv;
+}
+
+
+struct pcep_object_tlv_srpag_pol_name *
+pcep_tlv_create_srpag_pol_name(const char *pol_name, uint16_t pol_name_length)
+{
+       if (pol_name == NULL) {
+               return NULL;
+       }
+       struct pcep_object_tlv_srpag_pol_name *tlv =
+               (struct pcep_object_tlv_srpag_pol_name *)pcep_tlv_common_create(
+                       PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_NAME,
+                       sizeof(struct pcep_object_tlv_srpag_pol_name));
+       uint16_t length =
+               (normalize_pcep_tlv_length(pol_name_length) > MAX_POLICY_NAME)
+                       ? MAX_POLICY_NAME
+                       : pol_name_length;
+       memcpy(tlv->name, pol_name, length);
+       tlv->name_length = length;
+
+       return tlv;
+}
+struct pcep_object_tlv_srpag_cp_id *
+pcep_tlv_create_srpag_cp_id(uint8_t proto_origin, uint32_t asn,
+                           struct in6_addr *in6_addr_with_mapped_ipv4,
+                           uint32_t discriminator)
+{
+       if (!in6_addr_with_mapped_ipv4) {
+               return NULL;
+       }
+
+       struct pcep_object_tlv_srpag_cp_id *tlv =
+               (struct pcep_object_tlv_srpag_cp_id *)pcep_tlv_common_create(
+                       PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_ID,
+                       sizeof(struct pcep_object_tlv_srpag_cp_id));
+       tlv->proto = proto_origin;
+       tlv->orig_asn = asn;
+       memcpy(&(tlv->orig_addres), in6_addr_with_mapped_ipv4,
+              sizeof(*in6_addr_with_mapped_ipv4));
+       tlv->discriminator = discriminator;
+
+       return tlv;
+}
+struct pcep_object_tlv_srpag_cp_pref *
+pcep_tlv_create_srpag_cp_pref(uint32_t pref)
+{
+
+       struct pcep_object_tlv_srpag_cp_pref *tlv =
+               (struct pcep_object_tlv_srpag_cp_pref *)pcep_tlv_common_create(
+                       PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_PREFERENCE,
+                       sizeof(struct pcep_object_tlv_srpag_cp_pref));
+       tlv->preference = pref;
+
+       return tlv;
+}
+
+struct pcep_object_tlv_arbitrary *
+pcep_tlv_create_tlv_arbitrary(const char *data, uint16_t data_length,
+                             int tlv_id)
+{
+       if (data == NULL || data_length == 0) {
+               return NULL;
+       }
+
+       struct pcep_object_tlv_arbitrary *tlv =
+               (struct pcep_object_tlv_arbitrary *)pcep_tlv_common_create(
+                       PCEP_OBJ_TLV_TYPE_ARBITRARY,
+                       sizeof(struct pcep_object_tlv_arbitrary));
+
+       uint16_t length = (data_length > MAX_ARBITRARY_SIZE)
+                                 ? MAX_ARBITRARY_SIZE
+                                 : data_length;
+       memcpy(tlv->data, data, length);
+       tlv->data_length = length;
+       tlv->arbitraty_type = tlv_id;
+
+       return tlv;
+}
diff --git a/pceplib/pcep_msg_tlvs.h b/pceplib/pcep_msg_tlvs.h
new file mode 100644 (file)
index 0000000..5197201
--- /dev/null
@@ -0,0 +1,380 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ */
+
+
+/*
+ * This is a High Level PCEP message object TLV API.
+ */
+
+#ifndef PCEP_TLVS_H_
+#define PCEP_TLVS_H_
+
+#include <arpa/inet.h>
+#include <stdint.h>
+
+#include "pcep.h"
+#include "pcep_utils_double_linked_list.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Regarding memory usage:
+ * When creating TLVs, any TLVs passed into messages or objects with these APIs
+ * will be free'd when the the enclosing pcep_message is free'd. That includes
+ * the double_linked_list's. So, just create the objects and TLVs, put them in
+ * their double_linked_list's, and everything will be managed internally. The
+ * enclosing message will be deleted by pcep_msg_free_message() or
+ * pcep_msg_free_message_list() which, * in turn will call one of:
+ * pcep_obj_free_object() and pcep_obj_free_tlv().
+ * For received messages, call pcep_msg_free_message() to free them.
+ */
+
+/* These numbers can be found here:
+ * https://www.iana.org/assignments/pcep/pcep.xhtml */
+enum pcep_object_tlv_types {
+       PCEP_OBJ_TLV_TYPE_NO_PATH_VECTOR = 1,
+       PCEP_OBJ_TLV_TYPE_OBJECTIVE_FUNCTION_LIST = 4,  /* RFC 5541 */
+       PCEP_OBJ_TLV_TYPE_VENDOR_INFO = 7,              /* RFC 7470 */
+       PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY = 16, /* RFC 8231 */
+       PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME = 17,      /* RFC 8232 */
+       PCEP_OBJ_TLV_TYPE_IPV4_LSP_IDENTIFIERS = 18,    /* RFC 8231 */
+       PCEP_OBJ_TLV_TYPE_IPV6_LSP_IDENTIFIERS = 19,    /* RFC 8231 */
+       PCEP_OBJ_TLV_TYPE_LSP_ERROR_CODE = 20,          /* RFC 8232 */
+       PCEP_OBJ_TLV_TYPE_RSVP_ERROR_SPEC = 21,         /* RFC 8232 */
+       PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION = 23,          /* RFC 8232 */
+       PCEP_OBJ_TLV_TYPE_SPEAKER_ENTITY_ID = 24,       /* RFC 8232 */
+       PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY =
+               26, /* draft-ietf-pce-segment-routing-16 */
+       PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE = 28, /* RFC 8408 */
+       PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY =
+               34, /* RFC 8408, draft-ietf-pce-segment-routing-16 */
+       PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_ID =
+               60, /*TDB2 draft-barth-pce-segment-routing-policy-cp-04 */
+       PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_NAME =
+               61, /*TDB3 draft-barth-pce-segment-routing-policy-cp-04 */
+       PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_ID =
+               62, /*TDB4 draft-barth-pce-segment-routing-policy-cp-04 */
+       PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_PREFERENCE =
+               63, /*TDB5 draft-barth-pce-segment-routing-policy-cp-04 */
+       PCEP_OBJ_TLV_TYPE_UNKNOWN = 128,
+       PCEP_OBJ_TLV_TYPE_ARBITRARY =
+               65533 /* Max IANA To write arbitrary data */
+};
+
+struct pcep_object_tlv_header {
+       enum pcep_object_tlv_types type;
+       /* Pointer into encoded_message field from the pcep_message */
+       const uint8_t *encoded_tlv;
+       uint16_t encoded_tlv_length;
+};
+
+/* STATEFUL-PCE-CAPABILITY TLV, Used in Open Object. RFCs: 8231, 8232, 8281 */
+#define TLV_STATEFUL_PCE_CAP_FLAG_U 0x01
+#define TLV_STATEFUL_PCE_CAP_FLAG_S 0x02
+#define TLV_STATEFUL_PCE_CAP_FLAG_I 0x04
+#define TLV_STATEFUL_PCE_CAP_FLAG_T 0x08
+#define TLV_STATEFUL_PCE_CAP_FLAG_D 0x10
+#define TLV_STATEFUL_PCE_CAP_FLAG_F 0x20
+
+struct pcep_object_tlv_stateful_pce_capability {
+       struct pcep_object_tlv_header header;
+       bool flag_u_lsp_update_capability;        /* RFC 8231 */
+       bool flag_s_include_db_version;           /* RFC 8232 */
+       bool flag_i_lsp_instantiation_capability; /* RFC 8281 */
+       bool flag_t_triggered_resync;             /* RFC 8232 */
+       bool flag_d_delta_lsp_sync;               /* RFC 8232 */
+       bool flag_f_triggered_initial_sync;       /* RFC 8232 */
+};
+
+/* NOPATH-VECTOR TLV, Used in the Reply NoPath Object. */
+struct pcep_object_tlv_nopath_vector {
+       struct pcep_object_tlv_header header;
+       uint32_t error_code;
+};
+
+/* STATEFUL-PCE-CAPABILITY TLV, Used in Open Object. RFCs: 8232 */
+struct pcep_object_tlv_lsp_db_version {
+       struct pcep_object_tlv_header header;
+       uint64_t lsp_db_version;
+};
+
+/* Speaker Entity Identifier TLV, Used in Open Object. RFCs: 8232 */
+struct pcep_object_tlv_speaker_entity_identifier {
+       struct pcep_object_tlv_header header;
+       double_linked_list *speaker_entity_id_list; /* list of uint32_t speaker
+                                                      entity ids */
+};
+
+/* Ipv4 LSP Identifier TLV, Used in LSP Object. RFCs: 8231 */
+struct pcep_object_tlv_ipv4_lsp_identifier {
+       struct pcep_object_tlv_header header;
+       struct in_addr ipv4_tunnel_sender;
+       uint16_t lsp_id;
+       uint16_t tunnel_id;
+       struct in_addr extended_tunnel_id;
+       struct in_addr ipv4_tunnel_endpoint;
+};
+
+/* Ipv6 LSP Identifier TLV, Used in LSP Object. RFCs: 8231 */
+struct pcep_object_tlv_ipv6_lsp_identifier {
+       struct pcep_object_tlv_header header;
+       struct in6_addr ipv6_tunnel_sender;
+       uint16_t lsp_id;
+       uint16_t tunnel_id;
+       struct in6_addr extended_tunnel_id;
+       struct in6_addr ipv6_tunnel_endpoint;
+};
+
+/* Symbolic Path Name TLV, Used in LSP Object. RFCs: 8231 */
+#define MAX_SYMBOLIC_PATH_NAME 256
+
+struct pcep_object_tlv_symbolic_path_name {
+       struct pcep_object_tlv_header header;
+       uint16_t symbolic_path_name_length;
+       char symbolic_path_name[MAX_SYMBOLIC_PATH_NAME];
+};
+
+/* LSP Error Code TLV, Used in LSP Object. RFCs: 8231 */
+enum pcep_tlv_lsp_error_codes {
+       PCEP_TLV_LSP_ERROR_CODE_UNKNOWN = 1,
+       PCEP_TLV_LSP_ERROR_CODE_LSP_LIMIT_REACHED = 2,
+       PCEP_TLV_LSP_ERROR_CODE_TOO_MANY_PENDING_LSP_UPDATES = 3,
+       PCEP_TLV_LSP_ERROR_CODE_UNACCEPTABLE_PARAMS = 4,
+       PCEP_TLV_LSP_ERROR_CODE_INTERNAL_ERROR = 5,
+       PCEP_TLV_LSP_ERROR_CODE_LSP_BROUGHT_DOWN = 6,
+       PCEP_TLV_LSP_ERROR_CODE_LSP_PREEMPTED = 7,
+       PCEP_TLV_LSP_ERROR_CODE_RSVP_SIGNALING_ERROR = 8,
+};
+
+struct pcep_object_tlv_lsp_error_code {
+       struct pcep_object_tlv_header header;
+       enum pcep_tlv_lsp_error_codes lsp_error_code;
+};
+
+/* Path Setup Type TLV, Used in RP and SRP Object. RFCs: 8408,
+ * draft-ietf-pce-segment-routing-16 */
+#define SR_TE_PST 1
+
+struct pcep_object_tlv_path_setup_type {
+       struct pcep_object_tlv_header header;
+       uint8_t path_setup_type;
+};
+
+/* Path Setup Type Capability TLV, Used in Open Object. RFCs: 8408,
+ * draft-ietf-pce-segment-routing-16 */
+struct pcep_object_tlv_path_setup_type_capability {
+       struct pcep_object_tlv_header header;
+       double_linked_list *pst_list;     /* list of uint8_t PSTs */
+       double_linked_list *sub_tlv_list; /* list of sub_tlvs */
+};
+
+/* SR PCE Capability sub-TLV, Used in Open Object. RFCs:
+ * draft-ietf-pce-segment-routing-16 */
+#define TLV_SR_PCE_CAP_FLAG_X 0x01
+#define TLV_SR_PCE_CAP_FLAG_N 0x02
+
+struct pcep_object_tlv_sr_pce_capability {
+       struct pcep_object_tlv_header header;
+       bool flag_n;
+       bool flag_x;
+       uint8_t max_sid_depth;
+};
+
+
+/* RSVP Error Spec TLV, Used in LSP Object. RFCs: 8231, 2205 */
+#define RSVP_ERROR_SPEC_IPV4_CTYPE 1
+#define RSVP_ERROR_SPEC_IPV6_CTYPE 2
+#define RSVP_ERROR_SPEC_CLASS_NUM 6
+
+struct pcep_object_tlv_rsvp_error_spec {
+       struct pcep_object_tlv_header header;
+       uint8_t class_num;
+       uint8_t c_type;
+       uint8_t error_code;
+       uint16_t error_value;
+       /* Use the c_type to determine which union entry to use */
+       union error_spec_ip {
+               struct in_addr ipv4_error_node_address;
+               struct in6_addr ipv6_error_node_address;
+       } error_spec_ip;
+};
+
+/* SR Policy Identifier TLV Used in Association Object.
+ * draft-barth-pce-segment-routing-policy-cp-04*/
+struct pcep_object_tlv_srpag_pol_id {
+       struct pcep_object_tlv_header header;
+       uint32_t color;
+       bool is_ipv4;
+       union end_point_ {
+               struct in_addr ipv4;
+               struct in6_addr ipv6;
+       } end_point;
+};
+
+/*draft-ietf-spring-segment-routing-policy-06*/
+#define MAX_POLICY_NAME 256
+
+/* SR Policy Name TLV Used in Association Object.
+ * draft-barth-pce-segment-routing-policy-cp-04*/
+struct pcep_object_tlv_srpag_pol_name {
+       struct pcep_object_tlv_header header;
+       uint16_t name_length;
+       char name[MAX_POLICY_NAME];
+};
+
+/* SR Candidate Path Id  TLV Used in Association Object.
+ * draft-barth-pce-segment-routing-policy-cp-04*/
+struct pcep_object_tlv_srpag_cp_id {
+       struct pcep_object_tlv_header header;
+       uint8_t proto;
+       uint32_t orig_asn;
+       struct in6_addr orig_addres; /*With ipv4 embedded*/
+       uint32_t discriminator;
+};
+
+/* SR Candidate Preference TLV Used in Association Object.
+ * draft-barth-pce-segment-routing-policy-cp-04*/
+struct pcep_object_tlv_srpag_cp_pref {
+       struct pcep_object_tlv_header header;
+       uint32_t preference;
+};
+
+struct pcep_object_tlv_vendor_info {
+       struct pcep_object_tlv_header header;
+       uint32_t enterprise_number;
+       uint32_t enterprise_specific_info;
+};
+
+/* arbitrary TLV 65535 */
+#define MAX_ARBITRARY_SIZE 256
+struct pcep_object_tlv_arbitrary {
+       struct pcep_object_tlv_header header;
+       enum pcep_object_tlv_types arbitraty_type;
+       uint16_t data_length;
+       char data[MAX_ARBITRARY_SIZE];
+};
+
+/* Objective Functions List RFC 5541
+ * At least the following 6 OF codes must be supported */
+enum objective_function_codes {
+       PCEP_OF_CODE_MINIMUM_COST_PATH = 1,              /* MCP */
+       PCEP_OF_CODE_MINIMUM_LOAD_PATH = 2,              /* MLP */
+       PCEP_OF_CODE_MAXIMUM_BW_PATH = 3,                /* MBP */
+       PCEP_OF_CODE_MINIMIZE_AGGR_BW_CONSUMPTION = 4,   /* MBC */
+       PCEP_OF_CODE_MINIMIZE_MOST_LOADED_LINK = 5,      /* MLL */
+       PCEP_OF_CODE_MINIMIZE_CUMULATIVE_COST_PATHS = 6, /* MCC */
+};
+
+struct pcep_object_tlv_of_list {
+       struct pcep_object_tlv_header header;
+       double_linked_list *of_list; /* list of uint16_t OF code points */
+};
+
+/*
+ * TLV creation functions
+ */
+
+/*
+ * Open Object TLVs
+ */
+
+struct pcep_object_tlv_stateful_pce_capability *
+pcep_tlv_create_stateful_pce_capability(
+       bool flag_u_lsp_update_capability, bool flag_s_include_db_version,
+       bool flag_i_lsp_instantiation_capability, bool flag_t_triggered_resync,
+       bool flag_d_delta_lsp_sync, bool flag_f_triggered_initial_sync);
+struct pcep_object_tlv_lsp_db_version *
+pcep_tlv_create_lsp_db_version(uint64_t lsp_db_version);
+struct pcep_object_tlv_speaker_entity_identifier *
+pcep_tlv_create_speaker_entity_id(double_linked_list *speaker_entity_id_list);
+struct pcep_object_tlv_path_setup_type *
+pcep_tlv_create_path_setup_type(uint8_t pst);
+struct pcep_object_tlv_path_setup_type_capability *
+pcep_tlv_create_path_setup_type_capability(double_linked_list *pst_list,
+                                          double_linked_list *sub_tlv_list);
+struct pcep_object_tlv_sr_pce_capability *
+pcep_tlv_create_sr_pce_capability(bool flag_n, bool flag_x,
+                                 uint8_t max_sid_depth);
+struct pcep_object_tlv_of_list *
+pcep_tlv_create_of_list(double_linked_list *of_list);
+
+/*
+ * LSP Object TLVs
+ */
+
+struct pcep_object_tlv_ipv4_lsp_identifier *
+pcep_tlv_create_ipv4_lsp_identifiers(struct in_addr *ipv4_tunnel_sender,
+                                    struct in_addr *ipv4_tunnel_endpoint,
+                                    uint16_t lsp_id, uint16_t tunnel_id,
+                                    struct in_addr *extended_tunnel_id);
+struct pcep_object_tlv_ipv6_lsp_identifier *
+pcep_tlv_create_ipv6_lsp_identifiers(struct in6_addr *ipv6_tunnel_sender,
+                                    struct in6_addr *extended_tunnel_id,
+                                    uint16_t lsp_id, uint16_t tunnel_id,
+                                    struct in6_addr *ipv6_tunnel_endpoint);
+/* symbolic_path_name_length should NOT include the null terminator and cannot
+ * be zero */
+struct pcep_object_tlv_symbolic_path_name *
+pcep_tlv_create_symbolic_path_name(const char *symbolic_path_name,
+                                  uint16_t symbolic_path_name_length);
+struct pcep_object_tlv_lsp_error_code *
+pcep_tlv_create_lsp_error_code(enum pcep_tlv_lsp_error_codes lsp_error_code);
+struct pcep_object_tlv_rsvp_error_spec *
+pcep_tlv_create_rsvp_ipv4_error_spec(struct in_addr *error_node_ip,
+                                    uint8_t error_code, uint16_t error_value);
+struct pcep_object_tlv_rsvp_error_spec *
+pcep_tlv_create_rsvp_ipv6_error_spec(struct in6_addr *error_node_ip,
+                                    uint8_t error_code, uint16_t error_value);
+
+struct pcep_object_tlv_nopath_vector *
+pcep_tlv_create_nopath_vector(uint32_t error_code);
+struct pcep_object_tlv_vendor_info *
+pcep_tlv_create_vendor_info(uint32_t enterprise_number,
+                           uint32_t enterprise_specific_info);
+
+struct pcep_object_tlv_arbitrary *
+pcep_tlv_create_tlv_arbitrary(const char *data, uint16_t data_length,
+                             int tlv_id);
+/*
+ * SRPAG (SR Association Group) TLVs
+ */
+
+struct pcep_object_tlv_srpag_pol_id *
+pcep_tlv_create_srpag_pol_id_ipv4(uint32_t color, struct in_addr *ipv4);
+struct pcep_object_tlv_srpag_pol_id *
+pcep_tlv_create_srpag_pol_id_ipv6(uint32_t color, struct in6_addr *ipv6);
+struct pcep_object_tlv_srpag_pol_name *
+pcep_tlv_create_srpag_pol_name(const char *pol_name, uint16_t pol_name_length);
+struct pcep_object_tlv_srpag_cp_id *
+pcep_tlv_create_srpag_cp_id(uint8_t proto_origin, uint32_t asn,
+                           struct in6_addr *in6_addr_with_mapped_ipv4,
+                           uint32_t discriminator);
+struct pcep_object_tlv_srpag_cp_pref *
+pcep_tlv_create_srpag_cp_pref(uint32_t pref);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PCEP_TLVS_H_ */
diff --git a/pceplib/pcep_msg_tlvs_encoding.c b/pceplib/pcep_msg_tlvs_encoding.c
new file mode 100644 (file)
index 0000000..967f138
--- /dev/null
@@ -0,0 +1,1282 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+/*
+ * Encoding and decoding for PCEP Object TLVs.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "pcep.h"
+#include "pcep_msg_encoding.h"
+#include "pcep_msg_tlvs.h"
+#include "pcep_utils_logging.h"
+#include "pcep_utils_memory.h"
+
+void write_tlv_header(struct pcep_object_tlv_header *tlv_hdr,
+                     uint16_t tlv_length, struct pcep_versioning *versioning,
+                     uint8_t *buf);
+void pcep_decode_tlv_hdr(const uint8_t *tlv_buf,
+                        struct pcep_object_tlv_header *tlv_hdr);
+
+/*
+ * forward declarations for initialize_tlv_encoders()
+ */
+uint16_t pcep_encode_tlv_no_path_vector(struct pcep_object_tlv_header *tlv,
+                                       struct pcep_versioning *versioning,
+                                       uint8_t *tlv_body_buf);
+uint16_t
+pcep_encode_tlv_stateful_pce_capability(struct pcep_object_tlv_header *tlv,
+                                       struct pcep_versioning *versioning,
+                                       uint8_t *tlv_body_buf);
+uint16_t pcep_encode_tlv_symbolic_path_name(struct pcep_object_tlv_header *tlv,
+                                           struct pcep_versioning *versioning,
+                                           uint8_t *tlv_body_buf);
+uint16_t
+pcep_encode_tlv_ipv4_lsp_identifiers(struct pcep_object_tlv_header *tlv,
+                                    struct pcep_versioning *versioning,
+                                    uint8_t *tlv_body_buf);
+uint16_t
+pcep_encode_tlv_ipv6_lsp_identifiers(struct pcep_object_tlv_header *tlv,
+                                    struct pcep_versioning *versioning,
+                                    uint8_t *tlv_body_buf);
+uint16_t pcep_encode_tlv_lsp_error_code(struct pcep_object_tlv_header *tlv,
+                                       struct pcep_versioning *versioning,
+                                       uint8_t *tlv_body_buf);
+uint16_t pcep_encode_tlv_rsvp_error_spec(struct pcep_object_tlv_header *tlv,
+                                        struct pcep_versioning *versioning,
+                                        uint8_t *tlv_body_buf);
+uint16_t pcep_encode_tlv_lsp_db_version(struct pcep_object_tlv_header *tlv,
+                                       struct pcep_versioning *versioning,
+                                       uint8_t *tlv_body_buf);
+uint16_t pcep_encode_tlv_speaker_entity_id(struct pcep_object_tlv_header *tlv,
+                                          struct pcep_versioning *versioning,
+                                          uint8_t *tlv_body_buf);
+uint16_t pcep_encode_tlv_sr_pce_capability(struct pcep_object_tlv_header *tlv,
+                                          struct pcep_versioning *versioning,
+                                          uint8_t *tlv_body_buf);
+uint16_t pcep_encode_tlv_path_setup_type(struct pcep_object_tlv_header *tlv,
+                                        struct pcep_versioning *versioning,
+                                        uint8_t *tlv_body_buf);
+uint16_t
+pcep_encode_tlv_path_setup_type_capability(struct pcep_object_tlv_header *tlv,
+                                          struct pcep_versioning *versioning,
+                                          uint8_t *tlv_body_buf);
+uint16_t pcep_encode_tlv_pol_id(struct pcep_object_tlv_header *tlv,
+                               struct pcep_versioning *versioning,
+                               uint8_t *tlv_body_buf);
+uint16_t pcep_encode_tlv_pol_name(struct pcep_object_tlv_header *tlv,
+                                 struct pcep_versioning *versioning,
+                                 uint8_t *tlv_body_buf);
+uint16_t pcep_encode_tlv_cpath_id(struct pcep_object_tlv_header *tlv,
+                                 struct pcep_versioning *versioning,
+                                 uint8_t *tlv_body_buf);
+uint16_t pcep_encode_tlv_cpath_preference(struct pcep_object_tlv_header *tlv,
+                                         struct pcep_versioning *versioning,
+                                         uint8_t *tlv_body_buf);
+uint16_t pcep_encode_tlv_vendor_info(struct pcep_object_tlv_header *tlv,
+                                    struct pcep_versioning *versioning,
+                                    uint8_t *tlv_body_buf);
+uint16_t pcep_encode_tlv_arbitrary(struct pcep_object_tlv_header *tlv,
+                                  struct pcep_versioning *versioning,
+                                  uint8_t *tlv_body_buf);
+uint16_t pcep_encode_tlv_of_list(struct pcep_object_tlv_header *tlv,
+                                struct pcep_versioning *versioning,
+                                uint8_t *tlv_body_buf);
+typedef uint16_t (*tlv_encoder_funcptr)(struct pcep_object_tlv_header *,
+                                       struct pcep_versioning *versioning,
+                                       uint8_t *tlv_body_buf);
+
+#define MAX_TLV_ENCODER_INDEX 65533 + 1 // 65
+
+#define PCEP_TLV_ENCODERS_ARGS                                                 \
+       struct pcep_object_tlv_header *, struct pcep_versioning *versioning,   \
+               uint8_t *tlv_body_buf
+uint16_t (*const tlv_encoders[MAX_TLV_ENCODER_INDEX])(
+       PCEP_TLV_ENCODERS_ARGS) = {
+       [PCEP_OBJ_TLV_TYPE_NO_PATH_VECTOR] = pcep_encode_tlv_no_path_vector,
+       [PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY] =
+               pcep_encode_tlv_stateful_pce_capability,
+       [PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME] =
+               pcep_encode_tlv_symbolic_path_name,
+       [PCEP_OBJ_TLV_TYPE_IPV4_LSP_IDENTIFIERS] =
+               pcep_encode_tlv_ipv4_lsp_identifiers,
+       [PCEP_OBJ_TLV_TYPE_IPV6_LSP_IDENTIFIERS] =
+               pcep_encode_tlv_ipv6_lsp_identifiers,
+       [PCEP_OBJ_TLV_TYPE_LSP_ERROR_CODE] = pcep_encode_tlv_lsp_error_code,
+       [PCEP_OBJ_TLV_TYPE_RSVP_ERROR_SPEC] = pcep_encode_tlv_rsvp_error_spec,
+       [PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION] = pcep_encode_tlv_lsp_db_version,
+       [PCEP_OBJ_TLV_TYPE_SPEAKER_ENTITY_ID] =
+               pcep_encode_tlv_speaker_entity_id,
+       [PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY] =
+               pcep_encode_tlv_sr_pce_capability,
+       [PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE] = pcep_encode_tlv_path_setup_type,
+       [PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY] =
+               pcep_encode_tlv_path_setup_type_capability,
+       [PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_ID] = pcep_encode_tlv_pol_id,
+       [PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_NAME] = pcep_encode_tlv_pol_name,
+       [PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_ID] = pcep_encode_tlv_cpath_id,
+       [PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_PREFERENCE] =
+               pcep_encode_tlv_cpath_preference,
+       [PCEP_OBJ_TLV_TYPE_VENDOR_INFO] = pcep_encode_tlv_vendor_info,
+       [PCEP_OBJ_TLV_TYPE_ARBITRARY] = pcep_encode_tlv_arbitrary,
+       [PCEP_OBJ_TLV_TYPE_OBJECTIVE_FUNCTION_LIST] = pcep_encode_tlv_of_list,
+};
+/*
+ * forward declarations for initialize_tlv_decoders()
+ */
+struct pcep_object_tlv_header *
+pcep_decode_tlv_no_path_vector(struct pcep_object_tlv_header *tlv_hdr,
+                              const uint8_t *tlv_body_buf);
+struct pcep_object_tlv_header *
+pcep_decode_tlv_stateful_pce_capability(struct pcep_object_tlv_header *tlv_hdr,
+                                       const uint8_t *tlv_body_buf);
+struct pcep_object_tlv_header *
+pcep_decode_tlv_symbolic_path_name(struct pcep_object_tlv_header *tlv_hdr,
+                                  const uint8_t *tlv_body_buf);
+struct pcep_object_tlv_header *
+pcep_decode_tlv_ipv4_lsp_identifiers(struct pcep_object_tlv_header *tlv_hdr,
+                                    const uint8_t *tlv_body_buf);
+struct pcep_object_tlv_header *
+pcep_decode_tlv_ipv6_lsp_identifiers(struct pcep_object_tlv_header *tlv_hdr,
+                                    const uint8_t *tlv_body_buf);
+struct pcep_object_tlv_header *
+pcep_decode_tlv_lsp_error_code(struct pcep_object_tlv_header *tlv_hdr,
+                              const uint8_t *tlv_body_buf);
+struct pcep_object_tlv_header *
+pcep_decode_tlv_rsvp_error_spec(struct pcep_object_tlv_header *tlv_hdr,
+                               const uint8_t *tlv_body_buf);
+struct pcep_object_tlv_header *
+pcep_decode_tlv_lsp_db_version(struct pcep_object_tlv_header *tlv_hdr,
+                              const uint8_t *tlv_body_buf);
+struct pcep_object_tlv_header *
+pcep_decode_tlv_speaker_entity_id(struct pcep_object_tlv_header *tlv_hdr,
+                                 const uint8_t *tlv_body_buf);
+struct pcep_object_tlv_header *
+pcep_decode_tlv_sr_pce_capability(struct pcep_object_tlv_header *tlv_hdr,
+                                 const uint8_t *tlv_body_buf);
+struct pcep_object_tlv_header *
+pcep_decode_tlv_path_setup_type(struct pcep_object_tlv_header *tlv_hdr,
+                               const uint8_t *tlv_body_buf);
+struct pcep_object_tlv_header *pcep_decode_tlv_path_setup_type_capability(
+       struct pcep_object_tlv_header *tlv_hdr, const uint8_t *tlv_body_buf);
+struct pcep_object_tlv_header *
+pcep_decode_tlv_pol_id(struct pcep_object_tlv_header *tlv_hdr,
+                      const uint8_t *tlv_body_buf);
+struct pcep_object_tlv_header *
+pcep_decode_tlv_pol_name(struct pcep_object_tlv_header *tlv_hdr,
+                        const uint8_t *tlv_body_buf);
+struct pcep_object_tlv_header *
+pcep_decode_tlv_cpath_id(struct pcep_object_tlv_header *tlv_hdr,
+                        const uint8_t *tlv_body_buf);
+struct pcep_object_tlv_header *
+pcep_decode_tlv_cpath_preference(struct pcep_object_tlv_header *tlv_hdr,
+                                const uint8_t *tlv_body_buf);
+struct pcep_object_tlv_header *
+pcep_decode_tlv_vendor_info(struct pcep_object_tlv_header *tlv_hdr,
+                           const uint8_t *tlv_body_buf);
+struct pcep_object_tlv_header *
+pcep_decode_tlv_arbitrary(struct pcep_object_tlv_header *tlv_hdr,
+                         const uint8_t *tlv_body_buf);
+struct pcep_object_tlv_header *
+pcep_decode_tlv_of_list(struct pcep_object_tlv_header *tlv_hdr,
+                       const uint8_t *tlv_body_buf);
+typedef struct pcep_object_tlv_header *(*tlv_decoder_funcptr)(
+       struct pcep_object_tlv_header *tlv_hdr, const uint8_t *tlv_body_buf);
+
+// tlv_decoder_funcptr tlv_decoders[MAX_TLV_ENCODER_INDEX];
+
+#define PCEP_TLV_DECODERS_ARGS                                                 \
+       struct pcep_object_tlv_header *tlv_hdr, const uint8_t *tlv_body_buf
+
+struct pcep_object_tlv_header *(*const tlv_decoders[MAX_TLV_ENCODER_INDEX])(
+       PCEP_TLV_DECODERS_ARGS) = {
+       [PCEP_OBJ_TLV_TYPE_NO_PATH_VECTOR] = pcep_decode_tlv_no_path_vector,
+       [PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY] =
+               pcep_decode_tlv_stateful_pce_capability,
+       [PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME] =
+               pcep_decode_tlv_symbolic_path_name,
+       [PCEP_OBJ_TLV_TYPE_IPV4_LSP_IDENTIFIERS] =
+               pcep_decode_tlv_ipv4_lsp_identifiers,
+       [PCEP_OBJ_TLV_TYPE_IPV6_LSP_IDENTIFIERS] =
+               pcep_decode_tlv_ipv6_lsp_identifiers,
+       [PCEP_OBJ_TLV_TYPE_LSP_ERROR_CODE] = pcep_decode_tlv_lsp_error_code,
+       [PCEP_OBJ_TLV_TYPE_RSVP_ERROR_SPEC] = pcep_decode_tlv_rsvp_error_spec,
+       [PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION] = pcep_decode_tlv_lsp_db_version,
+       [PCEP_OBJ_TLV_TYPE_SPEAKER_ENTITY_ID] =
+               pcep_decode_tlv_speaker_entity_id,
+       [PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY] =
+               pcep_decode_tlv_sr_pce_capability,
+       [PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE] = pcep_decode_tlv_path_setup_type,
+       [PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY] =
+               pcep_decode_tlv_path_setup_type_capability,
+       [PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_ID] = pcep_decode_tlv_pol_id,
+       [PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_NAME] = pcep_decode_tlv_pol_name,
+       [PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_ID] = pcep_decode_tlv_cpath_id,
+       [PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_PREFERENCE] =
+               pcep_decode_tlv_cpath_preference,
+       [PCEP_OBJ_TLV_TYPE_VENDOR_INFO] = pcep_decode_tlv_vendor_info,
+       [PCEP_OBJ_TLV_TYPE_ARBITRARY] = pcep_decode_tlv_arbitrary,
+       [PCEP_OBJ_TLV_TYPE_OBJECTIVE_FUNCTION_LIST] = pcep_decode_tlv_of_list,
+};
+
+static void initialize_tlv_coders()
+{
+       static bool initialized = false;
+
+       if (initialized == true) {
+               return;
+       }
+
+       initialized = true;
+
+       /* Encoders */
+       /*
+       memset(tlv_encoders, 0, sizeof(tlv_encoder_funcptr) *
+       MAX_TLV_ENCODER_INDEX); tlv_encoders[PCEP_OBJ_TLV_TYPE_NO_PATH_VECTOR] =
+       pcep_encode_tlv_no_path_vector;
+       tlv_encoders[PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY]     =
+       pcep_encode_tlv_stateful_pce_capability;
+       tlv_encoders[PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME]          =
+       pcep_encode_tlv_symbolic_path_name;
+       tlv_encoders[PCEP_OBJ_TLV_TYPE_IPV4_LSP_IDENTIFIERS]        =
+       pcep_encode_tlv_ipv4_lsp_identifiers;
+       tlv_encoders[PCEP_OBJ_TLV_TYPE_IPV6_LSP_IDENTIFIERS]        =
+       pcep_encode_tlv_ipv6_lsp_identifiers;
+       tlv_encoders[PCEP_OBJ_TLV_TYPE_LSP_ERROR_CODE]              =
+       pcep_encode_tlv_lsp_error_code;
+       tlv_encoders[PCEP_OBJ_TLV_TYPE_RSVP_ERROR_SPEC]             =
+       pcep_encode_tlv_rsvp_error_spec;
+       tlv_encoders[PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION]              =
+       pcep_encode_tlv_lsp_db_version;
+       tlv_encoders[PCEP_OBJ_TLV_TYPE_SPEAKER_ENTITY_ID]           =
+       pcep_encode_tlv_speaker_entity_id;
+       tlv_encoders[PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY]           =
+       pcep_encode_tlv_sr_pce_capability;
+       tlv_encoders[PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE]             =
+       pcep_encode_tlv_path_setup_type;
+       tlv_encoders[PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY]  =
+       pcep_encode_tlv_path_setup_type_capability;
+       tlv_encoders[PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_ID]             =
+       pcep_encode_tlv_pol_id;
+       tlv_encoders[PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_NAME] =
+       pcep_encode_tlv_pol_name;
+       tlv_encoders[PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_ID] =
+       pcep_encode_tlv_cpath_id;
+       tlv_encoders[PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_PREFERENCE]   =
+       pcep_encode_tlv_cpath_preference;
+       tlv_encoders[PCEP_OBJ_TLV_TYPE_VENDOR_INFO]                 =
+       pcep_encode_tlv_vendor_info; tlv_encoders[PCEP_OBJ_TLV_TYPE_ARBITRARY] =
+       pcep_encode_tlv_arbitrary;
+       tlv_encoders[PCEP_OBJ_TLV_TYPE_OBJECTIVE_FUNCTION_LIST]     =
+       pcep_encode_tlv_of_list;
+       */
+
+       /* Decoders */
+       /*
+       memset(tlv_decoders, 0, sizeof(tlv_decoder_funcptr) *
+       MAX_TLV_ENCODER_INDEX); tlv_decoders[PCEP_OBJ_TLV_TYPE_NO_PATH_VECTOR] =
+       pcep_decode_tlv_no_path_vector;
+       tlv_decoders[PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY]     =
+       pcep_decode_tlv_stateful_pce_capability;
+       tlv_decoders[PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME]          =
+       pcep_decode_tlv_symbolic_path_name;
+       tlv_decoders[PCEP_OBJ_TLV_TYPE_IPV4_LSP_IDENTIFIERS]        =
+       pcep_decode_tlv_ipv4_lsp_identifiers;
+       tlv_decoders[PCEP_OBJ_TLV_TYPE_IPV6_LSP_IDENTIFIERS]        =
+       pcep_decode_tlv_ipv6_lsp_identifiers;
+       tlv_decoders[PCEP_OBJ_TLV_TYPE_LSP_ERROR_CODE]              =
+       pcep_decode_tlv_lsp_error_code;
+       tlv_decoders[PCEP_OBJ_TLV_TYPE_RSVP_ERROR_SPEC]             =
+       pcep_decode_tlv_rsvp_error_spec;
+       tlv_decoders[PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION]              =
+       pcep_decode_tlv_lsp_db_version;
+       tlv_decoders[PCEP_OBJ_TLV_TYPE_SPEAKER_ENTITY_ID]           =
+       pcep_decode_tlv_speaker_entity_id;
+       tlv_decoders[PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY]           =
+       pcep_decode_tlv_sr_pce_capability;
+       tlv_decoders[PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE]             =
+       pcep_decode_tlv_path_setup_type;
+       tlv_decoders[PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY]  =
+       pcep_decode_tlv_path_setup_type_capability;
+       tlv_decoders[PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_ID]             =
+       pcep_decode_tlv_pol_id;
+       tlv_decoders[PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_NAME] =
+       pcep_decode_tlv_pol_name;
+       tlv_decoders[PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_ID] =
+       pcep_decode_tlv_cpath_id;
+       tlv_decoders[PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_PREFERENCE]   =
+       pcep_decode_tlv_cpath_preference;
+       tlv_decoders[PCEP_OBJ_TLV_TYPE_VENDOR_INFO]                 =
+       pcep_decode_tlv_vendor_info; tlv_decoders[PCEP_OBJ_TLV_TYPE_ARBITRARY] =
+       pcep_decode_tlv_arbitrary;
+       tlv_decoders[PCEP_OBJ_TLV_TYPE_OBJECTIVE_FUNCTION_LIST]     =
+       pcep_decode_tlv_of_list;
+       */
+}
+
+uint16_t pcep_encode_tlv(struct pcep_object_tlv_header *tlv_hdr,
+                        struct pcep_versioning *versioning, uint8_t *buf)
+{
+       initialize_tlv_coders();
+
+       if (tlv_hdr->type >= MAX_TLV_ENCODER_INDEX) {
+               pcep_log(LOG_INFO,
+                        "%s: Cannot encode unknown Object class [%d]",
+                        __func__, tlv_hdr->type);
+               return 0;
+       }
+
+       tlv_encoder_funcptr tlv_encoder = tlv_encoders[tlv_hdr->type];
+       if (tlv_encoder == NULL) {
+               pcep_log(LOG_INFO,
+                        "%s: No object encoder found for Object class [%d]",
+                        __func__, tlv_hdr->type);
+               return 0;
+       }
+
+       /* Notice: The length in the TLV header does not include the TLV header,
+        * so the length returned from the tlv_encoder() is only the TLV body.
+        */
+       uint16_t tlv_length =
+               tlv_encoder(tlv_hdr, versioning, buf + TLV_HEADER_LENGTH);
+       write_tlv_header(tlv_hdr, tlv_length, versioning, buf);
+       tlv_hdr->encoded_tlv = buf;
+       tlv_hdr->encoded_tlv_length = tlv_length;
+
+       return normalize_pcep_tlv_length(tlv_length + TLV_HEADER_LENGTH);
+}
+
+/* TLV Header format
+ *
+ * 0                   1                   2                   3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |         Type (2 bytes)        |         Length (2 bytes)      |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                         Value (Variable)                      |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+void write_tlv_header(struct pcep_object_tlv_header *tlv_hdr,
+                     uint16_t tlv_length, struct pcep_versioning *versioning,
+                     uint8_t *buf)
+{
+       (void)versioning;
+       uint16_t *uint16_ptr = (uint16_t *)buf;
+       uint16_ptr[0] = htons(tlv_hdr->type);
+       uint16_ptr[1] = htons(tlv_length);
+}
+
+/*
+ * Functions to encode TLVs
+ */
+
+uint16_t pcep_encode_tlv_no_path_vector(struct pcep_object_tlv_header *tlv,
+                                       struct pcep_versioning *versioning,
+                                       uint8_t *tlv_body_buf)
+{
+       (void)versioning;
+       struct pcep_object_tlv_nopath_vector *nopath_tlv =
+               (struct pcep_object_tlv_nopath_vector *)tlv;
+       uint32_t *uint32_ptr = (uint32_t *)tlv_body_buf;
+       *uint32_ptr = htonl(nopath_tlv->error_code);
+
+       return LENGTH_1WORD;
+}
+
+uint16_t
+pcep_encode_tlv_stateful_pce_capability(struct pcep_object_tlv_header *tlv,
+                                       struct pcep_versioning *versioning,
+                                       uint8_t *tlv_body_buf)
+{
+       (void)versioning;
+       struct pcep_object_tlv_stateful_pce_capability *spc_tlv =
+               (struct pcep_object_tlv_stateful_pce_capability *)tlv;
+       tlv_body_buf[3] =
+               ((spc_tlv->flag_f_triggered_initial_sync == true
+                         ? TLV_STATEFUL_PCE_CAP_FLAG_F
+                         : 0x00)
+                | (spc_tlv->flag_d_delta_lsp_sync == true
+                           ? TLV_STATEFUL_PCE_CAP_FLAG_D
+                           : 0x00)
+                | (spc_tlv->flag_t_triggered_resync == true
+                           ? TLV_STATEFUL_PCE_CAP_FLAG_T
+                           : 0x00)
+                | (spc_tlv->flag_i_lsp_instantiation_capability == true
+                           ? TLV_STATEFUL_PCE_CAP_FLAG_I
+                           : 0x00)
+                | (spc_tlv->flag_s_include_db_version == true
+                           ? TLV_STATEFUL_PCE_CAP_FLAG_S
+                           : 0x00)
+                | (spc_tlv->flag_u_lsp_update_capability == true
+                           ? TLV_STATEFUL_PCE_CAP_FLAG_U
+                           : 0x00));
+
+       return LENGTH_1WORD;
+}
+
+uint16_t pcep_encode_tlv_symbolic_path_name(struct pcep_object_tlv_header *tlv,
+                                           struct pcep_versioning *versioning,
+                                           uint8_t *tlv_body_buf)
+{
+       (void)versioning;
+       struct pcep_object_tlv_symbolic_path_name *spn_tlv =
+               (struct pcep_object_tlv_symbolic_path_name *)tlv;
+       memcpy(tlv_body_buf, spn_tlv->symbolic_path_name,
+              spn_tlv->symbolic_path_name_length);
+
+       return spn_tlv->symbolic_path_name_length;
+}
+
+uint16_t
+pcep_encode_tlv_ipv4_lsp_identifiers(struct pcep_object_tlv_header *tlv,
+                                    struct pcep_versioning *versioning,
+                                    uint8_t *tlv_body_buf)
+{
+       (void)versioning;
+       struct pcep_object_tlv_ipv4_lsp_identifier *ipv4_lsp =
+               (struct pcep_object_tlv_ipv4_lsp_identifier *)tlv;
+       uint32_t *uint32_ptr = (uint32_t *)tlv_body_buf;
+       uint32_ptr[0] = ipv4_lsp->ipv4_tunnel_sender.s_addr;
+       /* uint32_t[1] is lsp_id and tunnel_id, below */
+       uint32_ptr[2] = ipv4_lsp->extended_tunnel_id.s_addr;
+       uint32_ptr[3] = ipv4_lsp->ipv4_tunnel_endpoint.s_addr;
+
+       uint16_t *uint16_ptr = (uint16_t *)(tlv_body_buf + LENGTH_1WORD);
+       uint16_ptr[0] = htons(ipv4_lsp->lsp_id);
+       uint16_ptr[1] = htons(ipv4_lsp->tunnel_id);
+
+       return LENGTH_4WORDS;
+}
+
+uint16_t
+pcep_encode_tlv_ipv6_lsp_identifiers(struct pcep_object_tlv_header *tlv,
+                                    struct pcep_versioning *versioning,
+                                    uint8_t *tlv_body_buf)
+{
+       (void)versioning;
+       struct pcep_object_tlv_ipv6_lsp_identifier *ipv6_lsp =
+               (struct pcep_object_tlv_ipv6_lsp_identifier *)tlv;
+       uint32_t *uint32_ptr = (uint32_t *)tlv_body_buf;
+       encode_ipv6(&ipv6_lsp->ipv6_tunnel_sender, uint32_ptr);
+       encode_ipv6(&ipv6_lsp->extended_tunnel_id, uint32_ptr + 5);
+       encode_ipv6(&ipv6_lsp->ipv6_tunnel_endpoint, uint32_ptr + 9);
+
+       uint16_t *uint16_ptr = (uint16_t *)(tlv_body_buf + LENGTH_4WORDS);
+       uint16_ptr[0] = htons(ipv6_lsp->lsp_id);
+       uint16_ptr[1] = htons(ipv6_lsp->tunnel_id);
+
+       return LENGTH_13WORDS;
+}
+
+uint16_t pcep_encode_tlv_lsp_error_code(struct pcep_object_tlv_header *tlv,
+                                       struct pcep_versioning *versioning,
+                                       uint8_t *tlv_body_buf)
+{
+       (void)versioning;
+       struct pcep_object_tlv_lsp_error_code *lsp_error_tlv =
+               (struct pcep_object_tlv_lsp_error_code *)tlv;
+       uint32_t *uint32_ptr = (uint32_t *)tlv_body_buf;
+       *uint32_ptr = htonl(lsp_error_tlv->lsp_error_code);
+
+       return LENGTH_1WORD;
+}
+
+uint16_t pcep_encode_tlv_rsvp_error_spec(struct pcep_object_tlv_header *tlv,
+                                        struct pcep_versioning *versioning,
+                                        uint8_t *tlv_body_buf)
+{
+       /* Same decode tlv function for both types:
+          pcep_create_tlv_rsvp_ipv4_error_spec(tlv);
+          pcep_create_tlv_rsvp_ipv6_error_spec(tlv); */
+
+       /*  RSVP Object Header
+        *
+        *       0             1              2             3
+        *  +-------------+-------------+-------------+-------------+
+        *  |       Length (bytes)      |  Class-Num  |   C-Type    |
+        *  +-------------+-------------+-------------+-------------+
+        *  |                                                       |
+        *  //                  (Object contents)                   //
+        *  |                                                       |
+        *  +-------------+-------------+-------------+-------------+
+        *
+        * IPv4 ERROR_SPEC object: Class = 6, C-Type = 1
+        *  +-------------+-------------+-------------+-------------+
+        *  |            IPv4 Error Node Address (4 bytes)          |
+        *  +-------------+-------------+-------------+-------------+
+        *  |    Flags    |  Error Code |        Error Value        |
+        *  +-------------+-------------+-------------+-------------+
+        *
+        * IPv6 ERROR_SPEC object: Class = 6, C-Type = 2
+        *  +-------------+-------------+-------------+-------------+
+        *  |            IPv6 Error Node Address (16 bytes)         |
+        *  +-------------+-------------+-------------+-------------+
+        *  |    Flags    |  Error Code |        Error Value        |
+        *  +-------------+-------------+-------------+-------------+
+        */
+
+       (void)versioning;
+       struct pcep_object_tlv_rsvp_error_spec *rsvp_hdr =
+               (struct pcep_object_tlv_rsvp_error_spec *)tlv;
+       tlv_body_buf[2] = rsvp_hdr->class_num;
+       tlv_body_buf[3] = rsvp_hdr->c_type;
+
+       uint16_t *length_ptr = (uint16_t *)tlv_body_buf;
+       uint32_t *uint32_ptr = (uint32_t *)(tlv_body_buf + LENGTH_1WORD);
+       if (rsvp_hdr->c_type == RSVP_ERROR_SPEC_IPV4_CTYPE) {
+               *length_ptr = htons(LENGTH_3WORDS);
+               *uint32_ptr =
+                       rsvp_hdr->error_spec_ip.ipv4_error_node_address.s_addr;
+               tlv_body_buf[LENGTH_2WORDS + 1] = rsvp_hdr->error_code;
+               uint16_t *uint16_ptr =
+                       (uint16_t *)(tlv_body_buf + LENGTH_2WORDS + 2);
+               *uint16_ptr = htons(rsvp_hdr->error_value);
+
+               return LENGTH_3WORDS;
+       } else if (rsvp_hdr->c_type == RSVP_ERROR_SPEC_IPV6_CTYPE) {
+               *length_ptr = htons(LENGTH_6WORDS);
+               encode_ipv6(&rsvp_hdr->error_spec_ip.ipv6_error_node_address,
+                           uint32_ptr);
+               tlv_body_buf[LENGTH_5WORDS + 1] = rsvp_hdr->error_code;
+               uint16_t *uint16_ptr =
+                       (uint16_t *)(tlv_body_buf + LENGTH_5WORDS + 2);
+               *uint16_ptr = htons(rsvp_hdr->error_value);
+
+               return LENGTH_6WORDS;
+       }
+
+       return 0;
+}
+
+uint16_t pcep_encode_tlv_lsp_db_version(struct pcep_object_tlv_header *tlv,
+                                       struct pcep_versioning *versioning,
+                                       uint8_t *tlv_body_buf)
+{
+       (void)versioning;
+       struct pcep_object_tlv_lsp_db_version *lsp_db_ver =
+               (struct pcep_object_tlv_lsp_db_version *)tlv;
+       *((uint64_t *)tlv_body_buf) = htobe64(lsp_db_ver->lsp_db_version);
+
+       return LENGTH_2WORDS;
+}
+
+uint16_t pcep_encode_tlv_speaker_entity_id(struct pcep_object_tlv_header *tlv,
+                                          struct pcep_versioning *versioning,
+                                          uint8_t *tlv_body_buf)
+{
+       (void)versioning;
+       struct pcep_object_tlv_speaker_entity_identifier *speaker_id =
+               (struct pcep_object_tlv_speaker_entity_identifier *)tlv;
+       if (speaker_id->speaker_entity_id_list == NULL) {
+               return 0;
+       }
+
+       int index = 0;
+       uint32_t *uint32_ptr = (uint32_t *)tlv_body_buf;
+       double_linked_list_node *node =
+               speaker_id->speaker_entity_id_list->head;
+       for (; node != NULL; node = node->next_node) {
+               uint32_ptr[index++] = htonl(*((uint32_t *)node->data));
+       }
+
+       return speaker_id->speaker_entity_id_list->num_entries * LENGTH_1WORD;
+}
+
+uint16_t pcep_encode_tlv_sr_pce_capability(struct pcep_object_tlv_header *tlv,
+                                          struct pcep_versioning *versioning,
+                                          uint8_t *tlv_body_buf)
+{
+       (void)versioning;
+       struct pcep_object_tlv_sr_pce_capability *sr_pce_cap =
+               (struct pcep_object_tlv_sr_pce_capability *)tlv;
+       tlv_body_buf[2] =
+               ((sr_pce_cap->flag_n == true ? TLV_SR_PCE_CAP_FLAG_N : 0x00)
+                | (sr_pce_cap->flag_x == true ? TLV_SR_PCE_CAP_FLAG_X : 0x00));
+       tlv_body_buf[3] = sr_pce_cap->max_sid_depth;
+
+       return LENGTH_1WORD;
+}
+
+uint16_t pcep_encode_tlv_path_setup_type(struct pcep_object_tlv_header *tlv,
+                                        struct pcep_versioning *versioning,
+                                        uint8_t *tlv_body_buf)
+{
+       (void)versioning;
+       struct pcep_object_tlv_path_setup_type *pst =
+               (struct pcep_object_tlv_path_setup_type *)tlv;
+       tlv_body_buf[3] = pst->path_setup_type;
+
+       return LENGTH_1WORD;
+}
+
+uint16_t
+pcep_encode_tlv_path_setup_type_capability(struct pcep_object_tlv_header *tlv,
+                                          struct pcep_versioning *versioning,
+                                          uint8_t *tlv_body_buf)
+{
+       (void)versioning;
+       struct pcep_object_tlv_path_setup_type_capability *pst_cap =
+               (struct pcep_object_tlv_path_setup_type_capability *)tlv;
+       if (pst_cap->pst_list == NULL) {
+               return 0;
+       }
+
+       tlv_body_buf[3] = pst_cap->pst_list->num_entries;
+
+       /* Index past the reserved and NumPSTs fields */
+       int index = 4;
+       double_linked_list_node *node = pst_cap->pst_list->head;
+       for (; node != NULL; node = node->next_node) {
+               tlv_body_buf[index++] = *((uint8_t *)node->data);
+       }
+
+       uint16_t pst_length = normalize_pcep_tlv_length(
+               LENGTH_1WORD + pst_cap->pst_list->num_entries);
+       if (pst_cap->sub_tlv_list == NULL) {
+               return pst_length;
+       }
+
+       /* Any padding used for the PSTs should not be included in the tlv
+        * header length */
+       index = normalize_pcep_tlv_length(index);
+       uint16_t sub_tlvs_length = 0;
+       node = pst_cap->sub_tlv_list->head;
+       for (; node != NULL; node = node->next_node) {
+               struct pcep_object_tlv_header *sub_tlv =
+                       (struct pcep_object_tlv_header *)node->data;
+               uint16_t sub_tlv_length = pcep_encode_tlv(sub_tlv, versioning,
+                                                         tlv_body_buf + index);
+               index += sub_tlv_length;
+               sub_tlvs_length += sub_tlv_length;
+       }
+
+       return sub_tlvs_length + pst_length;
+}
+uint16_t pcep_encode_tlv_pol_id(struct pcep_object_tlv_header *tlv,
+                               struct pcep_versioning *versioning,
+                               uint8_t *tlv_body_buf)
+{
+       (void)versioning;
+       uint32_t *uint32_ptr = (uint32_t *)tlv_body_buf;
+       struct pcep_object_tlv_srpag_pol_id *ipv4 =
+               (struct pcep_object_tlv_srpag_pol_id *)tlv;
+       if (ipv4->is_ipv4) {
+               uint32_ptr[0] = htonl(ipv4->color);
+               uint32_ptr[1] = ipv4->end_point.ipv4.s_addr;
+               return LENGTH_2WORDS;
+       } else {
+               struct pcep_object_tlv_srpag_pol_id *ipv6 =
+                       (struct pcep_object_tlv_srpag_pol_id *)tlv;
+               uint32_ptr[0] = htonl(ipv6->color);
+               encode_ipv6(&ipv6->end_point.ipv6, &uint32_ptr[1]);
+               return LENGTH_5WORDS;
+       }
+}
+
+uint16_t pcep_encode_tlv_pol_name(struct pcep_object_tlv_header *tlv,
+                                 struct pcep_versioning *versioning,
+                                 uint8_t *tlv_body_buf)
+{
+       (void)versioning;
+       struct pcep_object_tlv_srpag_pol_name *pol_name_tlv =
+               (struct pcep_object_tlv_srpag_pol_name *)tlv;
+       memcpy(tlv_body_buf, pol_name_tlv->name, pol_name_tlv->name_length);
+
+       return normalize_pcep_tlv_length(pol_name_tlv->name_length);
+}
+
+uint16_t pcep_encode_tlv_cpath_id(struct pcep_object_tlv_header *tlv,
+                                 struct pcep_versioning *versioning,
+                                 uint8_t *tlv_body_buf)
+{
+       (void)versioning;
+       struct pcep_object_tlv_srpag_cp_id *cpath_id_tlv =
+               (struct pcep_object_tlv_srpag_cp_id *)tlv;
+
+       uint32_t *uint32_ptr = (uint32_t *)tlv_body_buf;
+       tlv_body_buf[0] = cpath_id_tlv->proto;
+       uint32_ptr[1] = htonl(cpath_id_tlv->orig_asn);
+       encode_ipv6(&cpath_id_tlv->orig_addres, &uint32_ptr[2]);
+       uint32_ptr[6] = htonl(cpath_id_tlv->discriminator);
+
+       return sizeof(cpath_id_tlv->proto) + sizeof(cpath_id_tlv->orig_asn)
+              + sizeof(cpath_id_tlv->orig_addres)
+              + sizeof(cpath_id_tlv->discriminator);
+}
+
+uint16_t pcep_encode_tlv_cpath_preference(struct pcep_object_tlv_header *tlv,
+                                         struct pcep_versioning *versioning,
+                                         uint8_t *tlv_body_buf)
+{
+       (void)versioning;
+       struct pcep_object_tlv_srpag_cp_pref *cpath_pref_tlv =
+               (struct pcep_object_tlv_srpag_cp_pref *)tlv;
+
+       uint32_t *uint32_ptr = (uint32_t *)tlv_body_buf;
+       uint32_ptr[0] = htonl(cpath_pref_tlv->preference);
+
+       return sizeof(cpath_pref_tlv->preference);
+}
+
+uint16_t pcep_encode_tlv_vendor_info(struct pcep_object_tlv_header *tlv,
+                                    struct pcep_versioning *versioning,
+                                    uint8_t *tlv_body_buf)
+{
+       (void)versioning;
+       struct pcep_object_tlv_vendor_info *vendor_info =
+               (struct pcep_object_tlv_vendor_info *)tlv;
+
+       uint32_t *uint32_ptr = (uint32_t *)tlv_body_buf;
+       uint32_ptr[0] = htonl(vendor_info->enterprise_number);
+       uint32_ptr[1] = htonl(vendor_info->enterprise_specific_info);
+
+       return LENGTH_2WORDS;
+}
+
+uint16_t pcep_encode_tlv_arbitrary(struct pcep_object_tlv_header *tlv,
+                                  struct pcep_versioning *versioning,
+                                  uint8_t *tlv_body_buf)
+{
+       (void)versioning;
+       struct pcep_object_tlv_arbitrary *tlv_arbitrary =
+               (struct pcep_object_tlv_arbitrary *)tlv;
+       memcpy(tlv_body_buf, tlv_arbitrary->data, tlv_arbitrary->data_length);
+       tlv->type = tlv_arbitrary->arbitraty_type;
+
+       return tlv_arbitrary->data_length;
+}
+
+uint16_t pcep_encode_tlv_of_list(struct pcep_object_tlv_header *tlv,
+                                struct pcep_versioning *versioning,
+                                uint8_t *tlv_body_buf)
+{
+       (void)versioning;
+       struct pcep_object_tlv_of_list *of_list =
+               (struct pcep_object_tlv_of_list *)tlv;
+
+       if (of_list->of_list == NULL) {
+               return 0;
+       }
+
+       int index = 0;
+       double_linked_list_node *node = of_list->of_list->head;
+       while (node != NULL) {
+               uint16_t *of_code = (uint16_t *)node->data;
+               if (of_code == NULL) {
+                       return 0;
+               }
+
+               uint16_t *uint16_ptr = (uint16_t *)(tlv_body_buf + index);
+               *uint16_ptr = *of_code;
+               index += 2;
+
+               node = node->next_node;
+       }
+
+       return of_list->of_list->num_entries * 2;
+}
+
+/*
+ * Decoding functions
+ */
+
+void pcep_decode_tlv_hdr(const uint8_t *tlv_buf,
+                        struct pcep_object_tlv_header *tlv_hdr)
+{
+       memset(tlv_hdr, 0, sizeof(struct pcep_object_tlv_header));
+
+       uint16_t *uint16_ptr = (uint16_t *)tlv_buf;
+       tlv_hdr->type = ntohs(uint16_ptr[0]);
+       tlv_hdr->encoded_tlv_length = ntohs(uint16_ptr[1]);
+       tlv_hdr->encoded_tlv = tlv_buf;
+}
+
+struct pcep_object_tlv_header *pcep_decode_tlv(const uint8_t *tlv_buf)
+{
+       initialize_tlv_coders();
+
+       struct pcep_object_tlv_header tlv_hdr;
+       /* Only initializes and decodes the Object Header: class, type, flags,
+        * and length */
+       pcep_decode_tlv_hdr(tlv_buf, &tlv_hdr);
+
+       if (tlv_hdr.type >= MAX_TLV_ENCODER_INDEX) {
+               pcep_log(LOG_INFO, "%s: Cannot decode unknown TLV type [%d]",
+                        __func__, tlv_hdr.type);
+               return NULL;
+       }
+
+       tlv_decoder_funcptr tlv_decoder = tlv_decoders[tlv_hdr.type];
+       if (tlv_decoder == NULL) {
+               pcep_log(LOG_INFO, "%s: No TLV decoder found for TLV type [%d]",
+                        __func__, tlv_hdr.type);
+               return NULL;
+       }
+
+       return tlv_decoder(&tlv_hdr, tlv_buf + LENGTH_1WORD);
+}
+
+static struct pcep_object_tlv_header *
+common_tlv_create(struct pcep_object_tlv_header *hdr, uint16_t new_tlv_length)
+{
+       struct pcep_object_tlv_header *new_tlv =
+               pceplib_malloc(PCEPLIB_MESSAGES, new_tlv_length);
+       memset(new_tlv, 0, new_tlv_length);
+       memcpy(new_tlv, hdr, sizeof(struct pcep_object_tlv_header));
+
+       return new_tlv;
+}
+
+struct pcep_object_tlv_header *
+pcep_decode_tlv_no_path_vector(struct pcep_object_tlv_header *tlv_hdr,
+                              const uint8_t *tlv_body_buf)
+{
+       struct pcep_object_tlv_nopath_vector *tlv =
+               (struct pcep_object_tlv_nopath_vector *)common_tlv_create(
+                       tlv_hdr, sizeof(struct pcep_object_tlv_nopath_vector));
+
+       tlv->error_code = ntohl(*((uint32_t *)tlv_body_buf));
+
+       return (struct pcep_object_tlv_header *)tlv;
+}
+
+struct pcep_object_tlv_header *
+pcep_decode_tlv_stateful_pce_capability(struct pcep_object_tlv_header *tlv_hdr,
+                                       const uint8_t *tlv_body_buf)
+{
+       struct pcep_object_tlv_stateful_pce_capability *tlv =
+               (struct pcep_object_tlv_stateful_pce_capability *)
+                       common_tlv_create(
+                               tlv_hdr,
+                               sizeof(struct
+                                      pcep_object_tlv_stateful_pce_capability));
+
+       tlv->flag_f_triggered_initial_sync =
+               (tlv_body_buf[3] & TLV_STATEFUL_PCE_CAP_FLAG_F);
+       tlv->flag_d_delta_lsp_sync =
+               (tlv_body_buf[3] & TLV_STATEFUL_PCE_CAP_FLAG_D);
+       tlv->flag_t_triggered_resync =
+               (tlv_body_buf[3] & TLV_STATEFUL_PCE_CAP_FLAG_T);
+       tlv->flag_i_lsp_instantiation_capability =
+               (tlv_body_buf[3] & TLV_STATEFUL_PCE_CAP_FLAG_I);
+       tlv->flag_s_include_db_version =
+               (tlv_body_buf[3] & TLV_STATEFUL_PCE_CAP_FLAG_S);
+       tlv->flag_u_lsp_update_capability =
+               (tlv_body_buf[3] & TLV_STATEFUL_PCE_CAP_FLAG_U);
+
+       return (struct pcep_object_tlv_header *)tlv;
+}
+
+struct pcep_object_tlv_header *
+pcep_decode_tlv_symbolic_path_name(struct pcep_object_tlv_header *tlv_hdr,
+                                  const uint8_t *tlv_body_buf)
+{
+       struct pcep_object_tlv_symbolic_path_name *tlv =
+               (struct pcep_object_tlv_symbolic_path_name *)common_tlv_create(
+                       tlv_hdr,
+                       sizeof(struct pcep_object_tlv_symbolic_path_name));
+
+       uint16_t length = tlv_hdr->encoded_tlv_length;
+       if (length > MAX_SYMBOLIC_PATH_NAME) {
+               /* TODO should we also reset the tlv_hdr->encoded_tlv_length ?
+                */
+               length = MAX_SYMBOLIC_PATH_NAME;
+               pcep_log(
+                       LOG_INFO,
+                       "%s: Decoding Symbolic Path Name TLV, truncate path name from [%d] to [%d].\",",
+                       __func__, tlv_hdr->encoded_tlv_length,
+                       MAX_SYMBOLIC_PATH_NAME);
+       }
+
+       tlv->symbolic_path_name_length = length;
+       memcpy(tlv->symbolic_path_name, tlv_body_buf, length);
+
+       return (struct pcep_object_tlv_header *)tlv;
+}
+
+struct pcep_object_tlv_header *
+pcep_decode_tlv_ipv4_lsp_identifiers(struct pcep_object_tlv_header *tlv_hdr,
+                                    const uint8_t *tlv_body_buf)
+{
+       struct pcep_object_tlv_ipv4_lsp_identifier *tlv =
+               (struct pcep_object_tlv_ipv4_lsp_identifier *)common_tlv_create(
+                       tlv_hdr,
+                       sizeof(struct pcep_object_tlv_ipv4_lsp_identifier));
+
+       uint32_t *uint32_ptr = (uint32_t *)tlv_body_buf;
+       tlv->ipv4_tunnel_sender.s_addr = uint32_ptr[0];
+       /* uint32_t[1] is lsp_id and tunnel_id, below */
+       tlv->extended_tunnel_id.s_addr = uint32_ptr[2];
+       tlv->ipv4_tunnel_endpoint.s_addr = uint32_ptr[3];
+
+       uint16_t *uint16_ptr = (uint16_t *)(tlv_body_buf + LENGTH_1WORD);
+       tlv->lsp_id = ntohs(uint16_ptr[0]);
+       tlv->tunnel_id = ntohs(uint16_ptr[1]);
+
+       return (struct pcep_object_tlv_header *)tlv;
+}
+
+struct pcep_object_tlv_header *
+pcep_decode_tlv_ipv6_lsp_identifiers(struct pcep_object_tlv_header *tlv_hdr,
+                                    const uint8_t *tlv_body_buf)
+{
+       struct pcep_object_tlv_ipv6_lsp_identifier *tlv =
+               (struct pcep_object_tlv_ipv6_lsp_identifier *)common_tlv_create(
+                       tlv_hdr,
+                       sizeof(struct pcep_object_tlv_ipv6_lsp_identifier));
+
+       uint32_t *uint32_ptr = (uint32_t *)tlv_body_buf;
+       decode_ipv6(uint32_ptr, &tlv->ipv6_tunnel_sender);
+       decode_ipv6(uint32_ptr + 5, &tlv->extended_tunnel_id);
+       decode_ipv6(uint32_ptr + 9, &tlv->ipv6_tunnel_endpoint);
+
+       uint16_t *uint16_ptr = (uint16_t *)(tlv_body_buf + LENGTH_4WORDS);
+       tlv->lsp_id = htons(uint16_ptr[0]);
+       tlv->tunnel_id = htons(uint16_ptr[1]);
+
+       return (struct pcep_object_tlv_header *)tlv;
+}
+
+struct pcep_object_tlv_header *
+pcep_decode_tlv_lsp_error_code(struct pcep_object_tlv_header *tlv_hdr,
+                              const uint8_t *tlv_body_buf)
+{
+       struct pcep_object_tlv_lsp_error_code *tlv =
+               (struct pcep_object_tlv_lsp_error_code *)common_tlv_create(
+                       tlv_hdr, sizeof(struct pcep_object_tlv_lsp_error_code));
+
+       tlv->lsp_error_code = ntohl(*((uint32_t *)tlv_body_buf));
+
+       return (struct pcep_object_tlv_header *)tlv;
+}
+
+struct pcep_object_tlv_header *
+pcep_decode_tlv_rsvp_error_spec(struct pcep_object_tlv_header *tlv_hdr,
+                               const uint8_t *tlv_body_buf)
+{
+       uint8_t class_num = tlv_body_buf[2];
+       uint8_t ctype = tlv_body_buf[3];
+
+       if (class_num != RSVP_ERROR_SPEC_CLASS_NUM) {
+               pcep_log(
+                       LOG_INFO,
+                       "%s: Decoding RSVP Error Spec TLV, unknown class num [%d]",
+                       __func__, class_num);
+               return NULL;
+       }
+
+       if (ctype != RSVP_ERROR_SPEC_IPV4_CTYPE
+           && ctype != RSVP_ERROR_SPEC_IPV6_CTYPE) {
+               pcep_log(LOG_INFO,
+                        "%s: Decoding RSVP Error Spec TLV, unknown ctype [%d]",
+                        __func__, ctype);
+               return NULL;
+       }
+
+       struct pcep_object_tlv_rsvp_error_spec *tlv =
+               (struct pcep_object_tlv_rsvp_error_spec *)common_tlv_create(
+                       tlv_hdr,
+                       sizeof(struct pcep_object_tlv_rsvp_error_spec));
+
+       tlv->class_num = class_num;
+       tlv->c_type = ctype;
+
+       uint32_t *uint32_ptr = (uint32_t *)(tlv_body_buf + LENGTH_1WORD);
+       if (ctype == RSVP_ERROR_SPEC_IPV4_CTYPE) {
+               tlv->error_spec_ip.ipv4_error_node_address.s_addr = *uint32_ptr;
+               tlv->error_code = tlv_body_buf[LENGTH_2WORDS + 1];
+               tlv->error_value = ntohs(
+                       *((uint16_t *)(tlv_body_buf + LENGTH_2WORDS + 2)));
+       } else /* RSVP_ERROR_SPEC_IPV6_CTYPE */
+       {
+               decode_ipv6(uint32_ptr,
+                           &tlv->error_spec_ip.ipv6_error_node_address);
+               tlv->error_code = tlv_body_buf[LENGTH_5WORDS + 1];
+               tlv->error_value = ntohs(
+                       *((uint16_t *)(tlv_body_buf + LENGTH_5WORDS + 2)));
+       }
+
+       return (struct pcep_object_tlv_header *)tlv;
+}
+
+struct pcep_object_tlv_header *
+pcep_decode_tlv_lsp_db_version(struct pcep_object_tlv_header *tlv_hdr,
+                              const uint8_t *tlv_body_buf)
+{
+       struct pcep_object_tlv_lsp_db_version *tlv =
+               (struct pcep_object_tlv_lsp_db_version *)common_tlv_create(
+                       tlv_hdr, sizeof(struct pcep_object_tlv_lsp_db_version));
+
+       tlv->lsp_db_version = be64toh(*((uint64_t *)tlv_body_buf));
+
+       return (struct pcep_object_tlv_header *)tlv;
+}
+
+struct pcep_object_tlv_header *
+pcep_decode_tlv_speaker_entity_id(struct pcep_object_tlv_header *tlv_hdr,
+                                 const uint8_t *tlv_body_buf)
+{
+       struct pcep_object_tlv_speaker_entity_identifier *tlv =
+               (struct pcep_object_tlv_speaker_entity_identifier *)
+                       common_tlv_create(
+                               tlv_hdr,
+                               sizeof(struct
+                                      pcep_object_tlv_speaker_entity_identifier));
+
+       uint8_t num_entity_ids = tlv_hdr->encoded_tlv_length / LENGTH_1WORD;
+       if (num_entity_ids > MAX_ITERATIONS) {
+               num_entity_ids = MAX_ITERATIONS;
+               pcep_log(
+                       LOG_INFO,
+                       "%s: Decode Speaker Entity ID, truncating num entities from [%d] to [%d].",
+                       __func__, num_entity_ids, MAX_ITERATIONS);
+       }
+
+       uint32_t *uint32_ptr = (uint32_t *)tlv_body_buf;
+       tlv->speaker_entity_id_list = dll_initialize();
+       int i;
+       for (i = 0; i < num_entity_ids; i++) {
+               uint32_t *entity_id =
+                       pceplib_malloc(PCEPLIB_MESSAGES, sizeof(uint32_t));
+               *entity_id = ntohl(uint32_ptr[i]);
+               dll_append(tlv->speaker_entity_id_list, entity_id);
+       }
+
+       return (struct pcep_object_tlv_header *)tlv;
+}
+
+struct pcep_object_tlv_header *
+pcep_decode_tlv_sr_pce_capability(struct pcep_object_tlv_header *tlv_hdr,
+                                 const uint8_t *tlv_body_buf)
+{
+       struct pcep_object_tlv_sr_pce_capability *tlv =
+               (struct pcep_object_tlv_sr_pce_capability *)common_tlv_create(
+                       tlv_hdr,
+                       sizeof(struct pcep_object_tlv_sr_pce_capability));
+
+       tlv->flag_n = (tlv_body_buf[2] & TLV_SR_PCE_CAP_FLAG_N);
+       tlv->flag_x = (tlv_body_buf[2] & TLV_SR_PCE_CAP_FLAG_X);
+       tlv->max_sid_depth = tlv_body_buf[3];
+
+       return (struct pcep_object_tlv_header *)tlv;
+}
+
+struct pcep_object_tlv_header *
+pcep_decode_tlv_path_setup_type(struct pcep_object_tlv_header *tlv_hdr,
+                               const uint8_t *tlv_body_buf)
+{
+       struct pcep_object_tlv_path_setup_type *tlv =
+               (struct pcep_object_tlv_path_setup_type *)common_tlv_create(
+                       tlv_hdr,
+                       sizeof(struct pcep_object_tlv_path_setup_type));
+
+       tlv->path_setup_type = tlv_body_buf[3];
+
+       return (struct pcep_object_tlv_header *)tlv;
+}
+
+struct pcep_object_tlv_header *pcep_decode_tlv_path_setup_type_capability(
+       struct pcep_object_tlv_header *tlv_hdr, const uint8_t *tlv_body_buf)
+{
+       struct pcep_object_tlv_path_setup_type_capability *tlv =
+               (struct pcep_object_tlv_path_setup_type_capability *)
+                       common_tlv_create(
+                               tlv_hdr,
+                               sizeof(struct
+                                      pcep_object_tlv_path_setup_type_capability));
+
+       uint8_t num_psts = tlv_body_buf[3];
+       if (num_psts > MAX_ITERATIONS) {
+               pcep_log(
+                       LOG_INFO,
+                       "%s: Decode Path Setup Type Capability num PSTs [%d] exceeds MAX [%d] continuing anyways",
+                       __func__, num_psts, MAX_ITERATIONS);
+       }
+
+       int i;
+       tlv->pst_list = dll_initialize();
+       for (i = 0; i < num_psts; i++) {
+               uint8_t *pst =
+                       pceplib_malloc(PCEPLIB_MESSAGES, sizeof(uint8_t));
+               *pst = tlv_body_buf[i + LENGTH_1WORD];
+               dll_append(tlv->pst_list, pst);
+       }
+
+       if (tlv->header.encoded_tlv_length
+           == (TLV_HEADER_LENGTH + LENGTH_1WORD + num_psts)) {
+               return (struct pcep_object_tlv_header *)tlv;
+       }
+
+       uint8_t num_iterations = 0;
+       tlv->sub_tlv_list = dll_initialize();
+       uint16_t buf_index = normalize_pcep_tlv_length(
+               TLV_HEADER_LENGTH + LENGTH_1WORD + num_psts);
+       while ((tlv->header.encoded_tlv_length - buf_index) > TLV_HEADER_LENGTH
+              && num_iterations++ < MAX_ITERATIONS) {
+               struct pcep_object_tlv_header *sub_tlv =
+                       pcep_decode_tlv(tlv_body_buf + buf_index);
+               if (sub_tlv == NULL) {
+                       pcep_log(
+                               LOG_INFO,
+                               "%s: Decode PathSetupType Capability sub-TLV decode returned NULL",
+                               __func__);
+                       return (struct pcep_object_tlv_header *)tlv;
+               }
+
+               buf_index +=
+                       normalize_pcep_tlv_length(sub_tlv->encoded_tlv_length);
+               dll_append(tlv->sub_tlv_list, sub_tlv);
+       }
+
+       return (struct pcep_object_tlv_header *)tlv;
+}
+struct pcep_object_tlv_header *
+pcep_decode_tlv_pol_id(struct pcep_object_tlv_header *tlv_hdr,
+                      const uint8_t *tlv_body_buf)
+{
+       uint32_t *uint32_ptr = (uint32_t *)tlv_body_buf;
+       struct pcep_object_tlv_srpag_pol_id *ipv4 =
+               (struct pcep_object_tlv_srpag_pol_id *)common_tlv_create(
+                       tlv_hdr, sizeof(struct pcep_object_tlv_srpag_pol_id));
+       if (tlv_hdr->encoded_tlv_length == 8) {
+               ipv4->is_ipv4 = true;
+               ipv4->color = ntohl(uint32_ptr[0]);
+               ipv4->end_point.ipv4.s_addr = uint32_ptr[1];
+               return (struct pcep_object_tlv_header *)ipv4;
+       } else {
+               ipv4->is_ipv4 = false;
+               struct pcep_object_tlv_srpag_pol_id *ipv6 =
+                       (struct pcep_object_tlv_srpag_pol_id *)ipv4;
+               ipv6->color = ntohl(uint32_ptr[0]);
+               decode_ipv6(&uint32_ptr[1], &ipv6->end_point.ipv6);
+               return (struct pcep_object_tlv_header *)ipv6;
+       }
+}
+struct pcep_object_tlv_header *
+pcep_decode_tlv_pol_name(struct pcep_object_tlv_header *tlv_hdr,
+                        const uint8_t *tlv_body_buf)
+{
+       struct pcep_object_tlv_srpag_pol_name *tlv =
+               (struct pcep_object_tlv_srpag_pol_name *)common_tlv_create(
+                       tlv_hdr, sizeof(struct pcep_object_tlv_srpag_pol_name));
+
+       memcpy(tlv->name, tlv_body_buf, tlv->header.encoded_tlv_length);
+
+       return (struct pcep_object_tlv_header *)tlv;
+}
+struct pcep_object_tlv_header *
+pcep_decode_tlv_cpath_id(struct pcep_object_tlv_header *tlv_hdr,
+                        const uint8_t *tlv_body_buf)
+{
+       uint32_t *uint32_ptr = (uint32_t *)tlv_body_buf;
+       struct pcep_object_tlv_srpag_cp_id *tlv =
+               (struct pcep_object_tlv_srpag_cp_id *)common_tlv_create(
+                       tlv_hdr, sizeof(struct pcep_object_tlv_srpag_cp_id));
+
+       tlv->proto = tlv_body_buf[0];
+       tlv->orig_asn = ntohl(uint32_ptr[1]);
+       decode_ipv6(&uint32_ptr[2], &tlv->orig_addres);
+       tlv->discriminator = ntohl(uint32_ptr[6]);
+
+       return (struct pcep_object_tlv_header *)tlv;
+}
+struct pcep_object_tlv_header *
+pcep_decode_tlv_cpath_preference(struct pcep_object_tlv_header *tlv_hdr,
+                                const uint8_t *tlv_body_buf)
+{
+       uint32_t *uint32_ptr = (uint32_t *)tlv_body_buf;
+       struct pcep_object_tlv_srpag_cp_pref *tlv =
+               (struct pcep_object_tlv_srpag_cp_pref *)common_tlv_create(
+                       tlv_hdr, sizeof(struct pcep_object_tlv_srpag_cp_pref));
+
+       tlv->preference = ntohl(uint32_ptr[0]);
+
+       return (struct pcep_object_tlv_header *)tlv;
+}
+
+struct pcep_object_tlv_header *
+pcep_decode_tlv_vendor_info(struct pcep_object_tlv_header *tlv_hdr,
+                           const uint8_t *tlv_body_buf)
+{
+       struct pcep_object_tlv_vendor_info *tlv =
+               (struct pcep_object_tlv_vendor_info *)common_tlv_create(
+                       tlv_hdr, sizeof(struct pcep_object_tlv_vendor_info));
+
+       uint32_t *uint32_ptr = (uint32_t *)tlv_body_buf;
+       tlv->enterprise_number = ntohl(uint32_ptr[0]);
+       tlv->enterprise_specific_info = ntohl(uint32_ptr[1]);
+
+       return (struct pcep_object_tlv_header *)tlv;
+}
+
+struct pcep_object_tlv_header *
+pcep_decode_tlv_arbitrary(struct pcep_object_tlv_header *tlv_hdr,
+                         const uint8_t *tlv_body_buf)
+{
+       struct pcep_object_tlv_arbitrary *tlv_arbitrary =
+               (struct pcep_object_tlv_arbitrary *)common_tlv_create(
+                       tlv_hdr, sizeof(struct pcep_object_tlv_arbitrary));
+
+       uint16_t length = tlv_hdr->encoded_tlv_length;
+       if (length > MAX_ARBITRARY_SIZE) {
+               /* TODO should we also reset the tlv_hdr->encoded_tlv_length ?
+                */
+               length = MAX_ARBITRARY_SIZE;
+               pcep_log(
+                       LOG_INFO,
+                       "%s: Decoding Arbitrary TLV , truncate path name from [%d] to [%d].\",",
+                       __func__, tlv_hdr->encoded_tlv_length,
+                       MAX_ARBITRARY_SIZE);
+       }
+
+       tlv_arbitrary->data_length = length;
+       tlv_arbitrary->arbitraty_type = tlv_hdr->type;
+       tlv_hdr->type = PCEP_OBJ_TLV_TYPE_ARBITRARY;
+       memcpy(tlv_arbitrary->data, tlv_body_buf, length);
+
+       return (struct pcep_object_tlv_header *)tlv_arbitrary;
+}
+
+struct pcep_object_tlv_header *
+pcep_decode_tlv_of_list(struct pcep_object_tlv_header *tlv_hdr,
+                       const uint8_t *tlv_body_buf)
+{
+       struct pcep_object_tlv_of_list *of_tlv =
+               (struct pcep_object_tlv_of_list *)common_tlv_create(
+                       tlv_hdr, sizeof(struct pcep_object_tlv_of_list));
+
+       of_tlv->of_list = dll_initialize();
+       uint16_t *uint16_ptr = (uint16_t *)tlv_body_buf;
+       int i = 0;
+       for (; i < tlv_hdr->encoded_tlv_length && i < MAX_ITERATIONS; i++) {
+               uint16_t *of_code_ptr =
+                       pceplib_malloc(PCEPLIB_MESSAGES, sizeof(uint16_t));
+               *of_code_ptr = ntohs(uint16_ptr[i]);
+               dll_append(of_tlv->of_list, of_code_ptr);
+       }
+
+       return (struct pcep_object_tlv_header *)of_tlv;
+}
diff --git a/pceplib/pcep_msg_tools.c b/pceplib/pcep_msg_tools.c
new file mode 100644 (file)
index 0000000..e190d2a
--- /dev/null
@@ -0,0 +1,479 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "pcep_msg_tools.h"
+#include "pcep_msg_encoding.h"
+#include "pcep_utils_logging.h"
+#include "pcep_utils_memory.h"
+
+static const char *message_type_strs[] = {"NOT_IMPLEMENTED0",
+                                         "OPEN",
+                                         "KEEPALIVE",
+                                         "PCREQ",
+                                         "PCREP",
+                                         "PCNOTF",
+                                         "ERROR",
+                                         "CLOSE",
+                                         "NOT_IMPLEMENTED8",
+                                         "NOT_IMPLEMENTED9",
+                                         "REPORT",
+                                         "UPDATE",
+                                         "INITIATE",
+                                         "UNKOWN_MESSAGE_TYPE"};
+
+static const char *object_class_strs[] = {"NOT_IMPLEMENTED0",
+                                         "OPEN",
+                                         "RP",
+                                         "NOPATH",
+                                         "ENDPOINTS",
+                                         "BANDWIDTH",
+                                         "METRIC",
+                                         "ERO",
+                                         "RRO",
+                                         "LSPA",
+                                         "IRO",
+                                         "SVEC",
+                                         "NOTF",
+                                         "ERROR",
+                                         "NOT_IMPLEMENTED14",
+                                         "CLOSE",
+                                         "NOT_IMPLEMENTED16",
+                                         "NOT_IMPLEMENTED17",
+                                         "NOT_IMPLEMENTED18",
+                                         "NOT_IMPLEMENTED19",
+                                         "NOT_IMPLEMENTED20",
+                                         "OBJECTIVE_FUNCTION",
+                                         "NOT_IMPLEMENTED22",
+                                         "NOT_IMPLEMENTED23",
+                                         "NOT_IMPLEMENTED24",
+                                         "NOT_IMPLEMENTED25",
+                                         "NOT_IMPLEMENTED26",
+                                         "NOT_IMPLEMENTED27",
+                                         "NOT_IMPLEMENTED28",
+                                         "NOT_IMPLEMENTED29",
+                                         "NOT_IMPLEMENTED30",
+                                         "NOT_IMPLEMENTED31",
+                                         "LSP",
+                                         "SRP",
+                                         "VENDOR_INFO",
+                                         "NOT_IMPLEMENTED35",
+                                         "INTER_LAYER",
+                                         "SWITCH_LAYER",
+                                         "REQ_ADAP_CAP",
+                                         "SERVER_IND",
+                                         "ASSOCIATION", /* 40 */
+                                         "UNKNOWN_MESSAGE_TYPE"};
+
+
+double_linked_list *pcep_msg_read(int sock_fd)
+{
+       int ret;
+       uint8_t buffer[PCEP_MESSAGE_LENGTH] = {0};
+       uint16_t buffer_read = 0;
+
+
+       ret = read(sock_fd, &buffer, PCEP_MESSAGE_LENGTH);
+
+       if (ret < 0) {
+               pcep_log(
+                       LOG_INFO,
+                       "%s: pcep_msg_read: Failed to read from socket fd [%d] errno [%d %s]",
+                       __func__, sock_fd, errno, strerror(errno));
+               return NULL;
+       } else if (ret == 0) {
+               pcep_log(LOG_INFO, "%s: pcep_msg_read: Remote shutdown fd [%d]",
+                        __func__, sock_fd);
+               return NULL;
+       }
+
+       double_linked_list *msg_list = dll_initialize();
+       struct pcep_message *msg = NULL;
+
+       while (((uint16_t)ret - buffer_read) >= MESSAGE_HEADER_LENGTH) {
+
+               /* Get the Message header, validate it, and return the msg
+                * length */
+               int32_t msg_length =
+                       pcep_decode_validate_msg_header(buffer + buffer_read);
+               if (msg_length < 0 || msg_length > PCEP_MESSAGE_LENGTH) {
+                       /* If the message header is invalid, we cant keep
+                        * reading since the length may be invalid */
+                       pcep_log(
+                               LOG_INFO,
+                               "%s: pcep_msg_read: Received an invalid message fd [%d]",
+                               __func__, sock_fd);
+                       return msg_list;
+               }
+
+               /* Check if the msg_length is longer than what was read,
+                * in which case, we need to read the rest of the message. */
+               if ((ret - buffer_read) < msg_length) {
+                       int read_len = (msg_length - (ret - buffer_read));
+                       int read_ret = 0;
+                       pcep_log(
+                               LOG_INFO,
+                               "%s: pcep_msg_read: Message not fully read! Trying to read %d bytes more, fd [%d]",
+                               __func__, read_len, sock_fd);
+
+                       if (PCEP_MESSAGE_LENGTH - ret - buffer_read >= read_len )
+                               read_ret =
+                                       read(sock_fd, &buffer[ret], read_len);
+                       else {
+                               pcep_log(
+                                       LOG_ERR,
+                                       "%s: Trying to read size (%d) offset (%d) in a buff of size (%d)",
+                                       __func__, read_len, ret, PCEP_MESSAGE_LENGTH);
+                               return msg_list;
+                       }
+
+                       if (read_ret != read_len) {
+                               pcep_log(
+                                       LOG_INFO,
+                                       "%s: pcep_msg_read: Did not manage to read enough data (%d != %d) fd [%d]",
+                                       __func__, read_ret, read_len, sock_fd);
+                               return msg_list;
+                       }
+               }
+
+               msg = pcep_decode_message(buffer + buffer_read);
+               buffer_read += msg_length;
+
+               if (msg == NULL) {
+                       return msg_list;
+               } else {
+                       dll_append(msg_list, msg);
+               }
+       }
+
+       return msg_list;
+}
+
+struct pcep_message *pcep_msg_get(double_linked_list *msg_list, uint8_t type)
+{
+       if (msg_list == NULL) {
+               return NULL;
+       }
+
+       double_linked_list_node *node;
+       for (node = msg_list->head; node != NULL; node = node->next_node) {
+               if (((struct pcep_message *)node->data)->msg_header->type
+                   == type) {
+                       return (struct pcep_message *)node->data;
+               }
+       }
+
+       return NULL;
+}
+
+struct pcep_message *pcep_msg_get_next(double_linked_list *list,
+                                      struct pcep_message *current,
+                                      uint8_t type)
+{
+       if (list == NULL || current == NULL) {
+               return NULL;
+       }
+
+       if (list->head == NULL) {
+               return NULL;
+       }
+
+       double_linked_list_node *node;
+       for (node = list->head; node != NULL; node = node->next_node) {
+               if (node->data == current) {
+                       continue;
+               }
+
+               if (((struct pcep_message *)node->data)->msg_header->type
+                   == type) {
+                       return (struct pcep_message *)node->data;
+               }
+       }
+
+       return NULL;
+}
+
+struct pcep_object_header *pcep_obj_get(double_linked_list *list,
+                                       uint8_t object_class)
+{
+       if (list == NULL) {
+               return NULL;
+       }
+
+       if (list->head == NULL) {
+               return NULL;
+       }
+
+       double_linked_list_node *obj_item;
+       for (obj_item = list->head; obj_item != NULL;
+            obj_item = obj_item->next_node) {
+               if (((struct pcep_object_header *)obj_item->data)->object_class
+                   == object_class) {
+                       return (struct pcep_object_header *)obj_item->data;
+               }
+       }
+
+       return NULL;
+}
+
+struct pcep_object_header *pcep_obj_get_next(double_linked_list *list,
+                                            struct pcep_object_header *current,
+                                            uint8_t object_class)
+{
+       if (list == NULL || current == NULL) {
+               return NULL;
+       }
+
+       if (list->head == NULL) {
+               return NULL;
+       }
+
+       double_linked_list_node *node;
+       for (node = list->head; node != NULL; node = node->next_node) {
+               if (node->data == current) {
+                       continue;
+               }
+
+               if (((struct pcep_object_header *)node->data)->object_class
+                   == object_class) {
+                       return (struct pcep_object_header *)node->data;
+               }
+       }
+
+       return NULL;
+}
+
+void pcep_obj_free_tlv(struct pcep_object_tlv_header *tlv)
+{
+       /* Specific TLV freeing */
+       switch (tlv->type) {
+       case PCEP_OBJ_TLV_TYPE_SPEAKER_ENTITY_ID:
+               if (((struct pcep_object_tlv_speaker_entity_identifier *)tlv)
+                           ->speaker_entity_id_list
+                   != NULL) {
+                       dll_destroy_with_data_memtype(
+                               ((struct
+                                 pcep_object_tlv_speaker_entity_identifier *)
+                                        tlv)
+                                       ->speaker_entity_id_list,
+                               PCEPLIB_MESSAGES);
+               }
+               break;
+
+       case PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY:
+               if (((struct pcep_object_tlv_path_setup_type_capability *)tlv)
+                           ->pst_list
+                   != NULL) {
+                       dll_destroy_with_data_memtype(
+                               ((struct
+                                 pcep_object_tlv_path_setup_type_capability *)
+                                        tlv)
+                                       ->pst_list,
+                               PCEPLIB_MESSAGES);
+               }
+
+               if (((struct pcep_object_tlv_path_setup_type_capability *)tlv)
+                           ->sub_tlv_list
+                   != NULL) {
+                       dll_destroy_with_data_memtype(
+                               ((struct
+                                 pcep_object_tlv_path_setup_type_capability *)
+                                        tlv)
+                                       ->sub_tlv_list,
+                               PCEPLIB_MESSAGES);
+               }
+               break;
+
+       default:
+               break;
+       }
+
+       pceplib_free(PCEPLIB_MESSAGES, tlv);
+}
+
+void pcep_obj_free_object(struct pcep_object_header *obj)
+{
+       /* Iterate the TLVs and free each one */
+       if (obj->tlv_list != NULL) {
+               struct pcep_object_tlv_header *tlv;
+               while ((tlv = (struct pcep_object_tlv_header *)
+                               dll_delete_first_node(obj->tlv_list))
+                      != NULL) {
+                       pcep_obj_free_tlv(tlv);
+               }
+
+               dll_destroy(obj->tlv_list);
+       }
+
+       /* Specific object freeing */
+       switch (obj->object_class) {
+       case PCEP_OBJ_CLASS_ERO:
+       case PCEP_OBJ_CLASS_IRO:
+       case PCEP_OBJ_CLASS_RRO: {
+               if (((struct pcep_object_ro *)obj)->sub_objects != NULL) {
+                       double_linked_list_node *node =
+                               ((struct pcep_object_ro *)obj)
+                                       ->sub_objects->head;
+                       for (; node != NULL; node = node->next_node) {
+                               struct pcep_object_ro_subobj *ro_subobj =
+                                       (struct pcep_object_ro_subobj *)
+                                               node->data;
+                               if (ro_subobj->ro_subobj_type
+                                   == RO_SUBOBJ_TYPE_SR) {
+                                       if (((struct pcep_ro_subobj_sr *)
+                                                    ro_subobj)
+                                                   ->nai_list
+                                           != NULL) {
+                                               dll_destroy_with_data_memtype(
+                                                       ((struct
+                                                         pcep_ro_subobj_sr *)
+                                                                ro_subobj)
+                                                               ->nai_list,
+                                                       PCEPLIB_MESSAGES);
+                                       }
+                               }
+                       }
+                       dll_destroy_with_data_memtype(
+                               ((struct pcep_object_ro *)obj)->sub_objects,
+                               PCEPLIB_MESSAGES);
+               }
+       } break;
+
+       case PCEP_OBJ_CLASS_SVEC:
+               if (((struct pcep_object_svec *)obj)->request_id_list != NULL) {
+                       dll_destroy_with_data_memtype(
+                               ((struct pcep_object_svec *)obj)
+                                       ->request_id_list,
+                               PCEPLIB_MESSAGES);
+               }
+               break;
+
+       case PCEP_OBJ_CLASS_SWITCH_LAYER:
+               if (((struct pcep_object_switch_layer *)obj)->switch_layer_rows
+                   != NULL) {
+                       dll_destroy_with_data_memtype(
+                               ((struct pcep_object_switch_layer *)obj)
+                                       ->switch_layer_rows,
+                               PCEPLIB_MESSAGES);
+               }
+               break;
+
+       default:
+               break;
+       }
+
+       pceplib_free(PCEPLIB_MESSAGES, obj);
+}
+
+void pcep_msg_free_message(struct pcep_message *message)
+{
+       /* Iterate the objects and free each one */
+       if (message->obj_list != NULL) {
+               struct pcep_object_header *obj;
+               while ((obj = (struct pcep_object_header *)
+                               dll_delete_first_node(message->obj_list))
+                      != NULL) {
+                       pcep_obj_free_object(obj);
+               }
+
+               dll_destroy(message->obj_list);
+       }
+
+       if (message->msg_header != NULL) {
+               pceplib_free(PCEPLIB_MESSAGES, message->msg_header);
+       }
+
+       if (message->encoded_message != NULL) {
+               pceplib_free(PCEPLIB_MESSAGES, message->encoded_message);
+       }
+
+       pceplib_free(PCEPLIB_MESSAGES, message);
+}
+
+void pcep_msg_free_message_list(double_linked_list *list)
+{
+       /* Iterate the messages and free each one */
+       struct pcep_message *msg;
+       while ((msg = (struct pcep_message *)dll_delete_first_node(list))
+              != NULL) {
+               pcep_msg_free_message(msg);
+       }
+
+       dll_destroy(list);
+}
+
+const char *get_message_type_str(uint8_t type)
+{
+       uint8_t msg_type =
+               (type > PCEP_TYPE_INITIATE) ? PCEP_TYPE_INITIATE + 1 : type;
+
+       return message_type_strs[msg_type];
+}
+
+const char *get_object_class_str(uint8_t class)
+{
+       uint8_t object_class =
+               (class > PCEP_OBJ_CLASS_SRP) ? PCEP_OBJ_CLASS_SRP + 1 : class;
+
+       return object_class_strs[object_class];
+}
+
+/* Expecting a list of struct pcep_message pointers */
+void pcep_msg_print(double_linked_list *msg_list)
+{
+       double_linked_list_node *node;
+       for (node = msg_list->head; node != NULL; node = node->next_node) {
+               struct pcep_message *msg = (struct pcep_message *)node->data;
+               pcep_log(LOG_INFO, "%s: PCEP_MSG %s", __func__,
+                        get_message_type_str(msg->msg_header->type));
+
+               double_linked_list_node *obj_node =
+                       (msg->obj_list == NULL ? NULL : msg->obj_list->head);
+               for (; obj_node != NULL; obj_node = obj_node->next_node) {
+                       struct pcep_object_header *obj_header =
+                               ((struct pcep_object_header *)obj_node->data);
+                       pcep_log(
+                               LOG_INFO, "%s: PCEP_OBJ %s", __func__,
+                               get_object_class_str(obj_header->object_class));
+               }
+       }
+}
+
+int pcep_msg_send(int sock_fd, struct pcep_message *msg)
+{
+       if (msg == NULL) {
+               return 0;
+       }
+       int msg_length = ntohs(msg->encoded_message_length);
+       if (msg_length > PCEP_MESSAGE_LENGTH) {
+               pcep_log(LOG_ERR, "%s: Not sended, size(% d) exceed max(% d) ",
+                        __func__, msg_length, PCEP_MESSAGE_LENGTH);
+               return 0;
+       }
+
+       return write(sock_fd, msg->encoded_message, msg_length);
+}
diff --git a/pceplib/pcep_msg_tools.h b/pceplib/pcep_msg_tools.h
new file mode 100644 (file)
index 0000000..b62bdde
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ */
+
+#ifndef PCEP_TOOLS_H
+#define PCEP_TOOLS_H
+
+#include <stdint.h>
+#include <netinet/in.h> // struct in_addr
+
+#include "pcep_utils_double_linked_list.h"
+#include "pcep_msg_messages.h"
+#include "pcep_msg_objects.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define PCEP_MAX_SIZE 6000
+
+/* Returns a double linked list of PCEP messages */
+double_linked_list *pcep_msg_read(int sock_fd);
+/* Given a double linked list of PCEP messages, return the first node that has
+ * the same message type */
+struct pcep_message *pcep_msg_get(double_linked_list *msg_list, uint8_t type);
+/* Given a double linked list of PCEP messages, return the next node after
+ * current node that has the same message type */
+struct pcep_message *pcep_msg_get_next(double_linked_list *msg_list,
+                                      struct pcep_message *current,
+                                      uint8_t type);
+struct pcep_object_header *pcep_obj_get(double_linked_list *list,
+                                       uint8_t object_class);
+struct pcep_object_header *pcep_obj_get_next(double_linked_list *list,
+                                            struct pcep_object_header *current,
+                                            uint8_t object_class);
+struct pcep_object_tlv_header *pcep_tlv_get(double_linked_list *list,
+                                           uint16_t type);
+struct pcep_object_tlv_header *
+pcep_tlv_get_next(double_linked_list *list,
+                 struct pcep_object_tlv_header *current, uint16_t type);
+void pcep_obj_free_tlv(struct pcep_object_tlv_header *tlv);
+void pcep_obj_free_object(struct pcep_object_header *obj);
+void pcep_msg_free_message(struct pcep_message *message);
+void pcep_msg_free_message_list(double_linked_list *list);
+void pcep_msg_print(double_linked_list *list);
+const char *get_message_type_str(uint8_t type);
+const char *get_object_class_str(uint8_t class);
+int pcep_msg_send(int sock_fd, struct pcep_message *hdr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/pceplib/pcep_pcc.c b/pceplib/pcep_pcc.c
new file mode 100644 (file)
index 0000000..1a702a8
--- /dev/null
@@ -0,0 +1,520 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+/*
+ * Sample PCC implementation
+ */
+
+#include <zebra.h>
+
+#include <netdb.h> // gethostbyname
+#include <netinet/tcp.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "pcep_pcc_api.h"
+#include "pcep_utils_double_linked_list.h"
+#include "pcep_utils_logging.h"
+#include "pcep_utils_memory.h"
+
+/*
+ * PCEP PCC design spec:
+ * https://docs.google.com/presentation/d/1DYc3ZhYA1c_qg9A552HjhneJXQKdh_yrKW6v3NRYPtnbw/edit?usp=sharing
+ */
+#define MAX_SRC_IP_STR 40
+#define MAX_DST_IP_STR 40
+struct cmd_line_args {
+       char src_ip_str[MAX_SRC_IP_STR];
+       char dest_ip_str[MAX_DST_IP_STR];
+       short src_tcp_port;
+       short dest_tcp_port;
+       char tcp_md5_str[TCP_MD5SIG_MAXKEYLEN]; /* RFC 2385 */
+       bool is_ipv6;
+       bool eventpoll; /* poll for pcep_event's, or use callback (default) */
+};
+
+bool pcc_active_ = true;
+pcep_session *session = NULL;
+struct cmd_line_args *cmd_line_args = NULL;
+/* pcep_event callback variables */
+bool pcep_event_condition = false;
+struct pcep_event *event = NULL;
+pthread_mutex_t pcep_event_mutex;
+pthread_cond_t pcep_event_cond_var;
+
+static const char DEFAULT_DEST_HOSTNAME[] = "localhost";
+static const char DEFAULT_DEST_HOSTNAME_IPV6[] = "ip6-localhost";
+static const short DEFAULT_SRC_TCP_PORT = 4999;
+
+// Private fn's
+struct cmd_line_args *get_cmdline_args(int argc, char *argv[]);
+void handle_signal_action(int sig_number);
+int setup_signals(void);
+void send_pce_path_request_message(pcep_session *session);
+void send_pce_report_message(pcep_session *session);
+void print_queue_event(struct pcep_event *event);
+void pcep_event_callback(void *cb_data, pcep_event *e);
+
+struct cmd_line_args *get_cmdline_args(int argc, char *argv[])
+{
+       /* Allocate and set default values */
+       struct cmd_line_args *cmd_line_args =
+               malloc(sizeof(struct cmd_line_args));
+       memset(cmd_line_args, 0, sizeof(struct cmd_line_args));
+       strlcpy(cmd_line_args->dest_ip_str, DEFAULT_DEST_HOSTNAME,
+               MAX_DST_IP_STR);
+       cmd_line_args->src_tcp_port = DEFAULT_SRC_TCP_PORT;
+       cmd_line_args->is_ipv6 = false;
+
+       /* Parse the cmd_line args:
+        * -ipv6
+        * -srcip localhost
+        * -destip 192.168.0.2
+        * -srcport 4999
+        * -dstport 4189
+        * -tcpmd5 hello
+        * -event_poll */
+       int i = 1;
+       for (; i < argc; ++i) {
+               if (strcmp(argv[i], "-help") == 0
+                   || strcmp(argv[i], "--help") == 0
+                   || strcmp(argv[i], "-h") == 0) {
+                       pcep_log(
+                               LOG_INFO,
+                               "%s: pcep_pcc [-ipv6] [-srcip localhost] [-destip 192.168.0.1] [-srcport 4999] [-dstport 4189] [-tcpmd5 authstr] [-eventpoll]",
+                               __func__);
+                       free(cmd_line_args);
+                       return NULL;
+               } else if (strcmp(argv[i], "-ipv6") == 0) {
+                       cmd_line_args->is_ipv6 = true;
+                       if (argc == 2) {
+                               strlcpy(cmd_line_args->dest_ip_str,
+                                       DEFAULT_DEST_HOSTNAME_IPV6,
+                                       MAX_DST_IP_STR);
+                       }
+               } else if (strcmp(argv[i], "-eventpoll") == 0) {
+                       cmd_line_args->eventpoll = true;
+               } else if (strcmp(argv[i], "-srcip") == 0) {
+                       if (argc >= i + 2) {
+                               strlcpy(cmd_line_args->src_ip_str, argv[++i],
+                                       MAX_SRC_IP_STR);
+                       } else {
+                               pcep_log(
+                                       LOG_ERR,
+                                       "%s: Invalid number of cmd_line_args for \"-srcip\"",
+                                       __func__);
+                               free(cmd_line_args);
+                               return NULL;
+                       }
+               } else if (strcmp(argv[i], "-destip") == 0) {
+                       if (argc >= i + 2) {
+                               strlcpy(cmd_line_args->dest_ip_str, argv[++i],
+                                       MAX_DST_IP_STR);
+                       } else {
+                               pcep_log(
+                                       LOG_ERR,
+                                       "%s: Invalid number of cmd_line_args for \"-destip\"",
+                                       __func__);
+                               free(cmd_line_args);
+                               return NULL;
+                       }
+               } else if (strcmp(argv[i], "-srcport") == 0) {
+                       if (argc >= i + 2) {
+                               cmd_line_args->src_tcp_port = atoi(argv[++i]);
+                       } else {
+                               pcep_log(
+                                       LOG_ERR,
+                                       "%s: Invalid number of cmd_line_args for \"-srcport\"",
+                                       __func__);
+                               free(cmd_line_args);
+                               return NULL;
+                       }
+               } else if (strcmp(argv[i], "-destport") == 0) {
+                       if (argc >= i + 2) {
+                               cmd_line_args->dest_tcp_port = atoi(argv[++i]);
+                       } else {
+                               pcep_log(
+                                       LOG_ERR,
+                                       "%s: Invalid number of cmd_line_args for \"-destport\"",
+                                       __func__);
+                               free(cmd_line_args);
+                               return NULL;
+                       }
+               } else if (strcmp(argv[i], "-tcpmd5") == 0) {
+                       if (argc >= i + 2) {
+                               strlcpy(cmd_line_args->tcp_md5_str, argv[++i],
+                                       sizeof(cmd_line_args->tcp_md5_str));
+                       } else {
+                               pcep_log(
+                                       LOG_ERR,
+                                       "%s: Invalid number of cmd_line_args for \"-tcpmd5\"",
+                                       __func__);
+                               free(cmd_line_args);
+                               return NULL;
+                       }
+               } else {
+                       pcep_log(LOG_ERR, "%s: Invalid cmd_line_arg[%d] = %s",
+                                __func__, i, argv[i]);
+                       free(cmd_line_args);
+                       return NULL;
+               }
+       }
+
+       return cmd_line_args;
+}
+
+void handle_signal_action(int sig_number)
+{
+       if (sig_number == SIGINT) {
+               pcep_log(LOG_INFO, "%s: SIGINT was caught!", __func__);
+               pcc_active_ = false;
+               if (cmd_line_args->eventpoll == false) {
+                       pthread_mutex_lock(&pcep_event_mutex);
+                       pcep_event_condition = true;
+                       pthread_cond_signal(&pcep_event_cond_var);
+                       pthread_mutex_unlock(&pcep_event_mutex);
+               }
+       } else if (sig_number == SIGUSR1) {
+               pcep_log(LOG_INFO, "%s: SIGUSR1 was caught, dumping counters",
+                        __func__);
+               dump_pcep_session_counters(session);
+               pceplib_memory_dump();
+       } else if (sig_number == SIGUSR2) {
+               pcep_log(LOG_INFO, "%s: SIGUSR2 was caught, reseting counters",
+                        __func__);
+               reset_pcep_session_counters(session);
+       }
+}
+
+
+int setup_signals()
+{
+       struct sigaction sa;
+       memset(&sa, 0, sizeof(struct sigaction));
+       sa.sa_handler = handle_signal_action;
+       if (sigaction(SIGINT, &sa, 0) != 0) {
+               perror("sigaction()");
+               return -1;
+       }
+
+       if (sigaction(SIGUSR1, &sa, 0) != 0) {
+               perror("sigaction()");
+               return -1;
+       }
+
+       if (sigaction(SIGUSR2, &sa, 0) != 0) {
+               perror("sigaction()");
+               return -1;
+       }
+
+       return 0;
+}
+
+void send_pce_path_request_message(pcep_session *session)
+{
+       struct in_addr src_ipv4;
+       struct in_addr dst_ipv4;
+       inet_pton(AF_INET, "1.2.3.4", &src_ipv4);
+       inet_pton(AF_INET, "10.20.30.40", &dst_ipv4);
+
+       struct pcep_object_rp *rp_object =
+               pcep_obj_create_rp(1, false, false, false, false, 42, NULL);
+       struct pcep_object_endpoints_ipv4 *ep_object =
+               pcep_obj_create_endpoint_ipv4(&src_ipv4, &dst_ipv4);
+
+       struct pcep_message *path_request =
+               pcep_msg_create_request(rp_object, ep_object, NULL);
+       send_message(session, path_request, true);
+}
+
+void send_pce_report_message(pcep_session *session)
+{
+       double_linked_list *report_list = dll_initialize();
+
+       /* SRP Path Setup Type TLV */
+       struct pcep_object_tlv_path_setup_type *pst_tlv =
+               pcep_tlv_create_path_setup_type(SR_TE_PST);
+       double_linked_list *srp_tlv_list = dll_initialize();
+       dll_append(srp_tlv_list, pst_tlv);
+
+       /*
+        * Create the SRP object
+        */
+       uint32_t srp_id_number = 0x10203040;
+       struct pcep_object_header *obj =
+               (struct pcep_object_header *)pcep_obj_create_srp(
+                       false, srp_id_number, srp_tlv_list);
+       if (obj == NULL) {
+               pcep_log(LOG_WARNING,
+                        "%s: send_pce_report_message SRP object was NULL",
+                        __func__);
+                       dll_destroy_with_data(report_list);
+               return;
+       }
+       dll_append(report_list, obj);
+
+       /* LSP Symbolic path name TLV */
+       char symbolic_path_name[] = "second-default";
+       struct pcep_object_tlv_symbolic_path_name *spn_tlv =
+               pcep_tlv_create_symbolic_path_name(symbolic_path_name, 14);
+       double_linked_list *lsp_tlv_list = dll_initialize();
+       dll_append(lsp_tlv_list, spn_tlv);
+
+       /* LSP IPv4 LSP ID TLV */
+       struct in_addr ipv4_tunnel_sender;
+       struct in_addr ipv4_tunnel_endpoint;
+       inet_pton(AF_INET, "9.9.1.1", &ipv4_tunnel_sender);
+       inet_pton(AF_INET, "9.9.2.1", &ipv4_tunnel_endpoint);
+       struct pcep_object_tlv_ipv4_lsp_identifier *ipv4_lsp_id_tlv =
+               pcep_tlv_create_ipv4_lsp_identifiers(&ipv4_tunnel_sender,
+                                                    &ipv4_tunnel_endpoint, 42,
+                                                    1, NULL);
+       dll_append(lsp_tlv_list, ipv4_lsp_id_tlv);
+
+       /*
+        * Create the LSP object
+        */
+       uint32_t plsp_id = 42;
+       enum pcep_lsp_operational_status lsp_status =
+               PCEP_LSP_OPERATIONAL_ACTIVE;
+       bool c_flag = false; /* Lsp was created by PcInitiate msg */
+       bool a_flag = false; /* Admin state, active / inactive */
+       bool r_flag = false; /* true if LSP has been removed */
+       bool s_flag = true;  /* Synchronization */
+       bool d_flag = false; /* Delegate LSP to PCE */
+       obj = (struct pcep_object_header *)pcep_obj_create_lsp(
+               plsp_id, lsp_status, c_flag, a_flag, r_flag, s_flag, d_flag,
+               lsp_tlv_list);
+       if (obj == NULL) {
+               pcep_log(LOG_WARNING,
+                        "%s: send_pce_report_message LSP object was NULL",
+                        __func__);
+                       dll_destroy_with_data(report_list);
+               return;
+       }
+       dll_append(report_list, obj);
+
+       /* Create 2 ERO NONAI sub-objects */
+       double_linked_list *ero_subobj_list = dll_initialize();
+       struct pcep_ro_subobj_sr *sr_subobj_nonai1 =
+               pcep_obj_create_ro_subobj_sr_nonai(false, 503808, true, true);
+       dll_append(ero_subobj_list, sr_subobj_nonai1);
+
+       struct pcep_ro_subobj_sr *sr_subobj_nonai2 =
+               pcep_obj_create_ro_subobj_sr_nonai(false, 1867776, true, true);
+       dll_append(ero_subobj_list, sr_subobj_nonai2);
+
+       /* Create ERO IPv4 node sub-object */
+       struct in_addr sr_subobj_ipv4;
+       inet_pton(AF_INET, "9.9.9.1", &sr_subobj_ipv4);
+       struct pcep_ro_subobj_sr *sr_subobj_ipv4node =
+               pcep_obj_create_ro_subobj_sr_ipv4_node(
+                       false, false, false, true, 16060, &sr_subobj_ipv4);
+       if (sr_subobj_ipv4node == NULL) {
+               pcep_log(LOG_WARNING,
+                        "%s: send_pce_report_message ERO sub-object was NULL",
+                        __func__);
+               return;
+       }
+       dll_append(ero_subobj_list, sr_subobj_ipv4node);
+
+       /*
+        * Create the ERO object
+        */
+       obj = (struct pcep_object_header *)pcep_obj_create_ero(ero_subobj_list);
+       if (obj == NULL) {
+               pcep_log(LOG_WARNING,
+                        "%s: send_pce_report_message ERO object was NULL",
+                        __func__);
+                       dll_destroy_with_data(report_list);
+               return;
+       }
+       dll_append(report_list, obj);
+
+       /*
+        * Create the Metric object
+        */
+       obj = (struct pcep_object_header *)pcep_obj_create_metric(
+               PCEP_METRIC_TE, false, true, 16.0);
+       dll_append(report_list, obj);
+
+       /* Create and send the report message */
+       struct pcep_message *report_msg = pcep_msg_create_report(report_list);
+       send_message(session, report_msg, true);
+}
+
+void print_queue_event(struct pcep_event *event)
+{
+       pcep_log(
+               LOG_INFO,
+               "%s: [%ld-%ld] Received Event: type [%s] on session [%d] occurred at [%ld]",
+               __func__, time(NULL), pthread_self(),
+               get_event_type_str(event->event_type),
+               event->session->session_id, event->event_time);
+
+       if (event->event_type == MESSAGE_RECEIVED) {
+               pcep_log(
+                       LOG_INFO, "%s: \t Event message type [%s]", __func__,
+                       get_message_type_str(event->message->msg_header->type));
+       }
+}
+
+/* Called by pcep_session_logic when pcep_event's are ready */
+void pcep_event_callback(void *cb_data, pcep_event *e)
+{
+       (void)cb_data;
+       pcep_log(LOG_NOTICE, "%s: [%ld-%ld] pcep_event_callback", __func__,
+                time(NULL), pthread_self());
+       pthread_mutex_lock(&pcep_event_mutex);
+       event = e;
+       pcep_event_condition = true;
+       pthread_cond_signal(&pcep_event_cond_var);
+       pthread_mutex_unlock(&pcep_event_mutex);
+}
+
+int main(int argc, char **argv)
+{
+       pcep_log(LOG_NOTICE, "%s: [%ld-%ld] starting pcc_pcep example client",
+                __func__, time(NULL), pthread_self());
+
+       cmd_line_args = get_cmdline_args(argc, argv);
+       if (cmd_line_args == NULL) {
+               return -1;
+       }
+
+       setup_signals();
+
+       if (cmd_line_args->eventpoll == false) {
+               struct pceplib_infra_config infra_config;
+               memset(&infra_config, 0, sizeof(infra_config));
+               infra_config.pcep_event_func = pcep_event_callback;
+               if (!initialize_pcc_infra(&infra_config)) {
+                       pcep_log(LOG_ERR,
+                                "%s: Error initializing PCC with infra.",
+                                __func__);
+                       return -1;
+               }
+       } else {
+               if (!initialize_pcc()) {
+                       pcep_log(LOG_ERR, "%s: Error initializing PCC.",
+                                __func__);
+                       return -1;
+               }
+       }
+
+       pcep_configuration *config = create_default_pcep_configuration();
+       config->pcep_msg_versioning->draft_ietf_pce_segment_routing_07 = true;
+       config->src_pcep_port = cmd_line_args->src_tcp_port;
+       config->is_tcp_auth_md5 = true;
+
+       strlcpy(config->tcp_authentication_str, cmd_line_args->tcp_md5_str,
+               sizeof(config->tcp_authentication_str));
+
+       int af = (cmd_line_args->is_ipv6 ? AF_INET6 : AF_INET);
+       struct hostent *host_info =
+               gethostbyname2(cmd_line_args->dest_ip_str, af);
+       if (host_info == NULL) {
+               pcep_log(LOG_ERR, "%s: Error getting IP address.", __func__);
+               return -1;
+       }
+
+       if (cmd_line_args->is_ipv6) {
+               struct in6_addr host_address;
+               memcpy(&host_address, host_info->h_addr, host_info->h_length);
+               session = connect_pce_ipv6(config, &host_address);
+       } else {
+               struct in_addr host_address;
+               memcpy(&host_address, host_info->h_addr, host_info->h_length);
+               session = connect_pce(config, &host_address);
+       }
+
+       if (session == NULL) {
+               pcep_log(LOG_WARNING, "%s: Error in connect_pce.", __func__);
+               destroy_pcep_configuration(config);
+               return -1;
+       }
+
+       sleep(2);
+
+       send_pce_report_message(session);
+       /*send_pce_path_request_message(session);*/
+
+       /* Wait for pcep_event's either by polling the event queue or by
+        * callback */
+       if (cmd_line_args->eventpoll == true) {
+               /* Poll the pcep_event queue*/
+               while (pcc_active_) {
+                       if (event_queue_is_empty() == false) {
+                               struct pcep_event *event =
+                                       event_queue_get_event();
+                               print_queue_event(event);
+                               destroy_pcep_event(event);
+                       }
+
+                       sleep(5);
+               }
+       } else {
+               /* Get events via callback and conditional variable */
+               pthread_mutex_init(&pcep_event_mutex, NULL);
+               pthread_cond_init(&pcep_event_cond_var, NULL);
+               while (pcc_active_) {
+                       pthread_mutex_lock(&pcep_event_mutex);
+
+                       /* this internal loop helps avoid spurious interrupts */
+                       while (!pcep_event_condition) {
+                               pthread_cond_wait(&pcep_event_cond_var,
+                                                 &pcep_event_mutex);
+                       }
+
+                       /* Check if we have been interrupted by SIGINT */
+                       if (pcc_active_) {
+                               print_queue_event(event);
+                               destroy_pcep_event(event);
+                       }
+
+                       pcep_event_condition = false;
+                       pthread_mutex_unlock(&pcep_event_mutex);
+               }
+
+               pthread_mutex_destroy(&pcep_event_mutex);
+               pthread_cond_destroy(&pcep_event_cond_var);
+       }
+
+       pcep_log(LOG_NOTICE, "%s: Disconnecting from PCE", __func__);
+       disconnect_pce(session);
+       destroy_pcep_configuration(config);
+       free(cmd_line_args);
+
+       if (!destroy_pcc()) {
+               pcep_log(LOG_NOTICE, "%s: Error stopping PCC.", __func__);
+       }
+
+       pceplib_memory_dump();
+
+       return 0;
+}
diff --git a/pceplib/pcep_pcc_api.c b/pceplib/pcep_pcc_api.c
new file mode 100644 (file)
index 0000000..b7813c5
--- /dev/null
@@ -0,0 +1,392 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+/*
+ * Public PCEPlib PCC API implementation
+ */
+
+#include <zebra.h>
+
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "pcep_msg_messages.h"
+#include "pcep_pcc_api.h"
+#include "pcep_utils_counters.h"
+#include "pcep_utils_logging.h"
+
+/* Not using an array here since the enum pcep_event_type indeces go into the
+ * 100's */
+const char MESSAGE_RECEIVED_STR[] = "MESSAGE_RECEIVED";
+const char PCE_CLOSED_SOCKET_STR[] = "PCE_CLOSED_SOCKET";
+const char PCE_SENT_PCEP_CLOSE_STR[] = "PCE_SENT_PCEP_CLOSE";
+const char PCE_DEAD_TIMER_EXPIRED_STR[] = "PCE_DEAD_TIMER_EXPIRED";
+const char PCE_OPEN_KEEP_WAIT_TIMER_EXPIRED_STR[] =
+       "PCE_OPEN_KEEP_WAIT_TIMER_EXPIRED";
+const char PCC_CONNECTED_TO_PCE_STR[] = "PCC_CONNECTED_TO_PCE";
+const char PCC_PCEP_SESSION_CLOSED_STR[] = "PCC_PCEP_SESSION_CLOSED";
+const char PCC_RCVD_INVALID_OPEN_STR[] = "PCC_RCVD_INVALID_OPEN";
+const char PCC_RCVD_MAX_INVALID_MSGS_STR[] = "PCC_RCVD_MAX_INVALID_MSGS";
+const char PCC_RCVD_MAX_UNKOWN_MSGS_STR[] = "PCC_RCVD_MAX_UNKOWN_MSGS";
+const char UNKNOWN_EVENT_STR[] = "UNKNOWN Event Type";
+
+/* Session Logic Handle managed in pcep_session_logic.c */
+extern pcep_event_queue *session_logic_event_queue_;
+
+bool initialize_pcc()
+{
+       if (!run_session_logic()) {
+               pcep_log(LOG_ERR, "%s: Error initializing PCC session logic.",
+                        __func__);
+               return false;
+       }
+
+       return true;
+}
+
+
+bool initialize_pcc_infra(struct pceplib_infra_config *infra_config)
+{
+       if (infra_config == NULL) {
+               return initialize_pcc();
+       }
+
+       if (!run_session_logic_with_infra(infra_config)) {
+               pcep_log(LOG_ERR,
+                        "%s: Error initializing PCC session logic with infra.",
+                        __func__);
+               return false;
+       }
+
+       return true;
+}
+
+
+/* this function is blocking */
+bool initialize_pcc_wait_for_completion()
+{
+       return run_session_logic_wait_for_completion();
+}
+
+
+bool destroy_pcc()
+{
+       if (!stop_session_logic()) {
+               pcep_log(LOG_WARNING, "%s: Error stopping PCC session logic.",
+                        __func__);
+               return false;
+       }
+
+       return true;
+}
+
+
+pcep_configuration *create_default_pcep_configuration()
+{
+       pcep_configuration *config =
+               pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_configuration));
+       memset(config, 0, sizeof(pcep_configuration));
+
+       config->keep_alive_seconds = DEFAULT_CONFIG_KEEP_ALIVE;
+       /* This value will possibly be overwritten later with PCE config data */
+       config->keep_alive_pce_negotiated_timer_seconds =
+               DEFAULT_CONFIG_KEEP_ALIVE;
+       config->min_keep_alive_seconds = DEFAULT_MIN_CONFIG_KEEP_ALIVE;
+       config->max_keep_alive_seconds = DEFAULT_MAX_CONFIG_KEEP_ALIVE;
+
+       config->dead_timer_seconds = DEFAULT_CONFIG_DEAD_TIMER;
+       /* This value will be overwritten later with PCE config data */
+       config->dead_timer_pce_negotiated_seconds = DEFAULT_CONFIG_DEAD_TIMER;
+       config->min_dead_timer_seconds = DEFAULT_MIN_CONFIG_DEAD_TIMER;
+       config->max_dead_timer_seconds = DEFAULT_MAX_CONFIG_DEAD_TIMER;
+
+       config->request_time_seconds = DEFAULT_CONFIG_REQUEST_TIME;
+       config->max_unknown_messages = DEFAULT_CONFIG_MAX_UNKNOWN_MESSAGES;
+       config->max_unknown_requests = DEFAULT_CONFIG_MAX_UNKNOWN_REQUESTS;
+
+       config->socket_connect_timeout_millis =
+               DEFAULT_TCP_CONNECT_TIMEOUT_MILLIS;
+       config->support_stateful_pce_lsp_update = true;
+       config->support_pce_lsp_instantiation = true;
+       config->support_include_db_version = true;
+       config->lsp_db_version = 0;
+       config->support_lsp_triggered_resync = true;
+       config->support_lsp_delta_sync = true;
+       config->support_pce_triggered_initial_sync = true;
+       config->support_sr_te_pst = true;
+       config->pcc_can_resolve_nai_to_sid = true;
+       config->max_sid_depth = 0;
+       config->dst_pcep_port = 0;
+       config->src_pcep_port = 0;
+       config->src_ip.src_ipv4.s_addr = INADDR_ANY;
+       config->is_src_ipv6 = false;
+       config->pcep_msg_versioning = create_default_pcep_versioning();
+       config->tcp_authentication_str[0] = '\0';
+       config->is_tcp_auth_md5 = true;
+
+       return config;
+}
+
+void destroy_pcep_configuration(pcep_configuration *config)
+{
+       destroy_pcep_versioning(config->pcep_msg_versioning);
+       pceplib_free(PCEPLIB_INFRA, config);
+}
+
+pcep_session *connect_pce(pcep_configuration *config, struct in_addr *pce_ip)
+{
+       return create_pcep_session(config, pce_ip);
+}
+
+pcep_session *connect_pce_ipv6(pcep_configuration *config,
+                              struct in6_addr *pce_ip)
+{
+       return create_pcep_session_ipv6(config, pce_ip);
+}
+
+void disconnect_pce(pcep_session *session)
+{
+       if (session_exists(session) == false) {
+               pcep_log(
+                       LOG_WARNING,
+                       "%s: disconnect_pce session [%p] has already been deleted",
+                       __func__, session);
+               return;
+       }
+
+       if (session->socket_comm_session == NULL
+           || session->socket_comm_session->socket_fd < 0) {
+               /* If the socket has already been closed, just destroy the
+                * session */
+               destroy_pcep_session(session);
+       } else {
+               /* This will cause the session to be destroyed AFTER the close
+                * message is sent */
+               session->destroy_session_after_write = true;
+
+               /* Send a PCEP close message */
+               close_pcep_session(session);
+       }
+}
+
+void send_message(pcep_session *session, struct pcep_message *msg,
+                 bool free_after_send)
+{
+       if (session == NULL || msg == NULL) {
+               pcep_log(LOG_DEBUG,
+                        "%s: send_message NULL params session [%p] msg [%p]",
+                        __func__, session, msg);
+
+               return;
+       }
+
+       if (session_exists(session) == false) {
+               pcep_log(
+                       LOG_WARNING,
+                       "%s: send_message session [%p] has already been deleted",
+                       __func__, session);
+               return;
+       }
+
+       pcep_encode_message(msg, session->pcc_config.pcep_msg_versioning);
+       socket_comm_session_send_message(
+               session->socket_comm_session, (char *)msg->encoded_message,
+               msg->encoded_message_length, free_after_send);
+
+       increment_message_tx_counters(session, msg);
+
+       if (free_after_send == true) {
+               /* The encoded_message will be deleted once sent, so everything
+                * else in the message will be freed */
+               msg->encoded_message = NULL;
+               pcep_msg_free_message(msg);
+       }
+}
+
+/* Returns true if the queue is empty, false otherwise */
+bool event_queue_is_empty()
+{
+       if (session_logic_event_queue_ == NULL) {
+               pcep_log(
+                       LOG_WARNING,
+                       "%s: event_queue_is_empty Session Logic is not initialized yet",
+                       __func__);
+               return false;
+       }
+
+       pthread_mutex_lock(&session_logic_event_queue_->event_queue_mutex);
+       bool is_empty =
+               (session_logic_event_queue_->event_queue->num_entries == 0);
+       pthread_mutex_unlock(&session_logic_event_queue_->event_queue_mutex);
+
+       return is_empty;
+}
+
+
+/* Return the number of events on the queue, 0 if empty */
+uint32_t event_queue_num_events_available()
+{
+       if (session_logic_event_queue_ == NULL) {
+               pcep_log(
+                       LOG_WARNING,
+                       "%s: event_queue_num_events_available Session Logic is not initialized yet",
+                       __func__);
+               return 0;
+       }
+
+       pthread_mutex_lock(&session_logic_event_queue_->event_queue_mutex);
+       uint32_t num_events =
+               session_logic_event_queue_->event_queue->num_entries;
+       pthread_mutex_unlock(&session_logic_event_queue_->event_queue_mutex);
+
+       return num_events;
+}
+
+
+/* Return the next event on the queue, NULL if empty */
+struct pcep_event *event_queue_get_event()
+{
+       if (session_logic_event_queue_ == NULL) {
+               pcep_log(
+                       LOG_WARNING,
+                       "%s: event_queue_get_event Session Logic is not initialized yet",
+                       __func__);
+               return NULL;
+       }
+
+       pthread_mutex_lock(&session_logic_event_queue_->event_queue_mutex);
+       struct pcep_event *event = (struct pcep_event *)queue_dequeue(
+               session_logic_event_queue_->event_queue);
+       pthread_mutex_unlock(&session_logic_event_queue_->event_queue_mutex);
+
+       return event;
+}
+
+
+/* Free the PCEP Event resources, including the PCEP message */
+void destroy_pcep_event(struct pcep_event *event)
+{
+       if (event == NULL) {
+               pcep_log(LOG_WARNING,
+                        "%s: destroy_pcep_event cannot destroy NULL event",
+                        __func__);
+               return;
+       }
+
+       if (event->event_type == MESSAGE_RECEIVED && event->message != NULL) {
+               pcep_msg_free_message(event->message);
+       }
+
+       pceplib_free(PCEPLIB_INFRA, event);
+}
+
+const char *get_event_type_str(int event_type)
+{
+       switch (event_type) {
+       case MESSAGE_RECEIVED:
+               return MESSAGE_RECEIVED_STR;
+               break;
+       case PCE_CLOSED_SOCKET:
+               return PCE_CLOSED_SOCKET_STR;
+               break;
+       case PCE_SENT_PCEP_CLOSE:
+               return PCE_SENT_PCEP_CLOSE_STR;
+               break;
+       case PCE_DEAD_TIMER_EXPIRED:
+               return PCE_DEAD_TIMER_EXPIRED_STR;
+               break;
+       case PCE_OPEN_KEEP_WAIT_TIMER_EXPIRED:
+               return PCE_OPEN_KEEP_WAIT_TIMER_EXPIRED_STR;
+               break;
+       case PCC_CONNECTED_TO_PCE:
+               return PCC_CONNECTED_TO_PCE_STR;
+               break;
+       case PCC_PCEP_SESSION_CLOSED:
+               return PCC_PCEP_SESSION_CLOSED_STR;
+               break;
+       case PCC_RCVD_INVALID_OPEN:
+               return PCC_RCVD_INVALID_OPEN_STR;
+               break;
+       case PCC_RCVD_MAX_INVALID_MSGS:
+               return PCC_RCVD_MAX_INVALID_MSGS_STR;
+               break;
+       case PCC_RCVD_MAX_UNKOWN_MSGS:
+               return PCC_RCVD_MAX_UNKOWN_MSGS_STR;
+               break;
+       default:
+               return UNKNOWN_EVENT_STR;
+               break;
+       }
+}
+
+void dump_pcep_session_counters(pcep_session *session)
+{
+       if (session_exists(session) == false) {
+               pcep_log(
+                       LOG_WARNING,
+                       "%s: dump_pcep_session_counters session [%p] has already been deleted",
+                       __func__, session);
+               return;
+       }
+
+       /* Update the counters group name so that the PCE session connected time
+        * is accurate */
+       time_t now = time(NULL);
+       char counters_name[MAX_COUNTER_STR_LENGTH] = {0};
+       char ip_str[40] = {0};
+       if (session->socket_comm_session->is_ipv6) {
+               inet_ntop(AF_INET6,
+                         &session->socket_comm_session->dest_sock_addr
+                                  .dest_sock_addr_ipv6.sin6_addr,
+                         ip_str, 40);
+       } else {
+               inet_ntop(AF_INET,
+                         &session->socket_comm_session->dest_sock_addr
+                                  .dest_sock_addr_ipv4.sin_addr,
+                         ip_str, 40);
+       }
+       snprintf(counters_name, MAX_COUNTER_STR_LENGTH,
+                "PCEP Session [%d], connected to [%s] for [%u seconds]",
+                session->session_id, ip_str,
+                (uint32_t)(now - session->time_connected));
+       strlcpy(session->pcep_session_counters->counters_group_name,
+               counters_name,
+               sizeof(session->pcep_session_counters->counters_group_name));
+
+       dump_counters_group_to_log(session->pcep_session_counters);
+}
+
+void reset_pcep_session_counters(pcep_session *session)
+{
+       if (session_exists(session) == false) {
+               pcep_log(
+                       LOG_WARNING,
+                       "%s: reset_pcep_session_counters session [%p] has already been deleted",
+                       session);
+               return;
+       }
+
+       reset_group_counters(session->pcep_session_counters);
+}
diff --git a/pceplib/pcep_pcc_api.h b/pceplib/pcep_pcc_api.h
new file mode 100644 (file)
index 0000000..5756e23
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+/*
+ * Public PCEPlib PCC API
+ */
+
+#ifndef PCEPPCC_INCLUDE_PCEPPCCAPI_H_
+#define PCEPPCC_INCLUDE_PCEPPCCAPI_H_
+
+#include <stdbool.h>
+
+#include "pcep_session_logic.h"
+#include "pcep_timers.h"
+
+#define DEFAULT_PCEP_TCP_PORT 4189
+#define DEFAULT_CONFIG_KEEP_ALIVE 30
+#define DEFAULT_CONFIG_DEAD_TIMER DEFAULT_CONFIG_KEEP_ALIVE * 4
+#define DEFAULT_CONFIG_REQUEST_TIME 30
+#define DEFAULT_CONFIG_MAX_UNKNOWN_REQUESTS 5
+#define DEFAULT_CONFIG_MAX_UNKNOWN_MESSAGES 5
+#define DEFAULT_TCP_CONNECT_TIMEOUT_MILLIS 250
+
+/* Acceptable MIN and MAX values used in deciding if the PCEP
+ * Open received from a PCE should be accepted or rejected. */
+#define DEFAULT_MIN_CONFIG_KEEP_ALIVE 5
+#define DEFAULT_MAX_CONFIG_KEEP_ALIVE 120
+#define DEFAULT_MIN_CONFIG_DEAD_TIMER DEFAULT_MIN_CONFIG_KEEP_ALIVE * 4
+#define DEFAULT_MAX_CONFIG_DEAD_TIMER DEFAULT_MAX_CONFIG_KEEP_ALIVE * 4
+
+/*
+ * PCEP PCC library initialization/teardown functions
+ */
+
+/* Later when this is integrated with FRR pathd, it will be changed
+ * to just initialize_pcc(struct pceplib_infra_config *infra_config) */
+bool initialize_pcc(void);
+bool initialize_pcc_infra(struct pceplib_infra_config *infra_config);
+/* this function is blocking */
+bool initialize_pcc_wait_for_completion(void);
+bool destroy_pcc(void);
+
+
+/*
+ * PCEP session functions
+ */
+
+pcep_configuration *create_default_pcep_configuration(void);
+void destroy_pcep_configuration(pcep_configuration *config);
+
+/* Uses the standard PCEP TCP src and dest port = 4189.
+ * To use a specific dest or src port, set them other than 0 in the
+ * pcep_configuration. If src_ip is not set, INADDR_ANY will be used. */
+pcep_session *connect_pce(pcep_configuration *config, struct in_addr *pce_ip);
+pcep_session *connect_pce_ipv6(pcep_configuration *config,
+                              struct in6_addr *pce_ip);
+void disconnect_pce(pcep_session *session);
+void send_message(pcep_session *session, struct pcep_message *msg,
+                 bool free_after_send);
+
+void dump_pcep_session_counters(pcep_session *session);
+void reset_pcep_session_counters(pcep_session *session);
+
+/*
+ * Event Queue functions
+ */
+
+/* Returns true if the queue is empty, false otherwise */
+bool event_queue_is_empty(void);
+
+/* Return the number of events on the queue, 0 if empty */
+uint32_t event_queue_num_events_available(void);
+
+/* Return the next event on the queue, NULL if empty */
+struct pcep_event *event_queue_get_event(void);
+
+/* Free the PCEP Event resources, including the PCEP message */
+void destroy_pcep_event(struct pcep_event *event);
+
+const char *get_event_type_str(int event_type);
+
+
+#endif /* PCEPPCC_INCLUDE_PCEPPCCAPI_H_ */
diff --git a/pceplib/pcep_session_logic.c b/pceplib/pcep_session_logic.c
new file mode 100644 (file)
index 0000000..5265591
--- /dev/null
@@ -0,0 +1,683 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <errno.h>
+#include <limits.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+#include "pcep_msg_encoding.h"
+#include "pcep_session_logic.h"
+#include "pcep_session_logic_internals.h"
+#include "pcep_timers.h"
+#include "pcep_utils_counters.h"
+#include "pcep_utils_ordered_list.h"
+#include "pcep_utils_logging.h"
+#include "pcep_utils_memory.h"
+
+/*
+ * public API function implementations for the session_logic
+ */
+
+pcep_session_logic_handle *session_logic_handle_ = NULL;
+pcep_event_queue *session_logic_event_queue_ = NULL;
+int session_id_ = 0;
+
+void send_pcep_open(pcep_session *session); /* forward decl */
+
+static bool run_session_logic_common()
+{
+       if (session_logic_handle_ != NULL) {
+               pcep_log(LOG_WARNING,
+                        "%s: Session Logic is already initialized.", __func__);
+               return false;
+       }
+
+       session_logic_handle_ = pceplib_malloc(
+               PCEPLIB_INFRA, sizeof(pcep_session_logic_handle));
+       memset(session_logic_handle_, 0, sizeof(pcep_session_logic_handle));
+
+       session_logic_handle_->active = true;
+       session_logic_handle_->session_list =
+               ordered_list_initialize(pointer_compare_function);
+       session_logic_handle_->session_event_queue = queue_initialize();
+
+       /* Initialize the event queue */
+       session_logic_event_queue_ =
+               pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_event_queue));
+       session_logic_event_queue_->event_queue = queue_initialize();
+       if (pthread_mutex_init(&(session_logic_event_queue_->event_queue_mutex),
+                              NULL)
+           != 0) {
+               pcep_log(
+                       LOG_ERR,
+                       "%s: Cannot initialize session_logic event queue mutex.",
+                       __func__);
+               return false;
+       }
+
+       pthread_cond_init(&(session_logic_handle_->session_logic_cond_var),
+                         NULL);
+
+       if (pthread_mutex_init(&(session_logic_handle_->session_logic_mutex),
+                              NULL)
+           != 0) {
+               pcep_log(LOG_ERR, "%s: Cannot initialize session_logic mutex.",
+                        __func__);
+               return false;
+       }
+
+       pthread_mutex_lock(&(session_logic_handle_->session_logic_mutex));
+       session_logic_handle_->session_logic_condition = true;
+       pthread_cond_signal(&(session_logic_handle_->session_logic_cond_var));
+       pthread_mutex_unlock(&(session_logic_handle_->session_logic_mutex));
+
+       if (pthread_mutex_init(&(session_logic_handle_->session_list_mutex),
+                              NULL)
+           != 0) {
+               pcep_log(LOG_ERR, "%s: Cannot initialize session_list mutex.",
+                        __func__);
+               return false;
+       }
+
+       return true;
+}
+
+
+bool run_session_logic()
+{
+       if (!run_session_logic_common()) {
+               return false;
+       }
+
+       if (pthread_create(&(session_logic_handle_->session_logic_thread), NULL,
+                          session_logic_loop, session_logic_handle_)) {
+               pcep_log(LOG_ERR, "%s: Cannot initialize session_logic thread.",
+                        __func__);
+               return false;
+       }
+
+       if (!initialize_timers(session_logic_timer_expire_handler)) {
+               pcep_log(LOG_ERR, "%s: Cannot initialize session_logic timers.",
+                        __func__);
+               return false;
+       }
+
+       /* No need to call initialize_socket_comm_loop() since it will be
+        * called internally when the first socket_comm_session is created. */
+
+       return true;
+}
+
+
+bool run_session_logic_with_infra(pceplib_infra_config *infra_config)
+{
+       if (infra_config == NULL) {
+               return run_session_logic();
+       }
+
+       /* Initialize the memory infrastructure before anything gets allocated
+        */
+       if (infra_config->pceplib_infra_mt != NULL
+           && infra_config->pceplib_messages_mt != NULL) {
+               pceplib_memory_initialize(
+                       infra_config->pceplib_infra_mt,
+                       infra_config->pceplib_messages_mt,
+                       infra_config->malloc_func, infra_config->calloc_func,
+                       infra_config->realloc_func, infra_config->strdup_func,
+                       infra_config->free_func);
+       }
+
+       if (!run_session_logic_common()) {
+               return false;
+       }
+
+       /* Create the pcep_session_logic pthread so it can be managed externally
+        */
+       if (infra_config->pthread_create_func != NULL) {
+               if (infra_config->pthread_create_func(
+                           &(session_logic_handle_->session_logic_thread),
+                           NULL, session_logic_loop, session_logic_handle_,
+                           "pcep_session_logic")) {
+                       pcep_log(
+                               LOG_ERR,
+                               "%s: Cannot initialize external session_logic thread.",
+                               __func__);
+                       return false;
+               }
+       } else {
+               if (pthread_create(
+                           &(session_logic_handle_->session_logic_thread),
+                           NULL, session_logic_loop, session_logic_handle_)) {
+                       pcep_log(LOG_ERR,
+                                "%s: Cannot initialize session_logic thread.",
+                                __func__);
+                       return false;
+               }
+       }
+
+       session_logic_event_queue_->event_callback =
+               infra_config->pcep_event_func;
+       session_logic_event_queue_->event_callback_data =
+               infra_config->external_infra_data;
+
+       if (!initialize_timers_external_infra(
+                   session_logic_timer_expire_handler,
+                   infra_config->external_infra_data,
+                   infra_config->timer_create_func,
+                   infra_config->timer_cancel_func,
+                   infra_config->pthread_create_func)) {
+               pcep_log(
+                       LOG_ERR,
+                       "%s: Cannot initialize session_logic timers with infra.",
+                       __func__);
+               return false;
+       }
+
+       /* We found a problem with the FRR sockets, where not all the KeepAlive
+        * messages were received, so if the pthread_create_func is set, the
+        * internal PCEPlib socket infrastructure will be used. */
+
+       /* For the SocketComm, the socket_read/write_func and the
+        * pthread_create_func are mutually exclusive. */
+       if (infra_config->pthread_create_func != NULL) {
+               if (!initialize_socket_comm_external_infra(
+                           infra_config->external_infra_data, NULL, NULL,
+                           infra_config->pthread_create_func)) {
+                       pcep_log(
+                               LOG_ERR,
+                               "%s: Cannot initialize session_logic socket comm with infra.",
+                               __func__);
+                       return false;
+               }
+       } else if (infra_config->socket_read_func != NULL
+                  && infra_config->socket_write_func != NULL) {
+               if (!initialize_socket_comm_external_infra(
+                           infra_config->external_infra_data,
+                           infra_config->socket_read_func,
+                           infra_config->socket_write_func, NULL)) {
+                       pcep_log(
+                               LOG_ERR,
+                               "%s: Cannot initialize session_logic socket comm with infra.",
+                               __func__);
+                       return false;
+               }
+       }
+
+       return true;
+}
+
+bool run_session_logic_wait_for_completion()
+{
+       if (!run_session_logic()) {
+               return false;
+       }
+
+       /* Blocking call, waits for session logic thread to complete */
+       pthread_join(session_logic_handle_->session_logic_thread, NULL);
+
+       return true;
+}
+
+
+bool stop_session_logic()
+{
+       if (session_logic_handle_ == NULL) {
+               pcep_log(LOG_WARNING, "%s: Session logic already stopped",
+                        __func__);
+               return false;
+       }
+
+       session_logic_handle_->active = false;
+       teardown_timers();
+
+       pthread_mutex_lock(&(session_logic_handle_->session_logic_mutex));
+       session_logic_handle_->session_logic_condition = true;
+       pthread_cond_signal(&(session_logic_handle_->session_logic_cond_var));
+       pthread_mutex_unlock(&(session_logic_handle_->session_logic_mutex));
+       pthread_join(session_logic_handle_->session_logic_thread, NULL);
+
+       pthread_mutex_destroy(&(session_logic_handle_->session_logic_mutex));
+       pthread_mutex_destroy(&(session_logic_handle_->session_list_mutex));
+       ordered_list_destroy(session_logic_handle_->session_list);
+       queue_destroy(session_logic_handle_->session_event_queue);
+
+       /* destroy the event_queue */
+       pthread_mutex_destroy(&(session_logic_event_queue_->event_queue_mutex));
+       queue_destroy(session_logic_event_queue_->event_queue);
+       pceplib_free(PCEPLIB_INFRA, session_logic_event_queue_);
+
+       /* Explicitly stop the socket comm loop started by the pcep_sessions */
+       destroy_socket_comm_loop();
+
+       pceplib_free(PCEPLIB_INFRA, session_logic_handle_);
+       session_logic_handle_ = NULL;
+
+       return true;
+}
+
+
+void close_pcep_session(pcep_session *session)
+{
+       close_pcep_session_with_reason(session, PCEP_CLOSE_REASON_NO);
+}
+
+void close_pcep_session_with_reason(pcep_session *session,
+                                   enum pcep_close_reason reason)
+{
+       struct pcep_message *close_msg = pcep_msg_create_close(reason);
+
+       pcep_log(
+               LOG_INFO,
+               "%s: [%ld-%ld] pcep_session_logic send pcep_close message for session [%d]",
+               __func__, time(NULL), pthread_self(), session->session_id);
+
+       session_send_message(session, close_msg);
+       socket_comm_session_close_tcp_after_write(session->socket_comm_session);
+       session->session_state = SESSION_STATE_INITIALIZED;
+}
+
+
+void destroy_pcep_session(pcep_session *session)
+{
+       if (session == NULL) {
+               pcep_log(LOG_WARNING, "%s: Cannot destroy NULL session",
+                        __func__);
+               return;
+       }
+
+       /* Remove the session from the session_list and synchronize session
+        * destroy with the session_logic_loop, so that no in-flight events
+        * will be handled now that the session is destroyed. */
+       pthread_mutex_lock(&(session_logic_handle_->session_list_mutex));
+       ordered_list_remove_first_node_equals(
+               session_logic_handle_->session_list, session);
+       pcep_log(LOG_DEBUG,
+                "%s: destroy_pcep_session delete session_list sessionPtr %p",
+                __func__, session);
+
+       pcep_session_cancel_timers(session);
+       delete_counters_group(session->pcep_session_counters);
+       queue_destroy_with_data(session->num_unknown_messages_time_queue);
+       socket_comm_session_teardown(session->socket_comm_session);
+
+       if (session->pcc_config.pcep_msg_versioning != NULL) {
+               pceplib_free(PCEPLIB_INFRA,
+                            session->pcc_config.pcep_msg_versioning);
+       }
+
+       if (session->pce_config.pcep_msg_versioning != NULL) {
+               pceplib_free(PCEPLIB_INFRA,
+                            session->pce_config.pcep_msg_versioning);
+       }
+
+       int session_id = session->session_id;
+       pceplib_free(PCEPLIB_INFRA, session);
+       pcep_log(LOG_INFO, "%s: [%ld-%ld] session [%d] destroyed", __func__,
+                time(NULL), pthread_self(), session_id);
+       pthread_mutex_unlock(&(session_logic_handle_->session_list_mutex));
+}
+
+void pcep_session_cancel_timers(pcep_session *session)
+{
+       if (session == NULL) {
+               return;
+       }
+
+       if (session->timer_id_dead_timer != TIMER_ID_NOT_SET) {
+               cancel_timer(session->timer_id_dead_timer);
+       }
+
+       if (session->timer_id_keep_alive != TIMER_ID_NOT_SET) {
+               cancel_timer(session->timer_id_keep_alive);
+       }
+
+       if (session->timer_id_open_keep_wait != TIMER_ID_NOT_SET) {
+               cancel_timer(session->timer_id_open_keep_wait);
+       }
+
+       if (session->timer_id_open_keep_alive != TIMER_ID_NOT_SET) {
+               cancel_timer(session->timer_id_open_keep_alive);
+       }
+}
+
+/* Internal util function */
+static int get_next_session_id()
+{
+       if (session_id_ == INT_MAX) {
+               session_id_ = 0;
+       }
+
+       return session_id_++;
+}
+
+/* Internal util function */
+static pcep_session *create_pcep_session_pre_setup(pcep_configuration *config)
+{
+       if (config == NULL) {
+               pcep_log(LOG_WARNING,
+                        "%s: Cannot create pcep session with NULL config",
+                        __func__);
+               return NULL;
+       }
+
+       pcep_session *session =
+               pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_session));
+       memset(session, 0, sizeof(pcep_session));
+       session->session_id = get_next_session_id();
+       session->session_state = SESSION_STATE_INITIALIZED;
+       session->timer_id_open_keep_wait = TIMER_ID_NOT_SET;
+       session->timer_id_open_keep_alive = TIMER_ID_NOT_SET;
+       session->timer_id_dead_timer = TIMER_ID_NOT_SET;
+       session->timer_id_keep_alive = TIMER_ID_NOT_SET;
+       session->stateful_pce = false;
+       session->num_unknown_messages_time_queue = queue_initialize();
+       session->pce_open_received = false;
+       session->pce_open_rejected = false;
+       session->pce_open_keep_alive_sent = false;
+       session->pcc_open_rejected = false;
+       session->pce_open_accepted = false;
+       session->pcc_open_accepted = false;
+       session->destroy_session_after_write = false;
+       session->lsp_db_version = config->lsp_db_version;
+       memcpy(&(session->pcc_config), config, sizeof(pcep_configuration));
+       /* copy the pcc_config to the pce_config until we receive the open
+        * keep_alive response */
+       memcpy(&(session->pce_config), config, sizeof(pcep_configuration));
+       if (config->pcep_msg_versioning != NULL) {
+               session->pcc_config.pcep_msg_versioning = pceplib_malloc(
+                       PCEPLIB_INFRA, sizeof(struct pcep_versioning));
+               memcpy(session->pcc_config.pcep_msg_versioning,
+                      config->pcep_msg_versioning,
+                      sizeof(struct pcep_versioning));
+               session->pce_config.pcep_msg_versioning = pceplib_malloc(
+                       PCEPLIB_INFRA, sizeof(struct pcep_versioning));
+               memcpy(session->pce_config.pcep_msg_versioning,
+                      config->pcep_msg_versioning,
+                      sizeof(struct pcep_versioning));
+       }
+
+       pthread_mutex_lock(&(session_logic_handle_->session_list_mutex));
+       ordered_list_add_node(session_logic_handle_->session_list, session);
+       pcep_log(
+               LOG_DEBUG,
+               "%s: create_pcep_session_pre_setup add session_list sessionPtr %p",
+               __func__, session);
+       pthread_mutex_unlock(&(session_logic_handle_->session_list_mutex));
+
+       return session;
+}
+
+/* Internal util function */
+static bool create_pcep_session_post_setup(pcep_session *session)
+{
+       if (!socket_comm_session_connect_tcp(session->socket_comm_session)) {
+               pcep_log(LOG_WARNING, "%s: Cannot establish TCP socket.",
+                        __func__);
+               destroy_pcep_session(session);
+
+               return false;
+       }
+
+       session->time_connected = time(NULL);
+       create_session_counters(session);
+
+       send_pcep_open(session);
+
+       session->session_state = SESSION_STATE_PCEP_CONNECTING;
+       session->timer_id_open_keep_wait =
+               create_timer(session->pcc_config.keep_alive_seconds, session);
+       // session->session_state = SESSION_STATE_OPENED;
+
+       return true;
+}
+
+pcep_session *create_pcep_session(pcep_configuration *config,
+                                 struct in_addr *pce_ip)
+{
+       if (pce_ip == NULL) {
+               pcep_log(LOG_WARNING,
+                        "%s: Cannot create pcep session with NULL pce_ip",
+                        __func__);
+               return NULL;
+       }
+
+       pcep_session *session = create_pcep_session_pre_setup(config);
+       if (session == NULL) {
+               return NULL;
+       }
+
+       session->socket_comm_session = socket_comm_session_initialize_with_src(
+               NULL, session_logic_msg_ready_handler,
+               session_logic_message_sent_handler,
+               session_logic_conn_except_notifier, &(config->src_ip.src_ipv4),
+               ((config->src_pcep_port == 0) ? PCEP_TCP_PORT
+                                             : config->src_pcep_port),
+               pce_ip,
+               ((config->dst_pcep_port == 0) ? PCEP_TCP_PORT
+                                             : config->dst_pcep_port),
+               config->socket_connect_timeout_millis,
+               config->tcp_authentication_str, config->is_tcp_auth_md5,
+               session);
+       if (session->socket_comm_session == NULL) {
+               pcep_log(LOG_WARNING,
+                        "%s: Cannot establish socket_comm_session.", __func__);
+               destroy_pcep_session(session);
+
+               return NULL;
+       }
+
+       if (create_pcep_session_post_setup(session) == false) {
+               return NULL;
+       }
+
+       return session;
+}
+
+pcep_session *create_pcep_session_ipv6(pcep_configuration *config,
+                                      struct in6_addr *pce_ip)
+{
+       if (pce_ip == NULL) {
+               pcep_log(LOG_WARNING,
+                        "%s: Cannot create pcep session with NULL pce_ip",
+                        __func__);
+               return NULL;
+       }
+
+       pcep_session *session = create_pcep_session_pre_setup(config);
+       if (session == NULL) {
+               return NULL;
+       }
+
+       session->socket_comm_session =
+               socket_comm_session_initialize_with_src_ipv6(
+                       NULL, session_logic_msg_ready_handler,
+                       session_logic_message_sent_handler,
+                       session_logic_conn_except_notifier,
+                       &(config->src_ip.src_ipv6),
+                       ((config->src_pcep_port == 0) ? PCEP_TCP_PORT
+                                                     : config->src_pcep_port),
+                       pce_ip,
+                       ((config->dst_pcep_port == 0) ? PCEP_TCP_PORT
+                                                     : config->dst_pcep_port),
+                       config->socket_connect_timeout_millis,
+                       config->tcp_authentication_str, config->is_tcp_auth_md5,
+                       session);
+       if (session->socket_comm_session == NULL) {
+               pcep_log(LOG_WARNING,
+                        "%s: Cannot establish ipv6 socket_comm_session.",
+                        __func__);
+               destroy_pcep_session(session);
+
+               return NULL;
+       }
+
+       if (create_pcep_session_post_setup(session) == false) {
+               return NULL;
+       }
+
+       return session;
+}
+
+
+void session_send_message(pcep_session *session, struct pcep_message *message)
+{
+       pcep_encode_message(message, session->pcc_config.pcep_msg_versioning);
+       socket_comm_session_send_message(session->socket_comm_session,
+                                        (char *)message->encoded_message,
+                                        message->encoded_message_length, true);
+
+       increment_message_tx_counters(session, message);
+
+       /* The message->encoded_message will be freed in
+        * socket_comm_session_send_message() once sent.
+        * Setting to NULL here so pcep_msg_free_message() does not free it */
+       message->encoded_message = NULL;
+       pcep_msg_free_message(message);
+}
+
+
+/* This function is also used in pcep_session_logic_states.c */
+struct pcep_message *create_pcep_open(pcep_session *session)
+{
+       /* create and send PCEP open
+        * with PCEP, the PCC sends the config the PCE should use in the open
+        * message,
+        * and the PCE will send an open with the config the PCC should use. */
+       double_linked_list *tlv_list = dll_initialize();
+       if (session->pcc_config.support_stateful_pce_lsp_update
+           || session->pcc_config.support_pce_lsp_instantiation
+           || session->pcc_config.support_include_db_version
+           || session->pcc_config.support_lsp_triggered_resync
+           || session->pcc_config.support_lsp_delta_sync
+           || session->pcc_config.support_pce_triggered_initial_sync) {
+               /* Prepend this TLV as the first in the list */
+               dll_append(
+                       tlv_list,
+                       pcep_tlv_create_stateful_pce_capability(
+                               /* U flag */
+                               session->pcc_config
+                                       .support_stateful_pce_lsp_update,
+                               /* S flag */
+                               session->pcc_config.support_include_db_version,
+                               /* I flag */
+                               session->pcc_config
+                                       .support_pce_lsp_instantiation,
+                       /* T flag */
+                       session->pcc_config.support_lsp_triggered_resync,
+                       /* D flag */
+                       session->pcc_config.support_lsp_delta_sync,
+                       /* F flag */
+                       session->pcc_config.support_pce_triggered_initial_sync));
+       }
+
+       if (session->pcc_config.support_include_db_version) {
+               if (session->pcc_config.lsp_db_version != 0) {
+                       dll_append(tlv_list,
+                                  pcep_tlv_create_lsp_db_version(
+                                          session->pcc_config.lsp_db_version));
+               }
+       }
+
+       if (session->pcc_config.support_sr_te_pst) {
+               bool flag_n = false;
+               bool flag_x = false;
+               if (session->pcc_config.pcep_msg_versioning
+                           ->draft_ietf_pce_segment_routing_07
+                   == false) {
+                       flag_n = session->pcc_config.pcc_can_resolve_nai_to_sid;
+                       flag_x = (session->pcc_config.max_sid_depth == 0);
+               }
+
+               struct pcep_object_tlv_sr_pce_capability *sr_pce_cap_tlv =
+                       pcep_tlv_create_sr_pce_capability(
+                               flag_n, flag_x,
+                               session->pcc_config.max_sid_depth);
+
+               double_linked_list *sub_tlv_list = NULL;
+               if (session->pcc_config.pcep_msg_versioning
+                           ->draft_ietf_pce_segment_routing_07
+                   == true) {
+                       /* With draft07, send the sr_pce_cap_tlv as a normal TLV
+                        */
+                       dll_append(tlv_list, sr_pce_cap_tlv);
+               } else {
+                       /* With draft16, send the sr_pce_cap_tlv as a sub-TLV in
+                        * the path_setup_type_capability TLV */
+                       sub_tlv_list = dll_initialize();
+                       dll_append(sub_tlv_list, sr_pce_cap_tlv);
+               }
+
+               uint8_t *pst =
+                       pceplib_malloc(PCEPLIB_MESSAGES, sizeof(uint8_t));
+               *pst = SR_TE_PST;
+               double_linked_list *pst_list = dll_initialize();
+               dll_append(pst_list, pst);
+               dll_append(tlv_list, pcep_tlv_create_path_setup_type_capability(
+                                            pst_list, sub_tlv_list));
+       }
+
+       struct pcep_message *open_msg = pcep_msg_create_open_with_tlvs(
+               session->pcc_config.keep_alive_seconds,
+               session->pcc_config.dead_timer_seconds, session->session_id,
+               tlv_list);
+
+       pcep_log(
+               LOG_INFO,
+               "%s: [%ld-%ld] pcep_session_logic create open message: TLVs [%d] for session [%d]",
+               __func__, time(NULL), pthread_self(), tlv_list->num_entries,
+               session->session_id);
+
+       return (open_msg);
+}
+
+
+void send_pcep_open(pcep_session *session)
+{
+       session_send_message(session, create_pcep_open(session));
+}
+
+/* This is a blocking call, since it is synchronized with destroy_pcep_session()
+ * and session_logic_loop(). It may be possible that the session has been
+ * deleted but API users havent been informed yet.
+ */
+bool session_exists(pcep_session *session)
+{
+       if (session_logic_handle_ == NULL) {
+               pcep_log(LOG_DEBUG,
+                        "%s: session_exists session_logic_handle_ is NULL",
+                        __func__);
+               return false;
+       }
+
+       pthread_mutex_lock(&(session_logic_handle_->session_list_mutex));
+       bool retval =
+               (ordered_list_find(session_logic_handle_->session_list, session)
+                != NULL);
+       pthread_mutex_unlock(&(session_logic_handle_->session_list_mutex));
+
+       return retval;
+}
diff --git a/pceplib/pcep_session_logic.h b/pceplib/pcep_session_logic.h
new file mode 100644 (file)
index 0000000..a082ec6
--- /dev/null
@@ -0,0 +1,290 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#ifndef INCLUDE_PCEPSESSIONLOGIC_H_
+#define INCLUDE_PCEPSESSIONLOGIC_H_
+
+#include <stdbool.h>
+#include <netinet/tcp.h>
+
+#include "pcep_msg_encoding.h"
+#include "pcep_socket_comm.h"
+#include "pcep_msg_objects.h"
+#include "pcep_msg_tools.h"
+#include "pcep_timers.h"
+#include "pcep_utils_queue.h"
+#include "pcep_utils_memory.h"
+
+#define PCEP_TCP_PORT 4189
+
+typedef struct pcep_configuration_ {
+       /* These are the configuration values that will
+        * be sent to the PCE in the PCEP Open message */
+       int keep_alive_seconds;
+       int dead_timer_seconds;
+       int dead_timer_pce_negotiated_seconds; /* Config data negotiated with
+                                                 PCE */
+       int keep_alive_pce_negotiated_timer_seconds; /* Config data negotiated
+                                                       with PCE */
+       int request_time_seconds;
+
+       /* These are the acceptable ranges of values received by
+        * the PCE in the initial PCEP Open Message. If a value is
+        * received outside of these ranges, then the Open message
+        * will be rejected. */
+       int min_keep_alive_seconds;
+       int max_keep_alive_seconds;
+       int min_dead_timer_seconds;
+       int max_dead_timer_seconds;
+
+       /* If more than this many unknown messages/requests are received
+        * per minute, then the session will be closed. */
+       int max_unknown_messages;
+       int max_unknown_requests;
+
+       /* Maximum amount of time to wait to connect to the
+        * PCE TCP socket before failing, in milliseconds. */
+       uint32_t socket_connect_timeout_millis;
+
+       /* Set if the PCE/PCC will support stateful PCE LSP Updates
+        * according to RCF8231, section 7.1.1, defaults to true.
+        * Will cause an additional TLV to be sent from the PCC in
+        * the PCEP Open */
+       bool support_stateful_pce_lsp_update;
+
+       /* RFC 8281: I-bit, the PCC allows instantiation of an LSP by a PCE */
+       bool support_pce_lsp_instantiation;
+
+       /* RFC 8232: S-bit, the PCC will include the LSP-DB-VERSION
+        * TLV in each LSP object */
+       bool support_include_db_version;
+
+       /* Only set if support_include_db_version is true and if the LSP-DB
+        * survived a restart and is available. If this has a value other than
+        * 0, then a LSP-DB-VERSION TLV will be sent in the OPEN object. This
+        * value will be copied over to the pcep_session upon init. */
+       uint64_t lsp_db_version;
+
+       /* RFC 8232: T-bit, the PCE can trigger resynchronization of
+        * LSPs at any point in the life of the session */
+       bool support_lsp_triggered_resync;
+
+       /* RFC 8232: D-bit, the PCEP speaker allows incremental (delta)
+        * State Synchronization */
+       bool support_lsp_delta_sync;
+
+       /* RFC 8232: F-bit, the PCE SHOULD trigger initial (first)
+        * State Synchronization */
+       bool support_pce_triggered_initial_sync;
+
+       /* draft-ietf-pce-segment-routing-16: Send a SR PCE Capability
+        * sub-TLV in a Path Setup Type Capability TLV with a PST = 1,
+        * Path is setup using SR TE. */
+       bool support_sr_te_pst;
+       /* Used in the SR PCE Capability sub-TLV */
+       bool pcc_can_resolve_nai_to_sid;
+       /* Used in the SR TE Capability sub-TLV, 0 means there are no max sid
+        * limits */
+       uint8_t max_sid_depth;
+
+       /* If set to 0, then the default 4189 PCEP port will be used */
+       uint16_t dst_pcep_port;
+
+       /* If set to 0, then the default 4189 PCEP port will be used.
+        * This is according to the RFC5440, Section 5 */
+       uint16_t src_pcep_port;
+
+       union src_ip {
+               struct in_addr src_ipv4;
+               struct in6_addr src_ipv6;
+       } src_ip;
+       bool is_src_ipv6;
+
+       struct pcep_versioning *pcep_msg_versioning;
+
+       char tcp_authentication_str[TCP_MD5SIG_MAXKEYLEN];
+       bool is_tcp_auth_md5; /* true: RFC 2385, false: RFC 5925 */
+
+} pcep_configuration;
+
+
+typedef enum pcep_session_state_ {
+       SESSION_STATE_UNKNOWN = 0,
+       SESSION_STATE_INITIALIZED = 1,
+       SESSION_STATE_PCEP_CONNECTING = 2,
+       SESSION_STATE_PCEP_CONNECTED = 3
+
+} pcep_session_state;
+
+
+typedef struct pcep_session_ {
+       int session_id;
+       pcep_session_state session_state;
+       int timer_id_open_keep_wait;
+       int timer_id_open_keep_alive;
+       int timer_id_dead_timer;
+       int timer_id_keep_alive;
+       bool pce_open_received;
+       bool pce_open_rejected;
+       bool pce_open_accepted;
+       bool pce_open_keep_alive_sent;
+       bool pcc_open_rejected;
+       bool pcc_open_accepted;
+       bool stateful_pce;
+       time_t time_connected;
+       uint64_t lsp_db_version;
+       queue_handle *num_unknown_messages_time_queue;
+       /* set this flag when finalizing the session */
+       bool destroy_session_after_write;
+       pcep_socket_comm_session *socket_comm_session;
+       /* Configuration sent from the PCC to the PCE */
+       pcep_configuration pcc_config;
+       /* Configuration received from the PCE, to be used in the PCC */
+       pcep_configuration pce_config;
+       struct counters_group *pcep_session_counters;
+
+} pcep_session;
+
+
+typedef enum pcep_event_type {
+       MESSAGE_RECEIVED = 0,
+       PCE_CLOSED_SOCKET = 1,
+       PCE_SENT_PCEP_CLOSE = 2,
+       PCE_DEAD_TIMER_EXPIRED = 3,
+       PCE_OPEN_KEEP_WAIT_TIMER_EXPIRED = 4,
+       PCC_CONNECTED_TO_PCE = 100,
+       PCC_CONNECTION_FAILURE = 101,
+       PCC_PCEP_SESSION_CLOSED = 102,
+       PCC_RCVD_INVALID_OPEN = 103,
+       PCC_SENT_INVALID_OPEN = 104,
+       PCC_RCVD_MAX_INVALID_MSGS = 105,
+       PCC_RCVD_MAX_UNKOWN_MSGS = 106
+
+} pcep_event_type;
+
+
+typedef struct pcep_event {
+       enum pcep_event_type event_type;
+       time_t event_time;
+       struct pcep_message *message;
+       pcep_session *session;
+
+} pcep_event;
+
+typedef void (*pceplib_pcep_event_callback)(void *cb_data, pcep_event *);
+typedef int (*pthread_create_callback)(pthread_t *pthread_id,
+                                      const pthread_attr_t *attr,
+                                      void *(*start_routine)(void *),
+                                      void *data, const char *thread_name);
+
+
+typedef struct pcep_event_queue {
+       /* The event_queue and event_callback are mutually exclusive.
+        * If the event_callback is configured, then the event_queue
+        * will not be used. */
+       queue_handle *event_queue;
+       pthread_mutex_t event_queue_mutex;
+       pceplib_pcep_event_callback event_callback;
+       void *event_callback_data;
+
+} pcep_event_queue;
+
+
+typedef struct pceplib_infra_config {
+       /* Memory infrastructure */
+       void *pceplib_infra_mt;
+       void *pceplib_messages_mt;
+       pceplib_malloc_func malloc_func;
+       pceplib_calloc_func calloc_func;
+       pceplib_realloc_func realloc_func;
+       pceplib_strdup_func strdup_func;
+       pceplib_free_func free_func;
+
+       /* External Timer and Socket infrastructure */
+       void *external_infra_data;
+       ext_timer_create timer_create_func;
+       ext_timer_cancel timer_cancel_func;
+       ext_socket_write socket_write_func;
+       ext_socket_read socket_read_func;
+
+       /* External pcep_event infrastructure */
+       pceplib_pcep_event_callback pcep_event_func;
+
+       /* Callback to create pthreads */
+       pthread_create_callback pthread_create_func;
+
+} pceplib_infra_config;
+
+/*
+ * Counters Sub-groups definitions
+ */
+typedef enum pcep_session_counters_subgroup_ids {
+       COUNTER_SUBGROUP_ID_RX_MSG = 0,
+       COUNTER_SUBGROUP_ID_TX_MSG = 1,
+       COUNTER_SUBGROUP_ID_RX_OBJ = 2,
+       COUNTER_SUBGROUP_ID_TX_OBJ = 3,
+       COUNTER_SUBGROUP_ID_RX_SUBOBJ = 4,
+       COUNTER_SUBGROUP_ID_TX_SUBOBJ = 5,
+       COUNTER_SUBGROUP_ID_RX_RO_SR_SUBOBJ = 6,
+       COUNTER_SUBGROUP_ID_TX_RO_SR_SUBOBJ = 7,
+       COUNTER_SUBGROUP_ID_RX_TLV = 8,
+       COUNTER_SUBGROUP_ID_TX_TLV = 9,
+       COUNTER_SUBGROUP_ID_EVENT = 10
+
+} pcep_session_counters_subgroup_ids;
+
+bool run_session_logic(void);
+bool run_session_logic_with_infra(pceplib_infra_config *infra_config);
+
+bool run_session_logic_wait_for_completion(void);
+
+bool stop_session_logic(void);
+
+/* Uses the standard PCEP TCP dest port = 4189 and an ephemeral src port.
+ * To use a specific dest or src port, set them other than 0 in the
+ * pcep_configuration. */
+pcep_session *create_pcep_session(pcep_configuration *config,
+                                 struct in_addr *pce_ip);
+pcep_session *create_pcep_session_ipv6(pcep_configuration *config,
+                                      struct in6_addr *pce_ip);
+
+/* Send a PCEP close for this pcep_session */
+void close_pcep_session(pcep_session *session);
+void close_pcep_session_with_reason(pcep_session *session,
+                                   enum pcep_close_reason);
+
+/* Destroy the PCEP session, a PCEP close should have
+ * already been sent with close_pcep_session() */
+void destroy_pcep_session(pcep_session *session);
+
+void pcep_session_cancel_timers(pcep_session *session);
+
+/* Increments transmitted message counters, additionally counters for the
+ * objects, sub-objects, and TLVs in the message will be incremented.  Received
+ * counters are incremented internally. */
+void increment_message_tx_counters(pcep_session *session,
+                                  struct pcep_message *message);
+
+bool session_exists(pcep_session *session);
+
+#endif /* INCLUDE_PCEPSESSIONLOGIC_H_ */
diff --git a/pceplib/pcep_session_logic_counters.c b/pceplib/pcep_session_logic_counters.c
new file mode 100644 (file)
index 0000000..a6bd41b
--- /dev/null
@@ -0,0 +1,450 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+/*
+ * PCEP session logic counters configuration.
+ */
+
+#include <stdio.h>
+#include <time.h>
+
+#include "pcep_session_logic.h"
+#include "pcep_session_logic_internals.h"
+#include "pcep_utils_counters.h"
+#include "pcep_utils_logging.h"
+
+void increment_message_counters(pcep_session *session,
+                               struct pcep_message *message, bool is_rx);
+
+void create_session_counters(pcep_session *session)
+{
+       /*
+        * Message RX and TX counters
+        */
+       struct counters_subgroup *rx_msg_subgroup = create_counters_subgroup(
+               "RX Message counters", COUNTER_SUBGROUP_ID_RX_MSG,
+               PCEP_TYPE_MAX + 1);
+       create_subgroup_counter(rx_msg_subgroup, PCEP_TYPE_OPEN,
+                               "Message Open");
+       create_subgroup_counter(rx_msg_subgroup, PCEP_TYPE_KEEPALIVE,
+                               "Message KeepAlive");
+       create_subgroup_counter(rx_msg_subgroup, PCEP_TYPE_PCREQ,
+                               "Message PcReq");
+       create_subgroup_counter(rx_msg_subgroup, PCEP_TYPE_PCREP,
+                               "Message PcRep");
+       create_subgroup_counter(rx_msg_subgroup, PCEP_TYPE_PCNOTF,
+                               "Message Notify");
+       create_subgroup_counter(rx_msg_subgroup, PCEP_TYPE_ERROR,
+                               "Message Error");
+       create_subgroup_counter(rx_msg_subgroup, PCEP_TYPE_CLOSE,
+                               "Message Close");
+       create_subgroup_counter(rx_msg_subgroup, PCEP_TYPE_REPORT,
+                               "Message Report");
+       create_subgroup_counter(rx_msg_subgroup, PCEP_TYPE_UPDATE,
+                               "Message Update");
+       create_subgroup_counter(rx_msg_subgroup, PCEP_TYPE_INITIATE,
+                               "Message Initiate");
+       create_subgroup_counter(rx_msg_subgroup, PCEP_TYPE_START_TLS,
+                               "Message StartTls");
+       create_subgroup_counter(rx_msg_subgroup, PCEP_TYPE_MAX,
+                               "Message Erroneous");
+
+       struct counters_subgroup *tx_msg_subgroup =
+               clone_counters_subgroup(rx_msg_subgroup, "TX Message counters",
+                                       COUNTER_SUBGROUP_ID_TX_MSG);
+
+       /*
+        * Object RX and TX counters
+        */
+
+       /* For the Endpoints, the ID will be either 64 or 65, so setting
+        * num_counters to 100 */
+       struct counters_subgroup *rx_obj_subgroup = create_counters_subgroup(
+               "RX Object counters", COUNTER_SUBGROUP_ID_RX_OBJ, 100);
+       create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_OPEN,
+                               "Object Open");
+       create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_RP,
+                               "Object RP");
+       create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_NOPATH,
+                               "Object Nopath");
+       create_subgroup_counter(
+               rx_obj_subgroup,
+               ((PCEP_OBJ_CLASS_ENDPOINTS << 4) | PCEP_OBJ_TYPE_ENDPOINT_IPV4),
+               "Object Endpoint IPv4");
+       create_subgroup_counter(
+               rx_obj_subgroup,
+               ((PCEP_OBJ_CLASS_ENDPOINTS << 4) | PCEP_OBJ_TYPE_ENDPOINT_IPV6),
+               "Object Endpoint IPv6");
+       create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_BANDWIDTH,
+                               "Object Bandwidth");
+       create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_METRIC,
+                               "Object Metric");
+       create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_ERO,
+                               "Object ERO");
+       create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_RRO,
+                               "Object RRO");
+       create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_LSPA,
+                               "Object LSPA");
+       create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_IRO,
+                               "Object IRO");
+       create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_SVEC,
+                               "Object SVEC");
+       create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_NOTF,
+                               "Object Notify");
+       create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_ERROR,
+                               "Object Error");
+       create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_CLOSE,
+                               "Object Close");
+       create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_LSP,
+                               "Object LSP");
+       create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_SRP,
+                               "Object SRP");
+       create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_VENDOR_INFO,
+                               "Object Vendor Info");
+       create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_INTER_LAYER,
+                               "Object Inter-Layer");
+       create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_SWITCH_LAYER,
+                               "Object Switch-Layer");
+       create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_REQ_ADAP_CAP,
+                               "Object Requested Adap-Cap");
+       create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_SERVER_IND,
+                               "Object Server-Indication");
+       create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_ASSOCIATION,
+                               "Object Association");
+       create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_MAX,
+                               "Object Unknown");
+       create_subgroup_counter(rx_obj_subgroup, PCEP_OBJ_CLASS_MAX + 1,
+                               "Object Erroneous");
+
+       struct counters_subgroup *tx_obj_subgroup =
+               clone_counters_subgroup(rx_obj_subgroup, "TX Object counters",
+                                       COUNTER_SUBGROUP_ID_TX_OBJ);
+
+       /*
+        * Sub-Object RX and TX counters
+        */
+       struct counters_subgroup *rx_subobj_subgroup = create_counters_subgroup(
+               "RX RO Sub-Object counters", COUNTER_SUBGROUP_ID_RX_SUBOBJ,
+               RO_SUBOBJ_UNKNOWN + 2);
+       create_subgroup_counter(rx_subobj_subgroup, RO_SUBOBJ_TYPE_IPV4,
+                               "RO Sub-Object IPv4");
+       create_subgroup_counter(rx_subobj_subgroup, RO_SUBOBJ_TYPE_IPV6,
+                               "RO Sub-Object IPv6");
+       create_subgroup_counter(rx_subobj_subgroup, RO_SUBOBJ_TYPE_LABEL,
+                               "RO Sub-Object Label");
+       create_subgroup_counter(rx_subobj_subgroup, RO_SUBOBJ_TYPE_UNNUM,
+                               "RO Sub-Object Unnum");
+       create_subgroup_counter(rx_subobj_subgroup, RO_SUBOBJ_TYPE_ASN,
+                               "RO Sub-Object ASN");
+       create_subgroup_counter(rx_subobj_subgroup, RO_SUBOBJ_TYPE_SR,
+                               "RO Sub-Object SR");
+       create_subgroup_counter(rx_subobj_subgroup, RO_SUBOBJ_UNKNOWN,
+                               "RO Sub-Object Unknown");
+       create_subgroup_counter(rx_subobj_subgroup, RO_SUBOBJ_UNKNOWN + 1,
+                               "RO Sub-Object Erroneous");
+
+       struct counters_subgroup *tx_subobj_subgroup = clone_counters_subgroup(
+               rx_subobj_subgroup, "TX RO Sub-Object counters",
+               COUNTER_SUBGROUP_ID_TX_SUBOBJ);
+
+       /*
+        * RO SR Sub-Object RX and TX counters
+        */
+       struct counters_subgroup *rx_subobj_sr_nai_subgroup =
+               create_counters_subgroup("RX RO SR NAI Sub-Object counters",
+                                        COUNTER_SUBGROUP_ID_RX_RO_SR_SUBOBJ,
+                                        PCEP_SR_SUBOBJ_NAI_UNKNOWN + 1);
+       create_subgroup_counter(rx_subobj_sr_nai_subgroup,
+                               PCEP_SR_SUBOBJ_NAI_ABSENT,
+                               "RO Sub-Object SR NAI absent");
+       create_subgroup_counter(rx_subobj_sr_nai_subgroup,
+                               PCEP_SR_SUBOBJ_NAI_IPV4_NODE,
+                               "RO Sub-Object SR NAI IPv4 Node");
+       create_subgroup_counter(rx_subobj_sr_nai_subgroup,
+                               PCEP_SR_SUBOBJ_NAI_IPV6_NODE,
+                               "RO Sub-Object SR NAI IPv6 Node");
+       create_subgroup_counter(rx_subobj_sr_nai_subgroup,
+                               PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY,
+                               "RO Sub-Object SR NAI IPv4 Adj");
+       create_subgroup_counter(rx_subobj_sr_nai_subgroup,
+                               PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY,
+                               "RO Sub-Object SR NAI IPv6 Adj");
+       create_subgroup_counter(rx_subobj_sr_nai_subgroup,
+                               PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY,
+                               "RO Sub-Object SR NAI Unnumbered IPv4 Adj");
+       create_subgroup_counter(rx_subobj_sr_nai_subgroup,
+                               PCEP_SR_SUBOBJ_NAI_LINK_LOCAL_IPV6_ADJACENCY,
+                               "RO Sub-Object SR NAI Link Local IPv6 Adj");
+       create_subgroup_counter(rx_subobj_sr_nai_subgroup,
+                               PCEP_SR_SUBOBJ_NAI_UNKNOWN,
+                               "RO Sub-Object SR NAI Unknown");
+
+       struct counters_subgroup *tx_subobj_sr_nai_subgroup =
+               clone_counters_subgroup(rx_subobj_sr_nai_subgroup,
+                                       "TX RO SR NAI Sub-Object counters",
+                                       COUNTER_SUBGROUP_ID_TX_RO_SR_SUBOBJ);
+
+       /*
+        * TLV RX and TX counters
+        */
+       struct counters_subgroup *rx_tlv_subgroup = create_counters_subgroup(
+               "RX TLV counters", COUNTER_SUBGROUP_ID_RX_TLV,
+               PCEP_OBJ_TLV_TYPE_UNKNOWN + 1);
+       create_subgroup_counter(rx_tlv_subgroup,
+                               PCEP_OBJ_TLV_TYPE_NO_PATH_VECTOR,
+                               "TLV No Path Vector");
+       create_subgroup_counter(rx_tlv_subgroup, PCEP_OBJ_TLV_TYPE_VENDOR_INFO,
+                               "TLV Vendor Info");
+       create_subgroup_counter(rx_tlv_subgroup,
+                               PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY,
+                               "TLV Stateful PCE Capability");
+       create_subgroup_counter(rx_tlv_subgroup,
+                               PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME,
+                               "TLV Symbolic Path Name");
+       create_subgroup_counter(rx_tlv_subgroup,
+                               PCEP_OBJ_TLV_TYPE_IPV4_LSP_IDENTIFIERS,
+                               "TLV IPv4 LSP Identifier");
+       create_subgroup_counter(rx_tlv_subgroup,
+                               PCEP_OBJ_TLV_TYPE_IPV6_LSP_IDENTIFIERS,
+                               "TLV IPv6 LSP Identifier");
+       create_subgroup_counter(rx_tlv_subgroup,
+                               PCEP_OBJ_TLV_TYPE_LSP_ERROR_CODE,
+                               "TLV LSP Error Code");
+       create_subgroup_counter(rx_tlv_subgroup,
+                               PCEP_OBJ_TLV_TYPE_RSVP_ERROR_SPEC,
+                               "TLV RSVP Error Spec");
+       create_subgroup_counter(rx_tlv_subgroup,
+                               PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION,
+                               "TLV LSP DB Version");
+       create_subgroup_counter(rx_tlv_subgroup,
+                               PCEP_OBJ_TLV_TYPE_SPEAKER_ENTITY_ID,
+                               "TLV Speaker Entity ID");
+       create_subgroup_counter(rx_tlv_subgroup,
+                               PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY,
+                               "TLV SR PCE Capability");
+       create_subgroup_counter(rx_tlv_subgroup,
+                               PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE,
+                               "TLV Path Setup Type");
+       create_subgroup_counter(rx_tlv_subgroup,
+                               PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY,
+                               "TLV Path Setup Type Capability");
+       create_subgroup_counter(rx_tlv_subgroup,
+                               PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_ID,
+                               "TLV SR Policy PolId");
+       create_subgroup_counter(rx_tlv_subgroup,
+                               PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_NAME,
+                               "TLV SR Policy PolName");
+       create_subgroup_counter(rx_tlv_subgroup,
+                               PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_ID,
+                               "TLV SR Policy CpathId");
+       create_subgroup_counter(rx_tlv_subgroup,
+                               PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_PREFERENCE,
+                               "TLV SR Policy CpathRef");
+       create_subgroup_counter(rx_tlv_subgroup, PCEP_OBJ_TLV_TYPE_UNKNOWN,
+                               "TLV Unknown");
+
+       struct counters_subgroup *tx_tlv_subgroup = clone_counters_subgroup(
+               rx_tlv_subgroup, "TX TLV counters", COUNTER_SUBGROUP_ID_TX_TLV);
+
+       /*
+        * PCEP Event counters
+        */
+       struct counters_subgroup *events_subgroup = create_counters_subgroup(
+               "Events counters", COUNTER_SUBGROUP_ID_EVENT, MAX_COUNTERS);
+       create_subgroup_counter(events_subgroup,
+                               PCEP_EVENT_COUNTER_ID_PCC_CONNECT,
+                               "PCC connect");
+       create_subgroup_counter(events_subgroup,
+                               PCEP_EVENT_COUNTER_ID_PCE_CONNECT,
+                               "PCE connect");
+       create_subgroup_counter(events_subgroup,
+                               PCEP_EVENT_COUNTER_ID_PCC_DISCONNECT,
+                               "PCC disconnect");
+       create_subgroup_counter(events_subgroup,
+                               PCEP_EVENT_COUNTER_ID_PCE_DISCONNECT,
+                               "PCE disconnect");
+       create_subgroup_counter(events_subgroup,
+                               PCEP_EVENT_COUNTER_ID_TIMER_KEEPALIVE,
+                               "Timer KeepAlive expired");
+       create_subgroup_counter(events_subgroup,
+                               PCEP_EVENT_COUNTER_ID_TIMER_DEADTIMER,
+                               "Timer DeadTimer expired");
+       create_subgroup_counter(events_subgroup,
+                               PCEP_EVENT_COUNTER_ID_TIMER_OPENKEEPWAIT,
+                               "Timer OpenKeepWait expired");
+       create_subgroup_counter(events_subgroup,
+                               PCEP_EVENT_COUNTER_ID_TIMER_OPENKEEPALIVE,
+                               "Timer OpenKeepAlive expired");
+
+       /*
+        * Create the parent counters group
+        */
+       time_t now = time(NULL);
+       char counters_name[MAX_COUNTER_STR_LENGTH] = {0};
+       char ip_str[40] = {0};
+       if (session->socket_comm_session->is_ipv6) {
+               inet_ntop(AF_INET6,
+                         &session->socket_comm_session->dest_sock_addr
+                                  .dest_sock_addr_ipv6.sin6_addr,
+                         ip_str, 40);
+       } else {
+               inet_ntop(AF_INET,
+                         &session->socket_comm_session->dest_sock_addr
+                                  .dest_sock_addr_ipv4.sin_addr,
+                         ip_str, 40);
+       }
+       snprintf(counters_name, MAX_COUNTER_STR_LENGTH,
+                "PCEP Session [%d], connected to [%s] for [%u seconds]",
+                session->session_id, ip_str,
+                (uint32_t)(now - session->time_connected));
+       /* The (time(NULL) - session->time_connected) will probably be 0,
+        * so the group name will be updated when the counters are dumped */
+       session->pcep_session_counters =
+               create_counters_group(counters_name, MAX_COUNTER_GROUPS);
+
+       /*
+        * Add all the subgroups to the parent counters group
+        */
+       add_counters_subgroup(session->pcep_session_counters, rx_msg_subgroup);
+       add_counters_subgroup(session->pcep_session_counters, tx_msg_subgroup);
+       add_counters_subgroup(session->pcep_session_counters, rx_obj_subgroup);
+       add_counters_subgroup(session->pcep_session_counters, tx_obj_subgroup);
+       add_counters_subgroup(session->pcep_session_counters,
+                             rx_subobj_subgroup);
+       add_counters_subgroup(session->pcep_session_counters,
+                             tx_subobj_subgroup);
+       add_counters_subgroup(session->pcep_session_counters,
+                             rx_subobj_sr_nai_subgroup);
+       add_counters_subgroup(session->pcep_session_counters,
+                             tx_subobj_sr_nai_subgroup);
+       add_counters_subgroup(session->pcep_session_counters, rx_tlv_subgroup);
+       add_counters_subgroup(session->pcep_session_counters, tx_tlv_subgroup);
+       add_counters_subgroup(session->pcep_session_counters, events_subgroup);
+}
+
+/* Internal util function used by increment_message_rx_counters or
+ * increment_message_tx_counters */
+void increment_message_counters(pcep_session *session,
+                               struct pcep_message *message, bool is_rx)
+{
+       uint16_t counter_subgroup_id_msg = (is_rx ? COUNTER_SUBGROUP_ID_RX_MSG
+                                                 : COUNTER_SUBGROUP_ID_TX_MSG);
+       uint16_t counter_subgroup_id_obj = (is_rx ? COUNTER_SUBGROUP_ID_RX_OBJ
+                                                 : COUNTER_SUBGROUP_ID_TX_OBJ);
+       uint16_t counter_subgroup_id_subobj =
+               (is_rx ? COUNTER_SUBGROUP_ID_RX_SUBOBJ
+                      : COUNTER_SUBGROUP_ID_TX_SUBOBJ);
+       uint16_t counter_subgroup_id_ro_sr_subobj =
+               (is_rx ? COUNTER_SUBGROUP_ID_RX_RO_SR_SUBOBJ
+                      : COUNTER_SUBGROUP_ID_TX_RO_SR_SUBOBJ);
+       uint16_t counter_subgroup_id_tlv = (is_rx ? COUNTER_SUBGROUP_ID_RX_TLV
+                                                 : COUNTER_SUBGROUP_ID_TX_TLV);
+
+       increment_counter(session->pcep_session_counters,
+                         counter_subgroup_id_msg, message->msg_header->type);
+
+       /* Iterate the objects */
+       double_linked_list_node *obj_node =
+               (message->obj_list == NULL ? NULL : message->obj_list->head);
+       for (; obj_node != NULL; obj_node = obj_node->next_node) {
+               struct pcep_object_header *obj =
+                       (struct pcep_object_header *)obj_node->data;
+
+               /* Handle class: PCEP_OBJ_CLASS_ENDPOINTS,
+                *        type:  PCEP_OBJ_TYPE_ENDPOINT_IPV4 or
+                * PCEP_OBJ_TYPE_ENDPOINT_IPV6 */
+               uint16_t obj_counter_id =
+                       (obj->object_class == PCEP_OBJ_CLASS_ENDPOINTS
+                                ? (obj->object_class << 4) | obj->object_type
+                                : obj->object_class);
+
+               increment_counter(session->pcep_session_counters,
+                                 counter_subgroup_id_obj, obj_counter_id);
+
+               /* Iterate the RO Sub-objects */
+               if (obj->object_class == PCEP_OBJ_CLASS_ERO
+                   || obj->object_class == PCEP_OBJ_CLASS_IRO
+                   || obj->object_class == PCEP_OBJ_CLASS_RRO) {
+                       struct pcep_object_ro *ro_obj =
+                               (struct pcep_object_ro *)obj;
+
+                       double_linked_list_node *ro_subobj_node =
+                               (ro_obj->sub_objects == NULL
+                                        ? NULL
+                                        : ro_obj->sub_objects->head);
+                       for (; ro_subobj_node != NULL;
+                            ro_subobj_node = ro_subobj_node->next_node) {
+                               struct pcep_object_ro_subobj *ro_subobj =
+                                       (struct pcep_object_ro_subobj *)
+                                               ro_subobj_node->data;
+                               increment_counter(
+                                       session->pcep_session_counters,
+                                       counter_subgroup_id_subobj,
+                                       ro_subobj->ro_subobj_type);
+
+                               /* Handle the ro subobj type RO_SUBOBJ_TYPE_SR
+                                * different NAI types */
+                               if (ro_subobj->ro_subobj_type
+                                   == RO_SUBOBJ_TYPE_SR) {
+                                       struct pcep_ro_subobj_sr *ro_sr_subobj =
+                                               (struct pcep_ro_subobj_sr *)
+                                                       ro_subobj;
+                                       increment_counter(
+                                               session->pcep_session_counters,
+                                               counter_subgroup_id_ro_sr_subobj,
+                                               ro_sr_subobj->nai_type);
+                               }
+                       }
+               }
+
+               /* Iterate the TLVs */
+               double_linked_list_node *tlv_node =
+                       (obj->tlv_list == NULL ? NULL : obj->tlv_list->head);
+               for (; tlv_node != NULL; tlv_node = tlv_node->next_node) {
+                       struct pcep_object_tlv_header *tlv =
+                               (struct pcep_object_tlv_header *)tlv_node->data;
+                       increment_counter(session->pcep_session_counters,
+                                         counter_subgroup_id_tlv, tlv->type);
+               }
+       }
+}
+
+void increment_message_rx_counters(pcep_session *session,
+                                  struct pcep_message *message)
+{
+       increment_message_counters(session, message, true);
+}
+
+void increment_message_tx_counters(pcep_session *session,
+                                  struct pcep_message *message)
+{
+       increment_message_counters(session, message, false);
+}
+
+void increment_event_counters(
+       pcep_session *session,
+       pcep_session_counters_event_counter_ids counter_id)
+{
+       increment_counter(session->pcep_session_counters,
+                         COUNTER_SUBGROUP_ID_EVENT, counter_id);
+}
diff --git a/pceplib/pcep_session_logic_internals.h b/pceplib/pcep_session_logic_internals.h
new file mode 100644 (file)
index 0000000..004459b
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+/*
+ * Internal Session Logic declarations, not intended to be in the public API.
+ */
+
+#ifndef SRC_PCEPSESSIONLOGICINTERNALS_H_
+#define SRC_PCEPSESSIONLOGICINTERNALS_H_
+
+
+#include <pthread.h>
+#include <stdbool.h>
+
+#include "pcep_msg_tools.h"
+
+#include "pcep_utils_double_linked_list.h"
+#include "pcep_utils_ordered_list.h"
+#include "pcep_utils_queue.h"
+
+
+typedef struct pcep_session_logic_handle_ {
+       pthread_t session_logic_thread;
+       pthread_mutex_t session_logic_mutex;
+       pthread_cond_t session_logic_cond_var;
+       bool session_logic_condition;
+       bool active;
+
+       ordered_list_handle *session_list;
+       pthread_mutex_t session_list_mutex;
+       /* Internal timers and socket events */
+       queue_handle *session_event_queue;
+
+} pcep_session_logic_handle;
+
+
+/* Used internally for Session events: message received, timer expired,
+ * or socket closed */
+typedef struct pcep_session_event_ {
+       pcep_session *session;
+       int expired_timer_id;
+       double_linked_list *received_msg_list;
+       bool socket_closed;
+
+} pcep_session_event;
+
+/* Event Counters counter-id definitions */
+typedef enum pcep_session_counters_event_counter_ids {
+       PCEP_EVENT_COUNTER_ID_PCC_CONNECT = 0,
+       PCEP_EVENT_COUNTER_ID_PCE_CONNECT = 1,
+       PCEP_EVENT_COUNTER_ID_PCC_DISCONNECT = 2,
+       PCEP_EVENT_COUNTER_ID_PCE_DISCONNECT = 3,
+       PCEP_EVENT_COUNTER_ID_TIMER_KEEPALIVE = 4,
+       PCEP_EVENT_COUNTER_ID_TIMER_DEADTIMER = 5,
+       PCEP_EVENT_COUNTER_ID_TIMER_OPENKEEPWAIT = 6,
+       PCEP_EVENT_COUNTER_ID_TIMER_OPENKEEPALIVE = 7
+
+} pcep_session_counters_event_counter_ids;
+
+/* functions implemented in pcep_session_logic_loop.c */
+void *session_logic_loop(void *data);
+int session_logic_msg_ready_handler(void *data, int socket_fd);
+void session_logic_message_sent_handler(void *data, int socket_fd);
+void session_logic_conn_except_notifier(void *data, int socket_fd);
+void session_logic_timer_expire_handler(void *data, int timer_id);
+
+void handle_timer_event(pcep_session_event *event);
+void handle_socket_comm_event(pcep_session_event *event);
+void session_send_message(pcep_session *session, struct pcep_message *message);
+
+/* defined in pcep_session_logic_states.c */
+void send_pcep_error(pcep_session *session, enum pcep_error_type error_type,
+                    enum pcep_error_value error_value);
+void enqueue_event(pcep_session *session, pcep_event_type event_type,
+                  struct pcep_message *message);
+void increment_unknown_message(pcep_session *session);
+
+/* defined in pcep_session_logic_counters.c */
+void create_session_counters(pcep_session *session);
+void increment_event_counters(
+       pcep_session *session,
+       pcep_session_counters_event_counter_ids counter_id);
+void increment_message_rx_counters(pcep_session *session,
+                                  struct pcep_message *message);
+
+/* defined in pcep_session_logic.c, also used in pcep_session_logic_states.c */
+struct pcep_message *create_pcep_open(pcep_session *session);
+
+#endif /* SRC_PCEPSESSIONLOGICINTERNALS_H_ */
diff --git a/pceplib/pcep_session_logic_loop.c b/pceplib/pcep_session_logic_loop.c
new file mode 100644 (file)
index 0000000..269aa1e
--- /dev/null
@@ -0,0 +1,361 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdio.h>
+
+#include "pcep_session_logic.h"
+#include "pcep_session_logic_internals.h"
+#include "pcep_timers.h"
+#include "pcep_utils_logging.h"
+#include "pcep_utils_memory.h"
+
+/* global var needed for callback handlers */
+extern pcep_session_logic_handle *session_logic_handle_;
+
+/* internal util function to create session_event's */
+static pcep_session_event *create_session_event(pcep_session *session)
+{
+       pcep_session_event *event =
+               pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_session_event));
+       event->session = session;
+       event->expired_timer_id = TIMER_ID_NOT_SET;
+       event->received_msg_list = NULL;
+       event->socket_closed = false;
+
+       return event;
+}
+
+
+/* A function pointer to this function is passed to pcep_socket_comm
+ * for each pcep_session creation, so it will be called whenever
+ * messages are ready to be read. This function will be called
+ * by the socket_comm thread.
+ * This function will decode the read PCEP message and give it
+ * to the session_logic_loop so it can be handled by the session_logic
+ * state machine. */
+int session_logic_msg_ready_handler(void *data, int socket_fd)
+{
+       if (data == NULL) {
+               pcep_log(LOG_WARNING,
+                        "%s: Cannot handle msg_ready with NULL data",
+                        __func__);
+               return -1;
+       }
+
+       if (session_logic_handle_->active == false) {
+               pcep_log(
+                       LOG_WARNING,
+                       "%s: Received a message ready notification while the session logic is not active",
+                       __func__);
+               return -1;
+       }
+
+       pcep_session *session = (pcep_session *)data;
+
+       pthread_mutex_lock(&(session_logic_handle_->session_logic_mutex));
+       session_logic_handle_->session_logic_condition = true;
+
+       /* This event will ultimately be handled by handle_socket_comm_event()
+        * in pcep_session_logic_states.c */
+       pcep_session_event *rcvd_msg_event = create_session_event(session);
+
+       int msg_length = 0;
+       double_linked_list *msg_list = pcep_msg_read(socket_fd);
+
+       if (msg_list == NULL) {
+               /* The socket was closed, or there was a socket read error */
+               pcep_log(LOG_INFO,
+                        "%s: PCEP connection closed for session [%d]",
+                        __func__, session->session_id);
+               dll_destroy(msg_list);
+               rcvd_msg_event->socket_closed = true;
+               socket_comm_session_teardown(session->socket_comm_session);
+               pcep_session_cancel_timers(session);
+               session->socket_comm_session = NULL;
+               session->session_state = SESSION_STATE_INITIALIZED;
+               enqueue_event(session, PCE_CLOSED_SOCKET, NULL);
+       } else if (msg_list->num_entries == 0) {
+               /* Invalid message received */
+               increment_unknown_message(session);
+               dll_destroy_with_data(msg_list);
+       } else {
+               /* Just logging the first of potentially several messages
+                * received */
+               struct pcep_message *msg =
+                       ((struct pcep_message *)msg_list->head->data);
+               pcep_log(
+                       LOG_INFO,
+                       "%s: [%ld-%ld] session_logic_msg_ready_handler received message of type [%d] len [%d] on session [%d]",
+                       __func__, time(NULL), pthread_self(),
+                       msg->msg_header->type, msg->encoded_message_length,
+                       session->session_id);
+
+               rcvd_msg_event->received_msg_list = msg_list;
+               msg_length = msg->encoded_message_length;
+       }
+
+       queue_enqueue(session_logic_handle_->session_event_queue,
+                     rcvd_msg_event);
+       pthread_cond_signal(&(session_logic_handle_->session_logic_cond_var));
+       pthread_mutex_unlock(&(session_logic_handle_->session_logic_mutex));
+
+       return msg_length;
+}
+
+
+/* A function pointer to this function was passed to pcep_socket_comm,
+ * so it will be called when a message is sent. This is useful since
+ * message sending is asynchronous, and there are times that actions
+ * need to be performed only after a message has been sent. */
+void session_logic_message_sent_handler(void *data, int socket_fd)
+{
+       (void)socket_fd;
+
+       if (data == NULL) {
+               pcep_log(LOG_WARNING,
+                        "%s: Cannot handle msg_sent with NULL data", __func__);
+               return;
+       }
+
+       pcep_session *session = (pcep_session *)data;
+       if (session->destroy_session_after_write == true) {
+               /* Do not call destroy until all of the queued messages are
+                * written */
+               if (session->socket_comm_session != NULL
+                   && session->socket_comm_session->message_queue->num_entries
+                              == 0) {
+                       destroy_pcep_session(session);
+               }
+       } else {
+               /* Reset the keep alive timer for every message sent on
+                * the session, only if the session is not destroyed */
+               if (session->timer_id_keep_alive == TIMER_ID_NOT_SET) {
+                       pcep_log(
+                               LOG_INFO,
+                               "%s: [%ld-%ld] pcep_session_logic set keep alive timer [%d secs] for session [%d]",
+                               __func__, time(NULL), pthread_self(),
+                               session->pcc_config
+                                       .keep_alive_pce_negotiated_timer_seconds,
+                               session->session_id);
+                       session->timer_id_keep_alive = create_timer(
+                               session->pcc_config
+                                       .keep_alive_pce_negotiated_timer_seconds,
+                               session);
+               } else {
+                       pcep_log(
+                               LOG_INFO,
+                               "%s: [%ld-%ld] pcep_session_logic reset keep alive timer [%d secs] for session [%d]",
+                               __func__, time(NULL), pthread_self(),
+                               session->pcc_config
+                                       .keep_alive_pce_negotiated_timer_seconds,
+                               session->session_id);
+                       reset_timer(session->timer_id_keep_alive);
+               }
+       }
+}
+
+
+/* A function pointer to this function was passed to pcep_socket_comm,
+ * so it will be called whenever the socket is closed. this function
+ * will be called by the socket_comm thread. */
+void session_logic_conn_except_notifier(void *data, int socket_fd)
+{
+       if (data == NULL) {
+               pcep_log(LOG_WARNING,
+                        "%s: Cannot handle conn_except with NULL data",
+                        __func__);
+               return;
+       }
+
+       if (session_logic_handle_->active == false) {
+               pcep_log(
+                       LOG_WARNING,
+                       "%s: Received a connection exception notification while the session logic is not active",
+                       __func__);
+               return;
+       }
+
+       pcep_session *session = (pcep_session *)data;
+       pcep_log(
+               LOG_INFO,
+               "%s: [%ld-%ld] pcep_session_logic session_logic_conn_except_notifier socket closed [%d], session [%d]",
+               __func__, time(NULL), pthread_self(), socket_fd,
+               session->session_id);
+
+       pthread_mutex_lock(&(session_logic_handle_->session_logic_mutex));
+       pcep_session_event *socket_event = create_session_event(session);
+       socket_event->socket_closed = true;
+       queue_enqueue(session_logic_handle_->session_event_queue, socket_event);
+       session_logic_handle_->session_logic_condition = true;
+
+       pthread_cond_signal(&(session_logic_handle_->session_logic_cond_var));
+       pthread_mutex_unlock(&(session_logic_handle_->session_logic_mutex));
+}
+
+
+/*
+ * this method is the timer expire handler, and will only
+ * pass the event to the session_logic loop and notify it
+ * that there is a timer available. this function will be
+ * called by the timers thread.
+ */
+void session_logic_timer_expire_handler(void *data, int timer_id)
+{
+       if (data == NULL) {
+               pcep_log(LOG_WARNING, "%s: Cannot handle timer with NULL data",
+                        __func__);
+               return;
+       }
+
+       if (session_logic_handle_->active == false) {
+               pcep_log(
+                       LOG_WARNING,
+                       "%s: Received a timer expiration while the session logic is not active",
+                       __func__);
+               return;
+       }
+
+       pcep_log(LOG_INFO, "%s: [%ld-%ld] timer expired handler timer_id [%d]",
+                __func__, time(NULL), pthread_self(), timer_id);
+       pcep_session_event *expired_timer_event =
+               create_session_event((pcep_session *)data);
+       expired_timer_event->expired_timer_id = timer_id;
+
+       pthread_mutex_lock(&(session_logic_handle_->session_logic_mutex));
+       session_logic_handle_->session_logic_condition = true;
+       queue_enqueue(session_logic_handle_->session_event_queue,
+                     expired_timer_event);
+
+       pthread_cond_signal(&(session_logic_handle_->session_logic_cond_var));
+       pthread_mutex_unlock(&(session_logic_handle_->session_logic_mutex));
+}
+
+
+/*
+ * session_logic event loop
+ * this function is called upon thread creation from pcep_session_logic.c
+ */
+void *session_logic_loop(void *data)
+{
+       if (data == NULL) {
+               pcep_log(LOG_WARNING,
+                        "%s: Cannot start session_logic_loop with NULL data",
+                        __func__);
+
+               return NULL;
+       }
+
+       pcep_log(LOG_NOTICE, "%s: [%ld-%ld] Starting session_logic_loop thread",
+                __func__, time(NULL), pthread_self());
+
+       pcep_session_logic_handle *session_logic_handle =
+               (pcep_session_logic_handle *)data;
+
+       while (session_logic_handle->active) {
+               /* Mutex locking for session_logic_loop condition variable */
+               pthread_mutex_lock(
+                       &(session_logic_handle->session_logic_mutex));
+
+               /* this internal loop helps avoid spurious interrupts */
+               while (!session_logic_handle->session_logic_condition) {
+                       pthread_cond_wait(
+                               &(session_logic_handle->session_logic_cond_var),
+                               &(session_logic_handle->session_logic_mutex));
+               }
+
+               pcep_session_event *event = queue_dequeue(
+                       session_logic_handle->session_event_queue);
+               while (event != NULL) {
+                       if (event->session == NULL) {
+                               pcep_log(
+                                       LOG_INFO,
+                                       "%s: [%ld-%ld] Invalid session_logic_loop event [%s] with NULL session",
+                                       __func__, time(NULL), pthread_self(),
+                                       (event->expired_timer_id
+                                        != TIMER_ID_NOT_SET)
+                                               ? "timer"
+                                               : "message");
+                               pceplib_free(PCEPLIB_INFRA, event);
+                               event = queue_dequeue(
+                                       session_logic_handle
+                                               ->session_event_queue);
+                               continue;
+                       }
+
+                       /* Check if the session still exists, and synchronize
+                        * possible session destroy */
+                       pcep_log(
+                               LOG_DEBUG,
+                               "%s: session_logic_loop checking session_list sessionPtr %p",
+                               __func__, event->session);
+                       pthread_mutex_lock(
+                               &(session_logic_handle->session_list_mutex));
+                       if (ordered_list_find(
+                                   session_logic_handle->session_list,
+                                   event->session)
+                           == NULL) {
+                               pcep_log(
+                                       LOG_INFO,
+                                       "%s: [%ld-%ld] In-flight event [%s] for destroyed session being discarded",
+                                       __func__, time(NULL), pthread_self(),
+                                       (event->expired_timer_id
+                                        != TIMER_ID_NOT_SET)
+                                               ? "timer"
+                                               : "message");
+                               pceplib_free(PCEPLIB_INFRA, event);
+                               event = queue_dequeue(
+                                       session_logic_handle
+                                               ->session_event_queue);
+                               pthread_mutex_unlock(
+                                       &(session_logic_handle_
+                                                 ->session_list_mutex));
+                               continue;
+                       }
+
+                       if (event->expired_timer_id != TIMER_ID_NOT_SET) {
+                               handle_timer_event(event);
+                       }
+
+                       if (event->received_msg_list != NULL) {
+                               handle_socket_comm_event(event);
+                       }
+
+                       pceplib_free(PCEPLIB_INFRA, event);
+                       event = queue_dequeue(
+                               session_logic_handle->session_event_queue);
+
+                       pthread_mutex_unlock(
+                               &(session_logic_handle_->session_list_mutex));
+               }
+
+               session_logic_handle->session_logic_condition = false;
+               pthread_mutex_unlock(
+                       &(session_logic_handle->session_logic_mutex));
+       }
+
+       pcep_log(LOG_NOTICE, "%s: [%ld-%ld] Finished session_logic_loop thread",
+                __func__, time(NULL), pthread_self());
+
+       return NULL;
+}
diff --git a/pceplib/pcep_session_logic_states.c b/pceplib/pcep_session_logic_states.c
new file mode 100644 (file)
index 0000000..3beceef
--- /dev/null
@@ -0,0 +1,1135 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "pcep_msg_encoding.h"
+#include "pcep_session_logic.h"
+#include "pcep_session_logic_internals.h"
+#include "pcep_timers.h"
+#include "pcep_utils_logging.h"
+#include "pcep_utils_memory.h"
+
+#define TIMER_OPEN_KEEP_ALIVE_SECONDS 1
+
+/* Session Logic Handle managed in pcep_session_logic.c */
+extern pcep_event_queue *session_logic_event_queue_;
+void send_keep_alive(pcep_session *session);
+void send_pcep_error_with_object(pcep_session *session,
+                                enum pcep_error_type error_type,
+                                enum pcep_error_value error_value,
+                                struct pcep_object_header *object);
+void reset_dead_timer(pcep_session *session);
+bool verify_pcep_open_object(pcep_session *session,
+                            struct pcep_object_open *open_object);
+void send_reconciled_pcep_open(pcep_session *session,
+                              struct pcep_message *error_msg);
+bool handle_pcep_update(pcep_session *session, struct pcep_message *upd_msg);
+bool handle_pcep_initiate(pcep_session *session, struct pcep_message *init_msg);
+bool check_and_send_open_keep_alive(pcep_session *session);
+void log_pcc_pce_connection(pcep_session *session);
+bool handle_pcep_open(pcep_session *session, struct pcep_message *open_msg);
+
+/*
+ * util functions called by the state handling below
+ */
+
+void send_keep_alive(pcep_session *session)
+{
+       struct pcep_message *keep_alive_msg = pcep_msg_create_keepalive();
+
+       pcep_log(
+               LOG_INFO,
+               "%s: [%ld-%ld] pcep_session_logic send keep_alive message for session [%d]",
+               __func__, time(NULL), pthread_self(), session->session_id);
+
+       session_send_message(session, keep_alive_msg);
+
+       /* The keep alive timer will be (re)set once the message
+        * is sent in session_logic_message_sent_handler() */
+}
+
+
+/* Send an error message with the corrected or offending object */
+void send_pcep_error_with_object(pcep_session *session,
+                                enum pcep_error_type error_type,
+                                enum pcep_error_value error_value,
+                                struct pcep_object_header *object)
+{
+       double_linked_list *obj_list = dll_initialize();
+       dll_append(obj_list, object);
+       struct pcep_message *error_msg = pcep_msg_create_error_with_objects(
+               error_type, error_value, obj_list);
+
+       pcep_log(
+               LOG_INFO,
+               "%s: [%ld-%ld] pcep_session_logic send error message with object [%d][%d] for session [%d]",
+               __func__, time(NULL), pthread_self(), error_type, error_value,
+               session->session_id);
+
+       session_send_message(session, error_msg);
+}
+
+
+void send_pcep_error(pcep_session *session, enum pcep_error_type error_type,
+                    enum pcep_error_value error_value)
+{
+       struct pcep_message *error_msg =
+               pcep_msg_create_error(error_type, error_value);
+
+       pcep_log(
+               LOG_INFO,
+               "%s: [%ld-%ld] pcep_session_logic send error message [%d][%d] for session [%d]",
+               __func__, time(NULL), pthread_self(), error_type, error_value,
+               session->session_id);
+
+       session_send_message(session, error_msg);
+}
+
+
+void reset_dead_timer(pcep_session *session)
+{
+       /* Default to configured dead_timer if its not set yet or set to 0 by
+        * the PCE */
+       int dead_timer_seconds =
+               (session->pcc_config.dead_timer_pce_negotiated_seconds == 0)
+                       ? session->pcc_config.dead_timer_seconds
+                       : session->pcc_config.dead_timer_pce_negotiated_seconds;
+
+       if (session->timer_id_dead_timer == TIMER_ID_NOT_SET) {
+               session->timer_id_dead_timer =
+                       create_timer(dead_timer_seconds, session);
+               pcep_log(
+                       LOG_INFO,
+                       "%s: [%ld-%ld] pcep_session_logic set dead timer [%d secs] id [%d] for session [%d]",
+                       __func__, time(NULL), pthread_self(),
+                       dead_timer_seconds, session->timer_id_dead_timer,
+                       session->session_id);
+       } else {
+               pcep_log(
+                       LOG_INFO,
+                       "%s: [%ld-%ld] pcep_session_logic reset dead timer [%d secs] id [%d] for session [%d]",
+                       __func__, time(NULL), pthread_self(),
+                       dead_timer_seconds, session->timer_id_dead_timer,
+                       session->session_id);
+               reset_timer(session->timer_id_dead_timer);
+       }
+}
+
+
+void enqueue_event(pcep_session *session, pcep_event_type event_type,
+                  struct pcep_message *message)
+{
+       if (event_type == MESSAGE_RECEIVED && message == NULL) {
+               pcep_log(
+                       LOG_WARNING,
+                       "%s: enqueue_event cannot enqueue a NULL message session [%d]",
+                       __func__, session->session_id);
+               return;
+       }
+
+       pcep_event *event = pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_event));
+       memset(event, 0, sizeof(pcep_event));
+
+       event->session = session;
+       event->event_type = event_type;
+       event->event_time = time(NULL);
+       event->message = message;
+
+       pthread_mutex_lock(&session_logic_event_queue_->event_queue_mutex);
+       if (session_logic_event_queue_->event_callback != NULL) {
+               session_logic_event_queue_->event_callback(
+                       session_logic_event_queue_->event_callback_data, event);
+       } else {
+               queue_enqueue(session_logic_event_queue_->event_queue, event);
+       }
+       pthread_mutex_unlock(&session_logic_event_queue_->event_queue_mutex);
+}
+
+/* Verify the received PCEP Open object parameters are acceptable. If not,
+ * update the unacceptable value(s) with an acceptable value so it can be sent
+ * back to the sender. */
+bool verify_pcep_open_object(pcep_session *session,
+                            struct pcep_object_open *open_object)
+{
+       int retval = true;
+
+       if (open_object->open_keepalive
+           < session->pcc_config.min_keep_alive_seconds) {
+               pcep_log(
+                       LOG_INFO,
+                       "%s: Rejecting unsupported Open Keep Alive value [%d] min [%d]",
+                       __func__, open_object->open_keepalive,
+                       session->pcc_config.min_keep_alive_seconds);
+               open_object->open_keepalive =
+                       session->pcc_config.min_keep_alive_seconds;
+               retval = false;
+       } else if (open_object->open_keepalive
+                  > session->pcc_config.max_keep_alive_seconds) {
+               pcep_log(
+                       LOG_INFO,
+                       "%s: Rejecting unsupported Open Keep Alive value [%d] max [%d]",
+                       __func__, open_object->open_keepalive,
+                       session->pcc_config.max_keep_alive_seconds);
+               open_object->open_keepalive =
+                       session->pcc_config.max_keep_alive_seconds;
+               retval = false;
+       }
+
+       if (open_object->open_deadtimer
+           < session->pcc_config.min_dead_timer_seconds) {
+               pcep_log(LOG_INFO,
+                        "%s: Rejecting unsupported Open Dead Timer value [%d]",
+                        __func__, open_object->open_deadtimer);
+               open_object->open_deadtimer =
+                       session->pcc_config.min_dead_timer_seconds;
+               retval = false;
+       } else if (open_object->open_deadtimer
+                  > session->pcc_config.max_dead_timer_seconds) {
+               pcep_log(LOG_INFO,
+                        "%s: Rejecting unsupported Open Dead Timer value [%d]",
+                        __func__, open_object->open_deadtimer);
+               open_object->open_deadtimer =
+                       session->pcc_config.max_dead_timer_seconds;
+               retval = false;
+       }
+
+       /* Check for Open Object TLVs */
+       if (pcep_object_has_tlvs((struct pcep_object_header *)open_object)
+           == false) {
+               /* There are no TLVs, all done */
+               return retval;
+       }
+
+       double_linked_list_node *tlv_node = open_object->header.tlv_list->head;
+       while (tlv_node != NULL) {
+               struct pcep_object_tlv_header *tlv = tlv_node->data;
+               tlv_node = tlv_node->next_node;
+
+               /* Supported Open Object TLVs */
+               switch (tlv->type) {
+               case PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION:
+               case PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY:
+               case PCEP_OBJ_TLV_TYPE_SPEAKER_ENTITY_ID:
+               case PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY:
+               case PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY:
+                       break;
+
+               default:
+                       /* TODO how to handle unrecognized TLV ?? */
+                       pcep_log(
+                               LOG_INFO,
+                               "%s: Unhandled OPEN Object TLV type: %d, length %d",
+                               __func__, tlv->type, tlv->encoded_tlv_length);
+                       break;
+               }
+
+               /* Verify the STATEFUL-PCE-CAPABILITY TLV */
+               if (tlv->type == PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY) {
+                       struct pcep_object_tlv_stateful_pce_capability
+                               *pce_cap_tlv =
+                                       (struct
+                                        pcep_object_tlv_stateful_pce_capability
+                                                *)tlv;
+
+                       /* If the U flag is set, then the PCE is
+                        * capable of updating LSP parameters */
+                       if (pce_cap_tlv->flag_u_lsp_update_capability) {
+                               if (session->pce_config
+                                           .support_stateful_pce_lsp_update
+                                   == false) {
+                                       /* Turn off the U bit, as it is not
+                                        * supported */
+                                       pcep_log(
+                                               LOG_INFO,
+                                               "%s: Rejecting unsupported Open STATEFUL-PCE-CAPABILITY TLV U flag",
+                                               __func__);
+                                       pce_cap_tlv
+                                               ->flag_u_lsp_update_capability =
+                                               false;
+                                       retval = false;
+                               } else {
+                                       session->stateful_pce = true;
+                                       pcep_log(
+                                               LOG_INFO,
+                                               "%s: Setting PCEP session [%d] STATEFUL to support LSP updates",
+                                               __func__, session->session_id);
+                               }
+                       }
+                       /* TODO the rest of the flags are not implemented yet */
+                       else if (pce_cap_tlv->flag_s_include_db_version) {
+                               pcep_log(
+                                       LOG_INFO,
+                                       "%s: Ignoring Open STATEFUL-PCE-CAPABILITY TLV S Include DB Version flag",
+                                       __func__);
+                       } else if (
+                               pce_cap_tlv
+                                       ->flag_i_lsp_instantiation_capability) {
+                               pcep_log(
+                                       LOG_INFO,
+                                       "%s: Ignoring Open STATEFUL-PCE-CAPABILITY TLV I LSP Instantiation Capability flag",
+                                       __func__);
+                       } else if (pce_cap_tlv->flag_t_triggered_resync) {
+                               pcep_log(
+                                       LOG_INFO,
+                                       "%s: Ignoring Open STATEFUL-PCE-CAPABILITY TLV T Triggered Resync flag",
+                                       __func__);
+                       } else if (pce_cap_tlv->flag_d_delta_lsp_sync) {
+                               pcep_log(
+                                       LOG_INFO,
+                                       "%s: Ignoring Open STATEFUL-PCE-CAPABILITY TLV D Delta LSP Sync flag",
+                                       __func__);
+                       } else if (pce_cap_tlv->flag_f_triggered_initial_sync) {
+                               pcep_log(
+                                       LOG_INFO,
+                                       "%s: Ignoring Open STATEFUL-PCE-CAPABILITY TLV F Triggered Initial Sync flag",
+                                       __func__);
+                       }
+               } else if (tlv->type == PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION) {
+                       if (session->pce_config.support_include_db_version
+                           == false) {
+                               pcep_log(
+                                       LOG_INFO,
+                                       "%s: Rejecting unsupported Open LSP DB VERSION TLV",
+                                       __func__);
+                               /* Remove this TLV from the list */
+                               dll_delete_node(open_object->header.tlv_list,
+                                               tlv_node);
+                               retval = false;
+                       }
+               }
+       }
+
+       return retval;
+}
+
+
+bool handle_pcep_open(pcep_session *session, struct pcep_message *open_msg)
+{
+       /* Open Message validation and errors according to:
+        * https://tools.ietf.org/html/rfc5440#section-7.15 */
+
+       if (session->session_state != SESSION_STATE_PCEP_CONNECTING
+           && session->session_state != SESSION_STATE_INITIALIZED) {
+               pcep_log(
+                       LOG_INFO,
+                       "%s: Received unexpected OPEN, current session state [%d, replying with error]",
+                       __func__, session->session_state);
+               send_pcep_error(session,
+                               PCEP_ERRT_ATTEMPT_TO_ESTABLISH_2ND_PCEP_SESSION,
+                               PCEP_ERRV_RECVD_INVALID_OPEN_MSG);
+               return false;
+       }
+
+       if (session->pce_open_received == true
+           && session->pce_open_rejected == false) {
+               pcep_log(LOG_INFO,
+                        "%s: Received duplicate OPEN, replying with error",
+                        __func__);
+               send_pcep_error(session,
+                               PCEP_ERRT_ATTEMPT_TO_ESTABLISH_2ND_PCEP_SESSION,
+                               PCEP_ERRV_RECVD_INVALID_OPEN_MSG);
+               return false;
+       }
+
+       struct pcep_object_open *open_object =
+               (struct pcep_object_open *)pcep_obj_get(open_msg->obj_list,
+                                                       PCEP_OBJ_CLASS_OPEN);
+       if (open_object == NULL) {
+               pcep_log(
+                       LOG_INFO,
+                       "%s: Received OPEN message with no OPEN object, replying with error",
+                       __func__);
+               send_pcep_error(session, PCEP_ERRT_SESSION_FAILURE,
+                               PCEP_ERRV_RECVD_INVALID_OPEN_MSG);
+               return false;
+       }
+
+       /* Check for additional Open Msg objects */
+       if (open_msg->obj_list->num_entries > 1) {
+               pcep_log(
+                       LOG_INFO,
+                       "%s: Found additional unsupported objects in the Open message, replying with error",
+                       __func__);
+               send_pcep_error(session, PCEP_ERRT_SESSION_FAILURE,
+                               PCEP_ERRV_RECVD_INVALID_OPEN_MSG);
+               return false;
+       }
+
+       session->pce_open_received = true;
+
+       /* Verify the open object parameters and TLVs */
+       if (verify_pcep_open_object(session, open_object) == false) {
+               enqueue_event(session, PCC_RCVD_INVALID_OPEN, NULL);
+               if (session->pce_open_rejected) {
+                       /* The Open message was already rejected once, so
+                        * according to the spec, send an error message and
+                        * close the TCP connection. */
+                       pcep_log(
+                               LOG_INFO,
+                               "%s: Received 2 consecutive unsupported Open messages, closing the connection.",
+                               __func__);
+                       send_pcep_error(
+                               session, PCEP_ERRT_SESSION_FAILURE,
+                               PCEP_ERRV_RECVD_SECOND_OPEN_MSG_UNACCEPTABLE);
+                       socket_comm_session_close_tcp_after_write(
+                               session->socket_comm_session);
+                       session->session_state = SESSION_STATE_INITIALIZED;
+                       enqueue_event(session, PCC_CONNECTION_FAILURE, NULL);
+               } else {
+                       session->pce_open_rejected = true;
+                       /* Clone the object here, since the encapsulating
+                        * message will be deleted in handle_socket_comm_event()
+                        * most likely before this error message is sent */
+                       struct pcep_object_open *cloned_open_object =
+                               pceplib_malloc(PCEPLIB_MESSAGES,
+                                              sizeof(struct pcep_object_open));
+                       memcpy(cloned_open_object, open_object,
+                              sizeof(struct pcep_object_open));
+                       open_object->header.tlv_list = NULL;
+                       cloned_open_object->header.encoded_object = NULL;
+                       cloned_open_object->header.encoded_object_length = 0;
+                       send_pcep_error_with_object(
+                               session, PCEP_ERRT_SESSION_FAILURE,
+                               PCEP_ERRV_UNACCEPTABLE_OPEN_MSG_NEG,
+                               &cloned_open_object->header);
+               }
+
+               return false;
+       }
+
+       /*
+        * Open Message accepted
+        * Sending the keep-alive response will be managed the function caller
+        */
+
+       session->timer_id_open_keep_alive =
+               create_timer(TIMER_OPEN_KEEP_ALIVE_SECONDS, session);
+       session->pcc_config.dead_timer_pce_negotiated_seconds =
+               (int)open_object->open_deadtimer;
+       /* Cancel the timer so we can change the dead_timer value */
+       cancel_timer(session->timer_id_dead_timer);
+       session->timer_id_dead_timer = TIMER_ID_NOT_SET;
+       reset_dead_timer(session);
+
+       return true;
+}
+
+
+/* The original PCEP Open message sent to the PCE was rejected,
+ * try to reconcile the differences and re-send a new Open. */
+void send_reconciled_pcep_open(pcep_session *session,
+                              struct pcep_message *error_msg)
+{
+       struct pcep_message *open_msg = create_pcep_open(session);
+
+       struct pcep_object_open *error_open_obj =
+               (struct pcep_object_open *)pcep_obj_get(error_msg->obj_list,
+                                                       PCEP_OBJ_CLASS_OPEN);
+       if (error_open_obj == NULL) {
+               /* Nothing to reconcile, send the same Open message again */
+               pcep_log(
+                       LOG_INFO,
+                       "%s: No Open object received in Error, sending the same Open message",
+                       __func__);
+               session_send_message(session, open_msg);
+               return;
+       }
+
+       struct pcep_object_open *open_obj =
+               (struct pcep_object_open *)pcep_obj_get(open_msg->obj_list,
+                                                       PCEP_OBJ_CLASS_OPEN);
+       // open_msg can not have empty obj_list
+       assert(open_obj != NULL);
+
+       if (error_open_obj->open_deadtimer
+           != session->pce_config.dead_timer_seconds) {
+               if (error_open_obj->open_deadtimer
+                           >= session->pce_config.min_dead_timer_seconds
+                   && error_open_obj->open_deadtimer
+                              <= session->pce_config.max_dead_timer_seconds) {
+                       open_obj->open_deadtimer =
+                               error_open_obj->open_deadtimer;
+                       session->pcc_config.dead_timer_pce_negotiated_seconds =
+                               error_open_obj->open_deadtimer;
+                       pcep_log(
+                               LOG_INFO,
+                               "%s: Open deadtimer value [%d] rejected, using PCE value [%d]",
+                               __func__,
+                               session->pcc_config.dead_timer_seconds,
+                               session->pcc_config
+                                       .dead_timer_pce_negotiated_seconds);
+                       /* Reset the timer with the new value */
+                       cancel_timer(session->timer_id_dead_timer);
+                       session->timer_id_dead_timer = TIMER_ID_NOT_SET;
+                       reset_dead_timer(session);
+               } else {
+                       pcep_log(
+                               LOG_INFO,
+                               "%s: Can not reconcile Open with suggested deadtimer [%d]",
+                               __func__, error_open_obj->open_deadtimer);
+               }
+       }
+
+       if (error_open_obj->open_keepalive
+           != session->pce_config.keep_alive_seconds) {
+               if (error_open_obj->open_keepalive
+                           >= session->pce_config.min_keep_alive_seconds
+                   && error_open_obj->open_keepalive
+                              <= session->pce_config.max_keep_alive_seconds) {
+                       open_obj->open_keepalive =
+                               error_open_obj->open_keepalive;
+                       session->pcc_config
+                               .keep_alive_pce_negotiated_timer_seconds =
+                               error_open_obj->open_keepalive;
+                       pcep_log(
+                               LOG_INFO,
+                               "%s: Open keep alive value [%d] rejected, using PCE value [%d]",
+                               __func__,
+                               session->pcc_config.keep_alive_seconds,
+                               session->pcc_config
+                                       .keep_alive_pce_negotiated_timer_seconds);
+                       /* Cancel the timer, the timer will be set again with
+                        * the new value when this open message is sent */
+                       cancel_timer(session->timer_id_keep_alive);
+                       session->timer_id_keep_alive = TIMER_ID_NOT_SET;
+               } else {
+                       pcep_log(
+                               LOG_INFO,
+                               "%s: Can not reconcile Open with suggested keepalive [%d]",
+                               __func__, error_open_obj->open_keepalive);
+               }
+       }
+
+       /* TODO reconcile the TLVs */
+
+       session_send_message(session, open_msg);
+       reset_timer(session->timer_id_open_keep_alive);
+}
+
+
+bool handle_pcep_update(pcep_session *session, struct pcep_message *upd_msg)
+{
+       /* Update Message validation and errors according to:
+        * https://tools.ietf.org/html/rfc8231#section-6.2 */
+
+       if (upd_msg->obj_list == NULL) {
+               pcep_log(LOG_INFO,
+                        "%s: Invalid PcUpd message: Message has no objects",
+                        __func__);
+               send_pcep_error(session, PCEP_ERRT_MANDATORY_OBJECT_MISSING,
+                               PCEP_ERRV_SRP_OBJECT_MISSING);
+               return false;
+       }
+
+       /* Verify the mandatory objects are present */
+       struct pcep_object_header *obj =
+               pcep_obj_get(upd_msg->obj_list, PCEP_OBJ_CLASS_SRP);
+       if (obj == NULL) {
+               pcep_log(LOG_INFO,
+                        "%s: Invalid PcUpd message: Missing SRP object",
+                        __func__);
+               send_pcep_error(session, PCEP_ERRT_MANDATORY_OBJECT_MISSING,
+                               PCEP_ERRV_SRP_OBJECT_MISSING);
+               return false;
+       }
+
+       obj = pcep_obj_get(upd_msg->obj_list, PCEP_OBJ_CLASS_LSP);
+       if (obj == NULL) {
+               pcep_log(LOG_INFO,
+                        "%s: Invalid PcUpd message: Missing LSP object",
+                        __func__);
+               send_pcep_error(session, PCEP_ERRT_MANDATORY_OBJECT_MISSING,
+                               PCEP_ERRV_LSP_OBJECT_MISSING);
+               return false;
+       }
+
+       obj = pcep_obj_get(upd_msg->obj_list, PCEP_OBJ_CLASS_ERO);
+       if (obj == NULL) {
+               pcep_log(LOG_INFO,
+                        "%s: Invalid PcUpd message: Missing ERO object",
+                        __func__);
+               send_pcep_error(session, PCEP_ERRT_MANDATORY_OBJECT_MISSING,
+                               PCEP_ERRV_ERO_OBJECT_MISSING);
+               return false;
+       }
+
+       /* Verify the objects are are in the correct order */
+       double_linked_list_node *node = upd_msg->obj_list->head;
+       struct pcep_object_srp *srp_object =
+               (struct pcep_object_srp *)node->data;
+       if (srp_object->header.object_class != PCEP_OBJ_CLASS_SRP) {
+               pcep_log(
+                       LOG_INFO,
+                       "%s: Invalid PcUpd message: First object must be an SRP, found [%d]",
+                       __func__, srp_object->header.object_class);
+               send_pcep_error(session, PCEP_ERRT_MANDATORY_OBJECT_MISSING,
+                               PCEP_ERRV_SRP_OBJECT_MISSING);
+               return false;
+       }
+
+       node = node->next_node;
+       struct pcep_object_lsp *lsp_object =
+               (struct pcep_object_lsp *)node->data;
+       if (lsp_object->header.object_class != PCEP_OBJ_CLASS_LSP) {
+               pcep_log(
+                       LOG_INFO,
+                       "%s: Invalid PcUpd message: Second object must be an LSP, found [%d]",
+                       __func__, lsp_object->header.object_class);
+               send_pcep_error(session, PCEP_ERRT_MANDATORY_OBJECT_MISSING,
+                               PCEP_ERRV_LSP_OBJECT_MISSING);
+               return false;
+       }
+
+       node = node->next_node;
+       struct pcep_object_ro *ero_object = node->data;
+       if (ero_object->header.object_class != PCEP_OBJ_CLASS_ERO) {
+               pcep_log(
+                       LOG_INFO,
+                       "%s: Invalid PcUpd message: Third object must be an ERO, found [%d]",
+                       __func__, ero_object->header.object_class);
+               send_pcep_error(session, PCEP_ERRT_MANDATORY_OBJECT_MISSING,
+                               PCEP_ERRV_ERO_OBJECT_MISSING);
+               return false;
+       }
+
+       return true;
+}
+
+bool handle_pcep_initiate(pcep_session *session, struct pcep_message *init_msg)
+{
+       /* Instantiate Message validation and errors according to:
+        * https://tools.ietf.org/html/rfc8281#section-5 */
+
+       if (init_msg->obj_list == NULL) {
+               pcep_log(
+                       LOG_INFO,
+                       "%s: Invalid PcInitiate message: Message has no objects",
+                       __func__);
+               send_pcep_error(session, PCEP_ERRT_MANDATORY_OBJECT_MISSING,
+                               PCEP_ERRV_SRP_OBJECT_MISSING);
+               return false;
+       }
+
+       /* Verify the mandatory objects are present */
+       struct pcep_object_header *obj =
+               pcep_obj_get(init_msg->obj_list, PCEP_OBJ_CLASS_SRP);
+       if (obj == NULL) {
+               pcep_log(LOG_INFO,
+                        "%s: Invalid PcInitiate message: Missing SRP object",
+                        __func__);
+               send_pcep_error(session, PCEP_ERRT_MANDATORY_OBJECT_MISSING,
+                               PCEP_ERRV_SRP_OBJECT_MISSING);
+               return false;
+       }
+
+       obj = pcep_obj_get(init_msg->obj_list, PCEP_OBJ_CLASS_LSP);
+       if (obj == NULL) {
+               pcep_log(LOG_INFO,
+                        "%s: Invalid PcInitiate message: Missing LSP object",
+                        __func__);
+               send_pcep_error(session, PCEP_ERRT_MANDATORY_OBJECT_MISSING,
+                               PCEP_ERRV_LSP_OBJECT_MISSING);
+               return false;
+       }
+
+       /* Verify the objects are are in the correct order */
+       double_linked_list_node *node = init_msg->obj_list->head;
+       struct pcep_object_srp *srp_object =
+               (struct pcep_object_srp *)node->data;
+       if (srp_object->header.object_class != PCEP_OBJ_CLASS_SRP) {
+               pcep_log(
+                       LOG_INFO,
+                       "%s: Invalid PcInitiate message: First object must be an SRP, found [%d]",
+                       __func__, srp_object->header.object_class);
+               send_pcep_error(session, PCEP_ERRT_MANDATORY_OBJECT_MISSING,
+                               PCEP_ERRV_SRP_OBJECT_MISSING);
+               return false;
+       }
+
+       node = node->next_node;
+       struct pcep_object_lsp *lsp_object =
+               (struct pcep_object_lsp *)node->data;
+       if (lsp_object->header.object_class != PCEP_OBJ_CLASS_LSP) {
+               pcep_log(
+                       LOG_INFO,
+                       "%s: Invalid PcInitiate message: Second object must be an LSP, found [%d]",
+                       __func__, lsp_object->header.object_class);
+               send_pcep_error(session, PCEP_ERRT_MANDATORY_OBJECT_MISSING,
+                               PCEP_ERRV_LSP_OBJECT_MISSING);
+               return false;
+       }
+
+       /* There may be more optional objects */
+       return true;
+}
+
+void increment_unknown_message(pcep_session *session)
+{
+       /* https://tools.ietf.org/html/rfc5440#section-6.9
+        * If a PCC/PCE receives unrecognized messages at a rate equal or
+        * greater than MAX-UNKNOWN-MESSAGES unknown message requests per
+        * minute, the PCC/PCE MUST send a PCEP CLOSE message */
+
+       time_t *unknown_message_time =
+               pceplib_malloc(PCEPLIB_INFRA, sizeof(time_t));
+       *unknown_message_time = time(NULL);
+       time_t expire_time = *unknown_message_time + 60;
+       queue_enqueue(session->num_unknown_messages_time_queue,
+                     unknown_message_time);
+
+       /* Purge any entries older than 1 minute. The oldest entries are at the
+        * queue head */
+       queue_node *time_node = session->num_unknown_messages_time_queue->head;
+       while (time_node != NULL) {
+               if (*((time_t *)time_node->data) > expire_time) {
+                       pceplib_free(
+                               PCEPLIB_INFRA,
+                               queue_dequeue(
+                                       session->num_unknown_messages_time_queue));
+                       time_node =
+                               session->num_unknown_messages_time_queue->head;
+               } else {
+                       time_node = NULL;
+               }
+       }
+
+       if ((int)session->num_unknown_messages_time_queue->num_entries
+           >= session->pcc_config.max_unknown_messages) {
+               pcep_log(
+                       LOG_INFO,
+                       "%s: [%ld-%ld] Max unknown messages reached [%d] closing session [%d]",
+                       __func__, time(NULL), pthread_self(),
+                       session->pcc_config.max_unknown_messages,
+                       session->session_id);
+
+               close_pcep_session_with_reason(session,
+                                              PCEP_CLOSE_REASON_UNREC_MSG);
+               enqueue_event(session, PCC_RCVD_MAX_UNKOWN_MSGS, NULL);
+       }
+}
+
+bool check_and_send_open_keep_alive(pcep_session *session)
+{
+       if (session->pce_open_received == true
+           && session->pce_open_rejected == false
+           && session->pce_open_keep_alive_sent == false) {
+               /* Send the PCE Open keep-alive response if it hasnt been sent
+                * yet */
+               cancel_timer(session->timer_id_open_keep_alive);
+               session->timer_id_open_keep_alive = TIMER_ID_NOT_SET;
+               send_keep_alive(session);
+               session->pce_open_keep_alive_sent = true;
+
+               return true;
+       }
+
+       return false;
+}
+
+void log_pcc_pce_connection(pcep_session *session)
+{
+       if (session->socket_comm_session == NULL) {
+               /* This only happens in UT */
+               return;
+       }
+
+       char src_ip_buf[40] = {0}, dst_ip_buf[40] = {0};
+       uint16_t src_port, dst_port;
+
+       if (session->socket_comm_session->is_ipv6) {
+               inet_ntop(AF_INET6,
+                         &session->socket_comm_session->src_sock_addr
+                                  .src_sock_addr_ipv6.sin6_addr,
+                         src_ip_buf, sizeof(src_ip_buf));
+               inet_ntop(AF_INET6,
+                         &session->socket_comm_session->dest_sock_addr
+                                  .dest_sock_addr_ipv6.sin6_addr,
+                         dst_ip_buf, sizeof(dst_ip_buf));
+               src_port = htons(session->socket_comm_session->src_sock_addr
+                                        .src_sock_addr_ipv6.sin6_port);
+               dst_port = htons(session->socket_comm_session->dest_sock_addr
+                                        .dest_sock_addr_ipv6.sin6_port);
+       } else {
+               inet_ntop(AF_INET,
+                         &session->socket_comm_session->src_sock_addr
+                                  .src_sock_addr_ipv4.sin_addr,
+                         src_ip_buf, sizeof(src_ip_buf));
+               inet_ntop(AF_INET,
+                         &session->socket_comm_session->dest_sock_addr
+                                  .dest_sock_addr_ipv4.sin_addr,
+                         dst_ip_buf, sizeof(dst_ip_buf));
+               src_port = htons(session->socket_comm_session->src_sock_addr
+                                        .src_sock_addr_ipv4.sin_port);
+               dst_port = htons(session->socket_comm_session->dest_sock_addr
+                                        .dest_sock_addr_ipv4.sin_port);
+       }
+
+       pcep_log(
+               LOG_INFO,
+               "%s: [%ld-%ld] Successful PCC [%s:%d] connection to PCE [%s:%d] session [%d] fd [%d]",
+               __func__, time(NULL), pthread_self(), src_ip_buf, src_port,
+               dst_ip_buf, dst_port, session->session_id,
+               session->socket_comm_session->socket_fd);
+}
+
+/*
+ * these functions are called by session_logic_loop() from
+ * pcep_session_logic_loop.c these functions are executed in the
+ * session_logic_loop thread, and the mutex is locked before calling these
+ * functions, so they are thread safe.
+ */
+
+/* state machine handling for expired timers */
+void handle_timer_event(pcep_session_event *event)
+{
+       if (event == NULL) {
+               pcep_log(LOG_INFO, "%s: handle_timer_event NULL event",
+                        __func__);
+               return;
+       }
+
+       pcep_session *session = event->session;
+
+       pcep_log(
+               LOG_INFO,
+               "%s: [%ld-%ld] pcep_session_logic handle_timer_event: session [%d] event timer_id [%d] session timers [OKW, OKA, DT, KA] [%d, %d, %d, %d]",
+               __func__, time(NULL), pthread_self(), session->session_id,
+               event->expired_timer_id, session->timer_id_open_keep_wait,
+               session->timer_id_open_keep_alive, session->timer_id_dead_timer,
+               session->timer_id_keep_alive);
+
+       /*
+        * these timer expirations are independent of the session state
+        */
+       if (event->expired_timer_id == session->timer_id_dead_timer) {
+               session->timer_id_dead_timer = TIMER_ID_NOT_SET;
+               increment_event_counters(session,
+                                        PCEP_EVENT_COUNTER_ID_TIMER_DEADTIMER);
+               close_pcep_session_with_reason(session,
+                                              PCEP_CLOSE_REASON_DEADTIMER);
+               enqueue_event(session, PCE_DEAD_TIMER_EXPIRED, NULL);
+               return;
+       } else if (event->expired_timer_id == session->timer_id_keep_alive) {
+               session->timer_id_keep_alive = TIMER_ID_NOT_SET;
+               increment_event_counters(session,
+                                        PCEP_EVENT_COUNTER_ID_TIMER_KEEPALIVE);
+               send_keep_alive(session);
+               return;
+       }
+
+       /*
+        * handle timers that depend on the session state
+        */
+       switch (session->session_state) {
+       case SESSION_STATE_PCEP_CONNECTING:
+               if (event->expired_timer_id
+                   == session->timer_id_open_keep_wait) {
+                       /* close the TCP session */
+                       pcep_log(
+                               LOG_INFO,
+                               "%s: handle_timer_event open_keep_wait timer expired for session [%d]",
+                               __func__, session->session_id);
+                       increment_event_counters(
+                               session,
+                               PCEP_EVENT_COUNTER_ID_TIMER_OPENKEEPWAIT);
+                       socket_comm_session_close_tcp_after_write(
+                               session->socket_comm_session);
+                       session->session_state = SESSION_STATE_INITIALIZED;
+                       session->timer_id_open_keep_wait = TIMER_ID_NOT_SET;
+                       enqueue_event(session, PCE_OPEN_KEEP_WAIT_TIMER_EXPIRED,
+                                     NULL);
+               }
+
+               if (event->expired_timer_id
+                   == session->timer_id_open_keep_alive) {
+                       increment_event_counters(
+                               session,
+                               PCEP_EVENT_COUNTER_ID_TIMER_OPENKEEPALIVE);
+                       session->timer_id_open_keep_alive = TIMER_ID_NOT_SET;
+                       if (check_and_send_open_keep_alive(session) == true) {
+                               if (session->pcc_open_accepted == true
+                                   && session->session_state
+                                              != SESSION_STATE_PCEP_CONNECTED) {
+                                       log_pcc_pce_connection(session);
+                                       session->session_state =
+                                               SESSION_STATE_PCEP_CONNECTED;
+                                       increment_event_counters(
+                                               session,
+                                               PCEP_EVENT_COUNTER_ID_PCE_CONNECT);
+                                       enqueue_event(session,
+                                                     PCC_CONNECTED_TO_PCE,
+                                                     NULL);
+                               }
+                       }
+                       return;
+               }
+               break;
+
+       case SESSION_STATE_INITIALIZED:
+       case SESSION_STATE_PCEP_CONNECTED:
+       default:
+               pcep_log(
+                       LOG_INFO,
+                       "%s: handle_timer_event unrecognized state transition, timer_id [%d] state [%d] session [%d]",
+                       __func__, event->expired_timer_id,
+                       session->session_state, session->session_id);
+               break;
+       }
+}
+
+/* State machine handling for received messages.
+ * This event was created in session_logic_msg_ready_handler() in
+ * pcep_session_logic_loop.c */
+void handle_socket_comm_event(pcep_session_event *event)
+{
+       if (event == NULL) {
+               pcep_log(LOG_INFO, "%s: handle_socket_comm_event NULL event",
+                        __func__);
+               return;
+       }
+
+       pcep_session *session = event->session;
+
+       pcep_log(
+               LOG_INFO,
+               "%s: [%ld-%ld] pcep_session_logic handle_socket_comm_event: session [%d] num messages [%d] socket_closed [%d]",
+               __func__, time(NULL), pthread_self(), session->session_id,
+               (event->received_msg_list == NULL
+                        ? -1
+                        : (int)event->received_msg_list->num_entries),
+               event->socket_closed);
+
+       /*
+        * independent of the session state
+        */
+       if (event->socket_closed) {
+               pcep_log(
+                       LOG_INFO,
+                       "%s: handle_socket_comm_event socket closed for session [%d]",
+                       __func__, session->session_id);
+               socket_comm_session_close_tcp(session->socket_comm_session);
+               enqueue_event(session, PCE_CLOSED_SOCKET, NULL);
+               if (session->session_state == SESSION_STATE_PCEP_CONNECTING) {
+                       enqueue_event(session, PCC_CONNECTION_FAILURE, NULL);
+               }
+               session->session_state = SESSION_STATE_INITIALIZED;
+               increment_event_counters(session,
+                                        PCEP_EVENT_COUNTER_ID_PCE_DISCONNECT);
+               return;
+       }
+
+       reset_dead_timer(session);
+
+       if (event->received_msg_list == NULL) {
+               return;
+       }
+
+       /* Message received on socket */
+       double_linked_list_node *msg_node;
+       for (msg_node = event->received_msg_list->head; msg_node != NULL;
+            msg_node = msg_node->next_node) {
+               bool message_enqueued = false;
+               struct pcep_message *msg =
+                       (struct pcep_message *)msg_node->data;
+               pcep_log(LOG_INFO, "%s: \t %s message", __func__,
+                        get_message_type_str(msg->msg_header->type));
+
+               increment_message_rx_counters(session, msg);
+
+               switch (msg->msg_header->type) {
+               case PCEP_TYPE_OPEN:
+                       /* handle_pcep_open() checks session state, and for
+                        * duplicate erroneous open messages, and replies with
+                        * error messages as needed. It also sets
+                        * pce_open_received. */
+                       if (handle_pcep_open(session, msg) == true) {
+                               /* PCE Open Message Accepted */
+                               enqueue_event(session, MESSAGE_RECEIVED, msg);
+                               message_enqueued = true;
+                               session->pce_open_accepted = true;
+                               session->pce_open_rejected = false;
+                               if (session->pcc_open_accepted) {
+                                       /* If both the PCC and PCE Opens are
+                                        * accepted, then the session is
+                                        * connected */
+
+                                       check_and_send_open_keep_alive(session);
+                                       log_pcc_pce_connection(session);
+                                       session->session_state =
+                                               SESSION_STATE_PCEP_CONNECTED;
+                                       increment_event_counters(
+                                               session,
+                                               PCEP_EVENT_COUNTER_ID_PCE_CONNECT);
+                                       enqueue_event(session,
+                                                     PCC_CONNECTED_TO_PCE,
+                                                     NULL);
+                               }
+                       }
+                       break;
+
+               case PCEP_TYPE_KEEPALIVE:
+                       if (session->session_state
+                           == SESSION_STATE_PCEP_CONNECTING) {
+                               /* PCC Open Message Accepted */
+                               cancel_timer(session->timer_id_open_keep_wait);
+                               session->timer_id_open_keep_wait =
+                                       TIMER_ID_NOT_SET;
+                               session->pcc_open_accepted = true;
+                               session->pcc_open_rejected = false;
+                               check_and_send_open_keep_alive(session);
+
+                               if (session->pce_open_accepted) {
+                                       /* If both the PCC and PCE Opens are
+                                        * accepted, then the session is
+                                        * connected */
+                                       log_pcc_pce_connection(session);
+                                       session->session_state =
+                                               SESSION_STATE_PCEP_CONNECTED;
+                                       increment_event_counters(
+                                               session,
+                                               PCEP_EVENT_COUNTER_ID_PCC_CONNECT);
+                                       enqueue_event(session,
+                                                     PCC_CONNECTED_TO_PCE,
+                                                     NULL);
+                               }
+                       }
+                       /* The dead_timer was already reset above, so nothing
+                        * extra to do here */
+                       break;
+
+               case PCEP_TYPE_PCREP:
+                       enqueue_event(session, MESSAGE_RECEIVED, msg);
+                       message_enqueued = true;
+                       break;
+
+               case PCEP_TYPE_CLOSE:
+                       session->session_state = SESSION_STATE_INITIALIZED;
+                       socket_comm_session_close_tcp(
+                               session->socket_comm_session);
+                       /* TODO should we also enqueue the message, so they can
+                        * see the reasons?? */
+                       enqueue_event(session, PCE_SENT_PCEP_CLOSE, NULL);
+                       /* TODO could this duplicate the disconnect counter with
+                        * socket close ?? */
+                       increment_event_counters(
+                               session, PCEP_EVENT_COUNTER_ID_PCE_DISCONNECT);
+                       break;
+
+               case PCEP_TYPE_PCREQ:
+                       /* The PCC does not support receiving PcReq messages */
+                       send_pcep_error(session,
+                                       PCEP_ERRT_CAPABILITY_NOT_SUPPORTED,
+                                       PCEP_ERRV_UNASSIGNED);
+                       break;
+
+               case PCEP_TYPE_REPORT:
+                       /* The PCC does not support receiving Report messages */
+                       send_pcep_error(session,
+                                       PCEP_ERRT_CAPABILITY_NOT_SUPPORTED,
+                                       PCEP_ERRV_UNASSIGNED);
+                       break;
+
+               case PCEP_TYPE_UPDATE:
+                       /* Should reply with a PcRpt */
+                       if (handle_pcep_update(session, msg) == true) {
+                               enqueue_event(session, MESSAGE_RECEIVED, msg);
+                               message_enqueued = true;
+                       }
+                       break;
+
+               case PCEP_TYPE_INITIATE:
+                       /* Should reply with a PcRpt */
+                       if (handle_pcep_initiate(session, msg) == true) {
+                               enqueue_event(session, MESSAGE_RECEIVED, msg);
+                               message_enqueued = true;
+                       }
+                       break;
+
+               case PCEP_TYPE_PCNOTF:
+                       enqueue_event(session, MESSAGE_RECEIVED, msg);
+                       message_enqueued = true;
+                       break;
+
+               case PCEP_TYPE_ERROR:
+                       if (msg->obj_list != NULL
+                           && msg->obj_list->num_entries > 0) {
+                               struct pcep_object_header *obj_hdr =
+                                       pcep_obj_get(msg->obj_list,
+                                                    PCEP_OBJ_CLASS_ERROR);
+                               if (obj_hdr != NULL) {
+                                       struct pcep_object_error *error_obj =
+                                               (struct pcep_object_error *)
+                                                       obj_hdr;
+                                       pcep_log(
+                                               LOG_DEBUG,
+                                               "%s: Error object [type, value] = [%s, %s]",
+                                               __func__,
+                                               get_error_type_str(
+                                                       error_obj->error_type),
+                                               get_error_value_str(
+                                                       error_obj->error_type,
+                                                       error_obj
+                                                               ->error_value));
+                               }
+                       }
+
+                       if (session->session_state
+                           == SESSION_STATE_PCEP_CONNECTING) {
+                               /* A PCC_CONNECTION_FAILURE event will be sent
+                                * when the socket is closed, if the state is
+                                * SESSION_STATE_PCEP_CONNECTING, in case the
+                                * PCE allows more than 2 failed open messages.
+                                */
+                               pcep_log(LOG_INFO,
+                                        "%s: PCC Open message rejected by PCE",
+                                        __func__);
+                               session->pcc_open_rejected = true;
+                               send_reconciled_pcep_open(session, msg);
+                               enqueue_event(session, PCC_SENT_INVALID_OPEN,
+                                             NULL);
+                       }
+                       enqueue_event(session, MESSAGE_RECEIVED, msg);
+                       message_enqueued = true;
+                       break;
+
+               default:
+                       pcep_log(LOG_INFO, "%s: \t UnSupported message",
+                                __func__);
+                       send_pcep_error(session,
+                                       PCEP_ERRT_CAPABILITY_NOT_SUPPORTED,
+                                       PCEP_ERRV_UNASSIGNED);
+                       increment_unknown_message(session);
+                       break;
+               }
+
+               /* if the message was enqueued, dont free it yet */
+               if (message_enqueued == false) {
+                       pcep_msg_free_message(msg);
+               }
+       }
+       dll_destroy(event->received_msg_list);
+}
diff --git a/pceplib/pcep_socket_comm.c b/pceplib/pcep_socket_comm.c
new file mode 100644 (file)
index 0000000..e22eb6e
--- /dev/null
@@ -0,0 +1,781 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+/*
+ *  Implementation of public API functions.
+ */
+
+#include <zebra.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h> // gethostbyname
+#include <stdbool.h>
+#include <string.h>
+#include <unistd.h> // close
+
+#include <arpa/inet.h> // sockets etc.
+#include <sys/types.h> // sockets etc.
+#include <sys/socket.h> // sockets etc.
+
+#include "pcep.h"
+#include "pcep_socket_comm.h"
+#include "pcep_socket_comm_internals.h"
+#include "pcep_utils_logging.h"
+#include "pcep_utils_memory.h"
+#include "pcep_utils_ordered_list.h"
+#include "pcep_utils_queue.h"
+
+bool initialize_socket_comm_pre(void);
+bool socket_comm_session_initialize_post(
+       pcep_socket_comm_session *socket_comm_session);
+
+pcep_socket_comm_handle *socket_comm_handle_ = NULL;
+
+
+/* simple compare method callback used by pcep_utils_ordered_list
+ * for ordered list insertion. */
+int socket_fd_node_compare(void *list_entry, void *new_entry)
+{
+       return ((pcep_socket_comm_session *)new_entry)->socket_fd
+              - ((pcep_socket_comm_session *)list_entry)->socket_fd;
+}
+
+
+bool initialize_socket_comm_pre()
+{
+       socket_comm_handle_ =
+               pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_socket_comm_handle));
+       memset(socket_comm_handle_, 0, sizeof(pcep_socket_comm_handle));
+
+       socket_comm_handle_->active = true;
+       socket_comm_handle_->num_active_sessions = 0;
+       socket_comm_handle_->read_list =
+               ordered_list_initialize(socket_fd_node_compare);
+       socket_comm_handle_->write_list =
+               ordered_list_initialize(socket_fd_node_compare);
+       socket_comm_handle_->session_list =
+               ordered_list_initialize(pointer_compare_function);
+       FD_ZERO(&socket_comm_handle_->except_master_set);
+       FD_ZERO(&socket_comm_handle_->read_master_set);
+       FD_ZERO(&socket_comm_handle_->write_master_set);
+
+       if (pthread_mutex_init(&(socket_comm_handle_->socket_comm_mutex), NULL)
+           != 0) {
+               pcep_log(LOG_ERR, "%s: Cannot initialize socket_comm mutex.",
+                        __func__);
+               pceplib_free(PCEPLIB_INFRA, socket_comm_handle_);
+               socket_comm_handle_ = NULL;
+
+               return false;
+       }
+
+       return true;
+}
+
+bool initialize_socket_comm_external_infra(
+       void *external_infra_data, ext_socket_read socket_read_cb,
+       ext_socket_write socket_write_cb,
+       ext_socket_pthread_create_callback thread_create_func)
+{
+       if (socket_comm_handle_ != NULL) {
+               /* already initialized */
+               return true;
+       }
+
+       if (initialize_socket_comm_pre() == false) {
+               return false;
+       }
+
+       /* Notice: If the thread_create_func is set, then both the
+        * socket_read_cb and the socket_write_cb SHOULD be NULL. */
+       if (thread_create_func != NULL) {
+               if (thread_create_func(
+                           &(socket_comm_handle_->socket_comm_thread), NULL,
+                           socket_comm_loop, socket_comm_handle_,
+                           "pceplib_timers")) {
+                       pcep_log(
+                               LOG_ERR,
+                               "%s: Cannot initialize external socket_comm thread.",
+                               __func__);
+                       return false;
+               }
+       }
+
+       socket_comm_handle_->external_infra_data = external_infra_data;
+       socket_comm_handle_->socket_write_func = socket_write_cb;
+       socket_comm_handle_->socket_read_func = socket_read_cb;
+
+       return true;
+}
+
+bool initialize_socket_comm_loop()
+{
+       if (socket_comm_handle_ != NULL) {
+               /* already initialized */
+               return true;
+       }
+
+       if (initialize_socket_comm_pre() == false) {
+               return false;
+       }
+
+       /* Launch socket comm loop pthread */
+       if (pthread_create(&(socket_comm_handle_->socket_comm_thread), NULL,
+                          socket_comm_loop, socket_comm_handle_)) {
+               pcep_log(LOG_ERR, "%s: Cannot initialize socket_comm thread.",
+                        __func__);
+               return false;
+       }
+
+       return true;
+}
+
+
+bool destroy_socket_comm_loop()
+{
+       socket_comm_handle_->active = false;
+
+       pthread_join(socket_comm_handle_->socket_comm_thread, NULL);
+       ordered_list_destroy(socket_comm_handle_->read_list);
+       ordered_list_destroy(socket_comm_handle_->write_list);
+       ordered_list_destroy(socket_comm_handle_->session_list);
+       pthread_mutex_destroy(&(socket_comm_handle_->socket_comm_mutex));
+
+       pceplib_free(PCEPLIB_INFRA, socket_comm_handle_);
+       socket_comm_handle_ = NULL;
+
+       return true;
+}
+
+/* Internal common init function */
+static pcep_socket_comm_session *socket_comm_session_initialize_pre(
+       message_received_handler message_handler,
+       message_ready_to_read_handler message_ready_handler,
+       message_sent_notifier msg_sent_notifier,
+       connection_except_notifier notifier, uint32_t connect_timeout_millis,
+       const char *tcp_authentication_str, bool is_tcp_auth_md5,
+       void *session_data)
+{
+       /* check that not both message handlers were set */
+       if (message_handler != NULL && message_ready_handler != NULL) {
+               pcep_log(
+                       LOG_WARNING,
+                       "%s: Only one of <message_received_handler | message_ready_to_read_handler> can be set.",
+                       __func__);
+               return NULL;
+       }
+
+       /* check that at least one message handler was set */
+       if (message_handler == NULL && message_ready_handler == NULL) {
+               pcep_log(
+                       LOG_WARNING,
+                       "%s: At least one of <message_received_handler | message_ready_to_read_handler> must be set.",
+                       __func__);
+               return NULL;
+       }
+
+       if (!initialize_socket_comm_loop()) {
+               pcep_log(LOG_WARNING,
+                        "%s: ERROR: cannot initialize socket_comm_loop.",
+                        __func__);
+
+               return NULL;
+       }
+
+       /* initialize everything for a pcep_session socket_comm */
+
+       pcep_socket_comm_session *socket_comm_session =
+               pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_socket_comm_session));
+       memset(socket_comm_session, 0, sizeof(pcep_socket_comm_session));
+
+       socket_comm_handle_->num_active_sessions++;
+       socket_comm_session->close_after_write = false;
+       socket_comm_session->session_data = session_data;
+       socket_comm_session->message_handler = message_handler;
+       socket_comm_session->message_ready_to_read_handler =
+               message_ready_handler;
+       socket_comm_session->message_sent_handler = msg_sent_notifier;
+       socket_comm_session->conn_except_notifier = notifier;
+       socket_comm_session->message_queue = queue_initialize();
+       socket_comm_session->connect_timeout_millis = connect_timeout_millis;
+       socket_comm_session->external_socket_data = NULL;
+       if (tcp_authentication_str != NULL) {
+               socket_comm_session->is_tcp_auth_md5 = is_tcp_auth_md5;
+               strlcpy(socket_comm_session->tcp_authentication_str,
+                       tcp_authentication_str,
+                       sizeof(socket_comm_session->tcp_authentication_str));
+       }
+
+       return socket_comm_session;
+}
+
+/* Internal common init function */
+bool socket_comm_session_initialize_post(
+       pcep_socket_comm_session *socket_comm_session)
+{
+       /* If we dont use SO_REUSEADDR, the socket will take 2 TIME_WAIT
+        * periods before being closed in the kernel if bind() was called */
+       int reuse_addr = 1;
+       if (setsockopt(socket_comm_session->socket_fd, SOL_SOCKET, SO_REUSEADDR,
+                      &reuse_addr, sizeof(int))
+           < 0) {
+               pcep_log(
+                       LOG_WARNING,
+                       "%s: Error in setsockopt() SO_REUSEADDR errno [%d %s].",
+                       __func__, errno, strerror(errno));
+               socket_comm_session_teardown(socket_comm_session);
+
+               return false;
+       }
+
+       struct sockaddr *src_sock_addr =
+               (socket_comm_session->is_ipv6
+                        ? (struct sockaddr *)&(
+                                socket_comm_session->src_sock_addr
+                                        .src_sock_addr_ipv6)
+                        : (struct sockaddr *)&(
+                                socket_comm_session->src_sock_addr
+                                        .src_sock_addr_ipv4));
+       int addr_len = (socket_comm_session->is_ipv6
+                               ? sizeof(socket_comm_session->src_sock_addr
+                                                .src_sock_addr_ipv6)
+                               : sizeof(socket_comm_session->src_sock_addr
+                                                .src_sock_addr_ipv4));
+       if (bind(socket_comm_session->socket_fd, src_sock_addr, addr_len)
+           == -1) {
+               pcep_log(LOG_WARNING,
+                        "%s: Cannot bind address to socket errno [%d %s].",
+                        __func__, errno, strerror(errno));
+               socket_comm_session_teardown(socket_comm_session);
+
+               return false;
+       }
+
+       /* Register the session as active with the Socket Comm Loop */
+       pthread_mutex_lock(&(socket_comm_handle_->socket_comm_mutex));
+       ordered_list_add_node(socket_comm_handle_->session_list,
+                             socket_comm_session);
+       pthread_mutex_unlock(&(socket_comm_handle_->socket_comm_mutex));
+
+       /* dont connect to the destination yet, since the PCE will have a timer
+        * for max time between TCP connect and PCEP open. we'll connect later
+        * when we send the PCEP open. */
+
+       return true;
+}
+
+
+pcep_socket_comm_session *socket_comm_session_initialize(
+       message_received_handler message_handler,
+       message_ready_to_read_handler message_ready_handler,
+       message_sent_notifier msg_sent_notifier,
+       connection_except_notifier notifier, struct in_addr *dest_ip,
+       short dest_port, uint32_t connect_timeout_millis,
+       const char *tcp_authentication_str, bool is_tcp_auth_md5,
+       void *session_data)
+{
+       return socket_comm_session_initialize_with_src(
+               message_handler, message_ready_handler, msg_sent_notifier,
+               notifier, NULL, 0, dest_ip, dest_port, connect_timeout_millis,
+               tcp_authentication_str, is_tcp_auth_md5, session_data);
+}
+
+pcep_socket_comm_session *socket_comm_session_initialize_ipv6(
+       message_received_handler message_handler,
+       message_ready_to_read_handler message_ready_handler,
+       message_sent_notifier msg_sent_notifier,
+       connection_except_notifier notifier, struct in6_addr *dest_ip,
+       short dest_port, uint32_t connect_timeout_millis,
+       const char *tcp_authentication_str, bool is_tcp_auth_md5,
+       void *session_data)
+{
+       return socket_comm_session_initialize_with_src_ipv6(
+               message_handler, message_ready_handler, msg_sent_notifier,
+               notifier, NULL, 0, dest_ip, dest_port, connect_timeout_millis,
+               tcp_authentication_str, is_tcp_auth_md5, session_data);
+}
+
+
+pcep_socket_comm_session *socket_comm_session_initialize_with_src(
+       message_received_handler message_handler,
+       message_ready_to_read_handler message_ready_handler,
+       message_sent_notifier msg_sent_notifier,
+       connection_except_notifier notifier, struct in_addr *src_ip,
+       short src_port, struct in_addr *dest_ip, short dest_port,
+       uint32_t connect_timeout_millis, const char *tcp_authentication_str,
+       bool is_tcp_auth_md5, void *session_data)
+{
+       if (dest_ip == NULL) {
+               pcep_log(LOG_WARNING, "%s: dest_ipv4 is NULL", __func__);
+               return NULL;
+       }
+
+       pcep_socket_comm_session *socket_comm_session =
+               socket_comm_session_initialize_pre(
+                       message_handler, message_ready_handler,
+                       msg_sent_notifier, notifier, connect_timeout_millis,
+                       tcp_authentication_str, is_tcp_auth_md5, session_data);
+       if (socket_comm_session == NULL) {
+               return NULL;
+       }
+
+       socket_comm_session->socket_fd =
+               socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+       if (socket_comm_session->socket_fd == -1) {
+               pcep_log(LOG_WARNING,
+                        "%s: Cannot create ipv4 socket errno [%d %s].",
+                        __func__, errno, strerror(errno));
+               socket_comm_session_teardown(
+                       socket_comm_session); // socket_comm_session freed
+                                             // inside fn so NOLINT next.
+
+               return NULL; // NOLINT(clang-analyzer-unix.Malloc)
+       }
+
+       socket_comm_session->is_ipv6 = false;
+       socket_comm_session->dest_sock_addr.dest_sock_addr_ipv4.sin_family =
+               AF_INET;
+       socket_comm_session->src_sock_addr.src_sock_addr_ipv4.sin_family =
+               AF_INET;
+       socket_comm_session->dest_sock_addr.dest_sock_addr_ipv4.sin_port =
+               htons(dest_port);
+       socket_comm_session->src_sock_addr.src_sock_addr_ipv4.sin_port =
+               htons(src_port);
+       socket_comm_session->dest_sock_addr.dest_sock_addr_ipv4.sin_addr
+               .s_addr = dest_ip->s_addr;
+       if (src_ip != NULL) {
+               socket_comm_session->src_sock_addr.src_sock_addr_ipv4.sin_addr
+                       .s_addr = src_ip->s_addr;
+       } else {
+               socket_comm_session->src_sock_addr.src_sock_addr_ipv4.sin_addr
+                       .s_addr = INADDR_ANY;
+       }
+
+       if (socket_comm_session_initialize_post(socket_comm_session) == false) {
+               return NULL;
+       }
+
+       return socket_comm_session;
+}
+
+pcep_socket_comm_session *socket_comm_session_initialize_with_src_ipv6(
+       message_received_handler message_handler,
+       message_ready_to_read_handler message_ready_handler,
+       message_sent_notifier msg_sent_notifier,
+       connection_except_notifier notifier, struct in6_addr *src_ip,
+       short src_port, struct in6_addr *dest_ip, short dest_port,
+       uint32_t connect_timeout_millis, const char *tcp_authentication_str,
+       bool is_tcp_auth_md5, void *session_data)
+{
+       if (dest_ip == NULL) {
+               pcep_log(LOG_WARNING, "%s: dest_ipv6 is NULL", __func__);
+               return NULL;
+       }
+
+       pcep_socket_comm_session *socket_comm_session =
+               socket_comm_session_initialize_pre(
+                       message_handler, message_ready_handler,
+                       msg_sent_notifier, notifier, connect_timeout_millis,
+                       tcp_authentication_str, is_tcp_auth_md5, session_data);
+       if (socket_comm_session == NULL) {
+               return NULL;
+       }
+
+       socket_comm_session->socket_fd =
+               socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP);
+       if (socket_comm_session->socket_fd == -1) {
+               pcep_log(LOG_WARNING,
+                        "%s: Cannot create ipv6 socket errno [%d %s].",
+                        __func__, errno, strerror(errno));
+               socket_comm_session_teardown(
+                       socket_comm_session); // socket_comm_session freed
+                                             // inside fn so NOLINT next.
+
+               return NULL; // NOLINT(clang-analyzer-unix.Malloc)
+       }
+
+       socket_comm_session->is_ipv6 = true;
+       socket_comm_session->dest_sock_addr.dest_sock_addr_ipv6.sin6_family =
+               AF_INET6;
+       socket_comm_session->src_sock_addr.src_sock_addr_ipv6.sin6_family =
+               AF_INET6;
+       socket_comm_session->dest_sock_addr.dest_sock_addr_ipv6.sin6_port =
+               htons(dest_port);
+       socket_comm_session->src_sock_addr.src_sock_addr_ipv6.sin6_port =
+               htons(src_port);
+       memcpy(&socket_comm_session->dest_sock_addr.dest_sock_addr_ipv6
+                       .sin6_addr,
+              dest_ip, sizeof(struct in6_addr));
+       if (src_ip != NULL) {
+               memcpy(&socket_comm_session->src_sock_addr.src_sock_addr_ipv6
+                               .sin6_addr,
+                      src_ip, sizeof(struct in6_addr));
+       } else {
+               socket_comm_session->src_sock_addr.src_sock_addr_ipv6
+                       .sin6_addr = in6addr_any;
+       }
+
+       if (socket_comm_session_initialize_post(socket_comm_session) == false) {
+               return NULL;
+       }
+
+       return socket_comm_session;
+}
+
+
+bool socket_comm_session_connect_tcp(
+       pcep_socket_comm_session *socket_comm_session)
+{
+       if (socket_comm_session == NULL) {
+               pcep_log(
+                       LOG_WARNING,
+                       "%s: socket_comm_session_connect_tcp NULL socket_comm_session.",
+                       __func__);
+               return NULL;
+       }
+
+       /* Set the socket to non-blocking, so connect() does not block */
+       int fcntl_arg;
+       if ((fcntl_arg = fcntl(socket_comm_session->socket_fd, F_GETFL, NULL))
+           < 0) {
+               pcep_log(LOG_WARNING, "%s: Error fcntl(..., F_GETFL) [%d %s]",
+                        __func__, errno, strerror(errno));
+               return false;
+       }
+
+       fcntl_arg |= O_NONBLOCK;
+       if (fcntl(socket_comm_session->socket_fd, F_SETFL, fcntl_arg) < 0) {
+               pcep_log(LOG_WARNING, "%s: Error fcntl(..., F_SETFL) [%d %s]",
+                        __func__, errno, strerror(errno));
+               return false;
+       }
+
+#if HAVE_DECL_TCP_MD5SIG
+       /* TCP authentication, currently only TCP MD5 RFC2385 is supported */
+       if (socket_comm_session->tcp_authentication_str[0] != '\0') {
+#if defined(linux) || defined(GNU_LINUX)
+               struct tcp_md5sig sig;
+               memset(&sig, 0, sizeof(sig));
+               if (socket_comm_session->is_ipv6) {
+                       memcpy(&sig.tcpm_addr,
+                              &socket_comm_session->dest_sock_addr
+                                       .dest_sock_addr_ipv6,
+                              sizeof(struct sockaddr_in6));
+               } else {
+                       memcpy(&sig.tcpm_addr,
+                              &socket_comm_session->dest_sock_addr
+                                       .dest_sock_addr_ipv4,
+                              sizeof(struct sockaddr_in));
+               }
+               sig.tcpm_keylen =
+                       strlen(socket_comm_session->tcp_authentication_str);
+               memcpy(sig.tcpm_key,
+                      socket_comm_session->tcp_authentication_str,
+                      sig.tcpm_keylen);
+#else
+               int sig = 1;
+#endif
+               if (setsockopt(socket_comm_session->socket_fd, IPPROTO_TCP,
+                              TCP_MD5SIG, &sig, sizeof(sig))
+                   == -1) {
+                       pcep_log(LOG_ERR, "%s: Failed to setsockopt(): [%d %s]",
+                                __func__, errno, strerror(errno));
+                       return false;
+               }
+       }
+#endif
+
+       int connect_result = 0;
+       if (socket_comm_session->is_ipv6) {
+               connect_result = connect(
+                       socket_comm_session->socket_fd,
+                       (struct sockaddr *)&(socket_comm_session->dest_sock_addr
+                                                    .dest_sock_addr_ipv6),
+                       sizeof(socket_comm_session->dest_sock_addr
+                                      .dest_sock_addr_ipv6));
+       } else {
+               connect_result = connect(
+                       socket_comm_session->socket_fd,
+                       (struct sockaddr *)&(socket_comm_session->dest_sock_addr
+                                                    .dest_sock_addr_ipv4),
+                       sizeof(socket_comm_session->dest_sock_addr
+                                      .dest_sock_addr_ipv4));
+       }
+
+       if (connect_result < 0) {
+               if (errno == EINPROGRESS) {
+                       /* Calculate the configured timeout in seconds and
+                        * microseconds */
+                       struct timeval tv;
+                       if (socket_comm_session->connect_timeout_millis
+                           > 1000) {
+                               tv.tv_sec = socket_comm_session
+                                                   ->connect_timeout_millis
+                                           / 1000;
+                               tv.tv_usec = (socket_comm_session
+                                                     ->connect_timeout_millis
+                                             - (tv.tv_sec * 1000))
+                                            * 1000;
+                       } else {
+                               tv.tv_sec = 0;
+                               tv.tv_usec = socket_comm_session
+                                                    ->connect_timeout_millis
+                                            * 1000;
+                       }
+
+                       /* Use select to wait a max timeout for connect
+                        * https://stackoverflow.com/questions/2597608/c-socket-connection-timeout
+                        */
+                       fd_set fdset;
+                       FD_ZERO(&fdset);
+                       FD_SET(socket_comm_session->socket_fd, &fdset);
+                       if (select(socket_comm_session->socket_fd + 1, NULL,
+                                  &fdset, NULL, &tv)
+                           > 0) {
+                               int so_error;
+                               socklen_t len = sizeof(so_error);
+                               getsockopt(socket_comm_session->socket_fd,
+                                          SOL_SOCKET, SO_ERROR, &so_error,
+                                          &len);
+                               if (so_error) {
+                                       pcep_log(
+                                               LOG_WARNING,
+                                               "%s: TCP connect failed on socket_fd [%d].",
+                                               __func__,
+                                               socket_comm_session->socket_fd);
+                                       return false;
+                               }
+                       } else {
+                               pcep_log(
+                                       LOG_WARNING,
+                                       "%s: TCP connect timed-out on socket_fd [%d].",
+                                       __func__,
+                                       socket_comm_session->socket_fd);
+                               return false;
+                       }
+               } else {
+                       pcep_log(
+                               LOG_WARNING,
+                               "%s: TCP connect, error connecting on socket_fd [%d] errno [%d %s]",
+                               __func__, socket_comm_session->socket_fd, errno,
+                               strerror(errno));
+                       return false;
+               }
+       }
+
+       pthread_mutex_lock(&(socket_comm_handle_->socket_comm_mutex));
+       /* once the TCP connection is open, we should be ready to read at any
+        * time */
+       ordered_list_add_node(socket_comm_handle_->read_list,
+                             socket_comm_session);
+
+       if (socket_comm_handle_->socket_read_func != NULL) {
+               socket_comm_handle_->socket_read_func(
+                       socket_comm_handle_->external_infra_data,
+                       &socket_comm_session->external_socket_data,
+                       socket_comm_session->socket_fd, socket_comm_handle_);
+       }
+       pthread_mutex_unlock(&(socket_comm_handle_->socket_comm_mutex));
+
+       return true;
+}
+
+
+bool socket_comm_session_close_tcp(
+       pcep_socket_comm_session *socket_comm_session)
+{
+       if (socket_comm_session == NULL) {
+               pcep_log(
+                       LOG_WARNING,
+                       "%s: socket_comm_session_close_tcp NULL socket_comm_session.",
+                       __func__);
+               return false;
+       }
+
+       pcep_log(LOG_DEBUG,
+                "%s: socket_comm_session_close_tcp close() socket fd [%d]",
+                __func__, socket_comm_session->socket_fd);
+
+       pthread_mutex_lock(&(socket_comm_handle_->socket_comm_mutex));
+       ordered_list_remove_first_node_equals(socket_comm_handle_->read_list,
+                                             socket_comm_session);
+       ordered_list_remove_first_node_equals(socket_comm_handle_->write_list,
+                                             socket_comm_session);
+       // TODO should it be close() or shutdown()??
+       close(socket_comm_session->socket_fd);
+       socket_comm_session->socket_fd = -1;
+       pthread_mutex_unlock(&(socket_comm_handle_->socket_comm_mutex));
+
+       return true;
+}
+
+
+bool socket_comm_session_close_tcp_after_write(
+       pcep_socket_comm_session *socket_comm_session)
+{
+       if (socket_comm_session == NULL) {
+               pcep_log(
+                       LOG_WARNING,
+                       "%s: socket_comm_session_close_tcp_after_write NULL socket_comm_session.",
+                       __func__);
+               return false;
+       }
+
+       pthread_mutex_lock(&(socket_comm_handle_->socket_comm_mutex));
+       socket_comm_session->close_after_write = true;
+       pthread_mutex_unlock(&(socket_comm_handle_->socket_comm_mutex));
+
+       return true;
+}
+
+
+bool socket_comm_session_teardown(pcep_socket_comm_session *socket_comm_session)
+{
+       if (socket_comm_handle_ == NULL) {
+               pcep_log(LOG_WARNING,
+                        "%s: Cannot teardown NULL socket_comm_handle",
+                        __func__);
+               return false;
+       }
+
+       if (socket_comm_session == NULL) {
+               pcep_log(LOG_WARNING, "%s: Cannot teardown NULL session",
+                        __func__);
+               return false;
+       }
+
+       if (comm_session_exists_locking(socket_comm_handle_,
+                                       socket_comm_session)
+           == false) {
+               pcep_log(LOG_WARNING,
+                        "%s: Cannot teardown session that does not exist",
+                        __func__);
+               return false;
+       }
+
+       if (socket_comm_session->socket_fd >= 0) {
+               shutdown(socket_comm_session->socket_fd, SHUT_RDWR);
+               close(socket_comm_session->socket_fd);
+       }
+
+       pthread_mutex_lock(&(socket_comm_handle_->socket_comm_mutex));
+       queue_destroy(socket_comm_session->message_queue);
+       ordered_list_remove_first_node_equals(socket_comm_handle_->session_list,
+                                             socket_comm_session);
+       ordered_list_remove_first_node_equals(socket_comm_handle_->read_list,
+                                             socket_comm_session);
+       ordered_list_remove_first_node_equals(socket_comm_handle_->write_list,
+                                             socket_comm_session);
+       socket_comm_handle_->num_active_sessions--;
+       pthread_mutex_unlock(&(socket_comm_handle_->socket_comm_mutex));
+
+       pcep_log(
+               LOG_INFO,
+               "%s: [%ld-%ld] socket_comm_session fd [%d] destroyed, [%d] sessions remaining",
+               __func__, time(NULL), pthread_self(),
+               socket_comm_session->socket_fd,
+               socket_comm_handle_->num_active_sessions);
+
+       pceplib_free(PCEPLIB_INFRA, socket_comm_session);
+
+       /* It would be nice to call destroy_socket_comm_loop() here if
+        * socket_comm_handle_->num_active_sessions == 0, but this function
+        * will usually be called from the message_sent_notifier callback,
+        * which gets called in the middle of the socket_comm_loop, and that
+        * is dangerous, so destroy_socket_comm_loop() must be called upon
+        * application exit. */
+
+       return true;
+}
+
+
+void socket_comm_session_send_message(
+       pcep_socket_comm_session *socket_comm_session,
+       const char *encoded_message, unsigned int msg_length,
+       bool free_after_send)
+{
+       if (socket_comm_session == NULL) {
+               pcep_log(
+                       LOG_WARNING,
+                       "%s: socket_comm_session_send_message NULL socket_comm_session.",
+                       __func__);
+               return;
+       }
+
+       pcep_socket_comm_queued_message *queued_message = pceplib_malloc(
+               PCEPLIB_MESSAGES, sizeof(pcep_socket_comm_queued_message));
+       queued_message->encoded_message = encoded_message;
+       queued_message->msg_length = msg_length;
+       queued_message->free_after_send = free_after_send;
+
+       pthread_mutex_lock(&(socket_comm_handle_->socket_comm_mutex));
+
+       /* Do not proceed if the socket_comm_session has been deleted */
+       if (ordered_list_find(socket_comm_handle_->session_list,
+                             socket_comm_session)
+           == NULL) {
+               /* Should never get here, only if the session was deleted and
+                * someone still tries to write on it */
+               pcep_log(
+                       LOG_WARNING,
+                       "%s: Cannot write a message on a deleted socket comm session, discarding message",
+                       __func__);
+               pthread_mutex_unlock(&(socket_comm_handle_->socket_comm_mutex));
+               pceplib_free(PCEPLIB_MESSAGES, queued_message);
+
+               return;
+       }
+
+       /* Do not proceed if the socket has been closed */
+       if (socket_comm_session->socket_fd < 0) {
+               /* Should never get here, only if the session was deleted and
+                * someone still tries to write on it */
+               pcep_log(
+                       LOG_WARNING,
+                       "%s: Cannot write a message on a closed socket, discarding message",
+                       __func__);
+               pthread_mutex_unlock(&(socket_comm_handle_->socket_comm_mutex));
+               pceplib_free(PCEPLIB_MESSAGES, queued_message);
+
+               return;
+       }
+
+       queue_enqueue(socket_comm_session->message_queue, queued_message);
+
+       /* Add it to the write list only if its not already there */
+       if (ordered_list_find(socket_comm_handle_->write_list,
+                             socket_comm_session)
+           == NULL) {
+               ordered_list_add_node(socket_comm_handle_->write_list,
+                                     socket_comm_session);
+       }
+
+       if (socket_comm_handle_->socket_write_func != NULL) {
+               socket_comm_handle_->socket_write_func(
+                       socket_comm_handle_->external_infra_data,
+                       &socket_comm_session->external_socket_data,
+                       socket_comm_session->socket_fd, socket_comm_handle_);
+       }
+       pthread_mutex_unlock(&(socket_comm_handle_->socket_comm_mutex));
+}
diff --git a/pceplib/pcep_socket_comm.h b/pceplib/pcep_socket_comm.h
new file mode 100644 (file)
index 0000000..797ffda
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+/*
+ *  Declaration of public API functions.
+ */
+
+#ifndef INCLUDE_PCEPSOCKETCOMM_H_
+#define INCLUDE_PCEPSOCKETCOMM_H_
+
+#include "pcep.h"
+#include <arpa/inet.h> // sockaddr_in
+#include <netinet/tcp.h>
+#include <stdbool.h>
+
+#include "pcep_utils_queue.h"
+
+#define MAX_RECVD_MSG_SIZE 2048
+
+/*
+ * A socket_comm_session can be initialized with 1 of 2 types of mutually
+ * exclusive message callbacks:
+ * - message_received_handler : the socket_comm library reads the message and
+ * calls the callback with the message_data and message_length. this callback
+ * should be used for smaller/simpler messages.
+ * - message_ready_to_read_handler : the socket_comm library will call this
+ * callback when a message is ready to be read on a socket_fd. this callback
+ * should be used if the
+ */
+
+/* message received handler that receives the message data and message length */
+typedef void (*message_received_handler)(void *session_data,
+                                        const char *message_data,
+                                        unsigned int message_length);
+/* message ready received handler that should read the message on socket_fd
+ * and return the number of bytes read */
+typedef int (*message_ready_to_read_handler)(void *session_data, int socket_fd);
+/* callback handler called when a messages is sent */
+typedef void (*message_sent_notifier)(void *session_data, int socket_fd);
+/* callback handler called when the socket is closed */
+typedef void (*connection_except_notifier)(void *session_data, int socket_fd);
+
+/* Function pointers when an external socket infrastructure is used */
+typedef int (*ext_socket_write)(void *infra_data, void **infra_socket_data,
+                               int fd, void *data);
+typedef int (*ext_socket_read)(void *infra_data, void **infra_socket_data,
+                              int fd, void *data);
+typedef int (*ext_socket_pthread_create_callback)(
+       pthread_t *pthread_id, const pthread_attr_t *attr,
+       void *(*start_routine)(void *), void *data, const char *thread_name);
+
+typedef struct pcep_socket_comm_session_ {
+       message_received_handler message_handler;
+       message_ready_to_read_handler message_ready_to_read_handler;
+       message_sent_notifier message_sent_handler;
+       connection_except_notifier conn_except_notifier;
+       union src_sock_addr {
+               struct sockaddr_in src_sock_addr_ipv4;
+               struct sockaddr_in6 src_sock_addr_ipv6;
+       } src_sock_addr;
+       union dest_sock_addr {
+               struct sockaddr_in dest_sock_addr_ipv4;
+               struct sockaddr_in6 dest_sock_addr_ipv6;
+       } dest_sock_addr;
+       bool is_ipv6;
+       uint32_t connect_timeout_millis;
+       int socket_fd;
+       void *session_data;
+       queue_handle *message_queue;
+       char received_message[MAX_RECVD_MSG_SIZE];
+       int received_bytes;
+       bool close_after_write;
+       void *external_socket_data; /* used for external socket infra */
+       char tcp_authentication_str[TCP_MD5SIG_MAXKEYLEN
+                                   + 1]; /* should be used with is_tcp_auth_md5
+                                            flag */
+       bool is_tcp_auth_md5; /* flag to distinguish between rfc 2385 (md5) and
+                                rfc 5925 (tcp-ao) */
+
+} pcep_socket_comm_session;
+
+
+/* Need to document that when the msg_rcv_handler is called, the data needs
+ * to be handled in the same function call, else it may be overwritten by
+ * the next read from this socket */
+
+
+/* Initialize the Socket Comm infrastructure, with either an internal pthread
+ * or with an external infrastructure.
+ * If an internal pthread infrastructure is to be used, then it is not necessary
+ * to explicitly call initialize_socket_comm_loop() as it will be called
+ * internally when a socket comm session is initialized. */
+
+/* Initialize the Socket Comm infrastructure with an internal pthread */
+bool initialize_socket_comm_loop(void);
+/* Initialize the Socket Comm infrastructure with an external infrastructure.
+ * Notice: If the thread_create_func is set, then both the socket_read_cb
+ *         and the socket_write_cb SHOULD be NULL. */
+bool initialize_socket_comm_external_infra(
+       void *external_infra_data, ext_socket_read socket_read_cb,
+       ext_socket_write socket_write_cb,
+       ext_socket_pthread_create_callback thread_create_func);
+
+/* The msg_rcv_handler and msg_ready_handler are mutually exclusive, and only
+ * one can be set (as explained above), else NULL will be returned. */
+pcep_socket_comm_session *
+socket_comm_session_initialize(message_received_handler msg_rcv_handler,
+                              message_ready_to_read_handler msg_ready_handler,
+                              message_sent_notifier msg_sent_notifier,
+                              connection_except_notifier notifier,
+                              struct in_addr *dst_ip, short dst_port,
+                              uint32_t connect_timeout_millis,
+                              const char *tcp_authentication_str,
+                              bool is_tcp_auth_md5, void *session_data);
+
+pcep_socket_comm_session *socket_comm_session_initialize_ipv6(
+       message_received_handler msg_rcv_handler,
+       message_ready_to_read_handler msg_ready_handler,
+       message_sent_notifier msg_sent_notifier,
+       connection_except_notifier notifier, struct in6_addr *dst_ip,
+       short dst_port, uint32_t connect_timeout_millis,
+       const char *tcp_authentication_str, bool is_tcp_auth_md5,
+       void *session_data);
+
+pcep_socket_comm_session *socket_comm_session_initialize_with_src(
+       message_received_handler msg_rcv_handler,
+       message_ready_to_read_handler msg_ready_handler,
+       message_sent_notifier msg_sent_notifier,
+       connection_except_notifier notifier, struct in_addr *src_ip,
+       short src_port, struct in_addr *dst_ip, short dst_port,
+       uint32_t connect_timeout_millis, const char *tcp_authentication_str,
+       bool is_tcp_auth_md5, void *session_data);
+
+pcep_socket_comm_session *socket_comm_session_initialize_with_src_ipv6(
+       message_received_handler msg_rcv_handler,
+       message_ready_to_read_handler msg_ready_handler,
+       message_sent_notifier msg_sent_notifier,
+       connection_except_notifier notifier, struct in6_addr *src_ip,
+       short src_port, struct in6_addr *dst_ip, short dst_port,
+       uint32_t connect_timeout_millis, const char *tcp_authentication_str,
+       bool is_tcp_auth_md5, void *session_data);
+
+bool socket_comm_session_teardown(
+       pcep_socket_comm_session *socket_comm_session);
+
+bool socket_comm_session_connect_tcp(
+       pcep_socket_comm_session *socket_comm_session);
+
+/* Immediately close the TCP connection, irregardless if there are pending
+ * messages to be sent. */
+bool socket_comm_session_close_tcp(
+       pcep_socket_comm_session *socket_comm_session);
+
+/* Sets a flag to close the TCP connection either after all the pending messages
+ * are written, or if there are no pending messages, the next time the socket is
+ * checked to be writeable. */
+bool socket_comm_session_close_tcp_after_write(
+       pcep_socket_comm_session *socket_comm_session);
+
+void socket_comm_session_send_message(
+       pcep_socket_comm_session *socket_comm_session,
+       const char *encoded_message, unsigned int msg_length,
+       bool free_after_send);
+
+/* If an external Socket infra like FRR is used, then these functions will
+ * be called when a socket is ready to read/write in the external infra.
+ * Implemented in pcep_socket_comm_loop.c */
+int pceplib_external_socket_read(int fd, void *payload);
+int pceplib_external_socket_write(int fd, void *payload);
+
+/* the socket comm loop is started internally by
+ * socket_comm_session_initialize()
+ * but needs to be explicitly stopped with this call. */
+bool destroy_socket_comm_loop(void);
+
+int socket_fd_node_compare(void *list_entry, void *new_entry);
+
+#endif /* INCLUDE_PCEPSOCKETCOMM_H_ */
diff --git a/pceplib/pcep_socket_comm_internals.h b/pceplib/pcep_socket_comm_internals.h
new file mode 100644 (file)
index 0000000..4445a14
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#ifndef SRC_PCEPSOCKETCOMMINTERNALS_H_
+#define SRC_PCEPSOCKETCOMMINTERNALS_H_
+
+#include <pthread.h>
+#include <stdbool.h>
+
+#include "pcep_utils_ordered_list.h"
+#include "pcep_socket_comm.h"
+
+
+typedef struct pcep_socket_comm_handle_ {
+       bool active;
+       pthread_t socket_comm_thread;
+       pthread_mutex_t socket_comm_mutex;
+       fd_set read_master_set;
+       fd_set write_master_set;
+       fd_set except_master_set;
+       /* ordered_list of socket_descriptors to read from */
+       ordered_list_handle *read_list;
+       /* ordered_list of socket_descriptors to write to */
+       ordered_list_handle *write_list;
+       ordered_list_handle *session_list;
+       int num_active_sessions;
+       void *external_infra_data;
+       ext_socket_write socket_write_func;
+       ext_socket_read socket_read_func;
+
+} pcep_socket_comm_handle;
+
+
+typedef struct pcep_socket_comm_queued_message_ {
+       const char *encoded_message;
+       int msg_length;
+       bool free_after_send;
+
+} pcep_socket_comm_queued_message;
+
+
+/* Functions implemented in pcep_socket_comm_loop.c */
+void *socket_comm_loop(void *data);
+bool comm_session_exists(pcep_socket_comm_handle *socket_comm_handle,
+                        pcep_socket_comm_session *socket_comm_session);
+bool comm_session_exists_locking(pcep_socket_comm_handle *socket_comm_handle,
+                                pcep_socket_comm_session *socket_comm_session);
+
+#endif /* SRC_PCEPSOCKETCOMMINTERNALS_H_ */
diff --git a/pceplib/pcep_socket_comm_loop.c b/pceplib/pcep_socket_comm_loop.c
new file mode 100644 (file)
index 0000000..d58409c
--- /dev/null
@@ -0,0 +1,493 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <string.h>
+#include <unistd.h>
+#include <assert.h>
+
+#include "pcep_socket_comm_internals.h"
+#include "pcep_socket_comm_loop.h"
+#include "pcep_utils_logging.h"
+#include "pcep_utils_ordered_list.h"
+#include "pcep_utils_logging.h"
+#include "pcep_utils_memory.h"
+
+void write_message(int socket_fd, const char *message, unsigned int msg_length);
+unsigned int read_message(int socket_fd, char *received_message,
+                         unsigned int max_message_size);
+int build_fd_sets(pcep_socket_comm_handle *socket_comm_handle);
+void handle_writes(pcep_socket_comm_handle *socket_comm_handle);
+void handle_excepts(pcep_socket_comm_handle *socket_comm_handle);
+
+bool comm_session_exists(pcep_socket_comm_handle *socket_comm_handle,
+                        pcep_socket_comm_session *socket_comm_session)
+{
+       if (socket_comm_handle == NULL) {
+               return false;
+       }
+
+       return (ordered_list_find(socket_comm_handle->session_list,
+                                 socket_comm_session)
+               != NULL);
+}
+
+
+bool comm_session_exists_locking(pcep_socket_comm_handle *socket_comm_handle,
+                                pcep_socket_comm_session *socket_comm_session)
+{
+       if (socket_comm_handle == NULL) {
+               return false;
+       }
+
+       pthread_mutex_lock(&(socket_comm_handle->socket_comm_mutex));
+       bool exists =
+               comm_session_exists(socket_comm_handle, socket_comm_session);
+       pthread_mutex_unlock(&(socket_comm_handle->socket_comm_mutex));
+
+       return exists;
+}
+
+
+void write_message(int socket_fd, const char *message, unsigned int msg_length)
+{
+       ssize_t bytes_sent = 0;
+       unsigned int total_bytes_sent = 0;
+
+       while ((uint32_t)bytes_sent < msg_length) {
+               bytes_sent = write(socket_fd, message + total_bytes_sent,
+                                  msg_length);
+
+               pcep_log(
+                       LOG_INFO,
+                       "%s: [%ld-%ld] socket_comm writing on socket fd [%d] msg_lenth [%u] bytes sent [%d]",
+                       __func__, time(NULL), pthread_self(), socket_fd,
+                       msg_length, bytes_sent);
+
+               if (bytes_sent < 0) {
+                       if (errno != EAGAIN && errno != EWOULDBLOCK) {
+                               pcep_log(LOG_WARNING, "%s: send() failure",
+                                        __func__);
+
+                               return;
+                       }
+               } else {
+                       total_bytes_sent += bytes_sent;
+               }
+       }
+}
+
+
+unsigned int read_message(int socket_fd, char *received_message,
+                         unsigned int max_message_size)
+{
+       /* TODO what if bytes_read == max_message_size? there could be more to
+        * read */
+       unsigned int bytes_read =
+               read(socket_fd, received_message, max_message_size);
+       pcep_log(
+               LOG_INFO,
+               "%s: [%ld-%ld] socket_comm read message bytes_read [%u] on socket fd [%d]",
+               __func__, time(NULL), pthread_self(), bytes_read, socket_fd);
+
+       return bytes_read;
+}
+
+
+int build_fd_sets(pcep_socket_comm_handle *socket_comm_handle)
+{
+       int max_fd = 0;
+
+       pthread_mutex_lock(&(socket_comm_handle->socket_comm_mutex));
+
+       FD_ZERO(&socket_comm_handle->except_master_set);
+       FD_ZERO(&socket_comm_handle->read_master_set);
+       ordered_list_node *node = socket_comm_handle->read_list->head;
+       pcep_socket_comm_session *comm_session;
+       while (node != NULL) {
+               comm_session = (pcep_socket_comm_session *)node->data;
+               if (comm_session->socket_fd > max_fd) {
+                       max_fd = comm_session->socket_fd;
+               } else if (comm_session->socket_fd < 0) {
+                       pcep_log(LOG_ERR, "%s: Negative fd", __func__);
+                       assert(comm_session->socket_fd > 0);
+               }
+
+               /*pcep_log(LOG_DEBUG, ld] socket_comm::build_fdSets set
+                  ready_toRead
+                  [%d]", __func__, time(NULL), comm_session->socket_fd);*/
+               FD_SET(comm_session->socket_fd,
+                      &socket_comm_handle->read_master_set);
+               FD_SET(comm_session->socket_fd,
+                      &socket_comm_handle->except_master_set);
+               node = node->next_node;
+       }
+
+       FD_ZERO(&socket_comm_handle->write_master_set);
+       node = socket_comm_handle->write_list->head;
+       while (node != NULL) {
+               comm_session = (pcep_socket_comm_session *)node->data;
+               if (comm_session->socket_fd > max_fd) {
+                       max_fd = comm_session->socket_fd;
+               } else if (comm_session->socket_fd < 0) {
+                       pcep_log(LOG_ERR, "%s: Negative fd", __func__);
+                       assert(comm_session->socket_fd > 0);
+               }
+
+               /*pcep_log(LOG_DEBUG, "%s: [%ld] socket_comm::build_fdSets set
+                  ready_toWrite [%d]", __func__, time(NULL),
+                  comm_session->socket_fd);*/
+               FD_SET(comm_session->socket_fd,
+                      &socket_comm_handle->write_master_set);
+               FD_SET(comm_session->socket_fd,
+                      &socket_comm_handle->except_master_set);
+               node = node->next_node;
+       }
+
+       pthread_mutex_unlock(&(socket_comm_handle->socket_comm_mutex));
+
+       return max_fd + 1;
+}
+
+
+void handle_reads(pcep_socket_comm_handle *socket_comm_handle)
+{
+
+       /*
+        * iterate all the socket_fd's in the read_list. it may be that not
+        * all of them have something to read. dont remove the socket_fd
+        * from the read_list since messages could come at any time.
+        */
+
+       /* Notice: Only locking the mutex when accessing the read_list,
+        * since the read callbacks may end up calling back into the socket
+        * comm module to write messages which could be a deadlock. */
+       pthread_mutex_lock(&(socket_comm_handle->socket_comm_mutex));
+       ordered_list_node *node = socket_comm_handle->read_list->head;
+       pthread_mutex_unlock(&(socket_comm_handle->socket_comm_mutex));
+
+       while (node != NULL) {
+               pcep_socket_comm_session *comm_session =
+                       (pcep_socket_comm_session *)node->data;
+
+               pthread_mutex_lock(&(socket_comm_handle->socket_comm_mutex));
+               node = node->next_node;
+               if (!comm_session_exists(socket_comm_handle, comm_session)) {
+                       /* This comm_session has been deleted, move on to the
+                        * next one */
+                       pthread_mutex_unlock(
+                               &(socket_comm_handle->socket_comm_mutex));
+                       continue;
+               }
+
+               int is_set = FD_ISSET(comm_session->socket_fd,
+                                     &(socket_comm_handle->read_master_set));
+               /* Upon read failure, the comm_session might be free'd, so we
+                * cant store the received_bytes in the comm_session, until we
+                * know the read was successful. */
+               int received_bytes = 0;
+               pthread_mutex_unlock(&(socket_comm_handle->socket_comm_mutex));
+
+               if (is_set) {
+                       FD_CLR(comm_session->socket_fd,
+                              &(socket_comm_handle->read_master_set));
+
+                       /* either read the message locally, or call the
+                        * message_ready_handler to read it */
+                       if (comm_session->message_handler != NULL) {
+                               received_bytes = read_message(
+                                       comm_session->socket_fd,
+                                       comm_session->received_message,
+                                       MAX_RECVD_MSG_SIZE);
+                               if (received_bytes > 0) {
+                                       /* Send the received message to the
+                                        * handler */
+                                       comm_session->received_bytes =
+                                               received_bytes;
+                                       comm_session->message_handler(
+                                               comm_session->session_data,
+                                               comm_session->received_message,
+                                               comm_session->received_bytes);
+                               }
+                       } else {
+                               /* Tell the handler a message is ready to be
+                                * read. The comm_session may be destroyed in
+                                * this call, if
+                                * there is an error reading or if the socket is
+                                * closed. */
+                               received_bytes =
+                                       comm_session
+                                               ->message_ready_to_read_handler(
+                                                       comm_session
+                                                               ->session_data,
+                                                       comm_session
+                                                               ->socket_fd);
+                       }
+
+                       /* handle the read results */
+                       if (received_bytes == 0) {
+                               if (comm_session_exists_locking(
+                                           socket_comm_handle, comm_session)) {
+                                       comm_session->received_bytes = 0;
+                                       /* the socket was closed */
+                                       /* TODO should we define a socket except
+                                        * enum? or will the only time we call
+                                        * this is when the socket is closed??
+                                        */
+                                       if (comm_session->conn_except_notifier
+                                           != NULL) {
+                                               comm_session->conn_except_notifier(
+                                                       comm_session
+                                                               ->session_data,
+                                                       comm_session
+                                                               ->socket_fd);
+                                       }
+
+                                       /* stop reading from the socket if its
+                                        * closed */
+                                       pthread_mutex_lock(
+                                               &(socket_comm_handle
+                                                         ->socket_comm_mutex));
+                                       ordered_list_remove_first_node_equals(
+                                               socket_comm_handle->read_list,
+                                               comm_session);
+                                       pthread_mutex_unlock(
+                                               &(socket_comm_handle
+                                                         ->socket_comm_mutex));
+                               }
+                       } else if (received_bytes < 0) {
+                               /* TODO should we call conn_except_notifier()
+                                * here ? */
+                               pcep_log(
+                                       LOG_WARNING,
+                                       "%s: Error on socket fd [%d] : errno [%d][%s]",
+                                       __func__, comm_session->socket_fd,
+                                       errno, strerror(errno));
+                       } else {
+                               comm_session->received_bytes = received_bytes;
+                       }
+               }
+       }
+}
+
+
+void handle_writes(pcep_socket_comm_handle *socket_comm_handle)
+{
+       pthread_mutex_lock(&(socket_comm_handle->socket_comm_mutex));
+
+       /*
+        * iterate all the socket_fd's in the write_list. it may be that not
+        * all of them are ready to be written to. only remove the socket_fd
+        * from the list if it is ready to be written to.
+        */
+
+       ordered_list_node *node = socket_comm_handle->write_list->head;
+       pcep_socket_comm_session *comm_session;
+       bool msg_written;
+       while (node != NULL) {
+               comm_session = (pcep_socket_comm_session *)node->data;
+               node = node->next_node;
+               msg_written = false;
+
+               if (!comm_session_exists(socket_comm_handle, comm_session)) {
+                       /* This comm_session has been deleted, move on to the
+                        * next one */
+                       continue;
+               }
+
+               if (FD_ISSET(comm_session->socket_fd,
+                            &(socket_comm_handle->write_master_set))) {
+                       /* only remove the entry from the list, if it is written
+                        * to */
+                       ordered_list_remove_first_node_equals(
+                               socket_comm_handle->write_list, comm_session);
+                       FD_CLR(comm_session->socket_fd,
+                              &(socket_comm_handle->write_master_set));
+
+                       /* dequeue all the comm_session messages and send them
+                        */
+                       pcep_socket_comm_queued_message *queued_message =
+                               queue_dequeue(comm_session->message_queue);
+                       while (queued_message != NULL) {
+                               msg_written = true;
+                               write_message(comm_session->socket_fd,
+                                             queued_message->encoded_message,
+                                             queued_message->msg_length);
+                               if (queued_message->free_after_send) {
+                                       pceplib_free(PCEPLIB_MESSAGES,
+                                                    (void *)queued_message
+                                                            ->encoded_message);
+                               }
+                               pceplib_free(PCEPLIB_MESSAGES, queued_message);
+                               queued_message = queue_dequeue(
+                                       comm_session->message_queue);
+                       }
+               }
+
+               /* check if the socket should be closed after writing */
+               if (comm_session->close_after_write == true) {
+                       if (comm_session->message_queue->num_entries == 0) {
+                               /* TODO check to make sure modifying the
+                                * write_list while iterating it doesnt cause
+                                * problems. */
+                               pcep_log(
+                                       LOG_DEBUG,
+                                       "%s: handle_writes close() socket fd [%d]",
+                                       __func__, comm_session->socket_fd);
+                               ordered_list_remove_first_node_equals(
+                                       socket_comm_handle->read_list,
+                                       comm_session);
+                               ordered_list_remove_first_node_equals(
+                                       socket_comm_handle->write_list,
+                                       comm_session);
+                               close(comm_session->socket_fd);
+                               comm_session->socket_fd = -1;
+                       }
+               }
+
+               if (comm_session->message_sent_handler != NULL
+                   && msg_written == true) {
+                       /* Unlocking to allow the message_sent_handler to
+                        * make calls like destroy_socket_comm_session */
+                       pthread_mutex_unlock(
+                               &(socket_comm_handle->socket_comm_mutex));
+                       comm_session->message_sent_handler(
+                               comm_session->session_data,
+                               comm_session->socket_fd);
+                       pthread_mutex_lock(
+                               &(socket_comm_handle->socket_comm_mutex));
+               }
+       }
+
+       pthread_mutex_unlock(&(socket_comm_handle->socket_comm_mutex));
+}
+
+
+void handle_excepts(pcep_socket_comm_handle *socket_comm_handle)
+{
+       /* TODO finish this */
+       (void)socket_comm_handle;
+}
+
+
+/* pcep_socket_comm::initialize_socket_comm_loop() will create a thread and
+ * invoke this method */
+void *socket_comm_loop(void *data)
+{
+       if (data == NULL) {
+               pcep_log(
+                       LOG_WARNING,
+                       "%s: Cannot start socket_comm_loop with NULL pcep_socketcomm_handle",
+                       __func__);
+               return NULL;
+       }
+
+       pcep_log(LOG_NOTICE, "%s: [%ld-%ld] Starting socket_comm_loop thread",
+                __func__, time(NULL), pthread_self());
+
+       pcep_socket_comm_handle *socket_comm_handle =
+               (pcep_socket_comm_handle *)data;
+       struct timeval timer;
+       int max_fd;
+
+       while (socket_comm_handle->active) {
+               /* check the FD's every 1/4 sec, 250 milliseconds */
+               timer.tv_sec = 0;
+               timer.tv_usec = 250000;
+               max_fd = build_fd_sets(socket_comm_handle);
+
+               if (select(max_fd, &(socket_comm_handle->read_master_set),
+                          &(socket_comm_handle->write_master_set),
+                          &(socket_comm_handle->except_master_set), &timer)
+                   < 0) {
+                       /* TODO handle the error */
+                       pcep_log(
+                               LOG_WARNING,
+                               "%s: ERROR socket_comm_loop on select : errno [%d][%s]",
+                               __func__, errno, strerror(errno));
+               }
+
+               handle_reads(socket_comm_handle);
+               handle_writes(socket_comm_handle);
+               handle_excepts(socket_comm_handle);
+       }
+
+       pcep_log(LOG_NOTICE, "%s: [%ld-%ld] Finished socket_comm_loop thread",
+                __func__, time(NULL), pthread_self());
+
+       return NULL;
+}
+
+int pceplib_external_socket_read(int fd, void *payload)
+{
+       pcep_socket_comm_handle *socket_comm_handle =
+               (pcep_socket_comm_handle *)payload;
+       if (socket_comm_handle == NULL) {
+               return -1;
+       }
+
+       pthread_mutex_lock(&(socket_comm_handle->socket_comm_mutex));
+       FD_SET(fd, &(socket_comm_handle->read_master_set));
+       pthread_mutex_unlock(&(socket_comm_handle->socket_comm_mutex));
+
+       handle_reads(socket_comm_handle);
+
+       /* Get the socket_comm_session */
+       pcep_socket_comm_session find_session = {.socket_fd = fd};
+       pthread_mutex_lock(&(socket_comm_handle->socket_comm_mutex));
+       ordered_list_node *node =
+               ordered_list_find(socket_comm_handle->read_list, &find_session);
+
+       /* read again */
+       if (node != NULL) {
+               socket_comm_handle->socket_read_func(
+                       socket_comm_handle->external_infra_data,
+                       &((pcep_socket_comm_session *)node)
+                                ->external_socket_data,
+                       fd, socket_comm_handle);
+       }
+       pthread_mutex_unlock(&(socket_comm_handle->socket_comm_mutex));
+
+       return 0;
+}
+
+int pceplib_external_socket_write(int fd, void *payload)
+{
+       pcep_socket_comm_handle *socket_comm_handle =
+               (pcep_socket_comm_handle *)payload;
+       if (socket_comm_handle == NULL) {
+               return -1;
+       }
+
+       pthread_mutex_lock(&(socket_comm_handle->socket_comm_mutex));
+       FD_SET(fd, &(socket_comm_handle->write_master_set));
+       pthread_mutex_unlock(&(socket_comm_handle->socket_comm_mutex));
+
+       handle_writes(socket_comm_handle);
+
+       /* TODO do we need to cancel this FD from writing?? */
+
+       return 0;
+}
diff --git a/pceplib/pcep_socket_comm_loop.h b/pceplib/pcep_socket_comm_loop.h
new file mode 100644 (file)
index 0000000..3ca2c03
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Javier Garcia <javier.garcia@voltanet.io>
+ *
+ */
+
+/*
+ *  Timer definitions to be used internally by the pcep_timers library.
+ */
+
+#ifndef PCEPSOCKETCOMMLOOP_H_
+#define PCEPSOCKETCOMMLOOP_H_
+
+void handle_reads(pcep_socket_comm_handle *socket_comm_handle);
+
+#endif /* PCEPTIMERINTERNALS_H_ */
diff --git a/pceplib/pcep_socket_comm_mock.c b/pceplib/pcep_socket_comm_mock.c
new file mode 100644 (file)
index 0000000..069d0cf
--- /dev/null
@@ -0,0 +1,363 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+/*
+ * This module is built into a separate library, and is used by several
+ * other modules for unit testing, so that real sockets dont have to be
+ * created.
+ */
+
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <CUnit/CUnit.h>
+
+#include "pcep_socket_comm.h"
+#include "pcep_socket_comm_mock.h"
+#include "pcep_utils_queue.h"
+
+/* reset_mock_socket_comm_info() should be used before each test */
+mock_socket_comm_info mock_socket_metadata;
+
+void setup_mock_socket_comm_info(void)
+{
+       mock_socket_metadata.socket_comm_session_initialize_times_called = 0;
+       mock_socket_metadata.socket_comm_session_initialize_src_times_called =
+               0;
+       mock_socket_metadata.socket_comm_session_teardown_times_called = 0;
+       mock_socket_metadata.socket_comm_session_connect_tcp_times_called = 0;
+       mock_socket_metadata.socket_comm_session_send_message_times_called = 0;
+       mock_socket_metadata
+               .socket_comm_session_close_tcp_after_write_times_called = 0;
+       mock_socket_metadata.socket_comm_session_close_tcp_times_called = 0;
+       mock_socket_metadata.destroy_socket_comm_loop_times_called = 0;
+       mock_socket_metadata.send_message_save_message = false;
+       mock_socket_metadata.sent_message_list = dll_initialize();
+}
+
+void teardown_mock_socket_comm_info(void)
+{
+       dll_destroy(mock_socket_metadata.sent_message_list);
+}
+
+void reset_mock_socket_comm_info(void)
+{
+       teardown_mock_socket_comm_info();
+       setup_mock_socket_comm_info();
+}
+
+mock_socket_comm_info *get_mock_socket_comm_info(void)
+{
+       return &mock_socket_metadata;
+}
+
+void verify_socket_comm_times_called(int initialized, int teardown, int connect,
+                                    int send_message,
+                                    int close_tcp_after_write, int close_tcp,
+                                    int destroy)
+{
+       CU_ASSERT_EQUAL(initialized,
+                       mock_socket_metadata
+                               .socket_comm_session_initialize_times_called);
+       CU_ASSERT_EQUAL(
+               teardown,
+               mock_socket_metadata.socket_comm_session_teardown_times_called);
+       CU_ASSERT_EQUAL(connect,
+                       mock_socket_metadata
+                               .socket_comm_session_connect_tcp_times_called);
+       CU_ASSERT_EQUAL(send_message,
+                       mock_socket_metadata
+                               .socket_comm_session_send_message_times_called);
+       CU_ASSERT_EQUAL(
+               close_tcp_after_write,
+               mock_socket_metadata
+                       .socket_comm_session_close_tcp_after_write_times_called);
+       CU_ASSERT_EQUAL(close_tcp,
+                       mock_socket_metadata
+                               .socket_comm_session_close_tcp_times_called);
+       CU_ASSERT_EQUAL(
+               destroy,
+               mock_socket_metadata.destroy_socket_comm_loop_times_called);
+}
+
+
+/*
+ * Mock the socket_comm functions used by session_logic for Unit Testing
+ */
+
+bool initialize_socket_comm_external_infra(
+       void *external_infra_data, ext_socket_read socket_read_cb,
+       ext_socket_write socket_write_cb,
+       ext_socket_pthread_create_callback thread_create_func)
+{
+       (void)external_infra_data;
+       (void)socket_read_cb;
+       (void)socket_write_cb;
+       (void)thread_create_func;
+
+       mock_socket_metadata
+               .socket_comm_initialize_external_infra_times_called++;
+
+       return true;
+}
+
+bool destroy_socket_comm_loop()
+{
+       mock_socket_metadata.destroy_socket_comm_loop_times_called++;
+
+       return false;
+}
+
+pcep_socket_comm_session *
+socket_comm_session_initialize(message_received_handler msg_rcv_handler,
+                              message_ready_to_read_handler msg_ready_handler,
+                              message_sent_notifier msg_sent_notifier,
+                              connection_except_notifier notifier,
+                              struct in_addr *dst_ip, short dst_port,
+                              uint32_t connect_timeout_millis,
+                              const char *tcp_authentication_str,
+                              bool is_tcp_auth_md5, void *session_data)
+{
+       (void)msg_sent_notifier;
+       (void)tcp_authentication_str;
+       (void)is_tcp_auth_md5;
+
+       mock_socket_metadata.socket_comm_session_initialize_times_called++;
+
+       pcep_socket_comm_session *comm_session =
+               malloc(sizeof(pcep_socket_comm_session));
+       memset(comm_session, 0, sizeof(pcep_socket_comm_session));
+
+       comm_session->message_handler = msg_rcv_handler;
+       comm_session->message_ready_to_read_handler = msg_ready_handler;
+       comm_session->conn_except_notifier = notifier;
+       comm_session->message_queue = queue_initialize();
+       comm_session->session_data = session_data;
+       comm_session->close_after_write = false;
+       comm_session->connect_timeout_millis = connect_timeout_millis;
+       comm_session->is_ipv6 = false;
+       comm_session->dest_sock_addr.dest_sock_addr_ipv4.sin_family = AF_INET;
+       comm_session->dest_sock_addr.dest_sock_addr_ipv4.sin_port =
+               htons(dst_port);
+       comm_session->dest_sock_addr.dest_sock_addr_ipv4.sin_addr.s_addr =
+               dst_ip->s_addr;
+
+       return comm_session;
+}
+
+pcep_socket_comm_session *socket_comm_session_initialize_ipv6(
+       message_received_handler msg_rcv_handler,
+       message_ready_to_read_handler msg_ready_handler,
+       message_sent_notifier msg_sent_notifier,
+       connection_except_notifier notifier, struct in6_addr *dst_ip,
+       short dst_port, uint32_t connect_timeout_millis,
+       const char *tcp_authentication_str, bool is_tcp_auth_md5,
+       void *session_data)
+{
+       (void)msg_sent_notifier;
+       (void)tcp_authentication_str;
+       (void)is_tcp_auth_md5;
+
+       mock_socket_metadata.socket_comm_session_initialize_times_called++;
+
+       pcep_socket_comm_session *comm_session =
+               malloc(sizeof(pcep_socket_comm_session));
+       memset(comm_session, 0, sizeof(pcep_socket_comm_session));
+
+       comm_session->message_handler = msg_rcv_handler;
+       comm_session->message_ready_to_read_handler = msg_ready_handler;
+       comm_session->conn_except_notifier = notifier;
+       comm_session->message_queue = queue_initialize();
+       comm_session->session_data = session_data;
+       comm_session->close_after_write = false;
+       comm_session->connect_timeout_millis = connect_timeout_millis;
+       comm_session->is_ipv6 = true;
+       comm_session->dest_sock_addr.dest_sock_addr_ipv6.sin6_family = AF_INET6;
+       comm_session->dest_sock_addr.dest_sock_addr_ipv6.sin6_port =
+               htons(dst_port);
+       memcpy(&comm_session->dest_sock_addr.dest_sock_addr_ipv6.sin6_addr,
+              dst_ip, sizeof(struct in6_addr));
+
+       return comm_session;
+}
+
+pcep_socket_comm_session *socket_comm_session_initialize_with_src(
+       message_received_handler msg_rcv_handler,
+       message_ready_to_read_handler msg_ready_handler,
+       message_sent_notifier msg_sent_notifier,
+       connection_except_notifier notifier, struct in_addr *src_ip,
+       short src_port, struct in_addr *dst_ip, short dst_port,
+       uint32_t connect_timeout_millis, const char *tcp_authentication_str,
+       bool is_tcp_auth_md5, void *session_data)
+{
+       (void)msg_sent_notifier;
+       (void)tcp_authentication_str;
+       (void)is_tcp_auth_md5;
+
+       mock_socket_metadata.socket_comm_session_initialize_src_times_called++;
+
+       pcep_socket_comm_session *comm_session =
+               malloc(sizeof(pcep_socket_comm_session));
+       memset(comm_session, 0, sizeof(pcep_socket_comm_session));
+
+       comm_session->message_handler = msg_rcv_handler;
+       comm_session->message_ready_to_read_handler = msg_ready_handler;
+       comm_session->conn_except_notifier = notifier;
+       comm_session->message_queue = queue_initialize();
+       comm_session->session_data = session_data;
+       comm_session->close_after_write = false;
+       comm_session->connect_timeout_millis = connect_timeout_millis;
+       comm_session->is_ipv6 = false;
+       comm_session->src_sock_addr.src_sock_addr_ipv4.sin_family = AF_INET;
+       comm_session->src_sock_addr.src_sock_addr_ipv4.sin_port =
+               htons(src_port);
+       comm_session->src_sock_addr.src_sock_addr_ipv4.sin_addr.s_addr =
+               ((src_ip == NULL) ? INADDR_ANY : src_ip->s_addr);
+       comm_session->dest_sock_addr.dest_sock_addr_ipv4.sin_family = AF_INET;
+       comm_session->dest_sock_addr.dest_sock_addr_ipv4.sin_port =
+               htons(dst_port);
+       comm_session->dest_sock_addr.dest_sock_addr_ipv4.sin_addr.s_addr =
+               dst_ip->s_addr;
+
+       return comm_session;
+}
+
+pcep_socket_comm_session *socket_comm_session_initialize_with_src_ipv6(
+       message_received_handler msg_rcv_handler,
+       message_ready_to_read_handler msg_ready_handler,
+       message_sent_notifier msg_sent_notifier,
+       connection_except_notifier notifier, struct in6_addr *src_ip,
+       short src_port, struct in6_addr *dst_ip, short dst_port,
+       uint32_t connect_timeout_millis, const char *tcp_authentication_str,
+       bool is_tcp_auth_md5, void *session_data)
+{
+       (void)msg_sent_notifier;
+       (void)tcp_authentication_str;
+       (void)is_tcp_auth_md5;
+
+       mock_socket_metadata.socket_comm_session_initialize_src_times_called++;
+
+       pcep_socket_comm_session *comm_session =
+               malloc(sizeof(pcep_socket_comm_session));
+       memset(comm_session, 0, sizeof(pcep_socket_comm_session));
+
+       comm_session->message_handler = msg_rcv_handler;
+       comm_session->message_ready_to_read_handler = msg_ready_handler;
+       comm_session->conn_except_notifier = notifier;
+       comm_session->message_queue = queue_initialize();
+       comm_session->session_data = session_data;
+       comm_session->close_after_write = false;
+       comm_session->connect_timeout_millis = connect_timeout_millis;
+       comm_session->is_ipv6 = true;
+       comm_session->src_sock_addr.src_sock_addr_ipv6.sin6_family = AF_INET6;
+       comm_session->src_sock_addr.src_sock_addr_ipv6.sin6_port =
+               htons(src_port);
+       if (src_ip == NULL) {
+               comm_session->src_sock_addr.src_sock_addr_ipv6.sin6_addr =
+                       in6addr_any;
+       } else {
+               memcpy(&comm_session->src_sock_addr.src_sock_addr_ipv6
+                               .sin6_addr,
+                      src_ip, sizeof(struct in6_addr));
+       }
+       comm_session->dest_sock_addr.dest_sock_addr_ipv6.sin6_family = AF_INET6;
+       comm_session->dest_sock_addr.dest_sock_addr_ipv6.sin6_port =
+               htons(dst_port);
+       memcpy(&comm_session->dest_sock_addr.dest_sock_addr_ipv6.sin6_addr,
+              dst_ip, sizeof(struct in6_addr));
+
+       return comm_session;
+}
+
+bool socket_comm_session_teardown(pcep_socket_comm_session *socket_comm_session)
+{
+       mock_socket_metadata.socket_comm_session_teardown_times_called++;
+
+       if (socket_comm_session != NULL) {
+               queue_destroy(socket_comm_session->message_queue);
+               free(socket_comm_session);
+       }
+
+       return true;
+}
+
+
+bool socket_comm_session_connect_tcp(
+       pcep_socket_comm_session *socket_comm_session)
+{
+       (void)socket_comm_session;
+
+       mock_socket_metadata.socket_comm_session_connect_tcp_times_called++;
+
+       return true;
+}
+
+
+void socket_comm_session_send_message(
+       pcep_socket_comm_session *socket_comm_session,
+       const char *encoded_message, unsigned int msg_length,
+       bool delete_after_send)
+{
+       (void)socket_comm_session;
+       (void)msg_length;
+
+       mock_socket_metadata.socket_comm_session_send_message_times_called++;
+
+       if (mock_socket_metadata.send_message_save_message == true) {
+               /* the caller/test case is responsible for freeing the message
+                */
+               dll_append(mock_socket_metadata.sent_message_list,
+                          (char *)encoded_message);
+       } else {
+               if (delete_after_send == true) {
+                       free((void *)encoded_message);
+               }
+       }
+
+       return;
+}
+
+
+bool socket_comm_session_close_tcp_after_write(
+       pcep_socket_comm_session *socket_comm_session)
+{
+       (void)socket_comm_session;
+
+       mock_socket_metadata
+               .socket_comm_session_close_tcp_after_write_times_called++;
+
+       return true;
+}
+
+
+bool socket_comm_session_close_tcp(
+       pcep_socket_comm_session *socket_comm_session)
+{
+       (void)socket_comm_session;
+
+       mock_socket_metadata.socket_comm_session_close_tcp_times_called++;
+
+       return true;
+}
diff --git a/pceplib/pcep_socket_comm_mock.h b/pceplib/pcep_socket_comm_mock.h
new file mode 100644 (file)
index 0000000..ca0e38b
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+/*
+ * This module is built into a separate library, and is used by several
+ * other modules for unit testing, so that real sockets dont have to be
+ * created.
+ */
+
+#ifndef PCEP_SOCKET_COMM_MOCK_SOCKET_COMM_H_
+#define PCEP_SOCKET_COMM_MOCK_SOCKET_COMM_H_
+
+#include <stdbool.h>
+
+#include "pcep_utils_double_linked_list.h"
+
+typedef struct mock_socket_comm_info_ {
+       int socket_comm_initialize_external_infra_times_called;
+       int socket_comm_session_initialize_times_called;
+       int socket_comm_session_initialize_src_times_called;
+       int socket_comm_session_teardown_times_called;
+       int socket_comm_session_connect_tcp_times_called;
+       int socket_comm_session_send_message_times_called;
+       int socket_comm_session_close_tcp_after_write_times_called;
+       int socket_comm_session_close_tcp_times_called;
+       int destroy_socket_comm_loop_times_called;
+
+       /* TODO later if necessary, we can add return values for
+        *      those functions that return something */
+
+       /* Used to access messages sent with socket_comm_session_send_message()
+        */
+       bool send_message_save_message;
+       double_linked_list *sent_message_list;
+
+} mock_socket_comm_info;
+
+void setup_mock_socket_comm_info(void);
+void teardown_mock_socket_comm_info(void);
+void reset_mock_socket_comm_info(void);
+bool destroy_socket_comm_loop(void);
+
+mock_socket_comm_info *get_mock_socket_comm_info(void);
+void verify_socket_comm_times_called(int initialized, int teardown, int connect,
+                                    int send_message, int close_after_write,
+                                    int close, int destroy);
+
+#endif /* PCEP_SOCKET_COMM_MOCK_SOCKET_COMM_H_ */
diff --git a/pceplib/pcep_timer_internals.h b/pceplib/pcep_timer_internals.h
new file mode 100644 (file)
index 0000000..8221c78
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+/*
+ *  Timer definitions to be used internally by the pcep_timers library.
+ */
+
+#ifndef PCEPTIMERINTERNALS_H_
+#define PCEPTIMERINTERNALS_H_
+
+#include <stdint.h>
+#include <pthread.h>
+
+#include "pcep_utils_ordered_list.h"
+
+/* Function pointer to be called when timers expire.
+ * Parameters:
+ *    void *data - passed into create_timer
+ *    int timer_id - the timer_id returned by create_timer
+ */
+typedef void (*timer_expire_handler)(void *, int);
+
+/* Function pointer when an external timer infrastructure is used */
+typedef void (*ext_timer_create)(void *infra_data, void **timer, int seconds,
+                                void *data);
+typedef void (*ext_timer_cancel)(void **timer);
+typedef int (*ext_pthread_create_callback)(pthread_t *pthread_id,
+                                          const pthread_attr_t *attr,
+                                          void *(*start_routine)(void *),
+                                          void *data, const char *thread_name);
+
+typedef struct pcep_timer_ {
+       time_t expire_time;
+       uint16_t sleep_seconds;
+       int timer_id;
+       void *data;
+       void *external_timer;
+
+} pcep_timer;
+
+typedef struct pcep_timers_context_ {
+       ordered_list_handle *timer_list;
+       bool active;
+       timer_expire_handler expire_handler;
+       pthread_t event_loop_thread;
+       pthread_mutex_t timer_list_lock;
+       void *external_timer_infra_data;
+       ext_timer_create timer_create_func;
+       ext_timer_cancel timer_cancel_func;
+
+} pcep_timers_context;
+
+/* functions implemented in pcep_timers_loop.c */
+void *event_loop(void *context);
+
+
+#endif /* PCEPTIMERINTERNALS_H_ */
diff --git a/pceplib/pcep_timers.c b/pceplib/pcep_timers.c
new file mode 100644 (file)
index 0000000..e9d9d4b
--- /dev/null
@@ -0,0 +1,482 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+/*
+ *  Implementation of public API timer functions.
+ */
+
+#include <limits.h>
+#include <pthread.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include "pcep_timers.h"
+#include "pcep_utils_logging.h"
+#include "pcep_utils_memory.h"
+#include "pcep_utils_ordered_list.h"
+
+static pcep_timers_context *timers_context_ = NULL;
+static int timer_id_ = 0;
+
+
+/* simple compare method callback used by pcep_utils_ordered_list
+ * for ordered list insertion. */
+int timer_list_node_compare(void *list_entry, void *new_entry)
+{
+       /* return:
+        *   < 0  if new_entry < list_entry
+        *   == 0 if new_entry == list_entry (new_entry will be inserted after
+        * list_entry) > 0  if new_entry > list_entry */
+       return ((pcep_timer *)new_entry)->expire_time
+              - ((pcep_timer *)list_entry)->expire_time;
+}
+
+
+/* simple compare method callback used by pcep_utils_ordered_list
+ * ordered_list_remove_first_node_equals2 to remove a timer based on
+ * its timer_id. */
+int timer_list_node_timer_id_compare(void *list_entry, void *new_entry)
+{
+       return ((pcep_timer *)new_entry)->timer_id
+              - ((pcep_timer *)list_entry)->timer_id;
+}
+
+/* simple compare method callback used by pcep_utils_ordered_list
+ * ordered_list_remove_first_node_equals2 to remove a timer based on
+ * its address. */
+int timer_list_node_timer_ptr_compare(void *list_entry, void *new_entry)
+{
+       return ((char *)new_entry - (char *)list_entry);
+}
+
+/* internal util method */
+static pcep_timers_context *create_timers_context_()
+{
+       if (timers_context_ == NULL) {
+               timers_context_ = pceplib_malloc(PCEPLIB_INFRA,
+                                                sizeof(pcep_timers_context));
+               memset(timers_context_, 0, sizeof(pcep_timers_context));
+               timers_context_->active = false;
+       }
+
+       return timers_context_;
+}
+
+
+/* Internal util function */
+static bool initialize_timers_common(timer_expire_handler expire_handler)
+{
+       if (expire_handler == NULL) {
+               /* Cannot have a NULL handler function */
+               return false;
+       }
+
+       timers_context_ = create_timers_context_();
+
+       if (timers_context_->active == true) {
+               /* already initialized */
+               return false;
+       }
+
+       timers_context_->active = true;
+       timers_context_->timer_list =
+               ordered_list_initialize(timer_list_node_compare);
+       timers_context_->expire_handler = expire_handler;
+
+       if (pthread_mutex_init(&(timers_context_->timer_list_lock), NULL)
+           != 0) {
+               pcep_log(
+                       LOG_ERR,
+                       "%s: ERROR initializing timers, cannot initialize the mutex",
+                       __func__);
+               return false;
+       }
+
+       return true;
+}
+
+bool initialize_timers(timer_expire_handler expire_handler)
+{
+       if (initialize_timers_common(expire_handler) == false) {
+               return false;
+       }
+
+       if (pthread_create(&(timers_context_->event_loop_thread), NULL,
+                          event_loop, timers_context_)) {
+               pcep_log(
+                       LOG_ERR,
+                       "%s: ERROR initializing timers, cannot initialize the thread",
+                       __func__);
+               return false;
+       }
+
+       return true;
+}
+
+bool initialize_timers_external_infra(
+       timer_expire_handler expire_handler, void *external_timer_infra_data,
+       ext_timer_create timer_create_func, ext_timer_cancel timer_cancel_func,
+       ext_pthread_create_callback thread_create_func)
+{
+       if (initialize_timers_common(expire_handler) == false) {
+               return false;
+       }
+
+       if (thread_create_func != NULL) {
+               if (thread_create_func(&(timers_context_->event_loop_thread),
+                                      NULL, event_loop, timers_context_,
+                                      "pceplib_timers")) {
+                       pcep_log(
+                               LOG_ERR,
+                               "%s: Cannot initialize external timers thread.",
+                               __func__);
+                       return false;
+               }
+       } else {
+               if (pthread_create(&(timers_context_->event_loop_thread), NULL,
+                                  event_loop, timers_context_)) {
+                       pcep_log(
+                               LOG_ERR,
+                               "%s: ERROR initializing timers, cannot initialize the thread",
+                               __func__);
+                       return false;
+               }
+       }
+
+       timers_context_->external_timer_infra_data = external_timer_infra_data;
+       timers_context_->timer_create_func = timer_create_func;
+       timers_context_->timer_cancel_func = timer_cancel_func;
+
+       return true;
+}
+
+/*
+ * This function is only used to tear_down the timer data.
+ * Only the timer data is deleted, not the list itself,
+ * which is deleted by ordered_list_destroy().
+ */
+void free_all_timers(pcep_timers_context *timers_context)
+{
+       pthread_mutex_lock(&timers_context->timer_list_lock);
+
+       ordered_list_node *timer_node = timers_context->timer_list->head;
+
+       while (timer_node != NULL) {
+               if (timer_node->data != NULL) {
+                       pceplib_free(PCEPLIB_INFRA, timer_node->data);
+               }
+               timer_node = timer_node->next_node;
+       }
+
+       pthread_mutex_unlock(&timers_context->timer_list_lock);
+}
+
+
+bool teardown_timers()
+{
+       if (timers_context_ == NULL) {
+               pcep_log(
+                       LOG_WARNING,
+                       "%s: Trying to teardown the timers, but they are not initialized",
+                       __func__);
+               return false;
+       }
+
+       if (timers_context_->active == false) {
+               pcep_log(
+                       LOG_WARNING,
+                       "%s: Trying to teardown the timers, but they are not active",
+                       __func__);
+               return false;
+       }
+
+       timers_context_->active = false;
+       if (timers_context_->event_loop_thread != 0) {
+               /* TODO this does not build
+                * Instead of calling pthread_join() which could block if the
+               thread
+                * is blocked, try joining for at most 1 second.
+               struct timespec ts;
+               clock_gettime(CLOCK_REALTIME, &ts);
+               ts.tv_sec += 1;
+               int retval =
+               pthread_timedjoin_np(timers_context_->event_loop_thread, NULL,
+               &ts); if (retval != 0)
+               {
+                   pcep_log(LOG_WARNING, "%s: thread did not stop after 1
+               second waiting on it.", __func__);
+               }
+               */
+               pthread_join(timers_context_->event_loop_thread, NULL);
+       }
+
+       free_all_timers(timers_context_);
+       ordered_list_destroy(timers_context_->timer_list);
+
+       if (pthread_mutex_destroy(&(timers_context_->timer_list_lock)) != 0) {
+               pcep_log(
+                       LOG_WARNING,
+                       "%s: Trying to teardown the timers, cannot destroy the mutex",
+                       __func__);
+       }
+
+       pceplib_free(PCEPLIB_INFRA, timers_context_);
+       timers_context_ = NULL;
+
+       return true;
+}
+
+
+int get_next_timer_id()
+{
+       if (timer_id_ == INT_MAX) {
+               timer_id_ = 0;
+       }
+
+       return timer_id_++;
+}
+
+int create_timer(uint16_t sleep_seconds, void *data)
+{
+       if (timers_context_ == NULL) {
+               pcep_log(
+                       LOG_WARNING,
+                       "%s: Trying to create a timer: the timers have not been initialized",
+                       __func__);
+               return -1;
+       }
+
+       pcep_timer *timer = pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_timer));
+       memset(timer, 0, sizeof(pcep_timer));
+       timer->data = data;
+       timer->sleep_seconds = sleep_seconds;
+       timer->expire_time = time(NULL) + sleep_seconds;
+
+       pthread_mutex_lock(&timers_context_->timer_list_lock);
+       timer->timer_id = get_next_timer_id();
+
+       /* implemented in pcep_utils_ordered_list.c */
+       if (ordered_list_add_node(timers_context_->timer_list, timer) == NULL) {
+               pceplib_free(PCEPLIB_INFRA, timer);
+               pthread_mutex_unlock(&timers_context_->timer_list_lock);
+               pcep_log(
+                       LOG_WARNING,
+                       "%s: Trying to create a timer, cannot add the timer to the timer list",
+                       __func__);
+
+               return -1;
+       }
+
+       pthread_mutex_unlock(&timers_context_->timer_list_lock);
+
+       if (timers_context_->timer_create_func) {
+               timers_context_->timer_create_func(
+                       timers_context_->external_timer_infra_data,
+                       &timer->external_timer, sleep_seconds, timer);
+       }
+
+       return timer->timer_id;
+}
+
+
+bool cancel_timer(int timer_id)
+{
+       static pcep_timer compare_timer;
+
+       if (timers_context_ == NULL) {
+               pcep_log(
+                       LOG_WARNING,
+                       "%s: Trying to cancel a timer: the timers have not been initialized",
+                       __func__);
+               return false;
+       }
+
+       pthread_mutex_lock(&timers_context_->timer_list_lock);
+
+       compare_timer.timer_id = timer_id;
+       pcep_timer *timer_toRemove = ordered_list_remove_first_node_equals2(
+               timers_context_->timer_list, &compare_timer,
+               timer_list_node_timer_id_compare);
+       if (timer_toRemove == NULL) {
+               pthread_mutex_unlock(&timers_context_->timer_list_lock);
+               pcep_log(
+                       LOG_WARNING,
+                       "%s: Trying to cancel a timer [%d] that does not exist",
+                       __func__, timer_id);
+               return false;
+       }
+
+       pthread_mutex_unlock(&timers_context_->timer_list_lock);
+
+       if (timers_context_->timer_cancel_func) {
+               timers_context_->timer_cancel_func(
+                       &timer_toRemove->external_timer);
+       }
+
+       pceplib_free(PCEPLIB_INFRA, timer_toRemove);
+
+       return true;
+}
+
+
+bool reset_timer(int timer_id)
+{
+       static pcep_timer compare_timer;
+
+       if (timers_context_ == NULL) {
+               pcep_log(
+                       LOG_WARNING,
+                       "%s: Trying to reset a timer: the timers have not been initialized",
+                       __func__);
+
+               return false;
+       }
+
+       pthread_mutex_lock(&timers_context_->timer_list_lock);
+
+       compare_timer.timer_id = timer_id;
+       ordered_list_node *timer_to_reset_node =
+               ordered_list_find2(timers_context_->timer_list, &compare_timer,
+                                  timer_list_node_timer_id_compare);
+       if (timer_to_reset_node == NULL) {
+               pthread_mutex_unlock(&timers_context_->timer_list_lock);
+               pcep_log(LOG_WARNING,
+                        "%s: Trying to reset a timer node that does not exist",
+                        __func__);
+
+               return false;
+       }
+
+       pcep_timer *timer_to_reset = timer_to_reset_node->data;
+       if (timer_to_reset == NULL) {
+               pthread_mutex_unlock(&timers_context_->timer_list_lock);
+               pcep_log(LOG_WARNING,
+                        "%s: Trying to reset a timer that does not exist",
+                        __func__);
+
+               return false;
+       }
+
+       /* First check if the timer to reset already has the same expire time,
+        * which means multiple reset_timer() calls were made on the same timer
+        * in the same second */
+       time_t expire_time = time(NULL) + timer_to_reset->sleep_seconds;
+       if (timer_to_reset->expire_time == expire_time) {
+               pthread_mutex_unlock(&timers_context_->timer_list_lock);
+               return true;
+       }
+
+       ordered_list_remove_node2(timers_context_->timer_list,
+                                 timer_to_reset_node);
+
+       timer_to_reset->expire_time = expire_time;
+       if (ordered_list_add_node(timers_context_->timer_list, timer_to_reset)
+           == NULL) {
+               pceplib_free(PCEPLIB_INFRA, timer_to_reset);
+               pthread_mutex_unlock(&timers_context_->timer_list_lock);
+               pcep_log(
+                       LOG_WARNING,
+                       "%s: Trying to reset a timer, cannot add the timer to the timer list",
+                       __func__);
+
+               return false;
+       }
+
+       pthread_mutex_unlock(&timers_context_->timer_list_lock);
+
+       if (timers_context_->timer_cancel_func) {
+               /* Keeping this log for now, since in older versions of FRR the
+                * timer cancellation was blocking. This allows us to see how
+                * long the it takes.*/
+               pcep_log(LOG_DEBUG, "%s: Reseting timer [%d] with callback",
+                        __func__, timer_to_reset->timer_id);
+               timers_context_->timer_cancel_func(
+                       &timer_to_reset->external_timer);
+               timer_to_reset->external_timer = NULL;
+       }
+
+       if (timers_context_->timer_create_func) {
+               timers_context_->timer_create_func(
+                       timers_context_->external_timer_infra_data,
+                       &timer_to_reset->external_timer,
+                       timer_to_reset->sleep_seconds, timer_to_reset);
+               /* Keeping this log for now, since in older versions of FRR the
+                * timer cancellation was blocking. This allows us to see how
+                * long the it takes.*/
+               pcep_log(LOG_DEBUG, "%s: Reset timer [%d] with callback",
+                        __func__, timer_to_reset->timer_id);
+       }
+
+       return true;
+}
+
+
+void pceplib_external_timer_expire_handler(void *data)
+{
+       if (timers_context_ == NULL) {
+               pcep_log(
+                       LOG_WARNING,
+                       "%s: External timer expired but timers_context is not initialized",
+                       __func__);
+               return;
+       }
+
+       if (timers_context_->expire_handler == NULL) {
+               pcep_log(
+                       LOG_WARNING,
+                       "%s: External timer expired but expire_handler is not initialized",
+                       __func__);
+               return;
+       }
+
+       if (data == NULL) {
+               pcep_log(LOG_WARNING,
+                        "%s: External timer expired with NULL data", __func__);
+               return;
+       }
+
+       pcep_timer *timer = (pcep_timer *)data;
+       pthread_mutex_lock(&timers_context_->timer_list_lock);
+       ordered_list_node *timer_node =
+               ordered_list_find2(timers_context_->timer_list, timer,
+                                  timer_list_node_timer_ptr_compare);
+       pthread_mutex_unlock(&timers_context_->timer_list_lock);
+
+       /* Cannot continue if the timer does not exist */
+       if (timer_node == NULL) {
+               pcep_log(
+                       LOG_WARNING,
+                       "%s: pceplib_external_timer_expire_handler timer [%p] id [%d] does not exist",
+                       __func__, timer, timer->timer_id);
+               return;
+       }
+
+       timers_context_->expire_handler(timer->data, timer->timer_id);
+
+       pthread_mutex_lock(&timers_context_->timer_list_lock);
+       ordered_list_remove_node2(timers_context_->timer_list, timer_node);
+       pthread_mutex_unlock(&timers_context_->timer_list_lock);
+
+       pceplib_free(PCEPLIB_INFRA, timer);
+}
diff --git a/pceplib/pcep_timers.h b/pceplib/pcep_timers.h
new file mode 100644 (file)
index 0000000..b2cc6ec
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+/*
+ * Public API for pcep_timers
+ */
+
+#ifndef PCEPTIMERS_H_
+#define PCEPTIMERS_H_
+
+#include <pthread.h>
+#include <stdbool.h>
+
+#include "pcep_timer_internals.h"
+
+#define TIMER_ID_NOT_SET -1
+
+/*
+ * Initialize the timers module.
+ * The timer_expire_handler function pointer will be called each time a timer
+ * expires. Return true for successful initialization, false otherwise.
+ */
+bool initialize_timers(timer_expire_handler expire_handler);
+
+/*
+ * Initialize the timers module with an external back-end infrastructure, like
+ * FRR.
+ */
+bool initialize_timers_external_infra(
+       timer_expire_handler expire_handler, void *external_timer_infra_data,
+       ext_timer_create timer_create_func, ext_timer_cancel timer_cancel_func,
+       ext_pthread_create_callback thread_create_func);
+
+/*
+ * Teardown the timers module.
+ */
+bool teardown_timers(void);
+
+/*
+ * Create a new timer for "sleep_seconds" seconds.
+ * If the timer expires before being cancelled, the timer_expire_handler
+ * passed to initialize_timers() will be called with the pointer to "data".
+ * Returns a timer_id <= 0 that can be used to cancel_timer.
+ * Returns < 0 on error.
+ */
+int create_timer(uint16_t sleep_seconds, void *data);
+
+/*
+ * Cancel a timer created with create_timer().
+ * Returns true if the timer was found and cancelled, false otherwise.
+ */
+bool cancel_timer(int timer_id);
+
+/*
+ * Reset an previously created timer, maintaining the same timer_id.
+ * Returns true if the timer was found and reset, false otherwise.
+ */
+bool reset_timer(int timer_id);
+
+/*
+ * If an external timer infra like FRR is used, then this function
+ * will be called when the timers expire in the external infra.
+ */
+void pceplib_external_timer_expire_handler(void *data);
+
+int timer_list_node_compare(void *list_entry, void *new_entry);
+int timer_list_node_timer_id_compare(void *list_entry, void *new_entry);
+int timer_list_node_timer_ptr_compare(void *list_entry, void *new_entry);
+void free_all_timers(pcep_timers_context *timers_context);
+int get_next_timer_id(void);
+
+#endif /* PCEPTIMERS_H_ */
diff --git a/pceplib/pcep_timers_event_loop.c b/pceplib/pcep_timers_event_loop.c
new file mode 100644 (file)
index 0000000..932a53e
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <sys/select.h>
+
+#include "pcep_timers_event_loop.h"
+#include "pcep_timer_internals.h"
+#include "pcep_utils_ordered_list.h"
+#include "pcep_utils_logging.h"
+#include "pcep_utils_memory.h"
+
+/* For each expired timer: remove the timer from the list, call the
+ * expire_handler, and free the timer. */
+void walk_and_process_timers(pcep_timers_context *timers_context)
+{
+       pthread_mutex_lock(&timers_context->timer_list_lock);
+
+       bool keep_walking = true;
+       ordered_list_node *timer_node = timers_context->timer_list->head;
+       time_t now = time(NULL);
+       pcep_timer *timer_data;
+
+       /* the timers are sorted by expire_time, so we will only
+        * remove the top node each time through the loop */
+       while (timer_node != NULL && keep_walking) {
+               timer_data = (pcep_timer *)timer_node->data;
+               if (timer_data->expire_time <= now) {
+                       timer_node = timer_node->next_node;
+                       ordered_list_remove_first_node(
+                               timers_context->timer_list);
+                       /* call the timer expired handler */
+                       timers_context->expire_handler(timer_data->data,
+                                                      timer_data->timer_id);
+                       pceplib_free(PCEPLIB_INFRA, timer_data);
+               } else {
+                       keep_walking = false;
+               }
+       }
+
+       pthread_mutex_unlock(&timers_context->timer_list_lock);
+}
+
+
+/* pcep_timers::initialize() will create a thread and invoke this method */
+void *event_loop(void *context)
+{
+       if (context == NULL) {
+               pcep_log(
+                       LOG_WARNING,
+                       "%s: pcep_timers_event_loop cannot start event_loop with NULL data",
+                       __func__);
+               return NULL;
+       }
+
+       pcep_log(LOG_NOTICE, "%s: [%ld-%ld] Starting timers_event_loop thread",
+                __func__, time(NULL), pthread_self());
+
+       pcep_timers_context *timers_context = (pcep_timers_context *)context;
+       struct timeval timer;
+       int retval;
+
+       while (timers_context->active) {
+               /* check the timers every half second */
+               timer.tv_sec = 0;
+               timer.tv_usec = 500000;
+
+               do {
+                       /* if the select() call gets interrupted, select() will
+                        * set the remaining time in timer, so we need to call
+                        * it again.
+                        */
+                       retval = select(0, NULL, NULL, NULL, &timer);
+               } while (retval != 0 && errno == EINTR);
+
+               walk_and_process_timers(timers_context);
+       }
+
+       pcep_log(LOG_WARNING, "%s: [%ld-%ld] Finished timers_event_loop thread",
+                __func__, time(NULL), pthread_self());
+
+       return NULL;
+}
diff --git a/pceplib/pcep_timers_event_loop.h b/pceplib/pcep_timers_event_loop.h
new file mode 100644 (file)
index 0000000..c4a7264
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Javier Garcia <javier.garcia@voltanet.io>
+ *
+ */
+
+/*
+ *  Timer definitions to be used internally by the pcep_timers library.
+ */
+
+#ifndef PCEP_TIMERS_EVENT_LOOP_H_
+#define PCEP_TIMERS_EVENT_LOOP_H_
+
+#include "pcep_timer_internals.h"
+
+void walk_and_process_timers(pcep_timers_context *timers_context);
+
+#endif
diff --git a/pceplib/pcep_utils_counters.c b/pceplib/pcep_utils_counters.c
new file mode 100644 (file)
index 0000000..d8078f6
--- /dev/null
@@ -0,0 +1,475 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+/*
+ * Implementation of PCEP Counters.
+ */
+
+#include <zebra.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "pcep_utils_counters.h"
+#include "pcep_utils_logging.h"
+#include "pcep_utils_memory.h"
+
+struct counters_group *create_counters_group(const char *group_name,
+                                            uint16_t max_subgroups)
+{
+       if (group_name == NULL) {
+               pcep_log(
+                       LOG_INFO,
+                       "%s: Cannot create counters group: group_name is NULL.",
+                       __func__);
+               return NULL;
+       }
+
+       if (max_subgroups > MAX_COUNTER_GROUPS) {
+               pcep_log(
+                       LOG_INFO,
+                       "%s: Cannot create counters group: max_subgroups [%d] is larger than max the [%d].",
+                       __func__, max_subgroups, MAX_COUNTER_GROUPS);
+               return NULL;
+       }
+
+       struct counters_group *group =
+               pceplib_malloc(PCEPLIB_INFRA, sizeof(struct counters_group));
+       memset(group, 0, sizeof(struct counters_group));
+       group->subgroups =
+               pceplib_malloc(PCEPLIB_INFRA, sizeof(struct counters_subgroup *)
+                                                     * (max_subgroups + 1));
+       memset(group->subgroups, 0,
+              sizeof(struct counters_subgroup *) * (max_subgroups + 1));
+
+       strlcpy(group->counters_group_name, group_name,
+               sizeof(group->counters_group_name));
+       group->max_subgroups = max_subgroups;
+       group->start_time = time(NULL);
+
+       return group;
+}
+
+struct counters_subgroup *create_counters_subgroup(const char *subgroup_name,
+                                                  uint16_t subgroup_id,
+                                                  uint16_t max_counters)
+{
+       if (subgroup_name == NULL) {
+               pcep_log(
+                       LOG_INFO,
+                       "%s: Cannot create counters subgroup: subgroup_name is NULL.",
+                       __func__);
+               return NULL;
+       }
+
+       if (max_counters > MAX_COUNTERS) {
+               pcep_log(
+                       LOG_INFO,
+                       "%s: Cannot create counters subgroup: max_counters [%d] is larger than the max [%d].",
+                       __func__, max_counters, MAX_COUNTERS);
+               return NULL;
+       }
+
+       if (subgroup_id > MAX_COUNTER_GROUPS) {
+               pcep_log(
+                       LOG_INFO,
+                       "%s: Cannot create counters subgroup: subgroup_id [%d] is larger than max the [%d].",
+                       __func__, subgroup_id, MAX_COUNTER_GROUPS);
+               return NULL;
+       }
+
+       struct counters_subgroup *subgroup =
+               pceplib_malloc(PCEPLIB_INFRA, sizeof(struct counters_subgroup));
+       memset(subgroup, 0, sizeof(struct counters_subgroup));
+       subgroup->counters = pceplib_malloc(
+               PCEPLIB_INFRA, sizeof(struct counter *) * (max_counters + 1));
+       memset(subgroup->counters, 0,
+              sizeof(struct counter *) * (max_counters + 1));
+
+       strlcpy(subgroup->counters_subgroup_name, subgroup_name,
+               sizeof(subgroup->counters_subgroup_name));
+       subgroup->subgroup_id = subgroup_id;
+       subgroup->max_counters = max_counters;
+
+       return subgroup;
+}
+
+struct counters_subgroup *
+clone_counters_subgroup(struct counters_subgroup *subgroup,
+                       const char *subgroup_name, uint16_t subgroup_id)
+{
+       if (subgroup == NULL) {
+               pcep_log(
+                       LOG_INFO,
+                       "%s: Cannot clone counters subgroup: input counters_subgroup is NULL.",
+                       __func__);
+               return NULL;
+       }
+
+       if (subgroup_name == NULL) {
+               pcep_log(
+                       LOG_INFO,
+                       "%s: Cannot clone counters subgroup: subgroup_name is NULL.",
+                       __func__);
+               return NULL;
+       }
+
+       if (subgroup_id > MAX_COUNTER_GROUPS) {
+               pcep_log(
+                       LOG_INFO,
+                       "%s: Cannot clone counters subgroup: subgroup_id [%d] is larger than max the [%d].",
+                       __func__, subgroup_id, MAX_COUNTER_GROUPS);
+               return NULL;
+       }
+
+       struct counters_subgroup *cloned_subgroup = create_counters_subgroup(
+               subgroup_name, subgroup_id, subgroup->max_counters);
+       int i = 0;
+       for (; i <= subgroup->max_counters; i++) {
+               struct counter *counter = subgroup->counters[i];
+               if (counter != NULL) {
+                       create_subgroup_counter(cloned_subgroup,
+                                               counter->counter_id,
+                                               counter->counter_name);
+               }
+       }
+
+       return cloned_subgroup;
+}
+
+bool add_counters_subgroup(struct counters_group *group,
+                          struct counters_subgroup *subgroup)
+{
+       if (group == NULL) {
+               pcep_log(
+                       LOG_INFO,
+                       "%s: Cannot add counters subgroup: counters_group is NULL.",
+                       __func__);
+               return false;
+       }
+
+       if (subgroup == NULL) {
+               pcep_log(
+                       LOG_INFO,
+                       "%s: Cannot add counters subgroup: counters_subgroup is NULL.",
+                       __func__);
+               return false;
+       }
+
+       if (subgroup->subgroup_id >= group->max_subgroups) {
+               pcep_log(
+                       LOG_INFO,
+                       "%s: Cannot add counters subgroup: counters_subgroup id [%d] is larger than the group max_subgroups [%d].",
+                       __func__, subgroup->subgroup_id, group->max_subgroups);
+               return false;
+       }
+
+       group->num_subgroups++;
+       group->subgroups[subgroup->subgroup_id] = subgroup;
+
+       return true;
+}
+
+bool create_subgroup_counter(struct counters_subgroup *subgroup,
+                            uint32_t counter_id, const char *counter_name)
+{
+       if (subgroup == NULL) {
+               pcep_log(
+                       LOG_INFO,
+                       "%s: Cannot create subgroup counter: counters_subgroup is NULL.",
+                       __func__);
+               return false;
+       }
+
+       if (counter_id >= subgroup->max_counters) {
+               pcep_log(
+                       LOG_INFO,
+                       "%s: Cannot create subgroup counter: counter_id [%d] is larger than the subgroup max_counters [%d].",
+                       __func__, counter_id, subgroup->max_counters);
+               return false;
+       }
+
+       if (counter_name == NULL) {
+               pcep_log(
+                       LOG_INFO,
+                       "%s: Cannot create subgroup counter: counter_name is NULL.",
+                       __func__);
+               return NULL;
+       }
+
+       struct counter *counter =
+               pceplib_malloc(PCEPLIB_INFRA, sizeof(struct counter));
+       memset(counter, 0, sizeof(struct counter));
+       counter->counter_id = counter_id;
+       strlcpy(counter->counter_name, counter_name,
+               sizeof(counter->counter_name));
+
+       subgroup->num_counters++;
+       subgroup->counters[counter->counter_id] = counter;
+
+       return true;
+}
+
+bool delete_counters_group(struct counters_group *group)
+{
+       if (group == NULL) {
+               pcep_log(
+                       LOG_INFO,
+                       "%s: Cannot delete group counters: counters_group is NULL.",
+                       __func__);
+               return false;
+       }
+
+       int i = 0;
+       for (; i <= group->max_subgroups; i++) {
+               struct counters_subgroup *subgroup = group->subgroups[i];
+               if (subgroup != NULL) {
+                       delete_counters_subgroup(subgroup);
+               }
+       }
+
+       pceplib_free(PCEPLIB_INFRA, group->subgroups);
+       pceplib_free(PCEPLIB_INFRA, group);
+
+       return true;
+}
+
+bool delete_counters_subgroup(struct counters_subgroup *subgroup)
+{
+       if (subgroup == NULL || subgroup->counters == NULL) {
+               pcep_log(
+                       LOG_INFO,
+                       "%s: Cannot delete subgroup counters: counters_subgroup is NULL.",
+                       __func__);
+               return false;
+       }
+
+       int i = 0;
+       for (; i <= subgroup->max_counters; i++) {
+               struct counter *counter = subgroup->counters[i];
+               if (counter != NULL) {
+                       pceplib_free(PCEPLIB_INFRA, counter);
+               }
+       }
+
+       pceplib_free(PCEPLIB_INFRA, subgroup->counters);
+       pceplib_free(PCEPLIB_INFRA, subgroup);
+
+       return true;
+}
+
+bool reset_group_counters(struct counters_group *group)
+{
+       if (group == NULL) {
+               pcep_log(
+                       LOG_INFO,
+                       "%s: Cannot reset group counters: counters_group is NULL.",
+                       __func__);
+               return false;
+       }
+
+       int i = 0;
+       for (; i <= group->max_subgroups; i++) {
+               struct counters_subgroup *subgroup = group->subgroups[i];
+               if (subgroup != NULL) {
+                       reset_subgroup_counters(subgroup);
+               }
+       }
+
+       group->start_time = time(NULL);
+
+       return true;
+}
+
+bool reset_subgroup_counters(struct counters_subgroup *subgroup)
+{
+       if (subgroup == NULL) {
+               pcep_log(
+                       LOG_INFO,
+                       "%s: Cannot reset subgroup counters: counters_subgroup is NULL.",
+                       __func__);
+               return false;
+       }
+
+       int i = 0;
+       for (; i <= subgroup->max_counters; i++) {
+               struct counter *counter = subgroup->counters[i];
+               if (counter != NULL) {
+                       counter->counter_value = 0;
+               }
+       }
+
+       return true;
+}
+
+bool increment_counter(struct counters_group *group, uint16_t subgroup_id,
+                      uint16_t counter_id)
+{
+       if (group == NULL) {
+               pcep_log(
+                       LOG_INFO,
+                       "%s: Cannot increment counter: counters_group is NULL.",
+                       __func__);
+               return false;
+       }
+
+       if (subgroup_id >= group->max_subgroups) {
+               pcep_log(
+                       LOG_DEBUG,
+                       "%s: Cannot increment counter: subgroup_id [%d] is larger than the group max_subgroups [%d].",
+                       __func__, subgroup_id, group->max_subgroups);
+               return false;
+       }
+
+       struct counters_subgroup *subgroup = group->subgroups[subgroup_id];
+       if (subgroup == NULL) {
+               pcep_log(
+                       LOG_INFO,
+                       "%s: Cannot increment counter: counters_subgroup in counters_group is NULL.",
+                       __func__);
+               return false;
+       }
+
+       return increment_subgroup_counter(subgroup, counter_id);
+}
+
+bool increment_subgroup_counter(struct counters_subgroup *subgroup,
+                               uint16_t counter_id)
+{
+       if (subgroup == NULL) {
+               pcep_log(
+                       LOG_INFO,
+                       "%s: Cannot increment counter: counters_subgroup is NULL.",
+                       __func__);
+               return false;
+       }
+
+       if (counter_id >= subgroup->max_counters) {
+               pcep_log(
+                       LOG_DEBUG,
+                       "%s: Cannot increment counter: counter_id [%d] is larger than the subgroup max_counters [%d].",
+                       __func__, counter_id, subgroup->max_counters);
+               return false;
+       }
+
+       if (subgroup->counters[counter_id] == NULL) {
+               pcep_log(
+                       LOG_INFO,
+                       "%s: Cannot increment counter: No counter exists for counter_id [%d].",
+                       __func__, counter_id);
+               return false;
+       }
+
+       subgroup->counters[counter_id]->counter_value++;
+
+       return true;
+}
+
+bool dump_counters_group_to_log(struct counters_group *group)
+{
+       if (group == NULL) {
+               pcep_log(
+                       LOG_INFO,
+                       "%s: Cannot dump group counters to log: counters_group is NULL.",
+                       __func__);
+               return false;
+       }
+
+       time_t now = time(NULL);
+       pcep_log(
+               LOG_INFO,
+               "%s: PCEP Counters group:\n  %s \n  Sub-Groups [%d] \n  Active for [%d seconds]",
+               __func__, group->counters_group_name, group->num_subgroups,
+               (now - group->start_time));
+
+       int i = 0;
+       for (; i <= group->max_subgroups; i++) {
+               struct counters_subgroup *subgroup = group->subgroups[i];
+               if (subgroup != NULL) {
+                       dump_counters_subgroup_to_log(subgroup);
+               }
+       }
+
+       return true;
+}
+
+bool dump_counters_subgroup_to_log(struct counters_subgroup *subgroup)
+{
+       if (subgroup == NULL) {
+               pcep_log(
+                       LOG_INFO,
+                       "%s: Cannot dump subgroup counters to log: counters_subgroup is NULL.",
+                       __func__);
+               return false;
+       }
+
+       pcep_log(LOG_INFO,
+                "%s: \tPCEP Counters sub-group [%s] with [%d] counters",
+                __func__, subgroup->counters_subgroup_name,
+                subgroup->num_counters);
+
+       int i = 0;
+       for (; i <= subgroup->max_counters; i++) {
+               struct counter *counter = subgroup->counters[i];
+               if (counter != NULL) {
+                       pcep_log(LOG_INFO, "%s: \t\t%s %d", __func__,
+                                counter->counter_name, counter->counter_value);
+               }
+       }
+
+       return true;
+}
+
+struct counters_subgroup *find_subgroup(const struct counters_group *group,
+                                       uint16_t subgroup_id)
+{
+       int i = 0;
+       for (; i <= group->max_subgroups; i++) {
+               struct counters_subgroup *subgroup = group->subgroups[i];
+               if (subgroup != NULL) {
+                       if (subgroup->subgroup_id == subgroup_id) {
+                               return subgroup;
+                       }
+               }
+       }
+
+       return NULL;
+}
+
+uint32_t subgroup_counters_total(struct counters_subgroup *subgroup)
+{
+       if (subgroup == NULL) {
+               return 0;
+       }
+       uint32_t counter_total = 0;
+       int i = 0;
+       for (; i <= subgroup->max_counters; i++) {
+               struct counter *counter = subgroup->counters[i];
+               if (counter != NULL) {
+                       counter_total += counter->counter_value;
+               }
+       }
+
+       return counter_total;
+}
diff --git a/pceplib/pcep_utils_counters.h b/pceplib/pcep_utils_counters.h
new file mode 100644 (file)
index 0000000..240e975
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+/*
+ * Definitions of PCEP Counters.
+ */
+
+#ifndef PCEP_UTILS_INCLUDE_PCEP_UTILS_COUNTERS_H_
+#define PCEP_UTILS_INCLUDE_PCEP_UTILS_COUNTERS_H_
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Example Counter group with sub-groups and counters
+ *
+ *  pcep_counters {
+ *      counters_group_rx {
+ *          message_open;
+ *          message_keepalive;
+ *          message_pcreq;
+ *      }
+ *      counters_group_tx {
+ *          message_open;
+ *          message_keepalive;
+ *          message_pcreq;
+ *      }
+ *      counters_group_events {
+ *          pcc_connect;
+ *          pce_connect;
+ *          pcc_disconnect;
+ *          pce_disconnect;
+ *      }
+ *  }
+ *
+ * To create the above structure of groups, sub-groups, and counters, do the
+ * following:
+ *
+ * struct counters_subgroup *rx_subgroup = create_counters_subgroup("rx
+ * counters", 3); struct counters_subgroup *tx_subgroup =
+ * create_counters_subgroup("tx counters", 3); struct counters_subgroup
+ * *events_subgroup = create_counters_subgroup("events counters", 4);
+ *
+ * Use message_id: PCEP_TYPE_OPEN=1
+ * create_subgroup_counter(rx_subgroup, 1, "Message Open");
+ * create_subgroup_counter(rx_subgroup, 2, "Message KeepAlive");
+ * create_subgroup_counter(rx_subgroup, 3, "Message PcReq");
+ *
+ * create_subgroup_counter(tx_subgroup, 1, "Message Open");
+ * create_subgroup_counter(tx_subgroup, 2, "Message KeepAlive");
+ * create_subgroup_counter(tx_subgroup, 3, "Message PcReq");
+ *
+ * create_subgroup_counter(events_subgroup, 1, "PCC Connect");
+ * create_subgroup_counter(events_subgroup, 2, "PCE Connect");
+ * create_subgroup_counter(events_subgroup, 3, "PCC Disconnect");
+ * create_subgroup_counter(events_subgroup, 4, "PCE Disconnect");
+ *
+ * struct counters_group *cntrs_group = create_counters_group("PCEP Counters",
+ * 3); add_counters_subgroup(cntrs_group, rx_subgroup);
+ * add_counters_subgroup(cntrs_group, tx_subgroup);
+ * add_counters_subgroup(cntrs_group, events_subgroup);
+ */
+
+#define MAX_COUNTER_STR_LENGTH 128
+#define MAX_COUNTER_GROUPS 500
+#define MAX_COUNTERS 500
+
+struct counter {
+       uint16_t counter_id;
+       char counter_name[MAX_COUNTER_STR_LENGTH];
+       uint32_t counter_value;
+};
+
+struct counters_subgroup {
+       char counters_subgroup_name[MAX_COUNTER_STR_LENGTH];
+       uint16_t subgroup_id;
+       uint16_t num_counters;
+       uint16_t max_counters;
+       /* Array of (struct counter *) allocated when the subgroup is created.
+        * The array is indexed by the struct counter->counter_id */
+       struct counter **counters;
+};
+
+struct counters_group {
+       char counters_group_name[MAX_COUNTER_STR_LENGTH];
+       uint16_t num_subgroups;
+       uint16_t max_subgroups;
+       time_t start_time;
+       /* Array  of (struct counters_subgroup *) allocated when the group is
+        * created. The subgroup is indexed by the (struct counters_subgroup
+        * *)->subgroup_id */
+       struct counters_subgroup **subgroups;
+};
+
+/*
+ * Create a counters group with the given group_name and number of subgroups.
+ * Subgroup_ids are 0-based, so take that into account when setting
+ * max_subgroups. Return true on success or false if group_name is NULL or
+ * max_subgroups >= MAX_COUNTER_GROUPS.
+ */
+struct counters_group *create_counters_group(const char *group_name,
+                                            uint16_t max_subgroups);
+
+/*
+ * Create a counters subgroup with the given subgroup_name, subgroup_id and
+ * number of counters. The subgroup_id is 0-based. counter_ids are 0-based, so
+ * take that into account when setting max_counters. Return true on success or
+ * false if subgroup_name is NULL, subgroup_id >= MAX_COUNTER_GROUPS, or
+ * max_counters >= MAX_COUNTERS.
+ */
+struct counters_subgroup *create_counters_subgroup(const char *subgroup_name,
+                                                  uint16_t subgroup_id,
+                                                  uint16_t max_counters);
+
+/*
+ * Add a counter_subgroup to a counter_group.
+ * Return true on success or false if group is NULL or if subgroup is NULL.
+ */
+bool add_counters_subgroup(struct counters_group *group,
+                          struct counters_subgroup *subgroup);
+
+/*
+ * Clone a subgroup and set a new name and subgroup_id for the new subgroup.
+ * This is useful for RX and TX counters: just create the RX counters and clone
+ * it for the TX counters.
+ */
+struct counters_subgroup *
+clone_counters_subgroup(struct counters_subgroup *subgroup,
+                       const char *subgroup_name, uint16_t subgroup_id);
+
+/*
+ * Create a counter in a subgroup with the given counter_id and counter_name.
+ * The counter_id is 0-based.
+ * Return true on success or false if subgroup is NULL, counter_id >=
+ * MAX_COUNTERS, or if counter_name is NULL.
+ */
+bool create_subgroup_counter(struct counters_subgroup *subgroup,
+                            uint32_t counter_id, const char *counter_name);
+
+/*
+ * Delete the counters_group and recursively delete all subgroups and their
+ * counters. Return true on success or false if group is NULL.
+ */
+bool delete_counters_group(struct counters_group *group);
+
+/*
+ * Delete the counters_subgroup and all its counters counters.
+ * Return true on success or false if subgroup is NULL.
+ */
+bool delete_counters_subgroup(struct counters_subgroup *subgroup);
+
+/*
+ * Reset all the counters in all sub-groups contained in this group.
+ * Return true on success or false if group is NULL.
+ */
+bool reset_group_counters(struct counters_group *group);
+
+/*
+ * Reset all the counters in this subgroup.
+ * Return true on success or false if subgroup is NULL.
+ */
+bool reset_subgroup_counters(struct counters_subgroup *subgroup);
+
+/*
+ * Increment a counter given a counter_group, subgroup_id, and counter_id.
+ * Return true on success or false if group is NULL, subgroup_id >=
+ * MAX_COUNTER_GROUPS, or counter_id >= MAX_COUNTERS.
+ */
+bool increment_counter(struct counters_group *group, uint16_t subgroup_id,
+                      uint16_t counter_id);
+
+/*
+ * Increment a counter given the counter_subgroup and counter_id.
+ * Return true on success or false if subgroup is NULL or counter_id >=
+ * MAX_COUNTERS.
+ */
+bool increment_subgroup_counter(struct counters_subgroup *subgroup,
+                               uint16_t counter_id);
+
+/*
+ * Dump the counter_group info and all its counter_subgroups.
+ * Return true on success or false if group is NULL.
+ */
+bool dump_counters_group_to_log(struct counters_group *group);
+
+/*
+ * Dump all the counters in a counter_subgroup.
+ * Return true on success or false if subgroup is NULL.
+ */
+bool dump_counters_subgroup_to_log(struct counters_subgroup *subgroup);
+
+/*
+ * Search for a counters_subgroup by subgroup_id in a counters_group
+ * and return it, if found, else return NULL.
+ */
+struct counters_subgroup *find_subgroup(const struct counters_group *group,
+                                       uint16_t subgroup_id);
+
+/*
+ * Given a counters_subgroup, return the sum of all the counters.
+ */
+uint32_t subgroup_counters_total(struct counters_subgroup *subgroup);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PCEP_UTILS_INCLUDE_PCEP_UTILS_COUNTERS_H_ */
diff --git a/pceplib/pcep_utils_double_linked_list.c b/pceplib/pcep_utils_double_linked_list.c
new file mode 100644 (file)
index 0000000..acdcee0
--- /dev/null
@@ -0,0 +1,262 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+#include <stddef.h>
+#include <string.h>
+
+#include "pcep_utils_double_linked_list.h"
+#include "pcep_utils_logging.h"
+#include "pcep_utils_memory.h"
+
+double_linked_list *dll_initialize()
+{
+       double_linked_list *handle =
+               pceplib_malloc(PCEPLIB_INFRA, sizeof(double_linked_list));
+       if (handle != NULL) {
+               memset(handle, 0, sizeof(double_linked_list));
+               handle->num_entries = 0;
+               handle->head = NULL;
+               handle->tail = NULL;
+       } else {
+               pcep_log(LOG_WARNING,
+                        "%s: dll_initialize cannot allocate memory for handle",
+                        __func__);
+               return NULL;
+       }
+
+       return handle;
+}
+
+
+void dll_destroy(double_linked_list *handle)
+{
+       if (handle == NULL) {
+               pcep_log(LOG_WARNING,
+                        "%s: dll_destroy cannot destroy NULL handle",
+                        __func__);
+               return;
+       }
+
+       double_linked_list_node *node = handle->head;
+       while (node != NULL) {
+               double_linked_list_node *node_to_delete = node;
+               node = node->next_node;
+               pceplib_free(PCEPLIB_INFRA, node_to_delete);
+       }
+
+       pceplib_free(PCEPLIB_INFRA, handle);
+}
+
+
+void dll_destroy_with_data_memtype(double_linked_list *handle,
+                                  void *data_memory_type)
+{
+       if (handle == NULL) {
+               pcep_log(LOG_WARNING,
+                        "%s: dll_destroy_with_data cannot destroy NULL handle",
+                        __func__);
+               return;
+       }
+
+       double_linked_list_node *node = handle->head;
+       while (node != NULL) {
+               double_linked_list_node *node_to_delete = node;
+               pceplib_free(data_memory_type, node->data);
+               node = node->next_node;
+               pceplib_free(PCEPLIB_INFRA, node_to_delete);
+       }
+
+       pceplib_free(PCEPLIB_INFRA, handle);
+}
+
+
+void dll_destroy_with_data(double_linked_list *handle)
+{
+       /* Default to destroying the data with the INFRA mem type */
+       dll_destroy_with_data_memtype(handle, PCEPLIB_INFRA);
+}
+
+
+/* Creates a node and adds it as the first item in the list */
+double_linked_list_node *dll_prepend(double_linked_list *handle, void *data)
+{
+       if (handle == NULL) {
+               pcep_log(LOG_WARNING, "%s: dll_prepend_data NULL handle",
+                        __func__);
+               return NULL;
+       }
+
+       /* Create the new node */
+       double_linked_list_node *new_node =
+               pceplib_malloc(PCEPLIB_INFRA, sizeof(double_linked_list_node));
+       memset(new_node, 0, sizeof(double_linked_list_node));
+       new_node->data = data;
+
+       if (handle->head == NULL) {
+               handle->head = new_node;
+               handle->tail = new_node;
+       } else {
+               new_node->next_node = handle->head;
+               handle->head->prev_node = new_node;
+               handle->head = new_node;
+       }
+
+       (handle->num_entries)++;
+
+       return new_node;
+}
+
+
+/* Creates a node and adds it as the last item in the list */
+double_linked_list_node *dll_append(double_linked_list *handle, void *data)
+{
+       if (handle == NULL) {
+               pcep_log(LOG_WARNING, "%s: dll_append_data NULL handle",
+                        __func__);
+               return NULL;
+       }
+
+       /* Create the new node */
+       double_linked_list_node *new_node =
+               pceplib_malloc(PCEPLIB_INFRA, sizeof(double_linked_list_node));
+       memset(new_node, 0, sizeof(double_linked_list_node));
+       new_node->data = data;
+
+       if (handle->head == NULL) {
+               handle->head = new_node;
+               handle->tail = new_node;
+       } else {
+               new_node->prev_node = handle->tail;
+               handle->tail->next_node = new_node;
+               handle->tail = new_node;
+       }
+
+       (handle->num_entries)++;
+
+       return new_node;
+}
+
+
+/* Delete the first node in the list, and return the data */
+void *dll_delete_first_node(double_linked_list *handle)
+{
+       if (handle == NULL) {
+               pcep_log(LOG_WARNING, "%s: dll_delete_first_node NULL handle",
+                        __func__);
+               return NULL;
+       }
+
+       if (handle->head == NULL) {
+               return NULL;
+       }
+
+       double_linked_list_node *delete_node = handle->head;
+       void *data = delete_node->data;
+
+       if (delete_node->next_node == NULL) {
+               /* Its the last node in the list */
+               handle->head = NULL;
+               handle->tail = NULL;
+       } else {
+               handle->head = delete_node->next_node;
+               handle->head->prev_node = NULL;
+       }
+
+       pceplib_free(PCEPLIB_INFRA, delete_node);
+       (handle->num_entries)--;
+
+       return data;
+}
+
+
+/* Delete the last node in the list, and return the data */
+void *dll_delete_last_node(double_linked_list *handle)
+{
+       if (handle == NULL) {
+               pcep_log(LOG_WARNING, "%s: dll_delete_last_node NULL handle",
+                        __func__);
+               return NULL;
+       }
+
+       if (handle->head == NULL) {
+               return NULL;
+       }
+
+       double_linked_list_node *delete_node = handle->tail;
+       void *data = delete_node->data;
+
+       if (delete_node->prev_node == NULL) {
+               /* Its the last node in the list */
+               handle->head = NULL;
+               handle->tail = NULL;
+       } else {
+               handle->tail = delete_node->prev_node;
+               handle->tail->next_node = NULL;
+       }
+
+       pceplib_free(PCEPLIB_INFRA, delete_node);
+       (handle->num_entries)--;
+
+       return data;
+}
+
+
+/* Delete the designated node in the list, and return the data */
+void *dll_delete_node(double_linked_list *handle, double_linked_list_node *node)
+{
+       if (handle == NULL) {
+               pcep_log(LOG_WARNING, "%s: dll_delete_node NULL handle",
+                        __func__);
+               return NULL;
+       }
+
+       if (node == NULL) {
+               return NULL;
+       }
+
+       if (handle->head == NULL) {
+               return NULL;
+       }
+
+       void *data = node->data;
+
+       if (handle->head == handle->tail) {
+               /* Its the last node in the list */
+               handle->head = NULL;
+               handle->tail = NULL;
+       } else if (handle->head == node) {
+               handle->head = node->next_node;
+               handle->head->prev_node = NULL;
+       } else if (handle->tail == node) {
+               handle->tail = node->prev_node;
+               handle->tail->next_node = NULL;
+       } else {
+               /* Its somewhere in the middle of the list */
+               node->next_node->prev_node = node->prev_node;
+               node->prev_node->next_node = node->next_node;
+       }
+
+       pceplib_free(PCEPLIB_INFRA, node);
+       (handle->num_entries)--;
+
+       return data;
+}
diff --git a/pceplib/pcep_utils_double_linked_list.h b/pceplib/pcep_utils_double_linked_list.h
new file mode 100644 (file)
index 0000000..4fe0172
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#ifndef PCEP_UTILS_INCLUDE_PCEP_UTILS_DOUBLE_LINKED_LIST_H_
+#define PCEP_UTILS_INCLUDE_PCEP_UTILS_DOUBLE_LINKED_LIST_H_
+
+typedef struct double_linked_list_node_ {
+       struct double_linked_list_node_ *prev_node;
+       struct double_linked_list_node_ *next_node;
+       void *data;
+
+} double_linked_list_node;
+
+
+typedef struct double_linked_list_ {
+       double_linked_list_node *head;
+       double_linked_list_node *tail;
+       unsigned int num_entries;
+
+} double_linked_list;
+
+
+/* Initialize a double linked list */
+double_linked_list *dll_initialize(void);
+
+/* Destroy a double linked list, by freeing the handle and nodes,
+ * user data will not be freed, and may be leaked if not handled
+ * externally. */
+void dll_destroy(double_linked_list *handle);
+/* Destroy a double linked list, by freeing the handle and nodes,
+ * and the user data. */
+void dll_destroy_with_data(double_linked_list *handle);
+void dll_destroy_with_data_memtype(double_linked_list *handle,
+                                  void *data_memory_type);
+
+/* Creates a node and adds it as the first item in the list */
+double_linked_list_node *dll_prepend(double_linked_list *handle, void *data);
+
+/* Creates a node and adds it as the last item in the list */
+double_linked_list_node *dll_append(double_linked_list *handle, void *data);
+
+/* Delete the first node in the list, and return the data */
+void *dll_delete_first_node(double_linked_list *handle);
+
+/* Delete the last node in the list, and return the data */
+void *dll_delete_last_node(double_linked_list *handle);
+
+/* Delete the designated node in the list, and return the data */
+void *dll_delete_node(double_linked_list *handle,
+                     double_linked_list_node *node);
+
+#endif /* PCEP_UTILS_INCLUDE_PCEP_UTILS_DOUBLE_LINKED_LIST_H_ */
diff --git a/pceplib/pcep_utils_logging.c b/pceplib/pcep_utils_logging.c
new file mode 100644 (file)
index 0000000..65e1abb
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <stdarg.h>
+#include <stdio.h>
+#include "pcep_utils_logging.h"
+
+/* Forward declaration */
+int pcep_stdout_logger(int priority, const char *format, va_list args);
+
+static pcep_logger_func logger_func = pcep_stdout_logger;
+static int logging_level_ = LOG_INFO;
+
+void register_logger(pcep_logger_func logger)
+{
+       logger_func = logger;
+}
+
+void set_logging_level(int level)
+{
+       logging_level_ = level;
+}
+
+int get_logging_level()
+{
+       return logging_level_;
+}
+
+void pcep_log(int priority, const char *format, ...)
+{
+       va_list va;
+       va_start(va, format);
+       logger_func(priority, format, va);
+       va_end(va);
+}
+
+void pcep_log_hexbytes(int priority, const char *message, const uint8_t *bytes,
+                      uint8_t bytes_len)
+{
+       char byte_str[2048] = {0};
+       int i = 0;
+
+       snprintf(byte_str, 2048, "%s ", message);
+       for (; i < bytes_len; i++) {
+               snprintf(byte_str, 2048, "%02x ", bytes[i]);
+       }
+       snprintf(byte_str, 2048, "\n");
+
+       pcep_log(priority, "%s", byte_str);
+}
+
+/* Defined with a return type to match the FRR logging signature.
+ * Assuming glibc printf() is thread-safe. */
+int pcep_stdout_logger(int priority, const char *format, va_list args)
+{
+       if (priority <= logging_level_) {
+               vprintf(format, args);
+               printf("\n");
+       }
+
+       return 0;
+}
diff --git a/pceplib/pcep_utils_logging.h b/pceplib/pcep_utils_logging.h
new file mode 100644 (file)
index 0000000..24ea495
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#ifndef PCEP_UTILS_INCLUDE_PCEP_UTILS_LOGGING_H_
+#define PCEP_UTILS_INCLUDE_PCEP_UTILS_LOGGING_H_
+
+#include <syslog.h> /* Logging levels */
+#include <stdarg.h> /* va_list */
+#include <stdint.h> /* uint8_t */
+
+/*
+ * The logging defined here i intended to provide the infrastructure to
+ * be able to plug-in an external logger, primarily the FRR logger. There
+ * will be a default internal logger implemented that will write to stdout,
+ * but any other advanced logging features should be implemented externally.
+ */
+
+/* Only the following logging levels from syslog.h should be used:
+ *
+ *   LOG_DEBUG    - For all messages that are enabled by optional debugging
+ *                  features, typically preceded by "if (IS...DEBUG...)"
+ *   LOG_INFO     - Information that may be of interest, but
+ *                  everything seems to be working properly.
+ *   LOG_NOTICE   - Only for message pertaining to daemon startup or shutdown.
+ *   LOG_WARNING  - Warning conditions: unexpected events, but the daemon
+ *                  believes it can continue to operate correctly.
+ *   LOG_ERR      - Error situations indicating malfunctions.
+ *                  Probably requires attention.
+ */
+
+
+/* The signature of this logger function is the same as the FRR logger */
+typedef int (*pcep_logger_func)(int, const char *, va_list);
+void register_logger(pcep_logger_func logger);
+
+/* These functions only take affect when using the internal stdout logger */
+void set_logging_level(int level);
+int get_logging_level(void);
+
+/* Log messages either to a previously registered
+ * logger or to the internal default stdout logger. */
+void pcep_log(int priority, const char *format, ...);
+void pcep_log_hexbytes(int priority, const char *message, const uint8_t *bytes,
+                      uint8_t bytes_len);
+
+#endif /* PCEP_UTILS_INCLUDE_PCEP_UTILS_LOGGING_H_ */
diff --git a/pceplib/pcep_utils_memory.c b/pceplib/pcep_utils_memory.c
new file mode 100644 (file)
index 0000000..7362e34
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "pcep_utils_logging.h"
+#include "pcep_utils_memory.h"
+
+/* Set default values for memory function pointers */
+static pceplib_malloc_func mfunc = NULL;
+static pceplib_calloc_func cfunc = NULL;
+static pceplib_realloc_func rfunc = NULL;
+static pceplib_strdup_func sfunc = NULL;
+static pceplib_free_func ffunc = NULL;
+
+/* Internal memory types */
+struct pceplib_memory_type pceplib_infra_mt = {
+       .memory_type_name = "PCEPlib Infrastructure memory",
+       .total_bytes_allocated = 0,
+       .num_allocates = 0,
+       .total_bytes_freed = 0,
+       .num_frees = 0};
+struct pceplib_memory_type pceplib_messages_mt = {
+       .memory_type_name = "PCEPlib Messages memory",
+       .total_bytes_allocated = 0,
+       .num_allocates = 0,
+       .total_bytes_freed = 0,
+       .num_frees = 0};
+
+/* The memory type pointers default to the internal memory types */
+void *PCEPLIB_INFRA = &pceplib_infra_mt;
+void *PCEPLIB_MESSAGES = &pceplib_messages_mt;
+
+/* Initialize memory function pointers and memory type pointers */
+bool pceplib_memory_initialize(void *pceplib_infra_mt,
+                              void *pceplib_messages_mt,
+                              pceplib_malloc_func mf, pceplib_calloc_func cf,
+                              pceplib_realloc_func rf, pceplib_strdup_func sf,
+                              pceplib_free_func ff)
+{
+       PCEPLIB_INFRA = (pceplib_infra_mt ? pceplib_infra_mt : PCEPLIB_INFRA);
+       PCEPLIB_MESSAGES =
+               (pceplib_messages_mt ? pceplib_messages_mt : PCEPLIB_MESSAGES);
+
+       mfunc = (mf ? mf : mfunc);
+       cfunc = (cf ? cf : cfunc);
+       rfunc = (rf ? rf : rfunc);
+       sfunc = (sf ? sf : sfunc);
+       ffunc = (ff ? ff : ffunc);
+
+       return true;
+}
+
+void pceplib_memory_reset()
+{
+       pceplib_infra_mt.total_bytes_allocated = 0;
+       pceplib_infra_mt.num_allocates = 0;
+       pceplib_infra_mt.total_bytes_freed = 0;
+       pceplib_infra_mt.num_frees = 0;
+
+       pceplib_messages_mt.total_bytes_allocated = 0;
+       pceplib_messages_mt.num_allocates = 0;
+       pceplib_messages_mt.total_bytes_freed = 0;
+       pceplib_messages_mt.num_frees = 0;
+}
+
+void pceplib_memory_dump()
+{
+       if (PCEPLIB_INFRA) {
+               pcep_log(
+                       LOG_INFO,
+                       "%s: Memory Type [%s] Total [allocs, alloc bytes, frees] [%d, %d, %d]",
+                       __func__,
+                       ((struct pceplib_memory_type *)PCEPLIB_INFRA)
+                               ->memory_type_name,
+                       ((struct pceplib_memory_type *)PCEPLIB_INFRA)
+                               ->num_allocates,
+                       ((struct pceplib_memory_type *)PCEPLIB_INFRA)
+                               ->total_bytes_allocated,
+                       ((struct pceplib_memory_type *)PCEPLIB_INFRA)
+                               ->num_frees);
+       }
+
+       if (PCEPLIB_MESSAGES) {
+               pcep_log(
+                       LOG_INFO,
+                       "%s: Memory Type [%s] Total [allocs, alloc bytes, frees] [%d, %d, %d]",
+                       __func__,
+                       ((struct pceplib_memory_type *)PCEPLIB_MESSAGES)
+                               ->memory_type_name,
+                       ((struct pceplib_memory_type *)PCEPLIB_MESSAGES)
+                               ->num_allocates,
+                       ((struct pceplib_memory_type *)PCEPLIB_MESSAGES)
+                               ->total_bytes_allocated,
+                       ((struct pceplib_memory_type *)PCEPLIB_MESSAGES)
+                               ->num_frees);
+       }
+}
+
+/* PCEPlib memory functions:
+ * They either call the supplied function pointers, or use the internal
+ * implementations, which just increment simple counters and call the
+ * C stdlib memory implementations. */
+
+void *pceplib_malloc(void *mem_type, size_t size)
+{
+       if (mfunc == NULL) {
+               if (mem_type != NULL) {
+                       ((struct pceplib_memory_type *)mem_type)
+                               ->total_bytes_allocated += size;
+                       ((struct pceplib_memory_type *)mem_type)
+                               ->num_allocates++;
+               }
+
+               return malloc(size);
+       } else {
+               return mfunc(mem_type, size);
+       }
+}
+
+void *pceplib_calloc(void *mem_type, size_t size)
+{
+       if (cfunc == NULL) {
+               if (mem_type != NULL) {
+                       ((struct pceplib_memory_type *)mem_type)
+                               ->total_bytes_allocated += size;
+                       ((struct pceplib_memory_type *)mem_type)
+                               ->num_allocates++;
+               }
+
+               return calloc(1, size);
+       } else {
+               return cfunc(mem_type, size);
+       }
+}
+
+void *pceplib_realloc(void *mem_type, void *ptr, size_t size)
+{
+       if (rfunc == NULL) {
+               if (mem_type != NULL) {
+                       /* TODO should add previous allocated bytes to
+                        * total_bytes_freed */
+                       ((struct pceplib_memory_type *)mem_type)
+                               ->total_bytes_allocated += size;
+                       ((struct pceplib_memory_type *)mem_type)
+                               ->num_allocates++;
+               }
+
+               return realloc(ptr, size);
+       } else {
+               return rfunc(mem_type, ptr, size);
+       }
+}
+
+void *pceplib_strdup(void *mem_type, const char *str)
+{
+       if (sfunc == NULL) {
+               if (mem_type != NULL) {
+                       ((struct pceplib_memory_type *)mem_type)
+                               ->total_bytes_allocated += strlen(str);
+                       ((struct pceplib_memory_type *)mem_type)
+                               ->num_allocates++;
+               }
+
+               return strdup(str);
+       } else {
+               return sfunc(mem_type, str);
+       }
+}
+
+void pceplib_free(void *mem_type, void *ptr)
+{
+       if (ffunc == NULL) {
+               if (mem_type != NULL) {
+                       /* TODO in order to increment total_bytes_freed, we need
+                        * to keep track of the bytes allocated per pointer.
+                        * Currently not implemented. */
+                       ((struct pceplib_memory_type *)mem_type)->num_frees++;
+                       if (((struct pceplib_memory_type *)mem_type)
+                                   ->num_allocates
+                           < ((struct pceplib_memory_type *)mem_type)
+                                     ->num_frees) {
+                               pcep_log(
+                                       LOG_ERR,
+                                       "%s: pceplib_free MT N_Alloc < N_Free: MemType [%s] NumAllocates [%d] NumFrees [%d]",
+                                       __func__,
+                                       ((struct pceplib_memory_type *)mem_type)
+                                               ->memory_type_name,
+                                       ((struct pceplib_memory_type *)mem_type)
+                                               ->num_allocates,
+                                       ((struct pceplib_memory_type *)mem_type)
+                                               ->num_frees);
+                       }
+               }
+
+               return free(ptr);
+       } else {
+               return ffunc(mem_type, ptr);
+       }
+}
diff --git a/pceplib/pcep_utils_memory.h b/pceplib/pcep_utils_memory.h
new file mode 100644 (file)
index 0000000..4624a91
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+#ifndef PCEP_UTILS_INCLUDE_PCEP_UTILS_MEMORY_H_
+#define PCEP_UTILS_INCLUDE_PCEP_UTILS_MEMORY_H_
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+/* This module is intended to be used primarily with FRR's memory module,
+ * which has memory groups and memory types, although any memory infrastructure
+ * can be used that has memory types or the memory types in this module can be
+ * set to NULL. The PCEPlib can be used stand-alone, in which case the simple
+ * internal memory type system will be used.
+ */
+
+/* These memory function pointers are modeled after the memory functions
+ * in frr/lib/memory.h */
+typedef void *(*pceplib_malloc_func)(void *mem_type, size_t size);
+typedef void *(*pceplib_calloc_func)(void *mem_type, size_t size);
+typedef void *(*pceplib_realloc_func)(void *mem_type, void *ptr, size_t size);
+typedef void *(*pceplib_strdup_func)(void *mem_type, const char *str);
+typedef void (*pceplib_free_func)(void *mem_type, void *ptr);
+
+/* Either an internal pceplib_memory_type pointer
+ * or could be an FRR memory type pointer */
+extern void *PCEPLIB_INFRA;
+extern void *PCEPLIB_MESSAGES;
+
+/* Internal PCEPlib memory type */
+struct pceplib_memory_type {
+       char memory_type_name[64];
+       uint32_t total_bytes_allocated;
+       uint32_t num_allocates;
+       uint32_t total_bytes_freed; /* currently not used */
+       uint32_t num_frees;
+};
+
+/* Initialize this module by passing in the 2 memory types used in the PCEPlib
+ * and by passing in the different memory allocation/free function pointers.
+ * Any of these parameters can be NULL, in which case an internal implementation
+ * will be used.
+ */
+bool pceplib_memory_initialize(void *pceplib_infra_mt,
+                              void *pceplib_messages_mt,
+                              pceplib_malloc_func mfunc,
+                              pceplib_calloc_func cfunc,
+                              pceplib_realloc_func rfunc,
+                              pceplib_strdup_func sfunc,
+                              pceplib_free_func ffunc);
+
+/* Reset the internal allocation/free counters. Used mainly for internal
+ * testing. */
+void pceplib_memory_reset(void);
+void pceplib_memory_dump(void);
+
+/* Memory functions to be used throughout the PCEPlib. Internally, these
+ * functions will either used the function pointers passed in via
+ * pceplib_memory_initialize() or a simple internal implementation. The
+ * internal implementations just increment the internal memory type
+ * counters and call the C stdlib memory functions.
+ */
+void *pceplib_malloc(void *mem_type, size_t size);
+void *pceplib_calloc(void *mem_type, size_t size);
+void *pceplib_realloc(void *mem_type, void *ptr, size_t size);
+void *pceplib_strdup(void *mem_type, const char *str);
+void pceplib_free(void *mem_type, void *ptr);
+
+#endif /* PCEP_UTILS_INCLUDE_PCEP_UTILS_MEMORY_H_ */
diff --git a/pceplib/pcep_utils_ordered_list.c b/pceplib/pcep_utils_ordered_list.c
new file mode 100644 (file)
index 0000000..f5c7f70
--- /dev/null
@@ -0,0 +1,322 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+
+#include "pcep_utils_logging.h"
+#include "pcep_utils_memory.h"
+#include "pcep_utils_ordered_list.h"
+
+/* Compare function that simply compares pointers.
+ * return:
+ *   < 0  if new_entry  < list_entry
+ *   == 0 if new_entry == list_entry (new_entry will be inserted after
+ * list_entry) > 0  if new_entry  > list_entry
+ */
+int pointer_compare_function(void *list_entry, void *new_entry)
+{
+       return (char *)new_entry - (char *)list_entry;
+}
+
+ordered_list_handle *ordered_list_initialize(ordered_compare_function func_ptr)
+{
+       ordered_list_handle *handle =
+               pceplib_malloc(PCEPLIB_INFRA, sizeof(ordered_list_handle));
+       memset(handle, 0, sizeof(ordered_list_handle));
+       handle->head = NULL;
+       handle->num_entries = 0;
+       handle->compare_function = func_ptr;
+
+       return handle;
+}
+
+
+/* free all the ordered_list_node resources and the ordered_list_handle.
+ * it is assumed that the user is responsible fore freeing the data
+ * pointed to by the nodes.
+ */
+void ordered_list_destroy(ordered_list_handle *handle)
+{
+       if (handle == NULL) {
+               return;
+       }
+
+       ordered_list_node *node = handle->head;
+       ordered_list_node *next;
+
+       while (node != NULL) {
+               next = node->next_node;
+               pceplib_free(PCEPLIB_INFRA, node);
+               node = next;
+       }
+
+       pceplib_free(PCEPLIB_INFRA, handle);
+}
+
+
+ordered_list_node *ordered_list_add_node(ordered_list_handle *handle,
+                                        void *data)
+{
+       if (handle == NULL) {
+               pcep_log(
+                       LOG_WARNING,
+                       "%s: ordered_list_add_node, the list has not been initialized",
+                       __func__);
+               return NULL;
+       }
+       handle->num_entries++;
+
+       ordered_list_node *new_node =
+               pceplib_malloc(PCEPLIB_INFRA, sizeof(ordered_list_node));
+       memset(new_node, 0, sizeof(ordered_list_node));
+       new_node->data = data;
+       new_node->next_node = NULL;
+
+       /* check if its an empty list */
+       if (handle->head == NULL) {
+               handle->head = new_node;
+
+               return new_node;
+       }
+
+       ordered_list_node *prev_node = handle->head;
+       ordered_list_node *node = prev_node;
+       int compare_result;
+
+       while (node != NULL) {
+               compare_result = handle->compare_function(node->data, data);
+               if (compare_result < 0) {
+                       /* insert the node */
+                       new_node->next_node = node;
+                       if (handle->head == node) {
+                               /* add it at the beginning of the list */
+                               handle->head = new_node;
+                       } else {
+                               prev_node->next_node = new_node;
+                       }
+
+                       return new_node;
+               }
+
+               /* keep searching with the next node in the list */
+               prev_node = node;
+               node = node->next_node;
+       }
+
+       /* at the end of the list, add it here */
+       prev_node->next_node = new_node;
+
+       return new_node;
+}
+
+
+ordered_list_node *ordered_list_find2(ordered_list_handle *handle, void *data,
+                                     ordered_compare_function compare_func)
+{
+       if (handle == NULL) {
+               pcep_log(
+                       LOG_WARNING,
+                       "%s: ordered_list_find2, the list has not been initialized",
+                       __func__);
+               return NULL;
+       }
+
+       ordered_list_node *node = handle->head;
+       int compare_result;
+
+       while (node != NULL) {
+               compare_result = compare_func(node->data, data);
+               if (compare_result == 0) {
+                       return node;
+               } else {
+                       node = node->next_node;
+               }
+       }
+
+       return NULL;
+}
+
+
+ordered_list_node *ordered_list_find(ordered_list_handle *handle, void *data)
+{
+       if (handle == NULL) {
+               pcep_log(
+                       LOG_WARNING,
+                       "%s: ordered_list_find, the list has not been initialized",
+                       __func__);
+               return NULL;
+       }
+
+       return ordered_list_find2(handle, data, handle->compare_function);
+}
+
+
+void *ordered_list_remove_first_node(ordered_list_handle *handle)
+{
+       if (handle == NULL) {
+               pcep_log(
+                       LOG_WARNING,
+                       "%s: ordered_list_remove_first_node, the list has not been initialized",
+                       __func__);
+               return NULL;
+       }
+
+       if (handle->head == NULL) {
+               return NULL;
+       }
+       handle->num_entries--;
+
+       void *data = handle->head->data;
+       ordered_list_node *next_node = handle->head->next_node;
+       pceplib_free(PCEPLIB_INFRA, handle->head);
+       handle->head = next_node;
+
+       return data;
+}
+
+
+void *
+ordered_list_remove_first_node_equals2(ordered_list_handle *handle, void *data,
+                                      ordered_compare_function compare_func)
+{
+       if (handle == NULL) {
+               pcep_log(
+                       LOG_WARNING,
+                       "%s: ordered_list_remove_first_node_equals2, the list has not been initialized",
+                       __func__);
+               return NULL;
+       }
+
+       if (handle->head == NULL) {
+               return NULL;
+       }
+
+       ordered_list_node *prev_node = handle->head;
+       ordered_list_node *node = prev_node;
+       bool keep_walking = true;
+       void *return_data = NULL;
+       int compare_result;
+
+       while (node != NULL && keep_walking) {
+               compare_result = compare_func(node->data, data);
+               if (compare_result == 0) {
+                       return_data = node->data;
+                       keep_walking = false;
+                       handle->num_entries--;
+
+                       /* adjust the corresponding pointers accordingly */
+                       if (handle->head == node) {
+                               /* its the first node in the list */
+                               handle->head = node->next_node;
+                       } else {
+                               prev_node->next_node = node->next_node;
+                       }
+
+                       pceplib_free(PCEPLIB_INFRA, node);
+               } else {
+                       prev_node = node;
+                       node = node->next_node;
+               }
+       }
+
+       return return_data;
+}
+
+
+void *ordered_list_remove_first_node_equals(ordered_list_handle *handle,
+                                           void *data)
+{
+       if (handle == NULL) {
+               pcep_log(
+                       LOG_WARNING,
+                       "%s: ordered_list_remove_first_node_equals, the list has not been initialized",
+                       __func__);
+               return NULL;
+       }
+
+       return ordered_list_remove_first_node_equals2(handle, data,
+                                                     handle->compare_function);
+}
+
+
+void *ordered_list_remove_node(ordered_list_handle *handle,
+                              ordered_list_node *prev_node,
+                              ordered_list_node *node_toRemove)
+{
+       if (handle == NULL) {
+               pcep_log(
+                       LOG_WARNING,
+                       "%s: ordered_list_remove_node, the list has not been initialized",
+                       __func__);
+               return NULL;
+       }
+
+       if (handle->head == NULL) {
+               return NULL;
+       }
+
+       void *return_data = node_toRemove->data;
+       handle->num_entries--;
+
+       if (node_toRemove == handle->head) {
+               handle->head = node_toRemove->next_node;
+       } else {
+               prev_node->next_node = node_toRemove->next_node;
+       }
+
+       pceplib_free(PCEPLIB_INFRA, node_toRemove);
+
+       return return_data;
+}
+
+void *ordered_list_remove_node2(ordered_list_handle *handle,
+                               ordered_list_node *node_to_remove)
+{
+       if (handle == NULL) {
+               pcep_log(
+                       LOG_WARNING,
+                       "%s: ordered_list_remove_node2, the list has not been initialized",
+                       __func__);
+               return NULL;
+       }
+
+       if (handle->head == NULL) {
+               return NULL;
+       }
+
+       ordered_list_node *node = handle->head;
+       ordered_list_node *prev_node = handle->head;
+
+       while (node != NULL) {
+               if (node == node_to_remove) {
+                       return (ordered_list_remove_node(handle, prev_node,
+                                                        node));
+               } else {
+                       prev_node = node;
+                       node = node->next_node;
+               }
+       }
+
+       return NULL;
+}
diff --git a/pceplib/pcep_utils_ordered_list.h b/pceplib/pcep_utils_ordered_list.h
new file mode 100644 (file)
index 0000000..ec132dc
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#ifndef INCLUDE_PCEPUTILSORDEREDLIST_H_
+#define INCLUDE_PCEPUTILSORDEREDLIST_H_
+
+#include <stdbool.h>
+
+typedef struct ordered_list_node_ {
+       struct ordered_list_node_ *next_node;
+       void *data;
+
+} ordered_list_node;
+
+/* The implementation of this function will receive a pointer to the
+ * new data to be inserted and a pointer to the list_entry, and should
+ * return:
+ *   < 0  if new_entry  < list_entry
+ *   == 0 if new_entry == list_entry (new_entry will be inserted after
+ * list_entry) > 0  if new_entry  > list_entry
+ */
+typedef int (*ordered_compare_function)(void *list_entry, void *new_entry);
+
+/* Compare function that compares pointers */
+int pointer_compare_function(void *list_entry, void *new_entry);
+
+typedef struct ordered_list_handle_ {
+       ordered_list_node *head;
+       unsigned int num_entries;
+       ordered_compare_function compare_function;
+
+} ordered_list_handle;
+
+ordered_list_handle *ordered_list_initialize(ordered_compare_function func_ptr);
+void ordered_list_destroy(ordered_list_handle *handle);
+
+/* Add a new ordered_list_node to the list, using the ordered_compare_function
+ * to determine where in the list to add it. The newly created ordered_list_node
+ * will be returned.
+ */
+ordered_list_node *ordered_list_add_node(ordered_list_handle *handle,
+                                        void *data);
+
+/* Find an entry in the ordered_list using the ordered_compare_function to
+ * compare the data passed in.
+ * Return the node if found, NULL otherwise.
+ */
+ordered_list_node *ordered_list_find(ordered_list_handle *handle, void *data);
+
+/* The same as the previous function, but with a specific orderedComparefunction
+ */
+ordered_list_node *ordered_list_find2(ordered_list_handle *handle, void *data,
+                                     ordered_compare_function compare_func);
+
+/* Remove the first entry in the list and return the data it points to.
+ * Will return NULL if the handle is NULL or if the list is empty.
+ */
+void *ordered_list_remove_first_node(ordered_list_handle *handle);
+
+/* Remove the first entry in the list that has the same data, using the
+ * ordered_compare_function, and return the data it points to.
+ * Will return NULL if the handle is NULL or if the list is empty or
+ * if no entry is found that equals data.
+ */
+void *ordered_list_remove_first_node_equals(ordered_list_handle *handle,
+                                           void *data);
+
+/* The same as the previous function, but with a specific orderedComparefunction
+ */
+void *ordered_list_remove_first_node_equals2(ordered_list_handle *handle,
+                                            void *data,
+                                            ordered_compare_function func_ptr);
+
+/* Remove the node "node_to_remove" and adjust the "prev_node" pointers
+ * accordingly, returning the data pointed to by "node_to_remove". Will return
+ * NULL if the handle is NULL or if the list is empty.
+ */
+void *ordered_list_remove_node(ordered_list_handle *handle,
+                              ordered_list_node *prev_node,
+                              ordered_list_node *node_to_remove);
+
+/* Remove the node "node_to_remove" by searching for it in the entire list,
+ * returning the data pointed to by "node_to_remove".
+ * Will return NULL if the handle is NULL or if the list is empty.
+ */
+void *ordered_list_remove_node2(ordered_list_handle *handle,
+                               ordered_list_node *node_to_remove);
+
+#endif /* INCLUDE_PCEPUTILSORDEREDLIST_H_ */
diff --git a/pceplib/pcep_utils_queue.c b/pceplib/pcep_utils_queue.c
new file mode 100644 (file)
index 0000000..e8c3f2b
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "pcep_utils_logging.h"
+#include "pcep_utils_memory.h"
+#include "pcep_utils_queue.h"
+
+queue_handle *queue_initialize()
+{
+       /* Set the max_entries to 0 to disable it */
+       return queue_initialize_with_size(0);
+}
+
+
+queue_handle *queue_initialize_with_size(unsigned int max_entries)
+{
+       queue_handle *handle =
+               pceplib_malloc(PCEPLIB_INFRA, sizeof(queue_handle));
+       memset(handle, 0, sizeof(queue_handle));
+       handle->max_entries = max_entries;
+
+       return handle;
+}
+
+
+void queue_destroy(queue_handle *handle)
+{
+       if (handle == NULL) {
+               pcep_log(
+                       LOG_DEBUG,
+                       "%s: queue_destroy, the queue has not been initialized",
+                       __func__);
+               return;
+       }
+
+       while (queue_dequeue(handle) != NULL) {
+       }
+       pceplib_free(PCEPLIB_INFRA, handle);
+}
+
+
+void queue_destroy_with_data(queue_handle *handle)
+{
+       if (handle == NULL) {
+               pcep_log(
+                       LOG_DEBUG,
+                       "%s: queue_destroy_with_data, the queue has not been initialized",
+                       __func__);
+               return;
+       }
+
+       void *data = queue_dequeue(handle);
+       while (data != NULL) {
+               pceplib_free(PCEPLIB_INFRA, data);
+               data = queue_dequeue(handle);
+       }
+       pceplib_free(PCEPLIB_INFRA, handle);
+}
+
+
+queue_node *queue_enqueue(queue_handle *handle, void *data)
+{
+       if (handle == NULL) {
+               pcep_log(
+                       LOG_DEBUG,
+                       "%s: queue_enqueue, the queue has not been initialized",
+                       __func__);
+               return NULL;
+       }
+
+       if (handle->max_entries > 0
+           && handle->num_entries >= handle->max_entries) {
+               pcep_log(
+                       LOG_DEBUG,
+                       "%s: queue_enqueue, cannot enqueue: max entries hit [%u]",
+                       handle->num_entries);
+               return NULL;
+       }
+
+       queue_node *new_node =
+               pceplib_malloc(PCEPLIB_INFRA, sizeof(queue_node));
+       memset(new_node, 0, sizeof(queue_node));
+       new_node->data = data;
+       new_node->next_node = NULL;
+
+       (handle->num_entries)++;
+       if (handle->head == NULL) {
+               /* its the first entry in the queue */
+               handle->head = handle->tail = new_node;
+       } else {
+               handle->tail->next_node = new_node;
+               handle->tail = new_node;
+       }
+
+       return new_node;
+}
+
+
+void *queue_dequeue(queue_handle *handle)
+{
+       if (handle == NULL) {
+               pcep_log(
+                       LOG_DEBUG,
+                       "%s: queue_dequeue, the queue has not been initialized",
+                       __func__);
+               return NULL;
+       }
+
+       if (handle->head == NULL) {
+               return NULL;
+       }
+
+       void *node_data = handle->head->data;
+       queue_node *node = handle->head;
+       (handle->num_entries)--;
+       if (handle->head == handle->tail) {
+               /* its the last entry in the queue */
+               handle->head = handle->tail = NULL;
+       } else {
+               handle->head = node->next_node;
+       }
+
+       pceplib_free(PCEPLIB_INFRA, node);
+
+       return node_data;
+}
diff --git a/pceplib/pcep_utils_queue.h b/pceplib/pcep_utils_queue.h
new file mode 100644 (file)
index 0000000..8380676
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#ifndef INCLUDE_PCEPUTILSQUEUE_H_
+#define INCLUDE_PCEPUTILSQUEUE_H_
+
+typedef struct queue_node_ {
+       struct queue_node_ *next_node;
+       void *data;
+
+} queue_node;
+
+typedef struct queue_handle_ {
+       queue_node *head;
+       queue_node *tail;
+       unsigned int num_entries;
+       /* Set to 0 to disable */
+       unsigned int max_entries;
+
+} queue_handle;
+
+queue_handle *queue_initialize(void);
+queue_handle *queue_initialize_with_size(unsigned int max_entries);
+void queue_destroy(queue_handle *handle);
+void queue_destroy_with_data(queue_handle *handle);
+queue_node *queue_enqueue(queue_handle *handle, void *data);
+void *queue_dequeue(queue_handle *handle);
+
+#endif /* INCLUDE_PCEPUTILSQUEUE_H_ */
diff --git a/pceplib/subdir.am b/pceplib/subdir.am
new file mode 100644 (file)
index 0000000..eee2ec2
--- /dev/null
@@ -0,0 +1,62 @@
+if PATHD_PCEP
+
+noinst_LTLIBRARIES = pceplib/libpcep_pcc.la pceplib/libsocket_comm_mock.la
+pceplib_libpcep_pcc_la_CFLAGS = -fPIC
+pceplib_libpcep_pcc_la_SOURCES = pceplib/pcep_msg_messages.c \
+               pceplib/pcep_msg_objects.c \
+               pceplib/pcep_msg_tlvs.c \
+               pceplib/pcep_msg_tools.c \
+               pceplib/pcep_msg_messages_encoding.c \
+               pceplib/pcep_msg_objects_encoding.c \
+               pceplib/pcep_msg_tlvs_encoding.c \
+               pceplib/pcep_msg_object_error_types.c \
+               pceplib/pcep_pcc_api.c \
+               pceplib/pcep_session_logic.c \
+               pceplib/pcep_session_logic_loop.c \
+               pceplib/pcep_session_logic_states.c \
+               pceplib/pcep_session_logic_counters.c \
+               pceplib/pcep_socket_comm_loop.c \
+               pceplib/pcep_socket_comm.c \
+               pceplib/pcep_timers_event_loop.c \
+               pceplib/pcep_timers.c \
+               pceplib/pcep_utils_counters.c \
+               pceplib/pcep_utils_double_linked_list.c \
+               pceplib/pcep_utils_logging.c \
+               pceplib/pcep_utils_memory.c \
+               pceplib/pcep_utils_ordered_list.c \
+               pceplib/pcep_utils_queue.c
+
+if PATHD_PCEP_TEST
+# SocketComm Mock library used for Unit Testing
+pceplib_libsocket_comm_mock_la_SOURCES = pceplib/pcep_socket_comm_mock.c
+endif
+
+noinst_HEADERS += pceplib/pcep.h \
+               pceplib/pcep_msg_encoding.h \
+               pceplib/pcep_msg_messages.h \
+               pceplib/pcep_msg_object_error_types.h \
+               pceplib/pcep_msg_objects.h \
+               pceplib/pcep_msg_tlvs.h \
+               pceplib/pcep_msg_tools.h \
+               pceplib/pcep_pcc_api.h \
+               pceplib/pcep_session_logic.h \
+               pceplib/pcep_session_logic_internals.h \
+               pceplib/pcep_socket_comm.h \
+               pceplib/pcep_socket_comm_internals.h \
+               pceplib/pcep_socket_comm_loop.h \
+               pceplib/pcep_socket_comm_mock.h \
+               pceplib/pcep_timer_internals.h \
+               pceplib/pcep_timers.h \
+               pceplib/pcep_timers_event_loop.h \
+               pceplib/pcep_utils_counters.h \
+               pceplib/pcep_utils_double_linked_list.h \
+               pceplib/pcep_utils_logging.h \
+               pceplib/pcep_utils_memory.h \
+               pceplib/pcep_utils_ordered_list.h \
+               pceplib/pcep_utils_queue.h
+
+noinst_PROGRAMS += pceplib/pcep_pcc
+pceplib_pcep_pcc_SOURCES = pceplib/pcep_pcc.c
+pceplib_pcep_pcc_LDADD = pceplib/libpcep_pcc.la lib/libfrr.la -lpthread
+
+endif
diff --git a/pceplib/test/pcep_msg_messages_test.c b/pceplib/test/pcep_msg_messages_test.c
new file mode 100644 (file)
index 0000000..b8984a4
--- /dev/null
@@ -0,0 +1,514 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <stdlib.h>
+
+#include <CUnit/CUnit.h>
+
+#include "pcep_msg_encoding.h"
+#include "pcep_msg_messages.h"
+#include "pcep_msg_objects.h"
+#include "pcep_msg_tools.h"
+#include "pcep_utils_double_linked_list.h"
+#include "pcep_utils_memory.h"
+#include "pcep_msg_messages_test.h"
+
+/*
+ * Notice:
+ * All of these message Unit Tests encode the created messages by explicitly
+ * calling pcep_encode_message() thus testing the message creation and the
+ * message encoding.
+ */
+
+static struct pcep_versioning *versioning = NULL;
+
+int pcep_messages_test_suite_setup(void)
+{
+       pceplib_memory_reset();
+       return 0;
+}
+
+int pcep_messages_test_suite_teardown(void)
+{
+       printf("\n");
+       pceplib_memory_dump();
+       return 0;
+}
+
+void pcep_messages_test_setup()
+{
+       versioning = create_default_pcep_versioning();
+}
+
+void pcep_messages_test_teardown()
+{
+       destroy_pcep_versioning(versioning);
+}
+
+void test_pcep_msg_create_open()
+{
+       uint8_t keepalive = 30;
+       uint8_t deadtimer = 60;
+       uint8_t sid = 255;
+
+       struct pcep_message *message =
+               pcep_msg_create_open(keepalive, deadtimer, sid);
+       CU_ASSERT_PTR_NOT_NULL(message);
+       pcep_encode_message(message, versioning);
+       CU_ASSERT_PTR_NOT_NULL(message->msg_header);
+       CU_ASSERT_PTR_NOT_NULL(message->obj_list);
+       CU_ASSERT_EQUAL(message->obj_list->num_entries, 1);
+       CU_ASSERT_EQUAL(message->encoded_message_length,
+                       MESSAGE_HEADER_LENGTH
+                               + pcep_object_get_length(PCEP_OBJ_CLASS_OPEN,
+                                                        PCEP_OBJ_TYPE_OPEN));
+       CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_OPEN);
+       CU_ASSERT_EQUAL(message->msg_header->pcep_version,
+                       PCEP_MESSAGE_HEADER_VERSION);
+
+       /* Just check the class and type, the rest of the hdr fields
+        * are verified in pcep-objects-test.c */
+       struct pcep_object_open *open_obj =
+               (struct pcep_object_open *)message->obj_list->head->data;
+       CU_ASSERT_EQUAL(open_obj->header.object_class, PCEP_OBJ_CLASS_OPEN);
+       CU_ASSERT_EQUAL(open_obj->header.object_type, PCEP_OBJ_TYPE_OPEN);
+
+       CU_ASSERT_EQUAL(open_obj->open_deadtimer, deadtimer);
+       CU_ASSERT_EQUAL(open_obj->open_keepalive, keepalive);
+       CU_ASSERT_EQUAL(open_obj->open_sid, sid);
+       CU_ASSERT_EQUAL(open_obj->open_version, PCEP_OBJECT_OPEN_VERSION);
+       pcep_msg_free_message(message);
+}
+
+
+void test_pcep_msg_create_request()
+{
+       /* First test with NULL objects */
+       struct pcep_message *message =
+               pcep_msg_create_request(NULL, NULL, NULL);
+       CU_ASSERT_PTR_NULL(message);
+
+       /* Test IPv4 */
+       struct pcep_object_rp *rp_obj =
+               pcep_obj_create_rp(0, false, false, false, false, 10, NULL);
+       struct in_addr src_addr={}, dst_addr={};
+       struct pcep_object_endpoints_ipv4 *ipv4_obj =
+               pcep_obj_create_endpoint_ipv4(&src_addr, &dst_addr);
+       message = pcep_msg_create_request(rp_obj, ipv4_obj, NULL);
+
+       CU_ASSERT_PTR_NOT_NULL(message);
+       pcep_encode_message(message, versioning);
+       CU_ASSERT_PTR_NOT_NULL(message->msg_header);
+       CU_ASSERT_PTR_NOT_NULL(message->obj_list);
+       CU_ASSERT_EQUAL(message->obj_list->num_entries, 2);
+       CU_ASSERT_EQUAL(
+               message->encoded_message_length,
+               MESSAGE_HEADER_LENGTH
+                       + pcep_object_get_length_by_hdr(&rp_obj->header)
+                       + pcep_object_get_length_by_hdr(&ipv4_obj->header));
+       CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_PCREQ);
+       CU_ASSERT_EQUAL(message->msg_header->pcep_version,
+                       PCEP_MESSAGE_HEADER_VERSION);
+       pcep_msg_free_message(message);
+
+       /* Test IPv6 */
+       rp_obj = pcep_obj_create_rp(0, false, false, false, false, 10, NULL);
+       struct in6_addr src_addr_ipv6, dst_addr_ipv6;
+       struct pcep_object_endpoints_ipv6 *ipv6_obj =
+               pcep_obj_create_endpoint_ipv6(&src_addr_ipv6, &dst_addr_ipv6);
+       message = pcep_msg_create_request_ipv6(rp_obj, ipv6_obj, NULL);
+
+       CU_ASSERT_PTR_NOT_NULL(message);
+       pcep_encode_message(message, versioning);
+       CU_ASSERT_PTR_NOT_NULL(message->msg_header);
+       CU_ASSERT_PTR_NOT_NULL(message->obj_list);
+       CU_ASSERT_EQUAL(message->obj_list->num_entries, 2);
+       CU_ASSERT_EQUAL(
+               message->encoded_message_length,
+               MESSAGE_HEADER_LENGTH
+                       + pcep_object_get_length_by_hdr(&rp_obj->header)
+                       + pcep_object_get_length_by_hdr(&ipv6_obj->header));
+       CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_PCREQ);
+       CU_ASSERT_EQUAL(message->msg_header->pcep_version,
+                       PCEP_MESSAGE_HEADER_VERSION);
+       pcep_msg_free_message(message);
+
+       /* The objects get deleted with the message, so they need to be created
+        * again */
+       rp_obj = pcep_obj_create_rp(0, false, false, false, false, 10, NULL);
+       ipv4_obj = pcep_obj_create_endpoint_ipv4(&src_addr, &dst_addr);
+       struct pcep_object_bandwidth *bandwidth_obj =
+               pcep_obj_create_bandwidth(4.2);
+       double_linked_list *obj_list = dll_initialize();
+       dll_append(obj_list, bandwidth_obj);
+       message = pcep_msg_create_request(rp_obj, ipv4_obj, obj_list);
+
+       CU_ASSERT_PTR_NOT_NULL(message);
+       pcep_encode_message(message, versioning);
+       CU_ASSERT_PTR_NOT_NULL(message->msg_header);
+       CU_ASSERT_PTR_NOT_NULL(message->obj_list);
+       CU_ASSERT_EQUAL(message->obj_list->num_entries, 3);
+       CU_ASSERT_EQUAL(
+               message->encoded_message_length,
+               MESSAGE_HEADER_LENGTH
+                       + pcep_object_get_length_by_hdr(&rp_obj->header)
+                       + pcep_object_get_length_by_hdr(&ipv4_obj->header)
+                       + pcep_object_get_length_by_hdr(
+                               &bandwidth_obj->header));
+       CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_PCREQ);
+       CU_ASSERT_EQUAL(message->msg_header->pcep_version,
+                       PCEP_MESSAGE_HEADER_VERSION);
+       pcep_msg_free_message(message);
+}
+
+
+void test_pcep_msg_create_request_svec()
+{
+}
+
+
+void test_pcep_msg_create_reply_nopath()
+{
+       struct pcep_object_rp *rp_obj =
+               pcep_obj_create_rp(0, false, false, false, false, 10, NULL);
+       struct pcep_object_nopath *nopath_obj = pcep_obj_create_nopath(
+               false, false, PCEP_NOPATH_TLV_ERR_NO_TLV);
+       double_linked_list *obj_list = dll_initialize();
+       dll_append(obj_list, nopath_obj);
+
+       struct pcep_message *message = pcep_msg_create_reply(rp_obj, obj_list);
+       CU_ASSERT_PTR_NOT_NULL(message);
+       pcep_encode_message(message, versioning);
+       CU_ASSERT_PTR_NOT_NULL(message->msg_header);
+       CU_ASSERT_PTR_NOT_NULL(message->obj_list);
+       CU_ASSERT_EQUAL(message->obj_list->num_entries, 2);
+       CU_ASSERT_EQUAL(message->encoded_message_length,
+                       (MESSAGE_HEADER_LENGTH
+                        + pcep_object_get_length_by_hdr(&rp_obj->header)
+                        + pcep_object_get_length_by_hdr(&nopath_obj->header)));
+       CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_PCREP);
+       CU_ASSERT_EQUAL(message->msg_header->pcep_version,
+                       PCEP_MESSAGE_HEADER_VERSION);
+       pcep_msg_free_message(message);
+}
+
+
+void test_pcep_msg_create_reply()
+{
+       /* First test with NULL ero and rp objects */
+       struct pcep_message *message = pcep_msg_create_reply(NULL, NULL);
+
+       CU_ASSERT_PTR_NOT_NULL(message);
+       pcep_encode_message(message, versioning);
+       CU_ASSERT_PTR_NOT_NULL(message->msg_header);
+       CU_ASSERT_PTR_NOT_NULL(message->obj_list);
+       CU_ASSERT_EQUAL(message->obj_list->num_entries, 0);
+       CU_ASSERT_EQUAL(message->encoded_message_length, MESSAGE_HEADER_LENGTH);
+       CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_PCREP);
+       CU_ASSERT_EQUAL(message->msg_header->pcep_version,
+                       PCEP_MESSAGE_HEADER_VERSION);
+       pcep_msg_free_message(message);
+
+       double_linked_list *ero_subobj_list = dll_initialize();
+       struct pcep_object_ro_subobj *ero_subobj =
+               (struct pcep_object_ro_subobj *)
+                       pcep_obj_create_ro_subobj_32label(true, 1, 10);
+       dll_append(ero_subobj_list, ero_subobj);
+       struct pcep_object_ro *ero = pcep_obj_create_ero(ero_subobj_list);
+
+       double_linked_list *object_list = dll_initialize();
+       dll_append(object_list, ero);
+       struct pcep_object_rp *rp_obj =
+               pcep_obj_create_rp(0, false, false, false, false, 10, NULL);
+       message = pcep_msg_create_reply(rp_obj, object_list);
+       CU_ASSERT_PTR_NOT_NULL(message);
+       pcep_encode_message(message, versioning);
+       CU_ASSERT_PTR_NOT_NULL(message->msg_header);
+       CU_ASSERT_PTR_NOT_NULL(message->obj_list);
+       CU_ASSERT_EQUAL(message->obj_list->num_entries, 2);
+       CU_ASSERT_EQUAL(message->encoded_message_length,
+                       MESSAGE_HEADER_LENGTH
+                               + pcep_object_get_length_by_hdr(&rp_obj->header)
+                               + OBJECT_HEADER_LENGTH
+                               + OBJECT_RO_SUBOBJ_HEADER_LENGTH
+                               + 6 /* size of the 32label */);
+       CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_PCREP);
+       CU_ASSERT_EQUAL(message->msg_header->pcep_version,
+                       PCEP_MESSAGE_HEADER_VERSION);
+       pcep_msg_free_message(message);
+}
+
+
+void test_pcep_msg_create_close()
+{
+       uint8_t reason = PCEP_CLOSE_REASON_UNREC_MSG;
+
+       struct pcep_message *message = pcep_msg_create_close(reason);
+       CU_ASSERT_PTR_NOT_NULL(message);
+       pcep_encode_message(message, versioning);
+       CU_ASSERT_PTR_NOT_NULL(message->msg_header);
+       CU_ASSERT_PTR_NOT_NULL(message->obj_list);
+       CU_ASSERT_EQUAL(message->obj_list->num_entries, 1);
+       CU_ASSERT_EQUAL(message->encoded_message_length,
+                       MESSAGE_HEADER_LENGTH
+                               + pcep_object_get_length(PCEP_OBJ_CLASS_CLOSE,
+                                                        PCEP_OBJ_TYPE_CLOSE));
+       CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_CLOSE);
+       CU_ASSERT_EQUAL(message->msg_header->pcep_version,
+                       PCEP_MESSAGE_HEADER_VERSION);
+
+       /* Just check the class and type, the rest of the hdr fields
+        * are verified in pcep-objects-test.c */
+       struct pcep_object_close *close_obj =
+               (struct pcep_object_close *)message->obj_list->head->data;
+       CU_ASSERT_EQUAL(close_obj->header.object_class, PCEP_OBJ_CLASS_CLOSE);
+       CU_ASSERT_EQUAL(close_obj->header.object_type, PCEP_OBJ_TYPE_CLOSE);
+       CU_ASSERT_EQUAL(close_obj->reason, reason);
+       pcep_msg_free_message(message);
+}
+
+
+void test_pcep_msg_create_error()
+{
+       uint8_t error_type = PCEP_ERRT_RECEPTION_OF_INV_OBJECT;
+       uint8_t error_value = PCEP_ERRV_KEEPALIVEWAIT_TIMED_OUT;
+
+       struct pcep_message *message =
+               pcep_msg_create_error(error_type, error_value);
+       CU_ASSERT_PTR_NOT_NULL(message);
+       pcep_encode_message(message, versioning);
+       CU_ASSERT_PTR_NOT_NULL(message->msg_header);
+       CU_ASSERT_PTR_NOT_NULL(message->obj_list);
+       CU_ASSERT_EQUAL(message->obj_list->num_entries, 1);
+       CU_ASSERT_EQUAL(message->encoded_message_length,
+                       MESSAGE_HEADER_LENGTH
+                               + pcep_object_get_length(PCEP_OBJ_CLASS_ERROR,
+                                                        PCEP_OBJ_TYPE_ERROR));
+       CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_ERROR);
+       CU_ASSERT_EQUAL(message->msg_header->pcep_version,
+                       PCEP_MESSAGE_HEADER_VERSION);
+
+       /* Just check the class and type, the rest of the hdr fields
+        * are verified in pcep-objects-test.c */
+       struct pcep_object_error *error_obj =
+               (struct pcep_object_error *)message->obj_list->head->data;
+       CU_ASSERT_EQUAL(error_obj->header.object_class, PCEP_OBJ_CLASS_ERROR);
+       CU_ASSERT_EQUAL(error_obj->header.object_type, PCEP_OBJ_TYPE_ERROR);
+
+       CU_ASSERT_EQUAL(error_obj->error_type, error_type);
+       CU_ASSERT_EQUAL(error_obj->error_value, error_value);
+       pcep_msg_free_message(message);
+}
+
+
+void test_pcep_msg_create_keepalive()
+{
+       struct pcep_message *message = pcep_msg_create_keepalive();
+       CU_ASSERT_PTR_NOT_NULL(message);
+       pcep_encode_message(message, versioning);
+       CU_ASSERT_PTR_NOT_NULL(message->msg_header);
+       CU_ASSERT_PTR_NOT_NULL(message->obj_list);
+       CU_ASSERT_EQUAL(message->obj_list->num_entries, 0);
+       CU_ASSERT_EQUAL(message->encoded_message_length, MESSAGE_HEADER_LENGTH);
+       CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_KEEPALIVE);
+       CU_ASSERT_EQUAL(message->msg_header->pcep_version,
+                       PCEP_MESSAGE_HEADER_VERSION);
+       pcep_msg_free_message(message);
+}
+
+void test_pcep_msg_create_report()
+{
+       double_linked_list *obj_list = dll_initialize();
+
+       /* Should return NULL if obj_list is empty */
+       struct pcep_message *message = pcep_msg_create_report(NULL);
+       CU_ASSERT_PTR_NULL(message);
+
+       struct pcep_object_lsp *lsp =
+               pcep_obj_create_lsp(100, PCEP_LSP_OPERATIONAL_UP, true, true,
+                                   true, true, true, NULL);
+       dll_append(obj_list, lsp);
+       message = pcep_msg_create_report(obj_list);
+       CU_ASSERT_PTR_NOT_NULL(message);
+       pcep_encode_message(message, versioning);
+       CU_ASSERT_PTR_NOT_NULL(message->msg_header);
+       CU_ASSERT_PTR_NOT_NULL(message->obj_list);
+       CU_ASSERT_EQUAL(message->obj_list->num_entries, 1);
+       CU_ASSERT_EQUAL(message->encoded_message_length,
+                       MESSAGE_HEADER_LENGTH
+                               + lsp->header.encoded_object_length);
+       CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_REPORT);
+       CU_ASSERT_EQUAL(message->msg_header->pcep_version,
+                       PCEP_MESSAGE_HEADER_VERSION);
+
+       pcep_msg_free_message(message);
+}
+
+void test_pcep_msg_create_update()
+{
+       double_linked_list *obj_list = dll_initialize();
+       double_linked_list *ero_subobj_list = dll_initialize();
+
+       struct pcep_message *message = pcep_msg_create_update(NULL);
+       CU_ASSERT_PTR_NULL(message);
+
+       /* Should return NULL if obj_list is empty */
+       message = pcep_msg_create_update(obj_list);
+       CU_ASSERT_PTR_NULL(message);
+       if (message != NULL) {
+               pcep_msg_free_message(message);
+               message = NULL;
+       }
+
+       struct pcep_object_srp *srp = pcep_obj_create_srp(false, 100, NULL);
+       struct pcep_object_lsp *lsp =
+               pcep_obj_create_lsp(100, PCEP_LSP_OPERATIONAL_UP, true, true,
+                                   true, true, true, NULL);
+       dll_append(ero_subobj_list, pcep_obj_create_ro_subobj_asn(0x0102));
+       struct pcep_object_ro *ero = pcep_obj_create_ero(ero_subobj_list);
+
+       /* Should return NULL if obj_list does not have 3 entries */
+       dll_append(obj_list, srp);
+       dll_append(obj_list, lsp);
+       message = pcep_msg_create_update(obj_list);
+       CU_ASSERT_PTR_NULL(message);
+
+       dll_append(obj_list, ero);
+       if (message != NULL) {
+               pcep_msg_free_message(message);
+               message = NULL;
+       }
+       message = pcep_msg_create_update(obj_list);
+       CU_ASSERT_PTR_NOT_NULL(message);
+       pcep_encode_message(message, versioning);
+       CU_ASSERT_PTR_NOT_NULL(message->msg_header);
+       CU_ASSERT_PTR_NOT_NULL(message->obj_list);
+       CU_ASSERT_EQUAL(message->obj_list->num_entries, 3);
+       CU_ASSERT_EQUAL(message->encoded_message_length,
+                       MESSAGE_HEADER_LENGTH
+                               + srp->header.encoded_object_length
+                               + lsp->header.encoded_object_length
+                               + ero->header.encoded_object_length);
+       CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_UPDATE);
+       CU_ASSERT_EQUAL(message->msg_header->pcep_version,
+                       PCEP_MESSAGE_HEADER_VERSION);
+
+       pcep_msg_free_message(message);
+}
+
+void test_pcep_msg_create_initiate()
+{
+       double_linked_list *obj_list = dll_initialize();
+       double_linked_list *ero_subobj_list = dll_initialize();
+
+       /* Should return NULL if obj_list is empty */
+       struct pcep_message *message = pcep_msg_create_initiate(NULL);
+       CU_ASSERT_PTR_NULL(message);
+       if (message != NULL) {
+               pcep_msg_free_message(message);
+               message = NULL;
+       }
+
+       struct pcep_object_srp *srp = pcep_obj_create_srp(false, 100, NULL);
+       struct pcep_object_lsp *lsp =
+               pcep_obj_create_lsp(100, PCEP_LSP_OPERATIONAL_UP, true, true,
+                                   true, true, true, NULL);
+       dll_append(ero_subobj_list, pcep_obj_create_ro_subobj_asn(0x0102));
+       struct pcep_object_ro *ero = pcep_obj_create_ero(ero_subobj_list);
+
+       /* Should return NULL if obj_list does not have 2 entries */
+       dll_append(obj_list, srp);
+       message = pcep_msg_create_initiate(obj_list);
+       CU_ASSERT_PTR_NULL(message);
+       if (message != NULL) {
+               pcep_msg_free_message(message);
+               message = NULL;
+       }
+
+       dll_append(obj_list, lsp);
+       dll_append(obj_list, ero);
+       message = pcep_msg_create_initiate(obj_list);
+       CU_ASSERT_PTR_NOT_NULL(message);
+       pcep_encode_message(message, versioning);
+       CU_ASSERT_PTR_NOT_NULL(message->msg_header);
+       CU_ASSERT_PTR_NOT_NULL(message->obj_list);
+       CU_ASSERT_EQUAL(message->obj_list->num_entries, 3);
+       CU_ASSERT_EQUAL(message->encoded_message_length,
+                       MESSAGE_HEADER_LENGTH
+                               + srp->header.encoded_object_length
+                               + lsp->header.encoded_object_length
+                               + ero->header.encoded_object_length);
+       CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_INITIATE);
+       CU_ASSERT_EQUAL(message->msg_header->pcep_version,
+                       PCEP_MESSAGE_HEADER_VERSION);
+
+       pcep_msg_free_message(message);
+}
+
+void test_pcep_msg_create_notify(void)
+{
+       struct pcep_object_notify *notify_obj = pcep_obj_create_notify(
+               PCEP_NOTIFY_TYPE_PENDING_REQUEST_CANCELLED,
+               PCEP_NOTIFY_VALUE_PCC_CANCELLED_REQUEST);
+
+       /* Should return NULL if the notify obj is empty */
+       struct pcep_message *message = pcep_msg_create_notify(NULL, NULL);
+       CU_ASSERT_PTR_NULL(message);
+
+       message = pcep_msg_create_notify(notify_obj, NULL);
+       CU_ASSERT_PTR_NOT_NULL(message);
+       pcep_encode_message(message, versioning);
+       CU_ASSERT_PTR_NOT_NULL(message->obj_list);
+       CU_ASSERT_EQUAL(message->obj_list->num_entries, 1);
+       CU_ASSERT_EQUAL(message->encoded_message_length,
+                       MESSAGE_HEADER_LENGTH
+                               + notify_obj->header.encoded_object_length);
+       CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_PCNOTF);
+       CU_ASSERT_EQUAL(message->msg_header->pcep_version,
+                       PCEP_MESSAGE_HEADER_VERSION);
+
+       pcep_msg_free_message(message);
+
+       struct pcep_object_rp *rp_obj =
+               pcep_obj_create_rp(0, false, false, false, false, 10, NULL);
+       double_linked_list *obj_list = dll_initialize();
+       dll_append(obj_list, rp_obj);
+       notify_obj = pcep_obj_create_notify(
+               PCEP_NOTIFY_TYPE_PENDING_REQUEST_CANCELLED,
+               PCEP_NOTIFY_VALUE_PCC_CANCELLED_REQUEST);
+
+       message = pcep_msg_create_notify(notify_obj, obj_list);
+       CU_ASSERT_PTR_NOT_NULL(message);
+       pcep_encode_message(message, versioning);
+       CU_ASSERT_PTR_NOT_NULL(message->obj_list);
+       CU_ASSERT_EQUAL(message->obj_list->num_entries, 2);
+       CU_ASSERT_EQUAL(message->encoded_message_length,
+                       MESSAGE_HEADER_LENGTH
+                               + notify_obj->header.encoded_object_length
+                               + rp_obj->header.encoded_object_length);
+       CU_ASSERT_EQUAL(message->msg_header->type, PCEP_TYPE_PCNOTF);
+       CU_ASSERT_EQUAL(message->msg_header->pcep_version,
+                       PCEP_MESSAGE_HEADER_VERSION);
+
+       pcep_msg_free_message(message);
+}
diff --git a/pceplib/test/pcep_msg_messages_test.h b/pceplib/test/pcep_msg_messages_test.h
new file mode 100644 (file)
index 0000000..a3295c7
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Javier Garcia <javier.garcia@voltanet.io>
+ *
+ */
+
+/*
+ *  Timer definitions to be used internally by the pcep_timers library.
+ */
+
+#ifndef PCEP_MSG_MSG_TEST_H_
+#define PCEP_MSG_MSG_TEST_H_
+
+/* functions to be tested from pcep-messages.c */
+int pcep_messages_test_suite_setup(void);
+int pcep_messages_test_suite_teardown(void);
+void pcep_messages_test_setup(void);
+void pcep_messages_test_teardown(void);
+void test_pcep_msg_create_open(void);
+void test_pcep_msg_create_request(void);
+void test_pcep_msg_create_request_svec(void);
+void test_pcep_msg_create_reply_nopath(void);
+void test_pcep_msg_create_reply(void);
+void test_pcep_msg_create_close(void);
+void test_pcep_msg_create_error(void);
+void test_pcep_msg_create_keepalive(void);
+void test_pcep_msg_create_report(void);
+void test_pcep_msg_create_update(void);
+void test_pcep_msg_create_initiate(void);
+void test_pcep_msg_create_notify(void);
+
+#endif /* PCEPTIMERINTERNALS_H_ */
diff --git a/pceplib/test/pcep_msg_messages_tests.c b/pceplib/test/pcep_msg_messages_tests.c
new file mode 100644 (file)
index 0000000..bd85a16
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <CUnit/Basic.h>
+#include <CUnit/CUnit.h>
+#include <CUnit/TestDB.h>
+
+#include "pcep_msg_messages_test.h"
+#include "pcep_msg_tools_test.h"
+#include "pcep_msg_object_error_types.h"
+#include "pcep_msg_object_error_types_test.h"
+#include "pcep_msg_tlvs_test.h"
+#include "pcep_msg_objects_test.h"
+
+
+int main(int argc, char **argv)
+{
+       /* Unused parameters cause compilation warnings */
+       (void)argc;
+       (void)argv;
+
+       CU_initialize_registry();
+
+       CU_pSuite messages_suite = CU_add_suite_with_setup_and_teardown(
+               "PCEP Messages Test Suite", pcep_messages_test_suite_setup,
+               pcep_messages_test_suite_teardown, /* suite setup and cleanup
+                                                     function pointers */
+               pcep_messages_test_setup, pcep_messages_test_teardown);
+       CU_add_test(messages_suite, "test_pcep_msg_create_open",
+                   test_pcep_msg_create_open);
+       CU_add_test(messages_suite, "test_pcep_msg_create_request",
+                   test_pcep_msg_create_request);
+       CU_add_test(messages_suite, "test_pcep_msg_create_request_svec",
+                   test_pcep_msg_create_request_svec);
+       CU_add_test(messages_suite, "test_pcep_msg_create_reply_nopath",
+                   test_pcep_msg_create_reply_nopath);
+       CU_add_test(messages_suite, "test_pcep_msg_create_reply",
+                   test_pcep_msg_create_reply);
+       CU_add_test(messages_suite, "test_pcep_msg_create_close",
+                   test_pcep_msg_create_close);
+       CU_add_test(messages_suite, "test_pcep_msg_create_error",
+                   test_pcep_msg_create_error);
+       CU_add_test(messages_suite, "test_pcep_msg_create_keepalive",
+                   test_pcep_msg_create_keepalive);
+       CU_add_test(messages_suite, "test_pcep_msg_create_report",
+                   test_pcep_msg_create_report);
+       CU_add_test(messages_suite, "test_pcep_msg_create_update",
+                   test_pcep_msg_create_update);
+       CU_add_test(messages_suite, "test_pcep_msg_create_initiate",
+                   test_pcep_msg_create_initiate);
+       CU_add_test(messages_suite, "test_pcep_msg_create_notify",
+                   test_pcep_msg_create_notify);
+
+       CU_pSuite tlvs_suite = CU_add_suite_with_setup_and_teardown(
+               "PCEP TLVs Test Suite", pcep_tlvs_test_suite_setup,
+               pcep_tlvs_test_suite_teardown, /* suite setup and cleanup
+                                                 function pointers */
+               pcep_tlvs_test_setup, pcep_tlvs_test_teardown);
+       CU_add_test(tlvs_suite, "test_pcep_tlv_create_stateful_pce_capability",
+                   test_pcep_tlv_create_stateful_pce_capability);
+       CU_add_test(tlvs_suite, "test_pcep_tlv_create_speaker_entity_id",
+                   test_pcep_tlv_create_speaker_entity_id);
+       CU_add_test(tlvs_suite, "test_pcep_tlv_create_lsp_db_version",
+                   test_pcep_tlv_create_lsp_db_version);
+       CU_add_test(tlvs_suite, "test_pcep_tlv_create_path_setup_type",
+                   test_pcep_tlv_create_path_setup_type);
+       CU_add_test(tlvs_suite,
+                   "test_pcep_tlv_create_path_setup_type_capability",
+                   test_pcep_tlv_create_path_setup_type_capability);
+       CU_add_test(tlvs_suite, "test_pcep_tlv_create_sr_pce_capability",
+                   test_pcep_tlv_create_sr_pce_capability);
+       CU_add_test(tlvs_suite, "test_pcep_tlv_create_symbolic_path_name",
+                   test_pcep_tlv_create_symbolic_path_name);
+       CU_add_test(tlvs_suite, "test_pcep_tlv_create_ipv4_lsp_identifiers",
+                   test_pcep_tlv_create_ipv4_lsp_identifiers);
+       CU_add_test(tlvs_suite, "test_pcep_tlv_create_ipv6_lsp_identifiers",
+                   test_pcep_tlv_create_ipv6_lsp_identifiers);
+       CU_add_test(tlvs_suite, "test_pcep_tlv_create_srpag_pol_id_ipv4",
+                   test_pcep_tlv_create_srpag_pol_id_ipv4);
+       CU_add_test(tlvs_suite, "test_pcep_tlv_create_srpag_pol_id_ipv6",
+                   test_pcep_tlv_create_srpag_pol_id_ipv6);
+       CU_add_test(tlvs_suite, "test_pcep_tlv_create_srpag_pol_name",
+                   test_pcep_tlv_create_srpag_pol_name);
+       CU_add_test(tlvs_suite, "test_pcep_tlv_create_srpag_cp_id",
+                   test_pcep_tlv_create_srpag_cp_id);
+       CU_add_test(tlvs_suite, "test_pcep_tlv_create_srpag_cp_pref",
+                   test_pcep_tlv_create_srpag_cp_pref);
+       CU_add_test(tlvs_suite, "test_pcep_tlv_create_lsp_error_code",
+                   test_pcep_tlv_create_lsp_error_code);
+       CU_add_test(tlvs_suite, "test_pcep_tlv_create_rsvp_ipv4_error_spec",
+                   test_pcep_tlv_create_rsvp_ipv4_error_spec);
+       CU_add_test(tlvs_suite, "test_pcep_tlv_create_rsvp_ipv6_error_spec",
+                   test_pcep_tlv_create_rsvp_ipv6_error_spec);
+       CU_add_test(tlvs_suite, "test_pcep_tlv_create_nopath_vector",
+                   test_pcep_tlv_create_nopath_vector);
+       CU_add_test(tlvs_suite, "test_pcep_tlv_create_arbitrary",
+                   test_pcep_tlv_create_arbitrary);
+
+       CU_pSuite objects_suite = CU_add_suite_with_setup_and_teardown(
+               "PCEP Objects Test Suite", pcep_objects_test_suite_setup,
+               pcep_objects_test_suite_teardown, /* suite setup and cleanup
+                                                    function pointers */
+               pcep_objects_test_setup, pcep_objects_test_teardown);
+       CU_add_test(objects_suite, "test_pcep_obj_create_open",
+                   test_pcep_obj_create_open);
+       CU_add_test(objects_suite, "test_pcep_obj_create_open",
+                   test_pcep_obj_create_open_with_tlvs);
+       CU_add_test(objects_suite, "test_pcep_obj_create_rp",
+                   test_pcep_obj_create_rp);
+       CU_add_test(objects_suite, "test_pcep_obj_create_nopath",
+                   test_pcep_obj_create_nopath);
+       CU_add_test(objects_suite, "test_pcep_obj_create_enpoint_ipv4",
+                   test_pcep_obj_create_endpoint_ipv4);
+       CU_add_test(objects_suite, "test_pcep_obj_create_enpoint_ipv6",
+                   test_pcep_obj_create_endpoint_ipv6);
+       CU_add_test(objects_suite, "test_pcep_obj_create_association_ipv4",
+                   test_pcep_obj_create_association_ipv4);
+       CU_add_test(objects_suite, "test_pcep_obj_create_association_ipv6",
+                   test_pcep_obj_create_association_ipv6);
+       CU_add_test(objects_suite, "test_pcep_obj_create_bandwidth",
+                   test_pcep_obj_create_bandwidth);
+       CU_add_test(objects_suite, "test_pcep_obj_create_metric",
+                   test_pcep_obj_create_metric);
+       CU_add_test(objects_suite, "test_pcep_obj_create_lspa",
+                   test_pcep_obj_create_lspa);
+       CU_add_test(objects_suite, "test_pcep_obj_create_svec",
+                   test_pcep_obj_create_svec);
+       CU_add_test(objects_suite, "test_pcep_obj_create_error",
+                   test_pcep_obj_create_error);
+       CU_add_test(objects_suite, "test_pcep_obj_create_close",
+                   test_pcep_obj_create_close);
+       CU_add_test(objects_suite, "test_pcep_obj_create_srp",
+                   test_pcep_obj_create_srp);
+       CU_add_test(objects_suite, "test_pcep_obj_create_lsp",
+                   test_pcep_obj_create_lsp);
+       CU_add_test(objects_suite, "test_pcep_obj_create_vendor_info",
+                   test_pcep_obj_create_vendor_info);
+
+       CU_add_test(objects_suite, "test_pcep_obj_create_ero",
+                   test_pcep_obj_create_ero);
+       CU_add_test(objects_suite, "test_pcep_obj_create_rro",
+                   test_pcep_obj_create_rro);
+       CU_add_test(objects_suite, "test_pcep_obj_create_iro",
+                   test_pcep_obj_create_iro);
+       CU_add_test(objects_suite, "test_pcep_obj_create_ro_subobj_ipv4",
+                   test_pcep_obj_create_ro_subobj_ipv4);
+       CU_add_test(objects_suite, "test_pcep_obj_create_ro_subobj_ipv6",
+                   test_pcep_obj_create_ro_subobj_ipv6);
+       CU_add_test(objects_suite, "test_pcep_obj_create_ro_subobj_unnum",
+                   test_pcep_obj_create_ro_subobj_unnum);
+       CU_add_test(objects_suite, "test_pcep_obj_create_ro_subobj_32label",
+                   test_pcep_obj_create_ro_subobj_32label);
+       CU_add_test(objects_suite, "test_pcep_obj_create_ro_subobj_asn",
+                   test_pcep_obj_create_ro_subobj_asn);
+
+       CU_add_test(objects_suite, "test_pcep_obj_create_ro_subobj_sr_nonai",
+                   test_pcep_obj_create_ro_subobj_sr_nonai);
+       CU_add_test(objects_suite,
+                   "test_pcep_obj_create_ro_subobj_sr_ipv4_node",
+                   test_pcep_obj_create_ro_subobj_sr_ipv4_node);
+       CU_add_test(objects_suite,
+                   "test_pcep_obj_create_ro_subobj_sr_ipv6_node",
+                   test_pcep_obj_create_ro_subobj_sr_ipv6_node);
+       CU_add_test(objects_suite, "test_pcep_obj_create_ro_subobj_sr_ipv4_adj",
+                   test_pcep_obj_create_ro_subobj_sr_ipv4_adj);
+       CU_add_test(objects_suite, "test_pcep_obj_create_ro_subobj_sr_ipv6_adj",
+                   test_pcep_obj_create_ro_subobj_sr_ipv6_adj);
+       CU_add_test(objects_suite,
+                   "test_pcep_obj_create_ro_subobj_sr_unnumbered_ipv4_adj",
+                   test_pcep_obj_create_ro_subobj_sr_unnumbered_ipv4_adj);
+       CU_add_test(objects_suite,
+                   "test_pcep_obj_create_ro_subobj_sr_linklocal_ipv6_adj",
+                   test_pcep_obj_create_ro_subobj_sr_linklocal_ipv6_adj);
+
+       CU_pSuite tools_suite = CU_add_suite_with_setup_and_teardown(
+               "PCEP Tools Test Suite", pcep_tools_test_suite_setup,
+               pcep_tools_test_suite_teardown, pcep_tools_test_setup,
+               pcep_tools_test_teardown);
+       CU_add_test(tools_suite, "test_pcep_msg_read_pcep_initiate",
+                   test_pcep_msg_read_pcep_initiate);
+       CU_add_test(tools_suite, "test_pcep_msg_read_pcep_initiate2",
+                   test_pcep_msg_read_pcep_initiate2);
+       CU_add_test(tools_suite, "test_pcep_msg_read_pcep_update",
+                   test_pcep_msg_read_pcep_update);
+       CU_add_test(tools_suite, "test_pcep_msg_read_pcep_open",
+                   test_pcep_msg_read_pcep_open);
+       CU_add_test(tools_suite, "test_pcep_msg_read_pcep_open_initiate",
+                   test_pcep_msg_read_pcep_open_initiate);
+       CU_add_test(tools_suite, "test_validate_message_header",
+                   test_validate_message_header);
+       CU_add_test(tools_suite, "test_validate_message_objects",
+                   test_validate_message_objects);
+       CU_add_test(tools_suite, "test_validate_message_objects_invalid",
+                   test_validate_message_objects_invalid);
+       CU_add_test(tools_suite, "test_pcep_msg_read_pcep_open_cisco_pce",
+                   test_pcep_msg_read_pcep_open_cisco_pce);
+       CU_add_test(tools_suite, "test_pcep_msg_read_pcep_update_cisco_pce",
+                   test_pcep_msg_read_pcep_update_cisco_pce);
+       CU_add_test(tools_suite, "test_pcep_msg_read_pcep_report_cisco_pcc",
+                   test_pcep_msg_read_pcep_report_cisco_pcc);
+       CU_add_test(tools_suite, "test_pcep_msg_read_pcep_initiate_cisco_pcc",
+                   test_pcep_msg_read_pcep_initiate_cisco_pcc);
+
+       CU_pSuite obj_errors_suite = CU_add_suite_with_setup_and_teardown(
+               "PCEP Object Error Types Test Suite",
+               pcep_object_error_types_test_suite_setup,
+               pcep_object_error_types_test_suite_teardown,
+               pcep_object_error_types_test_setup,
+               pcep_object_error_types_test_teardown);
+       CU_add_test(obj_errors_suite, "test_get_error_type_str",
+                   test_get_error_type_str);
+       CU_add_test(obj_errors_suite, "test_get_error_value_str",
+                   test_get_error_value_str);
+
+       CU_basic_set_mode(CU_BRM_VERBOSE);
+       CU_basic_run_tests();
+       CU_FailureRecord *failure_record = CU_get_failure_list();
+       if (failure_record != NULL) {
+               printf("\nFailed tests:\n\t [Suite] [Test] [File:line-number]\n");
+               do {
+                       printf("\t [%s] [%s] [%s:%d]\n",
+                              failure_record->pSuite->pName,
+                              failure_record->pTest->pName,
+                              failure_record->strFileName,
+                              failure_record->uiLineNumber);
+                       failure_record = failure_record->pNext;
+
+               } while (failure_record != NULL);
+       }
+
+       CU_pRunSummary run_summary = CU_get_run_summary();
+       int result = run_summary->nTestsFailed;
+       CU_cleanup_registry();
+
+       return result;
+}
diff --git a/pceplib/test/pcep_msg_object_error_types_test.c b/pceplib/test/pcep_msg_object_error_types_test.c
new file mode 100644 (file)
index 0000000..7275eaf
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <stdio.h>
+
+#include <CUnit/CUnit.h>
+
+#include "pcep_msg_object_error_types.h"
+#include "pcep_msg_object_error_types_test.h"
+#include "pcep_utils_logging.h"
+#include "pcep_utils_memory.h"
+
+int pcep_object_error_types_test_suite_setup(void)
+{
+       pceplib_memory_reset();
+       set_logging_level(LOG_DEBUG);
+       return 0;
+}
+
+int pcep_object_error_types_test_suite_teardown(void)
+{
+       printf("\n");
+       pceplib_memory_dump();
+       return 0;
+}
+
+void pcep_object_error_types_test_setup(void)
+{
+}
+
+void pcep_object_error_types_test_teardown(void)
+{
+}
+
+void test_get_error_type_str()
+{
+       const char *error_type_str;
+       int i = 0;
+       for (; i < MAX_ERROR_TYPE; i++) {
+               error_type_str = get_error_type_str(i);
+               CU_ASSERT_PTR_NOT_NULL(error_type_str);
+       }
+
+       CU_ASSERT_PTR_NULL(get_error_type_str(-1));
+       CU_ASSERT_PTR_NULL(get_error_type_str(MAX_ERROR_TYPE));
+}
+
+void test_get_error_value_str()
+{
+       const char *error_value_str;
+       int i = 0, j = 0;
+
+       for (; i < MAX_ERROR_TYPE; i++) {
+               for (; j < MAX_ERROR_VALUE; j++) {
+                       error_value_str = get_error_value_str(i, j);
+                       CU_ASSERT_PTR_NOT_NULL(error_value_str);
+               }
+       }
+
+       CU_ASSERT_PTR_NULL(get_error_value_str(-1, 0));
+       CU_ASSERT_PTR_NULL(get_error_value_str(MAX_ERROR_TYPE, 0));
+       CU_ASSERT_PTR_NULL(get_error_value_str(1, -1));
+       CU_ASSERT_PTR_NULL(get_error_value_str(1, MAX_ERROR_VALUE));
+}
diff --git a/pceplib/test/pcep_msg_object_error_types_test.h b/pceplib/test/pcep_msg_object_error_types_test.h
new file mode 100644 (file)
index 0000000..863517d
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Javier Garcia <javier.garcia@voltanet.io>
+ *
+ */
+
+/*
+ *  Timer definitions to be used internally by the pcep_timers library.
+ */
+
+#ifndef PCEP_MSG_OBJECT_ERROR_TYPES_TEST_
+#define PCEP_MSG_OBJECT_ERROR_TYPES_TEST_
+
+int pcep_object_error_types_test_suite_setup(void);
+int pcep_object_error_types_test_suite_teardown(void);
+void pcep_object_error_types_test_setup(void);
+void pcep_object_error_types_test_teardown(void);
+void test_get_error_type_str(void);
+void test_get_error_value_str(void);
+
+#endif /* PCEPTIMERINTERNALS_H_ */
diff --git a/pceplib/test/pcep_msg_objects_test.c b/pceplib/test/pcep_msg_objects_test.c
new file mode 100644 (file)
index 0000000..a4c0699
--- /dev/null
@@ -0,0 +1,1289 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <stdlib.h>
+
+#include <CUnit/CUnit.h>
+
+#include "pcep_msg_encoding.h"
+#include "pcep_msg_objects.h"
+#include "pcep_msg_tools.h"
+#include "pcep_utils_memory.h"
+#include "pcep_msg_objects_test.h"
+
+/*
+ * Notice:
+ * All of these object Unit Tests encode the created objects by explicitly
+ * calling pcep_encode_object() thus testing the object creation and the object
+ * encoding. All APIs expect IPs to be in network byte order.
+ */
+
+static struct pcep_versioning *versioning = NULL;
+static uint8_t object_buf[2000];
+
+void reset_objects_buffer(void);
+
+int pcep_objects_test_suite_setup(void)
+{
+       pceplib_memory_reset();
+       return 0;
+}
+
+int pcep_objects_test_suite_teardown(void)
+{
+       printf("\n");
+       pceplib_memory_dump();
+       return 0;
+}
+
+void reset_objects_buffer()
+{
+       memset(object_buf, 0, 2000);
+}
+
+void pcep_objects_test_setup()
+{
+       versioning = create_default_pcep_versioning();
+       reset_objects_buffer();
+}
+
+void pcep_objects_test_teardown()
+{
+       destroy_pcep_versioning(versioning);
+}
+
+/* Internal util verification function */
+static void verify_pcep_obj_header2(uint8_t obj_class, uint8_t obj_type,
+                                   uint16_t obj_length, const uint8_t *obj_buf)
+{
+       /* Object Header
+        *
+        *  0                   1                   2                   3
+        *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+        *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+        *  | Object-Class  |   OT  |Res|P|I|   Object Length (bytes)       |
+        *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+        */
+
+       /* Not using CU_ASSERT_EQUAL here, so that in case of failure,
+        * we can provide more info in the error message. */
+       if (obj_buf[0] != obj_class) {
+               fprintf(stderr,
+                       "Test failure obj_class expected [%d] found [%d]\n",
+                       obj_class, obj_buf[0]);
+               CU_FAIL("Object Header Class");
+       }
+
+       uint8_t found8 = (obj_buf[1] >> 4) & 0x0f;
+       if (obj_type != found8) {
+               fprintf(stderr,
+                       "Test failure obj_class [%d] obj_type expected [%d] found [%d]\n",
+                       obj_class, obj_type, found8);
+               CU_FAIL("Object Header Type");
+       }
+
+       uint8_t exp8 = 0;
+       found8 = obj_buf[1] & 0x0f;
+       if (exp8 != found8) {
+               fprintf(stderr,
+                       "Test failure obj_class [%d] flags expected [%d] found [%d]\n",
+                       obj_class, exp8, found8);
+               CU_FAIL("Object Header Flags");
+       }
+
+       uint16_t found16 = ntohs(*((uint16_t *)(obj_buf + 2)));
+       if (obj_length != found16) {
+               fprintf(stderr,
+                       "Test failure obj_class [%d] obj_length expected [%d] found [%d]\n",
+                       obj_class, obj_length, found16);
+               CU_FAIL("Object Header Length");
+       }
+}
+
+/* Internal util verification function */
+static void verify_pcep_obj_header(uint8_t obj_class, uint8_t obj_type,
+                                  struct pcep_object_header *obj_hdr)
+{
+       verify_pcep_obj_header2(obj_class, obj_type,
+                               pcep_object_get_length_by_hdr(obj_hdr),
+                               obj_hdr->encoded_object);
+}
+
+void test_pcep_obj_create_open()
+{
+       uint8_t deadtimer = 60;
+       uint8_t keepalive = 30;
+       uint8_t sid = 1;
+
+       struct pcep_object_open *open =
+               pcep_obj_create_open(keepalive, deadtimer, sid, NULL);
+
+       CU_ASSERT_PTR_NOT_NULL(open);
+       pcep_encode_object(&open->header, versioning, object_buf);
+       verify_pcep_obj_header(PCEP_OBJ_CLASS_OPEN, PCEP_OBJ_TYPE_OPEN,
+                              &open->header);
+
+       CU_ASSERT_EQUAL(open->header.encoded_object[4],
+                       (PCEP_OBJECT_OPEN_VERSION << 5) & 0xe0);
+       CU_ASSERT_EQUAL(open->header.encoded_object[4] & 0x1f, 0);
+       CU_ASSERT_EQUAL(open->header.encoded_object[5], keepalive);
+       CU_ASSERT_EQUAL(open->header.encoded_object[6], deadtimer);
+       CU_ASSERT_EQUAL(open->header.encoded_object[7], sid);
+
+       pcep_obj_free_object((struct pcep_object_header *)open);
+}
+
+void test_pcep_obj_create_open_with_tlvs()
+{
+       uint8_t deadtimer = 60;
+       uint8_t keepalive = 30;
+       uint8_t sid = 1;
+       double_linked_list *tlv_list = dll_initialize();
+
+       struct pcep_object_tlv_stateful_pce_capability *tlv =
+               pcep_tlv_create_stateful_pce_capability(true, true, true, true,
+                                                       true, true);
+       dll_append(tlv_list, tlv);
+       struct pcep_object_open *open =
+               pcep_obj_create_open(keepalive, deadtimer, sid, tlv_list);
+
+       CU_ASSERT_PTR_NOT_NULL(open);
+       pcep_encode_object(&open->header, versioning, object_buf);
+       verify_pcep_obj_header2(PCEP_OBJ_CLASS_OPEN, PCEP_OBJ_TYPE_OPEN,
+                               pcep_object_get_length_by_hdr(&open->header)
+                                       + sizeof(uint32_t) * 2,
+                               open->header.encoded_object);
+       CU_ASSERT_PTR_NOT_NULL(open->header.tlv_list);
+       CU_ASSERT_EQUAL(open->header.tlv_list->num_entries, 1);
+
+       CU_ASSERT_EQUAL(open->header.encoded_object[4],
+                       (PCEP_OBJECT_OPEN_VERSION << 5) & 0xe0);
+       CU_ASSERT_EQUAL(open->header.encoded_object[4] & 0x1f, 0);
+       CU_ASSERT_EQUAL(open->header.encoded_object[5], keepalive);
+       CU_ASSERT_EQUAL(open->header.encoded_object[6], deadtimer);
+       CU_ASSERT_EQUAL(open->header.encoded_object[7], sid);
+
+       pcep_obj_free_object((struct pcep_object_header *)open);
+}
+
+void test_pcep_obj_create_rp()
+{
+       uint32_t reqid = 15;
+       uint8_t invalid_priority = 100;
+       uint8_t priority = 7;
+
+       struct pcep_object_rp *rp = pcep_obj_create_rp(
+               invalid_priority, true, false, false, true, reqid, NULL);
+       CU_ASSERT_PTR_NULL(rp);
+
+       rp = pcep_obj_create_rp(priority, true, false, false, true, reqid,
+                               NULL);
+       CU_ASSERT_PTR_NOT_NULL(rp);
+       pcep_encode_object(&rp->header, versioning, object_buf);
+       verify_pcep_obj_header(PCEP_OBJ_CLASS_RP, PCEP_OBJ_TYPE_RP,
+                              &rp->header);
+
+       CU_ASSERT_EQUAL(rp->header.encoded_object[4], 0);
+       CU_ASSERT_EQUAL(rp->header.encoded_object[5], 0);
+       CU_ASSERT_EQUAL(rp->header.encoded_object[6], 0);
+       CU_ASSERT_EQUAL((rp->header.encoded_object[7] & 0x07), priority);
+       CU_ASSERT_TRUE(rp->header.encoded_object[7] & OBJECT_RP_FLAG_R);
+       CU_ASSERT_TRUE(rp->header.encoded_object[7] & OBJECT_RP_FLAG_OF);
+       CU_ASSERT_TRUE(rp->header.encoded_object[7] & ~OBJECT_RP_FLAG_B);
+       CU_ASSERT_TRUE(rp->header.encoded_object[7] & ~OBJECT_RP_FLAG_O);
+       CU_ASSERT_EQUAL(*((uint32_t *)(rp->header.encoded_object + 8)),
+                       htonl(reqid));
+
+       pcep_obj_free_object((struct pcep_object_header *)rp);
+}
+
+void test_pcep_obj_create_nopath()
+{
+       uint8_t ni = 8;
+       uint32_t errorcode = 42;
+
+       struct pcep_object_nopath *nopath =
+               pcep_obj_create_nopath(ni, true, errorcode);
+
+       CU_ASSERT_PTR_NOT_NULL(nopath);
+       pcep_encode_object(&nopath->header, versioning, object_buf);
+       verify_pcep_obj_header(PCEP_OBJ_CLASS_NOPATH, PCEP_OBJ_TYPE_NOPATH,
+                              &nopath->header);
+
+       CU_ASSERT_EQUAL(nopath->header.encoded_object[4], ni);
+       CU_ASSERT_TRUE(nopath->header.encoded_object[5] & OBJECT_NOPATH_FLAG_C);
+       CU_ASSERT_EQUAL(nopath->header.encoded_object[6], 0);
+       CU_ASSERT_EQUAL(nopath->header.encoded_object[7], 0);
+
+       /* Verify the TLV */
+       CU_ASSERT_PTR_NOT_NULL(nopath->header.tlv_list);
+       struct pcep_object_tlv_nopath_vector *tlv =
+               (struct pcep_object_tlv_nopath_vector *)
+                       nopath->header.tlv_list->head->data;
+       CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, 4);
+       CU_ASSERT_EQUAL(tlv->header.type, 1);
+       CU_ASSERT_EQUAL(tlv->error_code, errorcode);
+
+       CU_ASSERT_EQUAL(*((uint16_t *)(nopath->header.encoded_object + 8)),
+                       htons(PCEP_OBJ_TLV_TYPE_NO_PATH_VECTOR));
+       CU_ASSERT_EQUAL(*((uint16_t *)(nopath->header.encoded_object + 10)),
+                       htons(4));
+       CU_ASSERT_EQUAL(*((uint32_t *)(nopath->header.encoded_object + 12)),
+                       htonl(errorcode));
+
+       pcep_obj_free_object((struct pcep_object_header *)nopath);
+}
+void test_pcep_obj_create_association_ipv4()
+{
+
+       uint16_t all_assoc_groups = 0xffff;
+       struct in_addr src;
+       inet_pton(AF_INET, "192.168.1.2", &src);
+
+       struct pcep_object_association_ipv4 *assoc =
+               pcep_obj_create_association_ipv4(
+                       false, PCEP_ASSOCIATION_TYPE_SR_POLICY_ASSOCIATION_TYPE,
+                       all_assoc_groups, src);
+       CU_ASSERT_PTR_NOT_NULL(assoc);
+       CU_ASSERT_EQUAL(assoc->association_type,
+                       PCEP_ASSOCIATION_TYPE_SR_POLICY_ASSOCIATION_TYPE);
+       CU_ASSERT_EQUAL(assoc->association_id, all_assoc_groups);
+       CU_ASSERT_EQUAL(assoc->header.object_class, PCEP_OBJ_CLASS_ASSOCIATION);
+       CU_ASSERT_EQUAL(assoc->header.object_type,
+                       PCEP_OBJ_TYPE_ASSOCIATION_IPV4);
+       CU_ASSERT_EQUAL(assoc->src.s_addr, src.s_addr);
+
+       pcep_obj_free_object((struct pcep_object_header *)assoc);
+}
+
+void test_pcep_obj_create_association_ipv6()
+{
+       uint32_t all_assoc_groups = 0xffff;
+       struct in6_addr src;
+       inet_pton(AF_INET6, "2001:db8::8a2e:370:7334", &src);
+
+       struct pcep_object_association_ipv6 *assoc =
+               pcep_obj_create_association_ipv6(
+                       false, PCEP_ASSOCIATION_TYPE_SR_POLICY_ASSOCIATION_TYPE,
+                       all_assoc_groups, src);
+       CU_ASSERT_PTR_NOT_NULL(assoc);
+       CU_ASSERT_EQUAL(assoc->association_type,
+                       PCEP_ASSOCIATION_TYPE_SR_POLICY_ASSOCIATION_TYPE);
+       CU_ASSERT_EQUAL(assoc->association_id, all_assoc_groups);
+       CU_ASSERT_EQUAL(assoc->header.object_class, PCEP_OBJ_CLASS_ASSOCIATION);
+       CU_ASSERT_EQUAL(assoc->header.object_type,
+                       PCEP_OBJ_TYPE_ASSOCIATION_IPV6);
+       CU_ASSERT_EQUAL(assoc->src.__in6_u.__u6_addr32[0],
+                       (src.__in6_u.__u6_addr32[0]));
+       CU_ASSERT_EQUAL(assoc->src.__in6_u.__u6_addr32[1],
+                       (src.__in6_u.__u6_addr32[1]));
+       CU_ASSERT_EQUAL(assoc->src.__in6_u.__u6_addr32[2],
+                       (src.__in6_u.__u6_addr32[2]));
+       CU_ASSERT_EQUAL(assoc->src.__in6_u.__u6_addr32[3],
+                       (src.__in6_u.__u6_addr32[3]));
+
+       pcep_obj_free_object((struct pcep_object_header *)assoc);
+}
+
+void test_pcep_obj_create_endpoint_ipv4()
+{
+       struct in_addr src_ipv4, dst_ipv4;
+       inet_pton(AF_INET, "192.168.1.2", &src_ipv4);
+       inet_pton(AF_INET, "172.168.1.2", &dst_ipv4);
+
+       struct pcep_object_endpoints_ipv4 *ipv4 =
+               pcep_obj_create_endpoint_ipv4(NULL, NULL);
+       CU_ASSERT_PTR_NULL(ipv4);
+
+       ipv4 = pcep_obj_create_endpoint_ipv4(&src_ipv4, NULL);
+       CU_ASSERT_PTR_NULL(ipv4);
+
+       ipv4 = pcep_obj_create_endpoint_ipv4(NULL, &dst_ipv4);
+       CU_ASSERT_PTR_NULL(ipv4);
+
+       ipv4 = pcep_obj_create_endpoint_ipv4(&src_ipv4, &dst_ipv4);
+       CU_ASSERT_PTR_NOT_NULL(ipv4);
+       pcep_encode_object(&ipv4->header, versioning, object_buf);
+       verify_pcep_obj_header(PCEP_OBJ_CLASS_ENDPOINTS,
+                              PCEP_OBJ_TYPE_ENDPOINT_IPV4, &ipv4->header);
+       CU_ASSERT_EQUAL(*((uint32_t *)(ipv4->header.encoded_object + 4)),
+                       src_ipv4.s_addr);
+       CU_ASSERT_EQUAL(*((uint32_t *)(ipv4->header.encoded_object + 8)),
+                       dst_ipv4.s_addr);
+
+       pcep_obj_free_object((struct pcep_object_header *)ipv4);
+}
+
+void test_pcep_obj_create_endpoint_ipv6()
+{
+       struct in6_addr src_ipv6, dst_ipv6;
+       inet_pton(AF_INET6, "2001:db8::8a2e:370:7334", &src_ipv6);
+       inet_pton(AF_INET6, "2001:db8::8a2e:370:8446", &dst_ipv6);
+
+       struct pcep_object_endpoints_ipv6 *ipv6 =
+               pcep_obj_create_endpoint_ipv6(NULL, NULL);
+       CU_ASSERT_PTR_NULL(ipv6);
+
+       ipv6 = pcep_obj_create_endpoint_ipv6(&src_ipv6, NULL);
+       CU_ASSERT_PTR_NULL(ipv6);
+
+       ipv6 = pcep_obj_create_endpoint_ipv6(NULL, &dst_ipv6);
+       CU_ASSERT_PTR_NULL(ipv6);
+
+       ipv6 = pcep_obj_create_endpoint_ipv6(&src_ipv6, &dst_ipv6);
+       CU_ASSERT_PTR_NOT_NULL(ipv6);
+       pcep_encode_object(&ipv6->header, versioning, object_buf);
+       verify_pcep_obj_header(PCEP_OBJ_CLASS_ENDPOINTS,
+                              PCEP_OBJ_TYPE_ENDPOINT_IPV6, &ipv6->header);
+       uint32_t *uint32_ptr = (uint32_t *)(ipv6->header.encoded_object + 4);
+       CU_ASSERT_EQUAL(uint32_ptr[0], src_ipv6.__in6_u.__u6_addr32[0]);
+       CU_ASSERT_EQUAL(uint32_ptr[1], src_ipv6.__in6_u.__u6_addr32[1]);
+       CU_ASSERT_EQUAL(uint32_ptr[2], src_ipv6.__in6_u.__u6_addr32[2]);
+       CU_ASSERT_EQUAL(uint32_ptr[3], src_ipv6.__in6_u.__u6_addr32[3]);
+       CU_ASSERT_EQUAL(uint32_ptr[4], dst_ipv6.__in6_u.__u6_addr32[0]);
+       CU_ASSERT_EQUAL(uint32_ptr[5], dst_ipv6.__in6_u.__u6_addr32[1]);
+       CU_ASSERT_EQUAL(uint32_ptr[6], dst_ipv6.__in6_u.__u6_addr32[2]);
+       CU_ASSERT_EQUAL(uint32_ptr[7], dst_ipv6.__in6_u.__u6_addr32[3]);
+
+       pcep_obj_free_object((struct pcep_object_header *)ipv6);
+}
+
+void test_pcep_obj_create_bandwidth()
+{
+       /* 1.8 => binary 1.11001101
+        * exponent = 127 => 0111 1111
+        * fraction = 1100 1101 0000 0000 0000 000 */
+       float bandwidth = 1.8;
+
+       struct pcep_object_bandwidth *bw = pcep_obj_create_bandwidth(bandwidth);
+
+       CU_ASSERT_PTR_NOT_NULL(bw);
+       pcep_encode_object(&bw->header, versioning, object_buf);
+       verify_pcep_obj_header(PCEP_OBJ_CLASS_BANDWIDTH,
+                              PCEP_OBJ_TYPE_BANDWIDTH_REQ, &bw->header);
+       CU_ASSERT_EQUAL(bw->header.encoded_object[4], 0x3f);
+       CU_ASSERT_EQUAL(bw->header.encoded_object[5], 0xe6);
+       CU_ASSERT_EQUAL(bw->header.encoded_object[6], 0x66);
+       CU_ASSERT_EQUAL(bw->header.encoded_object[7], 0x66);
+
+       pcep_obj_free_object((struct pcep_object_header *)bw);
+}
+
+void test_pcep_obj_create_metric()
+{
+       uint8_t type = PCEP_METRIC_BORDER_NODE_COUNT;
+       /* https://en.wikipedia.org/wiki/IEEE_754-1985
+        * 0.15625 = 1/8 + 1/32 = binary 0.00101 = 1.01 x 10^-3
+        * Exponent bias = 127, so exponent = (127-3) = 124 = 0111 1100
+        *            Sign  Exponent   Fraction
+        *                  (8 bits)   (23 bits)
+        * 0.15625 =>  0    0111 1100  010 0000 ... 0000 */
+       float value = 0.15625;
+
+       struct pcep_object_metric *metric =
+               pcep_obj_create_metric(type, true, true, value);
+
+       CU_ASSERT_PTR_NOT_NULL(metric);
+       pcep_encode_object(&metric->header, versioning, object_buf);
+       verify_pcep_obj_header(PCEP_OBJ_CLASS_METRIC, PCEP_OBJ_TYPE_METRIC,
+                              &metric->header);
+       CU_ASSERT_EQUAL(metric->header.encoded_object[4], 0);
+       CU_ASSERT_EQUAL(metric->header.encoded_object[5], 0);
+       CU_ASSERT_TRUE(metric->header.encoded_object[6] & OBJECT_METRIC_FLAC_B);
+       CU_ASSERT_TRUE(metric->header.encoded_object[6] & OBJECT_METRIC_FLAC_C);
+       CU_ASSERT_EQUAL(metric->header.encoded_object[7], type);
+       /* See comments above for explanation of these values */
+       CU_ASSERT_EQUAL(metric->header.encoded_object[8], 0x3e);
+       CU_ASSERT_EQUAL(metric->header.encoded_object[9], 0x20);
+       CU_ASSERT_EQUAL(metric->header.encoded_object[10], 0x00);
+       CU_ASSERT_EQUAL(metric->header.encoded_object[11], 0x00);
+
+       pcep_obj_free_object((struct pcep_object_header *)metric);
+}
+
+void test_pcep_obj_create_lspa()
+{
+       uint32_t exclude_any = 10;
+       uint32_t include_any = 20;
+       uint32_t include_all = 30;
+       uint8_t prio = 0;
+       uint8_t hold_prio = 10;
+
+       struct pcep_object_lspa *lspa = pcep_obj_create_lspa(
+               exclude_any, include_any, include_all, prio, hold_prio, true);
+
+       CU_ASSERT_PTR_NOT_NULL(lspa);
+       pcep_encode_object(&lspa->header, versioning, object_buf);
+       verify_pcep_obj_header(PCEP_OBJ_CLASS_LSPA, PCEP_OBJ_TYPE_LSPA,
+                              &lspa->header);
+       uint32_t *uint32_ptr = (uint32_t *)(lspa->header.encoded_object + 4);
+       CU_ASSERT_EQUAL(uint32_ptr[0], htonl(exclude_any));
+       CU_ASSERT_EQUAL(uint32_ptr[1], htonl(include_any));
+       CU_ASSERT_EQUAL(uint32_ptr[2], htonl(include_all));
+       CU_ASSERT_EQUAL(lspa->header.encoded_object[16], prio);
+       CU_ASSERT_EQUAL(lspa->header.encoded_object[17], hold_prio);
+       CU_ASSERT_TRUE(lspa->header.encoded_object[18] & OBJECT_LSPA_FLAG_L);
+       CU_ASSERT_EQUAL(lspa->header.encoded_object[19], 0);
+
+       pcep_obj_free_object((struct pcep_object_header *)lspa);
+}
+
+void test_pcep_obj_create_svec()
+{
+       struct pcep_object_svec *svec =
+               pcep_obj_create_svec(true, true, true, NULL);
+       CU_ASSERT_PTR_NULL(svec);
+
+       double_linked_list *id_list = dll_initialize();
+       uint32_t *uint32_ptr =
+               pceplib_malloc(PCEPLIB_MESSAGES, sizeof(uint32_t));
+       *uint32_ptr = 10;
+       dll_append(id_list, uint32_ptr);
+
+       svec = pcep_obj_create_svec(true, true, true, id_list);
+       CU_ASSERT_PTR_NOT_NULL(svec);
+       pcep_encode_object(&svec->header, versioning, object_buf);
+       verify_pcep_obj_header2(PCEP_OBJ_CLASS_SVEC, PCEP_OBJ_TYPE_SVEC,
+                               (OBJECT_HEADER_LENGTH + sizeof(uint32_t) * 2),
+                               svec->header.encoded_object);
+       CU_ASSERT_EQUAL(svec->header.encoded_object[4], 0);
+       CU_ASSERT_EQUAL(svec->header.encoded_object[5], 0);
+       CU_ASSERT_EQUAL(svec->header.encoded_object[6], 0);
+       CU_ASSERT_TRUE(svec->header.encoded_object[7] & OBJECT_SVEC_FLAG_S);
+       CU_ASSERT_TRUE(svec->header.encoded_object[7] & OBJECT_SVEC_FLAG_N);
+       CU_ASSERT_TRUE(svec->header.encoded_object[7] & OBJECT_SVEC_FLAG_L);
+       CU_ASSERT_EQUAL(*((uint32_t *)(svec->header.encoded_object + 8)),
+                       htonl(*uint32_ptr));
+
+       pcep_obj_free_object((struct pcep_object_header *)svec);
+}
+
+void test_pcep_obj_create_error()
+{
+       uint8_t error_type = PCEP_ERRT_SESSION_FAILURE;
+       uint8_t error_value = PCEP_ERRV_RECVD_INVALID_OPEN_MSG;
+
+       struct pcep_object_error *error =
+               pcep_obj_create_error(error_type, error_value);
+
+       CU_ASSERT_PTR_NOT_NULL(error);
+       pcep_encode_object(&error->header, versioning, object_buf);
+       verify_pcep_obj_header(PCEP_OBJ_CLASS_ERROR, PCEP_OBJ_TYPE_ERROR,
+                              &error->header);
+       CU_ASSERT_EQUAL(error->header.encoded_object[4], 0);
+       CU_ASSERT_EQUAL(error->header.encoded_object[5], 0);
+       CU_ASSERT_EQUAL(error->header.encoded_object[6], error_type);
+       CU_ASSERT_EQUAL(error->header.encoded_object[7], error_value);
+
+       pcep_obj_free_object((struct pcep_object_header *)error);
+}
+
+void test_pcep_obj_create_close()
+{
+       uint8_t reason = PCEP_CLOSE_REASON_DEADTIMER;
+
+       struct pcep_object_close *close = pcep_obj_create_close(reason);
+
+       CU_ASSERT_PTR_NOT_NULL(close);
+       pcep_encode_object(&close->header, versioning, object_buf);
+       verify_pcep_obj_header(PCEP_OBJ_CLASS_CLOSE, PCEP_OBJ_TYPE_CLOSE,
+                              &close->header);
+       CU_ASSERT_EQUAL(close->header.encoded_object[4], 0);
+       CU_ASSERT_EQUAL(close->header.encoded_object[5], 0);
+       CU_ASSERT_EQUAL(close->header.encoded_object[6], 0);
+       CU_ASSERT_EQUAL(close->header.encoded_object[7], reason);
+
+       pcep_obj_free_object((struct pcep_object_header *)close);
+}
+
+void test_pcep_obj_create_srp()
+{
+       bool lsp_remove = true;
+       uint32_t srp_id_number = 0x89674523;
+       struct pcep_object_srp *srp =
+               pcep_obj_create_srp(lsp_remove, srp_id_number, NULL);
+
+       CU_ASSERT_PTR_NOT_NULL(srp);
+       pcep_encode_object(&srp->header, versioning, object_buf);
+       verify_pcep_obj_header(PCEP_OBJ_CLASS_SRP, PCEP_OBJ_TYPE_SRP,
+                              &srp->header);
+       CU_ASSERT_EQUAL(srp->header.encoded_object[4], 0);
+       CU_ASSERT_EQUAL(srp->header.encoded_object[5], 0);
+       CU_ASSERT_EQUAL(srp->header.encoded_object[6], 0);
+       CU_ASSERT_TRUE(srp->header.encoded_object[7] & OBJECT_SRP_FLAG_R);
+       CU_ASSERT_EQUAL(*((uint32_t *)(srp->header.encoded_object + 8)),
+                       htonl(srp_id_number));
+
+       pcep_obj_free_object((struct pcep_object_header *)srp);
+}
+
+void test_pcep_obj_create_lsp()
+{
+       uint32_t plsp_id = 0x000fffff;
+       enum pcep_lsp_operational_status status = PCEP_LSP_OPERATIONAL_ACTIVE;
+       bool c_flag = true;
+       bool a_flag = true;
+       bool r_flag = true;
+       bool s_flag = true;
+       bool d_flag = true;
+
+       /* Should return for invalid plsp_id */
+       struct pcep_object_lsp *lsp =
+               pcep_obj_create_lsp(0x001fffff, status, c_flag, a_flag, r_flag,
+                                   s_flag, d_flag, NULL);
+       CU_ASSERT_PTR_NULL(lsp);
+
+       /* Should return for invalid status */
+       lsp = pcep_obj_create_lsp(plsp_id, 8, c_flag, a_flag, r_flag, s_flag,
+                                 d_flag, NULL);
+       CU_ASSERT_PTR_NULL(lsp);
+
+       lsp = pcep_obj_create_lsp(plsp_id, status, c_flag, a_flag, r_flag,
+                                 s_flag, d_flag, NULL);
+
+       CU_ASSERT_PTR_NOT_NULL(lsp);
+       pcep_encode_object(&lsp->header, versioning, object_buf);
+       verify_pcep_obj_header(PCEP_OBJ_CLASS_LSP, PCEP_OBJ_TYPE_LSP,
+                              &lsp->header);
+       CU_ASSERT_EQUAL((ntohl(*((uint32_t *)(lsp->header.encoded_object + 4)))
+                        >> 12) & 0x000fffff,
+                       plsp_id);
+       CU_ASSERT_EQUAL((lsp->header.encoded_object[7] >> 4) & 0x07, status);
+       CU_ASSERT_TRUE(lsp->header.encoded_object[7] & OBJECT_LSP_FLAG_A);
+       CU_ASSERT_TRUE(lsp->header.encoded_object[7] & OBJECT_LSP_FLAG_C);
+       CU_ASSERT_TRUE(lsp->header.encoded_object[7] & OBJECT_LSP_FLAG_D);
+       CU_ASSERT_TRUE(lsp->header.encoded_object[7] & OBJECT_LSP_FLAG_R);
+       CU_ASSERT_TRUE(lsp->header.encoded_object[7] & OBJECT_LSP_FLAG_S);
+
+       pcep_obj_free_object((struct pcep_object_header *)lsp);
+}
+
+void test_pcep_obj_create_vendor_info()
+{
+       uint32_t enterprise_number = 0x01020304;
+       uint32_t enterprise_specific_info = 0x05060708;
+
+       struct pcep_object_vendor_info *obj = pcep_obj_create_vendor_info(
+               enterprise_number, enterprise_specific_info);
+
+       CU_ASSERT_PTR_NOT_NULL(obj);
+       pcep_encode_object(&obj->header, versioning, object_buf);
+       verify_pcep_obj_header(PCEP_OBJ_CLASS_VENDOR_INFO,
+                              PCEP_OBJ_TYPE_VENDOR_INFO, &obj->header);
+       uint32_t *uint32_ptr = (uint32_t *)(obj->header.encoded_object + 4);
+       CU_ASSERT_EQUAL(uint32_ptr[0], htonl(enterprise_number));
+       CU_ASSERT_EQUAL(uint32_ptr[1], htonl(enterprise_specific_info));
+
+       pcep_obj_free_object((struct pcep_object_header *)obj);
+}
+
+/* Internal test function. The only difference between pcep_obj_create_ero(),
+ * pcep_obj_create_iro(), and pcep_obj_create_rro() is the object_class
+ * and the object_type.
+ */
+typedef struct pcep_object_ro *(*ro_func)(double_linked_list *);
+static void test_pcep_obj_create_object_common(ro_func func_to_test,
+                                              uint8_t object_class,
+                                              uint8_t object_type)
+{
+       double_linked_list *ero_list = dll_initialize();
+
+       struct pcep_object_ro *ero = func_to_test(NULL);
+       CU_ASSERT_PTR_NOT_NULL(ero);
+       pcep_encode_object(&ero->header, versioning, object_buf);
+       verify_pcep_obj_header2(object_class, object_type, OBJECT_HEADER_LENGTH,
+                               ero->header.encoded_object);
+       pcep_obj_free_object((struct pcep_object_header *)ero);
+
+       reset_objects_buffer();
+       ero = func_to_test(ero_list);
+       CU_ASSERT_PTR_NOT_NULL(ero);
+       pcep_encode_object(&ero->header, versioning, object_buf);
+       verify_pcep_obj_header2(object_class, object_type, OBJECT_HEADER_LENGTH,
+                               ero->header.encoded_object);
+       pcep_obj_free_object((struct pcep_object_header *)ero);
+
+       reset_objects_buffer();
+       struct pcep_ro_subobj_32label *ro_subobj =
+               pcep_obj_create_ro_subobj_32label(false, 0, 101);
+       ero_list = dll_initialize();
+       dll_append(ero_list, ro_subobj);
+       ero = func_to_test(ero_list);
+       CU_ASSERT_PTR_NOT_NULL(ero);
+       pcep_encode_object(&ero->header, versioning, object_buf);
+       /* 4 bytes for obj header +
+        * 2 bytes for ro_subobj header +
+        * 2 bytes for lable c-type and flags +
+        * 4 bytes for label */
+       verify_pcep_obj_header2(object_class, object_type,
+                               OBJECT_HEADER_LENGTH + sizeof(uint32_t) * 2,
+                               ero->header.encoded_object);
+       pcep_obj_free_object((struct pcep_object_header *)ero);
+}
+
+void test_pcep_obj_create_ero()
+{
+       test_pcep_obj_create_object_common(
+               pcep_obj_create_ero, PCEP_OBJ_CLASS_ERO, PCEP_OBJ_TYPE_ERO);
+}
+
+void test_pcep_obj_create_rro()
+{
+       test_pcep_obj_create_object_common(
+               pcep_obj_create_rro, PCEP_OBJ_CLASS_RRO, PCEP_OBJ_TYPE_RRO);
+}
+
+void test_pcep_obj_create_iro()
+{
+       test_pcep_obj_create_object_common(
+               pcep_obj_create_iro, PCEP_OBJ_CLASS_IRO, PCEP_OBJ_TYPE_IRO);
+}
+
+/* Internal util function to wrap an RO Subobj in a RO and encode it */
+static struct pcep_object_ro *encode_ro_subobj(struct pcep_object_ro_subobj *sr)
+{
+       double_linked_list *sr_subobj_list = dll_initialize();
+       dll_append(sr_subobj_list, sr);
+       struct pcep_object_ro *ro = pcep_obj_create_ero(sr_subobj_list);
+       pcep_encode_object(&ro->header, versioning, object_buf);
+
+       return ro;
+}
+
+static void verify_pcep_obj_ro_header(struct pcep_object_ro *ro,
+                                     struct pcep_object_ro_subobj *ro_subobj,
+                                     uint8_t ro_subobj_type, bool loose_hop,
+                                     uint16_t length)
+{
+       (void)ro_subobj;
+
+       verify_pcep_obj_header2(PCEP_OBJ_CLASS_ERO, PCEP_OBJ_TYPE_ERO, length,
+                               ro->header.encoded_object);
+
+       /* TODO consider printing the stack trace:
+        * https://stackoverflow.com/questions/105659/how-can-one-grab-a-stack-trace-in-c
+        */
+
+       /* Not using CU_ASSERT_EQUAL here, so that in case of failure,
+        * we can provide more info in the error message. */
+       uint8_t found_type = (ro->header.encoded_object[4]
+                             & 0x7f); /* remove the Loose hop bit */
+       if (found_type != ro_subobj_type) {
+               fprintf(stderr,
+                       "Test failure ro_sub_obj_type expected [%d] found [%d]\n",
+                       ro_subobj_type, found_type);
+               CU_FAIL("Sub Object Header Type");
+       }
+
+       bool loose_hop_found = (ro->header.encoded_object[4] & 0x80);
+       if (loose_hop != loose_hop_found) {
+               fprintf(stderr,
+                       "Test failure ro_sub_obj Loose Hop bit expected [%d] found [%d]\n",
+                       loose_hop, loose_hop_found);
+               CU_FAIL("Sub Object Header Loose Hop bit");
+       }
+
+       if (length - 4 != ro->header.encoded_object[5]) {
+               fprintf(stderr,
+                       "Test failure ro_sub_obj length expected [%d] found [%d]\n",
+                       length - 4, ro->header.encoded_object[5]);
+               CU_FAIL("Sub Object Length");
+       }
+}
+
+static void
+verify_pcep_obj_ro_sr_header(struct pcep_object_ro *ro,
+                            struct pcep_object_ro_subobj *ro_subobj,
+                            uint8_t nai_type, bool loose_hop, uint16_t length)
+{
+       verify_pcep_obj_ro_header(ro, ro_subobj, RO_SUBOBJ_TYPE_SR, loose_hop,
+                                 length);
+       uint8_t found_nai_type = ((ro->header.encoded_object[6] >> 4) & 0x0f);
+       if (nai_type != found_nai_type) {
+               fprintf(stderr,
+                       "Test failure ro_sr_sub_obj nai_type expected [%d] found [%d]\n",
+                       nai_type, found_nai_type);
+               CU_FAIL("Sub Object SR NAI Type");
+       }
+}
+
+void test_pcep_obj_create_ro_subobj_ipv4()
+{
+       struct in_addr ro_ipv4;
+       inet_pton(AF_INET, "192.168.1.2", &ro_ipv4);
+       uint8_t prefix_len = 8;
+
+       struct pcep_ro_subobj_ipv4 *ipv4 =
+               pcep_obj_create_ro_subobj_ipv4(true, NULL, prefix_len, false);
+       CU_ASSERT_PTR_NULL(ipv4);
+
+       ipv4 = pcep_obj_create_ro_subobj_ipv4(false, &ro_ipv4, prefix_len,
+                                             true);
+       CU_ASSERT_PTR_NOT_NULL(ipv4);
+       struct pcep_object_ro *ro = encode_ro_subobj(&ipv4->ro_subobj);
+       verify_pcep_obj_ro_header(ro, &ipv4->ro_subobj, RO_SUBOBJ_TYPE_IPV4,
+                                 false, sizeof(uint32_t) * 3);
+       CU_ASSERT_EQUAL(*((uint32_t *)(ro->header.encoded_object + 6)),
+                       ro_ipv4.s_addr);
+       CU_ASSERT_EQUAL(ro->header.encoded_object[10], prefix_len);
+       CU_ASSERT_TRUE(ro->header.encoded_object[11]
+                      & OBJECT_SUBOBJ_IP_FLAG_LOCAL_PROT);
+       pcep_obj_free_object((struct pcep_object_header *)ro);
+
+       reset_objects_buffer();
+       ipv4 = pcep_obj_create_ro_subobj_ipv4(true, &ro_ipv4, prefix_len,
+                                             false);
+       CU_ASSERT_PTR_NOT_NULL(ipv4);
+       ro = encode_ro_subobj(&ipv4->ro_subobj);
+       verify_pcep_obj_ro_header(ro, &ipv4->ro_subobj, RO_SUBOBJ_TYPE_IPV4,
+                                 true, sizeof(uint32_t) * 3);
+       CU_ASSERT_EQUAL(*((uint32_t *)(ro->header.encoded_object + 6)),
+                       ro_ipv4.s_addr);
+       CU_ASSERT_EQUAL(ro->header.encoded_object[10], prefix_len);
+       CU_ASSERT_EQUAL(ro->header.encoded_object[11], 0);
+       pcep_obj_free_object((struct pcep_object_header *)ro);
+}
+
+void test_pcep_obj_create_ro_subobj_ipv6()
+{
+       struct in6_addr ro_ipv6;
+       uint8_t prefix_len = 16;
+
+       struct pcep_ro_subobj_ipv6 *ipv6 =
+               pcep_obj_create_ro_subobj_ipv6(true, NULL, prefix_len, true);
+       CU_ASSERT_PTR_NULL(ipv6);
+
+       inet_pton(AF_INET6, "2001:db8::8a2e:370:7334", &ro_ipv6);
+       ipv6 = pcep_obj_create_ro_subobj_ipv6(false, &ro_ipv6, prefix_len,
+                                             true);
+       CU_ASSERT_PTR_NOT_NULL(ipv6);
+       struct pcep_object_ro *ro = encode_ro_subobj(&ipv6->ro_subobj);
+       verify_pcep_obj_ro_header(ro, &ipv6->ro_subobj, RO_SUBOBJ_TYPE_IPV6,
+                                 false, sizeof(uint32_t) * 6);
+       uint32_t *uint32_ptr = (uint32_t *)(ro->header.encoded_object + 6);
+       CU_ASSERT_EQUAL(uint32_ptr[0], ro_ipv6.__in6_u.__u6_addr32[0]);
+       CU_ASSERT_EQUAL(uint32_ptr[1], ro_ipv6.__in6_u.__u6_addr32[1]);
+       CU_ASSERT_EQUAL(uint32_ptr[2], ro_ipv6.__in6_u.__u6_addr32[2]);
+       CU_ASSERT_EQUAL(uint32_ptr[3], ro_ipv6.__in6_u.__u6_addr32[3]);
+       CU_ASSERT_EQUAL(ro->header.encoded_object[22], prefix_len);
+       CU_ASSERT_TRUE(ro->header.encoded_object[23]
+                      & OBJECT_SUBOBJ_IP_FLAG_LOCAL_PROT);
+       pcep_obj_free_object((struct pcep_object_header *)ro);
+
+       reset_objects_buffer();
+       ipv6 = pcep_obj_create_ro_subobj_ipv6(true, &ro_ipv6, prefix_len,
+                                             false);
+       CU_ASSERT_PTR_NOT_NULL(ipv6);
+       ro = encode_ro_subobj(&ipv6->ro_subobj);
+       verify_pcep_obj_ro_header(ro, &ipv6->ro_subobj, RO_SUBOBJ_TYPE_IPV6,
+                                 true, sizeof(uint32_t) * 6);
+       uint32_ptr = (uint32_t *)(ro->header.encoded_object + 6);
+       CU_ASSERT_EQUAL(uint32_ptr[0], ro_ipv6.__in6_u.__u6_addr32[0]);
+       CU_ASSERT_EQUAL(uint32_ptr[1], ro_ipv6.__in6_u.__u6_addr32[1]);
+       CU_ASSERT_EQUAL(uint32_ptr[2], ro_ipv6.__in6_u.__u6_addr32[2]);
+       CU_ASSERT_EQUAL(uint32_ptr[3], ro_ipv6.__in6_u.__u6_addr32[3]);
+       CU_ASSERT_EQUAL(ro->header.encoded_object[22], prefix_len);
+       CU_ASSERT_EQUAL(ro->header.encoded_object[23], 0);
+       pcep_obj_free_object((struct pcep_object_header *)ro);
+}
+
+void test_pcep_obj_create_ro_subobj_unnum()
+{
+       struct in_addr router_id;
+       uint32_t if_id = 123;
+
+       struct pcep_ro_subobj_unnum *unnum =
+               pcep_obj_create_ro_subobj_unnum(NULL, if_id);
+       CU_ASSERT_PTR_NULL(unnum);
+
+       inet_pton(AF_INET, "192.168.1.2", &router_id);
+       unnum = pcep_obj_create_ro_subobj_unnum(&router_id, if_id);
+       CU_ASSERT_PTR_NOT_NULL(unnum);
+       struct pcep_object_ro *ro = encode_ro_subobj(&unnum->ro_subobj);
+       verify_pcep_obj_ro_header(ro, &unnum->ro_subobj, RO_SUBOBJ_TYPE_UNNUM,
+                                 false, sizeof(uint32_t) * 4);
+       CU_ASSERT_EQUAL(ro->header.encoded_object[6], 0);
+       CU_ASSERT_EQUAL(ro->header.encoded_object[7], 0);
+       CU_ASSERT_EQUAL(*((uint32_t *)(ro->header.encoded_object + 8)),
+                       router_id.s_addr);
+       CU_ASSERT_EQUAL(*((uint32_t *)(ro->header.encoded_object + 12)),
+                       htonl(if_id));
+
+       pcep_obj_free_object((struct pcep_object_header *)ro);
+}
+
+void test_pcep_obj_create_ro_subobj_32label()
+{
+       uint8_t class_type = 1;
+       uint32_t label = 0xeeffaabb;
+
+       struct pcep_ro_subobj_32label *label32 =
+               pcep_obj_create_ro_subobj_32label(true, class_type, label);
+       CU_ASSERT_PTR_NOT_NULL(label32);
+       struct pcep_object_ro *ro = encode_ro_subobj(&label32->ro_subobj);
+       verify_pcep_obj_ro_header(ro, &label32->ro_subobj, RO_SUBOBJ_TYPE_LABEL,
+                                 false, sizeof(uint32_t) * 3);
+       CU_ASSERT_TRUE(ro->header.encoded_object[6]
+                      & OBJECT_SUBOBJ_LABEL_FLAG_GLOGAL);
+       CU_ASSERT_EQUAL(ro->header.encoded_object[7], class_type);
+       CU_ASSERT_EQUAL(*((uint32_t *)(ro->header.encoded_object + 8)),
+                       htonl(label));
+
+       pcep_obj_free_object((struct pcep_object_header *)ro);
+}
+
+void test_pcep_obj_create_ro_subobj_asn()
+{
+       uint16_t asn = 0x0102;
+
+       struct pcep_ro_subobj_asn *asn_obj = pcep_obj_create_ro_subobj_asn(asn);
+       CU_ASSERT_PTR_NOT_NULL(asn_obj);
+       struct pcep_object_ro *ro = encode_ro_subobj(&asn_obj->ro_subobj);
+       verify_pcep_obj_ro_header(ro, &asn_obj->ro_subobj, RO_SUBOBJ_TYPE_ASN,
+                                 false, sizeof(uint32_t) * 2);
+       CU_ASSERT_EQUAL(*((uint16_t *)(ro->header.encoded_object + 6)),
+                       htons(asn));
+
+       pcep_obj_free_object((struct pcep_object_header *)ro);
+}
+
+void test_pcep_obj_create_ro_subobj_sr_nonai()
+{
+       uint32_t sid = 0x01020304;
+
+       struct pcep_ro_subobj_sr *sr =
+               pcep_obj_create_ro_subobj_sr_nonai(false, sid, false, false);
+       CU_ASSERT_PTR_NOT_NULL(sr);
+       struct pcep_object_ro *ro = encode_ro_subobj(&sr->ro_subobj);
+       verify_pcep_obj_ro_sr_header(ro, &sr->ro_subobj,
+                                    PCEP_SR_SUBOBJ_NAI_ABSENT, false,
+                                    sizeof(uint32_t) * 3);
+       CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_S);
+       CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_F);
+       CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_C);
+       CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_M);
+       pcep_obj_free_object((struct pcep_object_header *)ro);
+
+       reset_objects_buffer();
+       sr = pcep_obj_create_ro_subobj_sr_nonai(true, sid, true, true);
+       CU_ASSERT_PTR_NOT_NULL(sr);
+       ro = encode_ro_subobj(&sr->ro_subobj);
+       verify_pcep_obj_ro_sr_header(ro, &sr->ro_subobj,
+                                    PCEP_SR_SUBOBJ_NAI_ABSENT, true,
+                                    sizeof(uint32_t) * 3);
+       CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_S);
+       CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_F);
+       CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_C);
+       CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_M);
+       pcep_obj_free_object((struct pcep_object_header *)ro);
+}
+
+void test_pcep_obj_create_ro_subobj_sr_ipv4_node()
+{
+       uint32_t sid = 0x01020304;
+       struct in_addr ipv4_node_id;
+       inet_pton(AF_INET, "192.168.1.2", &ipv4_node_id);
+
+       /* (loose_hop, sid_absent, c_flag, m_flag, sid, ipv4_node_id) */
+       struct pcep_ro_subobj_sr *sr = pcep_obj_create_ro_subobj_sr_ipv4_node(
+               true, false, true, true, sid, NULL);
+       CU_ASSERT_PTR_NULL(sr);
+
+       /* Test the sid is absent */
+       sr = pcep_obj_create_ro_subobj_sr_ipv4_node(true, true, false, false,
+                                                   sid, &ipv4_node_id);
+       CU_ASSERT_PTR_NOT_NULL(sr);
+       struct pcep_object_ro *ro = encode_ro_subobj(&sr->ro_subobj);
+       verify_pcep_obj_ro_sr_header(ro, &sr->ro_subobj,
+                                    PCEP_SR_SUBOBJ_NAI_IPV4_NODE, true,
+                                    sizeof(uint32_t) * 3);
+       CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_S);
+       CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_F);
+       CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_C);
+       CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_M);
+       CU_ASSERT_EQUAL(sr->sid, 0);
+       CU_ASSERT_EQUAL(*((uint32_t *)(ro->header.encoded_object + 8)),
+                       ipv4_node_id.s_addr);
+       pcep_obj_free_object((struct pcep_object_header *)ro);
+
+       /* Test the sid is present */
+       reset_objects_buffer();
+       inet_pton(AF_INET, "192.168.1.2", &ipv4_node_id);
+       sr = pcep_obj_create_ro_subobj_sr_ipv4_node(false, false, true, true,
+                                                   sid, &ipv4_node_id);
+       CU_ASSERT_PTR_NOT_NULL(sr);
+       ro = encode_ro_subobj(&sr->ro_subobj);
+       verify_pcep_obj_ro_sr_header(ro, &sr->ro_subobj,
+                                    PCEP_SR_SUBOBJ_NAI_IPV4_NODE, false,
+                                    sizeof(uint32_t) * 4);
+       CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_C);
+       CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_M);
+       CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_S);
+       CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_F);
+       CU_ASSERT_EQUAL(*((uint32_t *)(ro->header.encoded_object + 8)),
+                       htonl(sid));
+       CU_ASSERT_EQUAL(*((uint32_t *)(ro->header.encoded_object + 12)),
+                       ipv4_node_id.s_addr);
+       pcep_obj_free_object((struct pcep_object_header *)ro);
+}
+
+void test_pcep_obj_create_ro_subobj_sr_ipv6_node()
+{
+       uint32_t sid = 0x01020304;
+       struct in6_addr ipv6_node_id;
+       inet_pton(AF_INET6, "2001:db8::8a2e:370:7334", &ipv6_node_id);
+
+       /* (loose_hop, sid_absent, c_flag, m_flag, sid, ipv6_node_id) */
+       struct pcep_ro_subobj_sr *sr = pcep_obj_create_ro_subobj_sr_ipv6_node(
+               false, true, true, true, sid, NULL);
+       CU_ASSERT_PTR_NULL(sr);
+
+       /* Test the sid is absent */
+       sr = pcep_obj_create_ro_subobj_sr_ipv6_node(true, true, true, true, sid,
+                                                   &ipv6_node_id);
+       CU_ASSERT_PTR_NOT_NULL(sr);
+       struct pcep_object_ro *ro = encode_ro_subobj(&sr->ro_subobj);
+       verify_pcep_obj_ro_sr_header(ro, &sr->ro_subobj,
+                                    PCEP_SR_SUBOBJ_NAI_IPV6_NODE, true,
+                                    sizeof(uint32_t) * 6);
+       CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_S);
+       CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_F);
+       CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_C);
+       CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_M);
+       uint32_t *uint32_ptr = (uint32_t *)(ro->header.encoded_object + 8);
+       CU_ASSERT_EQUAL(uint32_ptr[0], ipv6_node_id.__in6_u.__u6_addr32[0]);
+       CU_ASSERT_EQUAL(uint32_ptr[1], ipv6_node_id.__in6_u.__u6_addr32[1]);
+       CU_ASSERT_EQUAL(uint32_ptr[2], ipv6_node_id.__in6_u.__u6_addr32[2]);
+       CU_ASSERT_EQUAL(uint32_ptr[3], ipv6_node_id.__in6_u.__u6_addr32[3]);
+       pcep_obj_free_object((struct pcep_object_header *)ro);
+
+       /* Test the sid is present */
+       reset_objects_buffer();
+       inet_pton(AF_INET6, "2001:db8::8a2e:370:7334", &ipv6_node_id);
+       sr = pcep_obj_create_ro_subobj_sr_ipv6_node(false, false, true, true,
+                                                   sid, &ipv6_node_id);
+       CU_ASSERT_PTR_NOT_NULL(sr);
+       ro = encode_ro_subobj(&sr->ro_subobj);
+       verify_pcep_obj_ro_sr_header(ro, &sr->ro_subobj,
+                                    PCEP_SR_SUBOBJ_NAI_IPV6_NODE, false,
+                                    sizeof(uint32_t) * 7);
+       CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_M);
+       CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_C);
+       CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_S);
+       CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_F);
+       uint32_ptr = (uint32_t *)(ro->header.encoded_object + 8);
+       CU_ASSERT_EQUAL(uint32_ptr[0], htonl(sid));
+       CU_ASSERT_EQUAL(uint32_ptr[1], ipv6_node_id.__in6_u.__u6_addr32[0]);
+       CU_ASSERT_EQUAL(uint32_ptr[2], ipv6_node_id.__in6_u.__u6_addr32[1]);
+       CU_ASSERT_EQUAL(uint32_ptr[3], ipv6_node_id.__in6_u.__u6_addr32[2]);
+       CU_ASSERT_EQUAL(uint32_ptr[4], ipv6_node_id.__in6_u.__u6_addr32[3]);
+       pcep_obj_free_object((struct pcep_object_header *)ro);
+}
+
+void test_pcep_obj_create_ro_subobj_sr_ipv4_adj()
+{
+       struct in_addr local_ipv4;
+       struct in_addr remote_ipv4;
+       inet_pton(AF_INET, "192.168.1.2", &local_ipv4);
+       inet_pton(AF_INET, "172.168.1.2", &remote_ipv4);
+
+       uint32_t sid = ENCODE_SR_ERO_SID(3, 7, 0, 188);
+       CU_ASSERT_EQUAL(sid, 16060);
+
+       /* (loose_hop, sid_absent, c_flag, m_flag, sid, local_ipv4, remote_ipv4)
+        */
+       struct pcep_ro_subobj_sr *sr = pcep_obj_create_ro_subobj_sr_ipv4_adj(
+               false, true, true, true, sid, NULL, NULL);
+       CU_ASSERT_PTR_NULL(sr);
+
+       sr = pcep_obj_create_ro_subobj_sr_ipv4_adj(false, true, true, true, sid,
+                                                  &local_ipv4, NULL);
+       CU_ASSERT_PTR_NULL(sr);
+
+       sr = pcep_obj_create_ro_subobj_sr_ipv4_adj(false, true, true, true, sid,
+                                                  NULL, &remote_ipv4);
+       CU_ASSERT_PTR_NULL(sr);
+
+       /* Test the sid is absent */
+       sr = pcep_obj_create_ro_subobj_sr_ipv4_adj(true, true, true, true, sid,
+                                                  &local_ipv4, &remote_ipv4);
+       CU_ASSERT_PTR_NOT_NULL(sr);
+       struct pcep_object_ro *ro = encode_ro_subobj(&sr->ro_subobj);
+       verify_pcep_obj_ro_sr_header(ro, &sr->ro_subobj,
+                                    PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY, true,
+                                    sizeof(uint32_t) * 4);
+       CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_S);
+       CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_F);
+       CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_C);
+       CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_M);
+       CU_ASSERT_EQUAL(sr->sid, 0);
+       uint32_t *uint32_ptr = (uint32_t *)(ro->header.encoded_object + 8);
+       CU_ASSERT_EQUAL(uint32_ptr[0], local_ipv4.s_addr);
+       CU_ASSERT_EQUAL(uint32_ptr[1], remote_ipv4.s_addr);
+       pcep_obj_free_object((struct pcep_object_header *)ro);
+
+       /* Test the sid is present */
+       inet_pton(AF_INET, "192.168.1.2", &local_ipv4);
+       inet_pton(AF_INET, "172.168.1.2", &remote_ipv4);
+       reset_objects_buffer();
+       sr = pcep_obj_create_ro_subobj_sr_ipv4_adj(
+               false, false, true, true, sid, &local_ipv4, &remote_ipv4);
+       CU_ASSERT_PTR_NOT_NULL(sr);
+       ro = encode_ro_subobj(&sr->ro_subobj);
+       verify_pcep_obj_ro_sr_header(ro, &sr->ro_subobj,
+                                    PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY, false,
+                                    sizeof(uint32_t) * 5);
+       CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_C);
+       CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_M);
+       CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_S);
+       CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_F);
+       uint32_ptr = (uint32_t *)(ro->header.encoded_object + 8);
+       CU_ASSERT_EQUAL(uint32_ptr[0], htonl(sid));
+       CU_ASSERT_EQUAL(uint32_ptr[1], local_ipv4.s_addr);
+       CU_ASSERT_EQUAL(uint32_ptr[2], remote_ipv4.s_addr);
+       pcep_obj_free_object((struct pcep_object_header *)ro);
+}
+
+void test_pcep_obj_create_ro_subobj_sr_ipv6_adj()
+{
+       uint32_t sid = 0x01020304;
+       struct in6_addr local_ipv6;
+       struct in6_addr remote_ipv6;
+       inet_pton(AF_INET6, "2001:db8::8a2e:370:8221", &local_ipv6);
+       inet_pton(AF_INET6, "2001:db8::8a2e:370:7334", &remote_ipv6);
+
+       /* (loose_hop, sid_absent, c_flag, m_flag, sid, local_ipv6, remote_ipv6)
+        */
+       struct pcep_ro_subobj_sr *sr = pcep_obj_create_ro_subobj_sr_ipv6_adj(
+               false, true, true, true, sid, NULL, NULL);
+       CU_ASSERT_PTR_NULL(sr);
+
+       sr = pcep_obj_create_ro_subobj_sr_ipv6_adj(false, true, true, true, sid,
+                                                  &local_ipv6, NULL);
+       CU_ASSERT_PTR_NULL(sr);
+
+       sr = pcep_obj_create_ro_subobj_sr_ipv6_adj(false, true, true, true, sid,
+                                                  NULL, &remote_ipv6);
+       CU_ASSERT_PTR_NULL(sr);
+
+       /* Test the sid is absent */
+       sr = pcep_obj_create_ro_subobj_sr_ipv6_adj(true, true, true, true, sid,
+                                                  &local_ipv6, &remote_ipv6);
+       CU_ASSERT_PTR_NOT_NULL(sr);
+       struct pcep_object_ro *ro = encode_ro_subobj(&sr->ro_subobj);
+       verify_pcep_obj_ro_sr_header(ro, &sr->ro_subobj,
+                                    PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY, true,
+                                    sizeof(uint32_t) * 10);
+       CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_S);
+       CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_F);
+       CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_C);
+       CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_M);
+       CU_ASSERT_EQUAL(sr->sid, 0);
+       uint32_t *uint32_ptr = (uint32_t *)(ro->header.encoded_object + 8);
+       CU_ASSERT_EQUAL(uint32_ptr[0], local_ipv6.__in6_u.__u6_addr32[0]);
+       CU_ASSERT_EQUAL(uint32_ptr[1], local_ipv6.__in6_u.__u6_addr32[1]);
+       CU_ASSERT_EQUAL(uint32_ptr[2], local_ipv6.__in6_u.__u6_addr32[2]);
+       CU_ASSERT_EQUAL(uint32_ptr[3], local_ipv6.__in6_u.__u6_addr32[3]);
+
+       CU_ASSERT_EQUAL(uint32_ptr[4], remote_ipv6.__in6_u.__u6_addr32[0]);
+       CU_ASSERT_EQUAL(uint32_ptr[5], remote_ipv6.__in6_u.__u6_addr32[1]);
+       CU_ASSERT_EQUAL(uint32_ptr[6], remote_ipv6.__in6_u.__u6_addr32[2]);
+       CU_ASSERT_EQUAL(uint32_ptr[7], remote_ipv6.__in6_u.__u6_addr32[3]);
+       pcep_obj_free_object((struct pcep_object_header *)ro);
+
+       /* Test the sid is present */
+       reset_objects_buffer();
+       inet_pton(AF_INET6, "2001:db8::8a2e:370:8221", &local_ipv6);
+       inet_pton(AF_INET6, "2001:db8::8a2e:370:7334", &remote_ipv6);
+       sr = pcep_obj_create_ro_subobj_sr_ipv6_adj(
+               false, false, true, false, sid, &local_ipv6, &remote_ipv6);
+       CU_ASSERT_PTR_NOT_NULL(sr);
+       ro = encode_ro_subobj(&sr->ro_subobj);
+       verify_pcep_obj_ro_sr_header(ro, &sr->ro_subobj,
+                                    PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY, false,
+                                    sizeof(uint32_t) * 11);
+       /* All flags are false */
+       CU_ASSERT_EQUAL(ro->header.encoded_object[7], 0);
+       uint32_ptr = (uint32_t *)(ro->header.encoded_object + 8);
+       CU_ASSERT_EQUAL(uint32_ptr[0], htonl(sid));
+       CU_ASSERT_EQUAL(uint32_ptr[1], local_ipv6.__in6_u.__u6_addr32[0]);
+       CU_ASSERT_EQUAL(uint32_ptr[2], local_ipv6.__in6_u.__u6_addr32[1]);
+       CU_ASSERT_EQUAL(uint32_ptr[3], local_ipv6.__in6_u.__u6_addr32[2]);
+       CU_ASSERT_EQUAL(uint32_ptr[4], local_ipv6.__in6_u.__u6_addr32[3]);
+
+       CU_ASSERT_EQUAL(uint32_ptr[5], remote_ipv6.__in6_u.__u6_addr32[0]);
+       CU_ASSERT_EQUAL(uint32_ptr[6], remote_ipv6.__in6_u.__u6_addr32[1]);
+       CU_ASSERT_EQUAL(uint32_ptr[7], remote_ipv6.__in6_u.__u6_addr32[2]);
+       CU_ASSERT_EQUAL(uint32_ptr[8], remote_ipv6.__in6_u.__u6_addr32[3]);
+       pcep_obj_free_object((struct pcep_object_header *)ro);
+}
+
+void test_pcep_obj_create_ro_subobj_sr_unnumbered_ipv4_adj()
+{
+       uint32_t sid = 0x01020304;
+       uint32_t local_node_id = 0x11223344;
+       uint32_t local_if_id = 0x55667788;
+       uint32_t remote_node_id = 0x99aabbcc;
+       uint32_t remote_if_id = 0xddeeff11;
+
+       /* (loose_hop, sid_absent, c_flag, m_flag,
+           sid, local_node_id, local_if_id, remote_node_id, remote_if_id) */
+
+       /* Test the sid is absent */
+       struct pcep_ro_subobj_sr *sr =
+               pcep_obj_create_ro_subobj_sr_unnumbered_ipv4_adj(
+                       true, true, true, true, sid, local_node_id, local_if_id,
+                       remote_node_id, remote_if_id);
+       CU_ASSERT_PTR_NOT_NULL(sr);
+       struct pcep_object_ro *ro = encode_ro_subobj(&sr->ro_subobj);
+       verify_pcep_obj_ro_sr_header(
+               ro, &sr->ro_subobj,
+               PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY, true,
+               sizeof(uint32_t) * 6);
+       CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_S);
+       CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_F);
+       CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_C);
+       CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_M);
+       CU_ASSERT_EQUAL(sr->sid, 0);
+       uint32_t *uint32_ptr = (uint32_t *)(ro->header.encoded_object + 8);
+       CU_ASSERT_EQUAL(uint32_ptr[0], local_node_id);
+       CU_ASSERT_EQUAL(uint32_ptr[1], local_if_id);
+       CU_ASSERT_EQUAL(uint32_ptr[2], remote_node_id);
+       CU_ASSERT_EQUAL(uint32_ptr[3], remote_if_id);
+       pcep_obj_free_object((struct pcep_object_header *)ro);
+
+       /* Test the sid is present */
+       reset_objects_buffer();
+       sr = pcep_obj_create_ro_subobj_sr_unnumbered_ipv4_adj(
+               false, false, true, true, sid, local_node_id, local_if_id,
+               remote_node_id, remote_if_id);
+       CU_ASSERT_PTR_NOT_NULL(sr);
+       ro = encode_ro_subobj(&sr->ro_subobj);
+       verify_pcep_obj_ro_sr_header(
+               ro, &sr->ro_subobj,
+               PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY, false,
+               sizeof(uint32_t) * 7);
+       CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_C);
+       CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_M);
+       CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_S);
+       CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_F);
+       uint32_ptr = (uint32_t *)(ro->header.encoded_object + 8);
+       CU_ASSERT_EQUAL(uint32_ptr[0], htonl(sid));
+       CU_ASSERT_EQUAL(uint32_ptr[1], local_node_id);
+       CU_ASSERT_EQUAL(uint32_ptr[2], local_if_id);
+       CU_ASSERT_EQUAL(uint32_ptr[3], remote_node_id);
+       CU_ASSERT_EQUAL(uint32_ptr[4], remote_if_id);
+       pcep_obj_free_object((struct pcep_object_header *)ro);
+
+       /* TODO Test draft07 types  */
+}
+
+void test_pcep_obj_create_ro_subobj_sr_linklocal_ipv6_adj()
+{
+       uint32_t sid = 0x01020304;
+       uint32_t local_if_id = 0x11002200;
+       uint32_t remote_if_id = 0x00110022;
+       struct in6_addr local_ipv6;
+       struct in6_addr remote_ipv6;
+       inet_pton(AF_INET6, "2001:db8::8a2e:370:8221", &local_ipv6);
+       inet_pton(AF_INET6, "2001:db8::8a2e:370:7334", &remote_ipv6);
+
+       /* (loose_hop, sid_absent, c_flag, m_flag, sid, local_ipv6, local_if_id,
+        * remote_ipv6, remote_if_id */
+       struct pcep_ro_subobj_sr *sr =
+               pcep_obj_create_ro_subobj_sr_linklocal_ipv6_adj(
+                       false, true, true, true, sid, NULL, local_if_id, NULL,
+                       remote_if_id);
+       CU_ASSERT_PTR_NULL(sr);
+
+       sr = pcep_obj_create_ro_subobj_sr_linklocal_ipv6_adj(
+               false, true, true, true, sid, &local_ipv6, local_if_id, NULL,
+               remote_if_id);
+       CU_ASSERT_PTR_NULL(sr);
+
+       sr = pcep_obj_create_ro_subobj_sr_linklocal_ipv6_adj(
+               false, true, true, true, sid, NULL, local_if_id, &remote_ipv6,
+               remote_if_id);
+       CU_ASSERT_PTR_NULL(sr);
+
+       /* Test the sid is absent */
+       sr = pcep_obj_create_ro_subobj_sr_linklocal_ipv6_adj(
+               true, true, true, true, sid, &local_ipv6, local_if_id,
+               &remote_ipv6, remote_if_id);
+       CU_ASSERT_PTR_NOT_NULL(sr);
+       struct pcep_object_ro *ro = encode_ro_subobj(&sr->ro_subobj);
+       verify_pcep_obj_ro_sr_header(
+               ro, &sr->ro_subobj,
+               PCEP_SR_SUBOBJ_NAI_LINK_LOCAL_IPV6_ADJACENCY, true,
+               sizeof(uint32_t) * 12);
+       CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_S);
+       CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_F);
+       CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_C);
+       CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_M);
+       CU_ASSERT_EQUAL(sr->sid, 0);
+       uint32_t *uint32_ptr = (uint32_t *)(ro->header.encoded_object + 8);
+       CU_ASSERT_EQUAL(uint32_ptr[0], local_ipv6.__in6_u.__u6_addr32[0]);
+       CU_ASSERT_EQUAL(uint32_ptr[1], local_ipv6.__in6_u.__u6_addr32[1]);
+       CU_ASSERT_EQUAL(uint32_ptr[2], local_ipv6.__in6_u.__u6_addr32[2]);
+       CU_ASSERT_EQUAL(uint32_ptr[3], local_ipv6.__in6_u.__u6_addr32[3]);
+       CU_ASSERT_EQUAL(uint32_ptr[4], local_if_id);
+
+       CU_ASSERT_EQUAL(uint32_ptr[5], remote_ipv6.__in6_u.__u6_addr32[0]);
+       CU_ASSERT_EQUAL(uint32_ptr[6], remote_ipv6.__in6_u.__u6_addr32[1]);
+       CU_ASSERT_EQUAL(uint32_ptr[7], remote_ipv6.__in6_u.__u6_addr32[2]);
+       CU_ASSERT_EQUAL(uint32_ptr[8], remote_ipv6.__in6_u.__u6_addr32[3]);
+       CU_ASSERT_EQUAL(uint32_ptr[9], remote_if_id);
+       pcep_obj_free_object((struct pcep_object_header *)ro);
+
+       /* Test the sid is present */
+       inet_pton(AF_INET6, "2001:db8::8a2e:370:8221", &local_ipv6);
+       inet_pton(AF_INET6, "2001:db8::8a2e:370:7334", &remote_ipv6);
+       reset_objects_buffer();
+       sr = pcep_obj_create_ro_subobj_sr_linklocal_ipv6_adj(
+               false, false, true, true, sid, &local_ipv6, local_if_id,
+               &remote_ipv6, remote_if_id);
+       CU_ASSERT_PTR_NOT_NULL(sr);
+       ro = encode_ro_subobj(&sr->ro_subobj);
+       verify_pcep_obj_ro_sr_header(
+               ro, &sr->ro_subobj,
+               PCEP_SR_SUBOBJ_NAI_LINK_LOCAL_IPV6_ADJACENCY, false,
+               sizeof(uint32_t) * 13);
+       CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_C);
+       CU_ASSERT_TRUE(ro->header.encoded_object[7] & OBJECT_SUBOBJ_SR_FLAG_M);
+       CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_S);
+       CU_ASSERT_TRUE(ro->header.encoded_object[7] & ~OBJECT_SUBOBJ_SR_FLAG_F);
+       uint32_ptr = (uint32_t *)(ro->header.encoded_object + 8);
+       CU_ASSERT_EQUAL(uint32_ptr[0], htonl(sid));
+       CU_ASSERT_EQUAL(uint32_ptr[1], local_ipv6.__in6_u.__u6_addr32[0]);
+       CU_ASSERT_EQUAL(uint32_ptr[2], local_ipv6.__in6_u.__u6_addr32[1]);
+       CU_ASSERT_EQUAL(uint32_ptr[3], local_ipv6.__in6_u.__u6_addr32[2]);
+       CU_ASSERT_EQUAL(uint32_ptr[4], local_ipv6.__in6_u.__u6_addr32[3]);
+       CU_ASSERT_EQUAL(uint32_ptr[5], local_if_id);
+
+       CU_ASSERT_EQUAL(uint32_ptr[6], remote_ipv6.__in6_u.__u6_addr32[0]);
+       CU_ASSERT_EQUAL(uint32_ptr[7], remote_ipv6.__in6_u.__u6_addr32[1]);
+       CU_ASSERT_EQUAL(uint32_ptr[8], remote_ipv6.__in6_u.__u6_addr32[2]);
+       CU_ASSERT_EQUAL(uint32_ptr[9], remote_ipv6.__in6_u.__u6_addr32[3]);
+       CU_ASSERT_EQUAL(uint32_ptr[10], remote_if_id);
+       pcep_obj_free_object((struct pcep_object_header *)ro);
+}
diff --git a/pceplib/test/pcep_msg_objects_test.h b/pceplib/test/pcep_msg_objects_test.h
new file mode 100644 (file)
index 0000000..0f08193
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Javier Garcia <javier.garcia@voltanet.io>
+ *
+ */
+
+
+#ifndef PCEP_MSG_OBJECTS_TEST_H_
+#define PCEP_MSG_OBJECTS_TEST_H_
+
+int pcep_objects_test_suite_setup(void);
+int pcep_objects_test_suite_teardown(void);
+void pcep_objects_test_setup(void);
+void pcep_objects_test_teardown(void);
+void test_pcep_obj_create_open(void);
+void test_pcep_obj_create_open_with_tlvs(void);
+void test_pcep_obj_create_rp(void);
+void test_pcep_obj_create_nopath(void);
+void test_pcep_obj_create_endpoint_ipv4(void);
+void test_pcep_obj_create_endpoint_ipv6(void);
+void test_pcep_obj_create_association_ipv4(void);
+void test_pcep_obj_create_association_ipv6(void);
+void test_pcep_obj_create_bandwidth(void);
+void test_pcep_obj_create_metric(void);
+void test_pcep_obj_create_lspa(void);
+void test_pcep_obj_create_svec(void);
+void test_pcep_obj_create_error(void);
+void test_pcep_obj_create_close(void);
+void test_pcep_obj_create_srp(void);
+void test_pcep_obj_create_lsp(void);
+void test_pcep_obj_create_vendor_info(void);
+void test_pcep_obj_create_ero(void);
+void test_pcep_obj_create_rro(void);
+void test_pcep_obj_create_iro(void);
+void test_pcep_obj_create_ro_subobj_ipv4(void);
+void test_pcep_obj_create_ro_subobj_ipv6(void);
+void test_pcep_obj_create_ro_subobj_unnum(void);
+void test_pcep_obj_create_ro_subobj_32label(void);
+void test_pcep_obj_create_ro_subobj_asn(void);
+void test_pcep_obj_create_ro_subobj_sr_nonai(void);
+void test_pcep_obj_create_ro_subobj_sr_ipv4_node(void);
+void test_pcep_obj_create_ro_subobj_sr_ipv6_node(void);
+void test_pcep_obj_create_ro_subobj_sr_ipv4_adj(void);
+void test_pcep_obj_create_ro_subobj_sr_ipv6_adj(void);
+void test_pcep_obj_create_ro_subobj_sr_unnumbered_ipv4_adj(void);
+void test_pcep_obj_create_ro_subobj_sr_linklocal_ipv6_adj(void);
+
+#endif
diff --git a/pceplib/test/pcep_msg_tests_valgrind.sh b/pceplib/test/pcep_msg_tests_valgrind.sh
new file mode 100755 (executable)
index 0000000..4a9a999
--- /dev/null
@@ -0,0 +1,2 @@
+source pceplib/test/pcep_tests_valgrind.sh
+valgrind_test pceplib/test/pcep_msg_tests
diff --git a/pceplib/test/pcep_msg_tlvs_test.c b/pceplib/test/pcep_msg_tlvs_test.c
new file mode 100644 (file)
index 0000000..6b650f6
--- /dev/null
@@ -0,0 +1,691 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <stdlib.h>
+
+#include <CUnit/CUnit.h>
+
+#include "pcep_msg_encoding.h"
+#include "pcep_msg_objects.h"
+#include "pcep_msg_tlvs.h"
+#include "pcep_msg_tools.h"
+#include "pcep_utils_memory.h"
+#include "pcep_msg_tlvs_test.h"
+
+/*
+ * Notice:
+ * All of these TLV Unit Tests encode the created TLVs by explicitly calling
+ * pcep_encode_tlv() thus testing the TLV creation and the TLV encoding.
+ * All APIs expect IPs to be in network byte order.
+ */
+
+static struct pcep_versioning *versioning = NULL;
+static uint8_t tlv_buf[2000];
+
+void reset_tlv_buffer(void);
+
+int pcep_tlvs_test_suite_setup(void)
+{
+       pceplib_memory_reset();
+       return 0;
+}
+
+int pcep_tlvs_test_suite_teardown(void)
+{
+       printf("\n");
+       pceplib_memory_dump();
+       return 0;
+}
+
+void reset_tlv_buffer()
+{
+       memset(tlv_buf, 0, 2000);
+}
+
+void pcep_tlvs_test_setup()
+{
+       versioning = create_default_pcep_versioning();
+       reset_tlv_buffer();
+}
+
+void pcep_tlvs_test_teardown()
+{
+       destroy_pcep_versioning(versioning);
+}
+
+void test_pcep_tlv_create_stateful_pce_capability()
+{
+       struct pcep_object_tlv_stateful_pce_capability *tlv =
+               pcep_tlv_create_stateful_pce_capability(true, true, true, true,
+                                                       true, true);
+       CU_ASSERT_PTR_NOT_NULL(tlv);
+
+       pcep_encode_tlv(&tlv->header, versioning, tlv_buf);
+       CU_ASSERT_EQUAL(tlv->header.type,
+                       PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY);
+       CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, sizeof(uint32_t));
+       CU_ASSERT_TRUE(tlv->flag_u_lsp_update_capability);
+       CU_ASSERT_TRUE(tlv->flag_s_include_db_version);
+       CU_ASSERT_TRUE(tlv->flag_i_lsp_instantiation_capability);
+       CU_ASSERT_TRUE(tlv->flag_t_triggered_resync);
+       CU_ASSERT_TRUE(tlv->flag_d_delta_lsp_sync);
+       CU_ASSERT_TRUE(tlv->flag_f_triggered_initial_sync);
+       CU_ASSERT_EQUAL(tlv->header.encoded_tlv[7], 0x3f);
+       /* TODO add a new function: verify_tlv_header(tlv->header.encoded_tlv)
+        * to all tests */
+
+       pcep_obj_free_tlv(&tlv->header);
+}
+
+void test_pcep_tlv_create_speaker_entity_id()
+{
+       struct pcep_object_tlv_speaker_entity_identifier *tlv =
+               pcep_tlv_create_speaker_entity_id(NULL);
+       CU_ASSERT_PTR_NULL(tlv);
+
+       double_linked_list *list = dll_initialize();
+       tlv = pcep_tlv_create_speaker_entity_id(list);
+       CU_ASSERT_PTR_NULL(tlv);
+       if (tlv != NULL) {
+               pceplib_free(PCEPLIB_INFRA, tlv);
+               tlv = NULL;
+       }
+
+       uint32_t *speaker_entity =
+               pceplib_malloc(PCEPLIB_MESSAGES, sizeof(uint32_t));
+       *speaker_entity = 42;
+       dll_append(list, speaker_entity);
+       tlv = pcep_tlv_create_speaker_entity_id(list);
+       CU_ASSERT_PTR_NOT_NULL(tlv);
+
+       pcep_encode_tlv(&tlv->header, versioning, tlv_buf);
+       CU_ASSERT_EQUAL(tlv->header.type, PCEP_OBJ_TLV_TYPE_SPEAKER_ENTITY_ID);
+       CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, sizeof(uint32_t));
+       CU_ASSERT_PTR_NOT_NULL(tlv->speaker_entity_id_list);
+       CU_ASSERT_EQUAL(tlv->speaker_entity_id_list->num_entries, 1);
+       uint32_t *uint32_ptr = (uint32_t *)tlv->header.encoded_tlv;
+       CU_ASSERT_EQUAL(uint32_ptr[1], htonl(*speaker_entity));
+
+       pcep_obj_free_tlv(&tlv->header);
+}
+
+void test_pcep_tlv_create_lsp_db_version()
+{
+       uint64_t lsp_db_version = 0xf005ba11ba5eba11;
+       struct pcep_object_tlv_lsp_db_version *tlv =
+               pcep_tlv_create_lsp_db_version(lsp_db_version);
+       CU_ASSERT_PTR_NOT_NULL(tlv);
+
+       pcep_encode_tlv(&tlv->header, versioning, tlv_buf);
+       CU_ASSERT_EQUAL(tlv->header.type, PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION);
+       CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, sizeof(uint64_t));
+       CU_ASSERT_EQUAL(tlv->lsp_db_version, lsp_db_version);
+       CU_ASSERT_EQUAL(*((uint64_t *)(tlv->header.encoded_tlv + 4)),
+                       be64toh(lsp_db_version));
+
+       pcep_obj_free_tlv(&tlv->header);
+}
+
+void test_pcep_tlv_create_path_setup_type()
+{
+       uint8_t pst = 0x89;
+
+       struct pcep_object_tlv_path_setup_type *tlv =
+               pcep_tlv_create_path_setup_type(pst);
+       CU_ASSERT_PTR_NOT_NULL(tlv);
+       pcep_encode_tlv(&tlv->header, versioning, tlv_buf);
+       CU_ASSERT_EQUAL(tlv->header.type, PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE);
+       CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, sizeof(uint32_t));
+       CU_ASSERT_EQUAL(tlv->path_setup_type, pst);
+       uint32_t *uint32_ptr = (uint32_t *)tlv->header.encoded_tlv;
+       CU_ASSERT_EQUAL(uint32_ptr[1], htonl(0x000000FF & pst));
+
+       pcep_obj_free_tlv(&tlv->header);
+}
+
+void test_pcep_tlv_create_path_setup_type_capability()
+{
+       /* The sub_tlv list is optional */
+
+       /* Should return NULL if pst_list is NULL */
+       struct pcep_object_tlv_path_setup_type_capability *tlv =
+               pcep_tlv_create_path_setup_type_capability(NULL, NULL);
+       CU_ASSERT_PTR_NULL(tlv);
+
+       /* Should return NULL if pst_list is empty */
+       double_linked_list *pst_list = dll_initialize();
+       tlv = pcep_tlv_create_path_setup_type_capability(pst_list, NULL);
+       CU_ASSERT_PTR_NULL(tlv);
+       if (tlv != NULL) {
+               pcep_obj_free_tlv(&tlv->header);
+               tlv = NULL;
+       }
+
+       /* Should still return NULL if pst_list is NULL */
+       double_linked_list *sub_tlv_list = dll_initialize();
+       tlv = pcep_tlv_create_path_setup_type_capability(NULL, sub_tlv_list);
+       CU_ASSERT_PTR_NULL(tlv);
+       if (tlv != NULL) {
+               pcep_obj_free_tlv(&tlv->header);
+               tlv = NULL;
+       }
+
+       /* Should still return NULL if pst_list is empty */
+       tlv = pcep_tlv_create_path_setup_type_capability(pst_list,
+                                                        sub_tlv_list);
+       CU_ASSERT_PTR_NULL(tlv);
+       if (tlv != NULL) {
+               pcep_obj_free_tlv(&tlv->header);
+               tlv = NULL;
+       }
+
+       /* Test only populating the pst list */
+       uint8_t *pst1 = pceplib_malloc(PCEPLIB_MESSAGES, 1);
+       uint8_t *pst2 = pceplib_malloc(PCEPLIB_MESSAGES, 1);
+       uint8_t *pst3 = pceplib_malloc(PCEPLIB_MESSAGES, 1);
+       *pst1 = 1;
+       *pst2 = 2;
+       *pst3 = 3;
+       dll_append(pst_list, pst1);
+       dll_append(pst_list, pst2);
+       dll_append(pst_list, pst3);
+       tlv = pcep_tlv_create_path_setup_type_capability(pst_list,
+                                                        sub_tlv_list);
+       CU_ASSERT_PTR_NOT_NULL(tlv);
+       if (tlv == NULL) {
+               CU_ASSERT_TRUE(tlv != NULL);
+               return;
+       }
+
+       pcep_encode_tlv(&tlv->header, versioning, tlv_buf);
+       CU_ASSERT_EQUAL(tlv->header.type,
+                       PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY);
+       CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, sizeof(uint32_t) * 2);
+       CU_ASSERT_PTR_NOT_NULL(tlv->pst_list);
+       CU_ASSERT_EQUAL(tlv->pst_list->num_entries, 3);
+       uint32_t *uint32_ptr = (uint32_t *)tlv->header.encoded_tlv;
+       CU_ASSERT_EQUAL(uint32_ptr[1], htonl(0x00000003));
+       CU_ASSERT_EQUAL(uint32_ptr[2], htonl(0x01020300));
+       pcep_obj_free_tlv(&tlv->header);
+
+       /* Now test populating both the pst_list and the sub_tlv_list */
+       reset_tlv_buffer();
+       struct pcep_object_tlv_header *sub_tlv =
+               (struct pcep_object_tlv_header *)
+                       pcep_tlv_create_sr_pce_capability(true, true, 0);
+       pst_list = dll_initialize();
+       sub_tlv_list = dll_initialize();
+       pst1 = pceplib_malloc(PCEPLIB_MESSAGES, 1);
+       *pst1 = 1;
+       dll_append(pst_list, pst1);
+       dll_append(sub_tlv_list, sub_tlv);
+       tlv = pcep_tlv_create_path_setup_type_capability(pst_list,
+                                                        sub_tlv_list);
+       CU_ASSERT_PTR_NOT_NULL(tlv);
+
+       pcep_encode_tlv(&tlv->header, versioning, tlv_buf);
+       CU_ASSERT_EQUAL(tlv->header.type,
+                       PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY);
+       CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length,
+                       sizeof(uint32_t) * 2 + TLV_HEADER_LENGTH
+                               + sub_tlv->encoded_tlv_length);
+       CU_ASSERT_PTR_NOT_NULL(tlv->pst_list);
+       CU_ASSERT_PTR_NOT_NULL(tlv->sub_tlv_list);
+       uint32_ptr = (uint32_t *)tlv->header.encoded_tlv;
+       uint16_t *uint16_ptr = (uint16_t *)tlv->header.encoded_tlv;
+       CU_ASSERT_EQUAL(uint16_ptr[0],
+                       htons(PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY));
+       CU_ASSERT_EQUAL(uint16_ptr[1], htons(tlv->header.encoded_tlv_length));
+       CU_ASSERT_EQUAL(uint32_ptr[1], htonl(0x00000001));
+       CU_ASSERT_EQUAL(uint32_ptr[2], htonl(0x01000000));
+       /* Verify the Sub-TLV */
+       uint16_ptr = (uint16_t *)(tlv->header.encoded_tlv + 12);
+       CU_ASSERT_EQUAL(uint16_ptr[0],
+                       htons(PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY));
+       CU_ASSERT_EQUAL(uint16_ptr[1], htons(4));
+       CU_ASSERT_EQUAL(uint16_ptr[2], 0);
+       CU_ASSERT_EQUAL(uint16_ptr[3], htons(0x0300));
+
+       pcep_obj_free_tlv(&tlv->header);
+}
+
+void test_pcep_tlv_create_sr_pce_capability()
+{
+       struct pcep_object_tlv_sr_pce_capability *tlv =
+               pcep_tlv_create_sr_pce_capability(true, true, 8);
+       CU_ASSERT_PTR_NOT_NULL(tlv);
+
+       pcep_encode_tlv(&tlv->header, versioning, tlv_buf);
+       CU_ASSERT_EQUAL(tlv->header.type, PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY);
+       CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, sizeof(uint32_t));
+       uint16_t *uint16_ptr = (uint16_t *)tlv->header.encoded_tlv;
+       CU_ASSERT_EQUAL(uint16_ptr[0],
+                       htons(PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY));
+       CU_ASSERT_EQUAL(uint16_ptr[1], htons(tlv->header.encoded_tlv_length));
+       uint32_t *uint32_ptr = (uint32_t *)tlv->header.encoded_tlv;
+       CU_ASSERT_EQUAL(uint32_ptr[1], htonl(0x00000308));
+
+       pcep_obj_free_tlv(&tlv->header);
+}
+
+void test_pcep_tlv_create_symbolic_path_name()
+{
+       /* char *symbolic_path_name, uint16_t symbolic_path_name_length); */
+       char path_name[16] = "Some Path Name";
+       uint16_t path_name_length = 14;
+       struct pcep_object_tlv_symbolic_path_name *tlv =
+               pcep_tlv_create_symbolic_path_name(path_name, path_name_length);
+       CU_ASSERT_PTR_NOT_NULL(tlv);
+
+       pcep_encode_tlv(&tlv->header, versioning, tlv_buf);
+       CU_ASSERT_EQUAL(tlv->header.type, PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME);
+       CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, path_name_length);
+       /* Test the padding is correct */
+       CU_ASSERT_EQUAL(0, strncmp((char *)&(tlv->header.encoded_tlv[4]),
+                                  &path_name[0], 4));
+       CU_ASSERT_EQUAL(0, strncmp((char *)&(tlv->header.encoded_tlv[8]),
+                                  &path_name[4], 4));
+       CU_ASSERT_EQUAL(0, strncmp((char *)&(tlv->header.encoded_tlv[12]),
+                                  &path_name[8], 4));
+       CU_ASSERT_EQUAL(tlv->header.encoded_tlv[16], 'm');
+       CU_ASSERT_EQUAL(tlv->header.encoded_tlv[17], 'e');
+       CU_ASSERT_EQUAL(tlv->header.encoded_tlv[18], 0);
+       CU_ASSERT_EQUAL(tlv->header.encoded_tlv[19], 0);
+       pcep_obj_free_tlv(&tlv->header);
+
+       reset_tlv_buffer();
+       tlv = pcep_tlv_create_symbolic_path_name(path_name, 3);
+       CU_ASSERT_PTR_NOT_NULL(tlv);
+       pcep_encode_tlv(&tlv->header, versioning, tlv_buf);
+       CU_ASSERT_EQUAL(tlv->header.type, PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME);
+       CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, 3);
+       CU_ASSERT_EQUAL(tlv->header.encoded_tlv[4], 'S');
+       CU_ASSERT_EQUAL(tlv->header.encoded_tlv[5], 'o');
+       CU_ASSERT_EQUAL(tlv->header.encoded_tlv[6], 'm');
+       CU_ASSERT_EQUAL(tlv->header.encoded_tlv[7], 0);
+
+       pcep_obj_free_tlv(&tlv->header);
+}
+
+void test_pcep_tlv_create_ipv4_lsp_identifiers()
+{
+       struct in_addr sender_ip, endpoint_ip;
+       uint16_t lsp_id = 7;
+       uint16_t tunnel_id = 16;
+       struct in_addr extended_tunnel_id;
+       extended_tunnel_id.s_addr = 256;
+       inet_pton(AF_INET, "192.168.1.1", &sender_ip);
+       inet_pton(AF_INET, "192.168.1.2", &endpoint_ip);
+
+       struct pcep_object_tlv_ipv4_lsp_identifier *tlv =
+               pcep_tlv_create_ipv4_lsp_identifiers(NULL, &endpoint_ip, lsp_id,
+                                                    tunnel_id,
+                                                    &extended_tunnel_id);
+       CU_ASSERT_PTR_NULL(tlv);
+
+       tlv = pcep_tlv_create_ipv4_lsp_identifiers(
+               &sender_ip, NULL, lsp_id, tunnel_id, &extended_tunnel_id);
+       CU_ASSERT_PTR_NULL(tlv);
+
+       tlv = pcep_tlv_create_ipv4_lsp_identifiers(
+               NULL, NULL, lsp_id, tunnel_id, &extended_tunnel_id);
+       CU_ASSERT_PTR_NULL(tlv);
+
+       tlv = pcep_tlv_create_ipv4_lsp_identifiers(&sender_ip, &endpoint_ip,
+                                                  lsp_id, tunnel_id,
+                                                  &extended_tunnel_id);
+       CU_ASSERT_PTR_NOT_NULL(tlv);
+
+       pcep_encode_tlv(&tlv->header, versioning, tlv_buf);
+       CU_ASSERT_EQUAL(tlv->header.type,
+                       PCEP_OBJ_TLV_TYPE_IPV4_LSP_IDENTIFIERS);
+       CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, sizeof(uint32_t) * 4);
+       uint32_t *uint32_ptr = (uint32_t *)tlv->header.encoded_tlv;
+       CU_ASSERT_EQUAL(uint32_ptr[1], sender_ip.s_addr);
+       CU_ASSERT_EQUAL(uint32_ptr[2],
+                       (uint32_t)(htons(tunnel_id) << 16) | htons(lsp_id));
+       CU_ASSERT_EQUAL(uint32_ptr[3], extended_tunnel_id.s_addr);
+       CU_ASSERT_EQUAL(uint32_ptr[4], endpoint_ip.s_addr);
+       pcep_obj_free_tlv(&tlv->header);
+
+       reset_tlv_buffer();
+       tlv = pcep_tlv_create_ipv4_lsp_identifiers(&sender_ip, &endpoint_ip,
+                                                  lsp_id, tunnel_id, NULL);
+       CU_ASSERT_PTR_NOT_NULL(tlv);
+
+       pcep_encode_tlv(&tlv->header, versioning, tlv_buf);
+       CU_ASSERT_EQUAL(tlv->header.type,
+                       PCEP_OBJ_TLV_TYPE_IPV4_LSP_IDENTIFIERS);
+       CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, sizeof(uint32_t) * 4);
+       uint32_ptr = (uint32_t *)tlv->header.encoded_tlv;
+       CU_ASSERT_EQUAL(uint32_ptr[1], sender_ip.s_addr);
+       CU_ASSERT_EQUAL(uint32_ptr[2],
+                       (uint32_t)(htons(tunnel_id) << 16) | htons(lsp_id));
+       CU_ASSERT_EQUAL(uint32_ptr[3], INADDR_ANY);
+       CU_ASSERT_EQUAL(uint32_ptr[4], endpoint_ip.s_addr);
+       pcep_obj_free_tlv(&tlv->header);
+}
+
+void test_pcep_tlv_create_ipv6_lsp_identifiers()
+{
+       struct in6_addr sender_ip, endpoint_ip;
+       uint16_t lsp_id = 3;
+       uint16_t tunnel_id = 16;
+       uint32_t extended_tunnel_id[4];
+
+       inet_pton(AF_INET6, "2001:db8::8a2e:370:7334", &sender_ip);
+       inet_pton(AF_INET6, "2001:db8::8a2e:370:8446", &endpoint_ip);
+       extended_tunnel_id[0] = 1;
+       extended_tunnel_id[1] = 2;
+       extended_tunnel_id[2] = 3;
+       extended_tunnel_id[3] = 4;
+
+       struct pcep_object_tlv_ipv6_lsp_identifier *tlv =
+               pcep_tlv_create_ipv6_lsp_identifiers(
+                       NULL, &endpoint_ip, lsp_id, tunnel_id,
+                       (struct in6_addr *)&extended_tunnel_id);
+       CU_ASSERT_PTR_NULL(tlv);
+
+       tlv = pcep_tlv_create_ipv6_lsp_identifiers(
+               &sender_ip, NULL, lsp_id, tunnel_id,
+               (struct in6_addr *)&extended_tunnel_id);
+       CU_ASSERT_PTR_NULL(tlv);
+
+       tlv = pcep_tlv_create_ipv6_lsp_identifiers(
+               NULL, NULL, lsp_id, tunnel_id,
+               (struct in6_addr *)&extended_tunnel_id);
+       CU_ASSERT_PTR_NULL(tlv);
+
+       tlv = pcep_tlv_create_ipv6_lsp_identifiers(
+               &sender_ip, &endpoint_ip, lsp_id, tunnel_id,
+               (struct in6_addr *)&extended_tunnel_id);
+       CU_ASSERT_PTR_NOT_NULL(tlv);
+
+       pcep_encode_tlv(&tlv->header, versioning, tlv_buf);
+       CU_ASSERT_EQUAL(tlv->header.type,
+                       PCEP_OBJ_TLV_TYPE_IPV6_LSP_IDENTIFIERS);
+       CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, 52);
+       uint32_t *uint32_ptr = (uint32_t *)tlv->header.encoded_tlv;
+       CU_ASSERT_EQUAL(uint32_ptr[5],
+                       (uint32_t)(htons(tunnel_id) << 16) | htons(lsp_id));
+
+       pcep_obj_free_tlv(&tlv->header);
+}
+void test_pcep_tlv_create_srpag_pol_id_ipv4()
+{
+       uint32_t color = 1;
+       struct in_addr src;
+       inet_pton(AF_INET, "192.168.1.2", &src);
+
+       struct pcep_object_tlv_srpag_pol_id *tlv =
+               pcep_tlv_create_srpag_pol_id_ipv4(color, (void *)&src);
+       CU_ASSERT_PTR_NOT_NULL(tlv);
+
+       pcep_encode_tlv(&tlv->header, versioning, tlv_buf);
+       CU_ASSERT_EQUAL(tlv->header.type, (PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_ID));
+       CU_ASSERT_EQUAL(
+               tlv->header.encoded_tlv_length,
+               (8 /*draft-barth-pce-segment-routing-policy-cp-04#5.1*/));
+       CU_ASSERT_EQUAL(tlv->color, (color));
+       uint32_t aux_color = htonl(color); // Is color right encoded
+       CU_ASSERT_EQUAL(0, memcmp(&tlv_buf[0] + TLV_HEADER_LENGTH, &aux_color,
+                                 sizeof(color)));
+       CU_ASSERT_EQUAL(tlv->end_point.ipv4.s_addr, (src.s_addr));
+       // Are simetrical?
+       struct pcep_object_tlv_header *dec_hdr = pcep_decode_tlv(tlv_buf);
+       struct pcep_object_tlv_srpag_pol_id *dec_tlv =
+               (struct pcep_object_tlv_srpag_pol_id *)dec_hdr;
+       CU_ASSERT_EQUAL(tlv->color, dec_tlv->color);
+
+       pceplib_free(PCEPLIB_MESSAGES, dec_hdr);
+       pcep_obj_free_tlv(&tlv->header);
+}
+void test_pcep_tlv_create_srpag_pol_id_ipv6()
+{
+
+       uint32_t color = 1;
+       struct in6_addr src;
+       inet_pton(AF_INET6, "2001:db8::8a2e:370:7334", &src);
+
+       struct pcep_object_tlv_srpag_pol_id *tlv =
+               pcep_tlv_create_srpag_pol_id_ipv6(color, &src);
+
+       pcep_encode_tlv(&tlv->header, versioning, tlv_buf);
+       CU_ASSERT_EQUAL(tlv->header.type, (PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_ID));
+       CU_ASSERT_EQUAL(
+               tlv->header.encoded_tlv_length,
+               (20 /*draft-barth-pce-segment-routing-policy-cp-04#5.1*/));
+       CU_ASSERT_EQUAL(tlv->color, (color));
+       CU_ASSERT_EQUAL(0, memcmp(&tlv->end_point.ipv6, &src, sizeof(src)));
+
+       uint32_t aux_color = htonl(color);
+       CU_ASSERT_EQUAL(0, memcmp(&aux_color, tlv_buf + TLV_HEADER_LENGTH,
+                                 sizeof(tlv->color)));
+       // Are simetrical?
+       struct pcep_object_tlv_header *dec_hdr = pcep_decode_tlv(tlv_buf);
+       struct pcep_object_tlv_srpag_pol_id *dec_tlv =
+               (struct pcep_object_tlv_srpag_pol_id *)dec_hdr;
+       CU_ASSERT_EQUAL(tlv->color, dec_tlv->color);
+
+       pceplib_free(PCEPLIB_MESSAGES, dec_hdr);
+       pcep_obj_free_tlv(&tlv->header);
+}
+void test_pcep_tlv_create_srpag_pol_name()
+{
+       const char *pol_name = "Some Pol  Name";
+
+       struct pcep_object_tlv_srpag_pol_name *tlv =
+               pcep_tlv_create_srpag_pol_name(pol_name, strlen(pol_name));
+       CU_ASSERT_PTR_NOT_NULL(tlv);
+
+       pcep_encode_tlv(&tlv->header, versioning, tlv_buf);
+       CU_ASSERT_EQUAL(tlv->header.type,
+                       (PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_NAME));
+       CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length,
+                       (normalize_pcep_tlv_length(strlen(pol_name))));
+       CU_ASSERT_EQUAL(0, strcmp(pol_name, (char *)tlv->name));
+
+
+       pcep_obj_free_tlv(&tlv->header);
+}
+
+void test_pcep_tlv_create_srpag_cp_id()
+{
+       // draft-ietf-spring-segment-routing-policy-06.pdf#2.3
+       // 10 PCEP, 20 BGP SR Policy, 30 Via Configuration
+       uint8_t proto_origin = 10;
+       uint32_t ASN = 0;
+       struct in6_addr with_mapped_ipv4;
+       inet_pton(AF_INET6, "::ffff:192.0.2.128", &with_mapped_ipv4);
+       uint32_t discriminator = 0;
+
+       struct pcep_object_tlv_srpag_cp_id *tlv = pcep_tlv_create_srpag_cp_id(
+               proto_origin, ASN, &with_mapped_ipv4, discriminator);
+
+       pcep_encode_tlv(&tlv->header, versioning, tlv_buf);
+       CU_ASSERT_EQUAL(tlv->header.type,
+                       (PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_ID));
+       CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length,
+                       (sizeof(proto_origin) + sizeof(ASN)
+                        + sizeof(with_mapped_ipv4) + sizeof(discriminator)));
+       CU_ASSERT_EQUAL(tlv->proto, (proto_origin));
+       CU_ASSERT_EQUAL(tlv->orig_asn, (ASN));
+       CU_ASSERT_EQUAL(0, memcmp(&tlv->orig_addres, &with_mapped_ipv4,
+                                 sizeof(with_mapped_ipv4)));
+       CU_ASSERT_EQUAL(tlv->discriminator, (discriminator));
+       // Are simetrical?
+       struct pcep_object_tlv_header *dec_hdr = pcep_decode_tlv(tlv_buf);
+       struct pcep_object_tlv_srpag_cp_id *dec_tlv =
+               (struct pcep_object_tlv_srpag_cp_id *)dec_hdr;
+       CU_ASSERT_EQUAL(tlv->proto, dec_tlv->proto);
+
+       pceplib_free(PCEPLIB_MESSAGES, dec_hdr);
+       pcep_obj_free_tlv(&tlv->header);
+}
+
+void test_pcep_tlv_create_srpag_cp_pref()
+{
+       uint32_t preference_default = 100;
+
+       struct pcep_object_tlv_srpag_cp_pref *tlv =
+               pcep_tlv_create_srpag_cp_pref(preference_default);
+       CU_ASSERT_PTR_NOT_NULL(tlv);
+
+       pcep_encode_tlv(&tlv->header, versioning, tlv_buf);
+       CU_ASSERT_EQUAL(tlv->header.type,
+                       (PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_PREFERENCE));
+       printf(" encoded length vs sizeof pref (%d) vs (%ld)\n",
+              tlv->header.encoded_tlv_length, sizeof(preference_default));
+       CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length,
+                       sizeof(preference_default));
+       CU_ASSERT_EQUAL(tlv->preference, (preference_default));
+       uint32_t aux_pref = htonl(preference_default); // Is pref right encoded
+       CU_ASSERT_EQUAL(0, memcmp(tlv_buf + TLV_HEADER_LENGTH, &aux_pref,
+                                 sizeof(preference_default)));
+       // Are simetrical?
+       struct pcep_object_tlv_header *dec_hdr = pcep_decode_tlv(tlv_buf);
+       struct pcep_object_tlv_srpag_cp_pref *dec_tlv =
+               (struct pcep_object_tlv_srpag_cp_pref *)dec_hdr;
+       CU_ASSERT_EQUAL(tlv->preference, dec_tlv->preference);
+
+       pceplib_free(PCEPLIB_MESSAGES, dec_hdr);
+       pcep_obj_free_tlv(&tlv->header);
+}
+void test_pcep_tlv_create_lsp_error_code()
+{
+       struct pcep_object_tlv_lsp_error_code *tlv =
+               pcep_tlv_create_lsp_error_code(
+                       PCEP_TLV_LSP_ERROR_CODE_RSVP_SIGNALING_ERROR);
+       CU_ASSERT_PTR_NOT_NULL(tlv);
+
+       pcep_encode_tlv(&tlv->header, versioning, tlv_buf);
+       CU_ASSERT_EQUAL(tlv->header.type, PCEP_OBJ_TLV_TYPE_LSP_ERROR_CODE);
+       CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, sizeof(uint32_t));
+       uint32_t *uint32_ptr = (uint32_t *)tlv->header.encoded_tlv;
+       CU_ASSERT_EQUAL(uint32_ptr[1],
+                       htonl(PCEP_TLV_LSP_ERROR_CODE_RSVP_SIGNALING_ERROR));
+
+       pcep_obj_free_tlv(&tlv->header);
+}
+
+void test_pcep_tlv_create_rsvp_ipv4_error_spec()
+{
+       struct in_addr error_node_ip;
+       inet_pton(AF_INET, "192.168.1.1", &error_node_ip);
+       uint8_t error_code = 8;
+       uint16_t error_value = 0xaabb;
+
+       struct pcep_object_tlv_rsvp_error_spec *tlv =
+               pcep_tlv_create_rsvp_ipv4_error_spec(NULL, error_code,
+                                                    error_value);
+       CU_ASSERT_PTR_NULL(tlv);
+
+       tlv = pcep_tlv_create_rsvp_ipv4_error_spec(&error_node_ip, error_code,
+                                                  error_value);
+       CU_ASSERT_PTR_NOT_NULL(tlv);
+
+       pcep_encode_tlv(&tlv->header, versioning, tlv_buf);
+       CU_ASSERT_EQUAL(tlv->header.type, PCEP_OBJ_TLV_TYPE_RSVP_ERROR_SPEC);
+       CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, 12);
+
+       pcep_obj_free_tlv(&tlv->header);
+}
+
+void test_pcep_tlv_create_rsvp_ipv6_error_spec()
+{
+       struct in6_addr error_node_ip;
+       inet_pton(AF_INET6, "2001:db8::8a2e:370:7334", &error_node_ip);
+       uint8_t error_code = 8;
+       uint16_t error_value = 0xaabb;
+
+       struct pcep_object_tlv_rsvp_error_spec *tlv =
+               pcep_tlv_create_rsvp_ipv6_error_spec(NULL, error_code,
+                                                    error_value);
+       CU_ASSERT_PTR_NULL(tlv);
+
+       tlv = pcep_tlv_create_rsvp_ipv6_error_spec(&error_node_ip, error_code,
+                                                  error_value);
+       CU_ASSERT_PTR_NOT_NULL(tlv);
+
+       pcep_encode_tlv(&tlv->header, versioning, tlv_buf);
+       CU_ASSERT_EQUAL(tlv->header.type, PCEP_OBJ_TLV_TYPE_RSVP_ERROR_SPEC);
+       CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, 24);
+
+       pcep_obj_free_tlv(&tlv->header);
+}
+
+void test_pcep_tlv_create_nopath_vector()
+{
+       uint32_t enterprise_number = 0x01020304;
+       uint32_t enterprise_specific_info = 0x05060708;
+
+       struct pcep_object_tlv_vendor_info *tlv = pcep_tlv_create_vendor_info(
+               enterprise_number, enterprise_specific_info);
+       CU_ASSERT_PTR_NOT_NULL(tlv);
+
+       pcep_encode_tlv(&tlv->header, versioning, tlv_buf);
+       CU_ASSERT_EQUAL(tlv->header.type, PCEP_OBJ_TLV_TYPE_VENDOR_INFO);
+       CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, 8);
+       uint32_t *uint32_ptr = (uint32_t *)tlv->header.encoded_tlv;
+       CU_ASSERT_EQUAL(uint32_ptr[1], htonl(enterprise_number));
+       CU_ASSERT_EQUAL(uint32_ptr[2], htonl(enterprise_specific_info));
+
+       pcep_obj_free_tlv(&tlv->header);
+}
+
+void test_pcep_tlv_create_arbitrary()
+{
+       char data[16] = "Some Data";
+       uint16_t data_length = 9;
+       uint16_t tlv_id_unknown = 1; // 65505; // Whatever id to be created
+       struct pcep_object_tlv_arbitrary *tlv = pcep_tlv_create_tlv_arbitrary(
+               data, data_length, tlv_id_unknown);
+       CU_ASSERT_PTR_NOT_NULL(tlv);
+
+       pcep_encode_tlv(&tlv->header, versioning, tlv_buf);
+       CU_ASSERT_EQUAL(tlv->header.type, tlv_id_unknown);
+       CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, data_length);
+       /* Test the padding is correct */
+       CU_ASSERT_EQUAL(
+               0, strncmp((char *)&(tlv->header.encoded_tlv[4]), &data[0], 4));
+       CU_ASSERT_EQUAL(
+               0, strncmp((char *)&(tlv->header.encoded_tlv[8]), &data[4], 4));
+       CU_ASSERT_EQUAL(tlv->header.encoded_tlv[11], 't');
+       CU_ASSERT_EQUAL(tlv->header.encoded_tlv[12], 'a');
+       CU_ASSERT_EQUAL(tlv->header.encoded_tlv[13], 0);
+       CU_ASSERT_EQUAL(tlv->header.encoded_tlv[14], 0);
+       pcep_obj_free_tlv(&tlv->header);
+
+       reset_tlv_buffer();
+       tlv = pcep_tlv_create_tlv_arbitrary(data, 3, tlv_id_unknown);
+       CU_ASSERT_PTR_NOT_NULL(tlv);
+       pcep_encode_tlv(&tlv->header, versioning, tlv_buf);
+       CU_ASSERT_EQUAL(tlv->header.type, tlv_id_unknown);
+       CU_ASSERT_EQUAL(tlv->header.encoded_tlv_length, 3);
+       CU_ASSERT_EQUAL(tlv->header.encoded_tlv[4], 'S');
+       CU_ASSERT_EQUAL(tlv->header.encoded_tlv[5], 'o');
+       CU_ASSERT_EQUAL(tlv->header.encoded_tlv[6], 'm');
+       CU_ASSERT_EQUAL(tlv->header.encoded_tlv[7], 0);
+
+       pcep_obj_free_tlv(&tlv->header);
+}
diff --git a/pceplib/test/pcep_msg_tlvs_test.h b/pceplib/test/pcep_msg_tlvs_test.h
new file mode 100644 (file)
index 0000000..a961d7e
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Javier Garcia <javier.garcia@voltanet.io>
+ *
+ */
+
+#ifndef PCEP_MSG_TLVS_TEST_H_
+#define PCEP_MSG_TLVS_TEST_H_
+
+int pcep_tlvs_test_suite_setup(void);
+int pcep_tlvs_test_suite_teardown(void);
+void pcep_tlvs_test_setup(void);
+void pcep_tlvs_test_teardown(void);
+void test_pcep_tlv_create_stateful_pce_capability(void);
+void test_pcep_tlv_create_speaker_entity_id(void);
+void test_pcep_tlv_create_lsp_db_version(void);
+void test_pcep_tlv_create_path_setup_type(void);
+void test_pcep_tlv_create_path_setup_type_capability(void);
+void test_pcep_tlv_create_sr_pce_capability(void);
+void test_pcep_tlv_create_symbolic_path_name(void);
+void test_pcep_tlv_create_ipv4_lsp_identifiers(void);
+void test_pcep_tlv_create_ipv6_lsp_identifiers(void);
+void test_pcep_tlv_create_lsp_error_code(void);
+void test_pcep_tlv_create_rsvp_ipv4_error_spec(void);
+void test_pcep_tlv_create_rsvp_ipv6_error_spec(void);
+void test_pcep_tlv_create_srpag_pol_id_ipv4(void);
+void test_pcep_tlv_create_srpag_pol_id_ipv6(void);
+void test_pcep_tlv_create_srpag_pol_name(void);
+void test_pcep_tlv_create_srpag_cp_id(void);
+void test_pcep_tlv_create_srpag_cp_pref(void);
+void test_pcep_tlv_create_nopath_vector(void);
+void test_pcep_tlv_create_arbitrary(void);
+
+
+#endif
diff --git a/pceplib/test/pcep_msg_tools_test.c b/pceplib/test/pcep_msg_tools_test.c
new file mode 100644 (file)
index 0000000..ff5fc62
--- /dev/null
@@ -0,0 +1,1305 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+
+#include <CUnit/CUnit.h>
+
+#include "pcep_msg_encoding.h"
+#include "pcep_msg_messages.h"
+#include "pcep_msg_tools.h"
+#include "pcep_msg_tools_test.h"
+#include "pcep_utils_double_linked_list.h"
+#include "pcep_utils_logging.h"
+#include "pcep_utils_memory.h"
+
+const uint8_t any_obj_class = 255;
+
+uint16_t pcep_open_hexbyte_strs_length = 28;
+const char *pcep_open_odl_hexbyte_strs[] = {
+       "20", "01", "00", "1c", "01", "10", "00", "18", "20", "1e",
+       "78", "55", "00", "10", "00", "04", "00", "00", "00", "3f",
+       "00", "1a", "00", "04", "00", "00", "00", "00"};
+
+/* PCEP INITIATE str received from ODL with 4 objects: [SRP, LSP, Endpoints,
+ * ERO] The LSP has a SYMBOLIC_PATH_NAME TLV. The ERO has 2 IPV4 Endpoints. */
+uint16_t pcep_initiate_hexbyte_strs_length = 68;
+const char *pcep_initiate_hexbyte_strs[] = {
+       "20", "0c", "00", "44", "21", "12", "00", "0c", "00", "00", "00", "00",
+       "00", "00", "00", "01", "20", "10", "00", "14", "00", "00", "00", "09",
+       "00", "11", "00", "08", "66", "61", "39", "33", "33", "39", "32", "39",
+       "04", "10", "00", "0c", "7f", "00", "00", "01", "28", "28", "28", "28",
+       "07", "10", "00", "14", "01", "08", "0a", "00", "01", "01", "18", "00",
+       "01", "08", "0a", "00", "07", "04", "18", "00"};
+
+uint16_t pcep_initiate2_hexbyte_strs_length = 72;
+const char *pcep_initiate2_hexbyte_strs[] = {
+       "20", "0c", "00", "48", "21", "12", "00", "14", "00", "00", "00", "00",
+       "00", "00", "00", "01", "00", "1c", "00", "04", "00", "00", "00", "01",
+       "20", "10", "00", "14", "00", "00", "00", "09", "00", "11", "00", "08",
+       "36", "65", "31", "31", "38", "39", "32", "31", "04", "10", "00", "0c",
+       "c0", "a8", "14", "05", "01", "01", "01", "01", "07", "10", "00", "10",
+       "05", "0c", "10", "01", "03", "e8", "a0", "00", "01", "01", "01", "01"};
+
+uint16_t pcep_update_hexbyte_strs_length = 48;
+const char *pcep_update_hexbyte_strs[] = {
+       "20", "0b", "00", "30", "21", "12", "00", "14", "00", "00", "00", "00",
+       "00", "00", "00", "01", "00", "1c", "00", "04", "00", "00", "00", "01",
+       "20", "10", "00", "08", "00", "02", "a0", "09", "07", "10", "00", "10",
+       "05", "0c", "10", "01", "03", "e8", "a0", "00", "01", "01", "01", "01"};
+
+/* Test that pcep_msg_read() can read multiple messages in 1 call */
+uint16_t pcep_open_initiate_hexbyte_strs_length = 100;
+const char *pcep_open_initiate_odl_hexbyte_strs[] = {
+       "20", "01", "00", "1c", "01", "10", "00", "18", "20", "1e", "78", "55",
+       "00", "10", "00", "04", "00", "00", "00", "3f", "00", "1a", "00", "04",
+       "00", "00", "00", "00", "20", "0c", "00", "48", "21", "12", "00", "14",
+       "00", "00", "00", "00", "00", "00", "00", "01", "00", "1c", "00", "04",
+       "00", "00", "00", "01", "20", "10", "00", "14", "00", "00", "00", "09",
+       "00", "11", "00", "08", "36", "65", "31", "31", "38", "39", "32", "31",
+       "04", "10", "00", "0c", "c0", "a8", "14", "05", "01", "01", "01", "01",
+       "07", "10", "00", "10", "05", "0c", "10", "01", "03", "e8", "a0", "00",
+       "01", "01", "01", "01"};
+
+uint16_t pcep_open_cisco_pce_hexbyte_strs_length = 28;
+const char *pcep_open_cisco_pce_hexbyte_strs[] = {
+       "20", "01", "00", "1c", "01", "10", "00", "18", "20", "3c",
+       "78", "00", "00", "10", "00", "04", "00", "00", "00", "05",
+       "00", "1a", "00", "04", "00", "00", "00", "0a"};
+
+uint16_t pcep_update_cisco_pce_hexbyte_strs_length = 100;
+const char *pcep_update_cisco_pce_hexbyte_strs[] = {
+       "20", "0b", "00", "64", "21", "10", "00", "14", "00", "00", "00", "00",
+       "00", "00", "00", "01", "00", "1c", "00", "04", "00", "00", "00", "01",
+       "20", "10", "00", "18", "80", "00", "f0", "89", "00", "07", "00", "0c",
+       "00", "00", "00", "09", "00", "03", "00", "04", "00", "00", "00", "01",
+       "07", "10", "00", "28", "24", "0c", "10", "01", "04", "65", "50", "00",
+       "0a", "0a", "0a", "05", "24", "0c", "10", "01", "04", "65", "20", "00",
+       "0a", "0a", "0a", "02", "24", "0c", "10", "01", "04", "65", "10", "00",
+       "0a", "0a", "0a", "01", "06", "10", "00", "0c", "00", "00", "00", "02",
+       "41", "f0", "00", "00"};
+
+uint16_t pcep_report_cisco_pcc_hexbyte_strs_length = 148;
+const char *pcep_report_cisco_pcc_hexbyte_strs[] = {
+       "20", "0a", "00", "94", "21", "10", "00", "14", "00", "00", "00", "00",
+       "00", "00", "00", "00", "00", "1c", "00", "04", "00", "00", "00", "01",
+       "20", "10", "00", "3c", "80", "00", "f0", "09", "00", "12", "00", "10",
+       "0a", "0a", "0a", "06", "00", "02", "00", "0f", "0a", "0a", "0a", "06",
+       "0a", "0a", "0a", "01", "00", "11", "00", "0d", "63", "66", "67", "5f",
+       "52", "36", "2d", "74", "6f", "2d", "52", "31", "00", "00", "00", "00",
+       "ff", "e1", "00", "06", "00", "00", "05", "dd", "70", "00", "00", "00",
+       "07", "10", "00", "04", "09", "10", "00", "14", "00", "00", "00", "00",
+       "00", "00", "00", "00", "00", "00", "00", "00", "07", "07", "01", "00",
+       "05", "12", "00", "08", "00", "00", "00", "00", "05", "52", "00", "08",
+       "00", "00", "00", "00", "06", "10", "00", "0c", "00", "00", "00", "02",
+       "00", "00", "00", "00", "06", "10", "00", "0c", "00", "00", "01", "04",
+       "41", "80", "00", "00"};
+
+/* Cisco PcInitiate with the following objects:
+ *   SRP, LSP, Endpoint, Inter-layer, Switch-layer, ERO
+ */
+uint16_t pcep_initiate_cisco_pcc_hexbyte_strs_length = 104;
+const char *pcep_initiate_cisco_pcc_hexbyte_strs[] = {
+       "20", "0c", "00", "68", "21", "10", "00", "14", "00", "00", "00", "00",
+       "00", "00", "00", "01", "00", "1c", "00", "04", "00", "00", "00", "01",
+       "20", "10", "00", "30", "00", "00", "00", "89", "00", "11", "00", "13",
+       "50", "4f", "4c", "31", "5f", "50", "43", "49", "4e", "49", "54", "41",
+       "54", "45", "5f", "54", "45", "53", "54", "00", "00", "07", "00", "0c",
+       "00", "00", "00", "09", "00", "03", "00", "04", "00", "00", "00", "01",
+       "04", "10", "00", "0c", "0a", "0a", "0a", "0a", "0a", "0a", "0a", "04",
+       "24", "10", "00", "08", "00", "00", "01", "4d", "25", "10", "00", "08",
+       "00", "00", "00", "64", "07", "10", "00", "04"};
+
+struct pcep_message *create_message(uint8_t msg_type, uint8_t obj1_class,
+                                   uint8_t obj2_class, uint8_t obj3_class,
+                                   uint8_t obj4_class);
+int convert_hexstrs_to_binary(const char *hexbyte_strs[],
+                             uint16_t hexbyte_strs_length);
+
+int pcep_tools_test_suite_setup(void)
+{
+       pceplib_memory_reset();
+       return 0;
+}
+
+int pcep_tools_test_suite_teardown(void)
+{
+       printf("\n");
+       pceplib_memory_dump();
+       return 0;
+}
+
+void pcep_tools_test_setup(void)
+{
+}
+
+void pcep_tools_test_teardown(void)
+{
+}
+
+/* Reads an array of hexbyte strs, and writes them to a temporary file.
+ * The caller should close the returned file. */
+int convert_hexstrs_to_binary(const char *hexbyte_strs[],
+                             uint16_t hexbyte_strs_length)
+{
+       mode_t oldumask;
+       oldumask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH);
+       /* Set umask before anything for security */
+       umask(0027);
+       char tmpfile[] = "/tmp/pceplib_XXXXXX";
+       int fd = mkstemp(tmpfile);
+       umask(oldumask);
+       if (fd == -1)
+               return -1;
+
+       int i = 0;
+       for (; i < hexbyte_strs_length; i++) {
+               uint8_t byte = (uint8_t)strtol(hexbyte_strs[i], 0, 16);
+               if (write(fd, (char *)&byte, 1) < 0) {
+                       return -1;
+               }
+       }
+
+       /* Go back to the beginning of the file */
+       lseek(fd, 0, SEEK_SET);
+       return fd;
+}
+
+static bool pcep_obj_has_tlv(struct pcep_object_header *obj_hdr)
+{
+       if (obj_hdr->tlv_list == NULL) {
+               return false;
+       }
+
+       return (obj_hdr->tlv_list->num_entries > 0);
+}
+
+void test_pcep_msg_read_pcep_initiate()
+{
+       int fd = convert_hexstrs_to_binary(pcep_initiate_hexbyte_strs,
+                                          pcep_initiate_hexbyte_strs_length);
+       if(fd == -1){
+               CU_ASSERT_TRUE(fd>=0);
+               return;
+       }
+       double_linked_list *msg_list = pcep_msg_read(fd);
+       CU_ASSERT_PTR_NOT_NULL(msg_list);
+       CU_ASSERT_EQUAL(msg_list->num_entries, 1);
+
+       struct pcep_message *msg = (struct pcep_message *)msg_list->head->data;
+       CU_ASSERT_EQUAL(msg->obj_list->num_entries, 4);
+       CU_ASSERT_EQUAL(msg->msg_header->type, PCEP_TYPE_INITIATE);
+       CU_ASSERT_EQUAL(msg->encoded_message_length,
+                       pcep_initiate_hexbyte_strs_length);
+
+       /* Verify each of the object types */
+
+       /* SRP object */
+       double_linked_list_node *node = msg->obj_list->head;
+       struct pcep_object_header *obj_hdr =
+               (struct pcep_object_header *)node->data;
+       CU_ASSERT_EQUAL(obj_hdr->object_class, PCEP_OBJ_CLASS_SRP);
+       CU_ASSERT_EQUAL(obj_hdr->object_type, PCEP_OBJ_TYPE_SRP);
+       CU_ASSERT_EQUAL(obj_hdr->encoded_object_length,
+                       pcep_object_get_length_by_hdr(obj_hdr));
+       CU_ASSERT_FALSE(pcep_obj_has_tlv(obj_hdr));
+
+       /* LSP object and its TLV*/
+       node = node->next_node;
+       obj_hdr = (struct pcep_object_header *)node->data;
+       CU_ASSERT_EQUAL(obj_hdr->object_class, PCEP_OBJ_CLASS_LSP);
+       CU_ASSERT_EQUAL(obj_hdr->object_type, PCEP_OBJ_TYPE_LSP);
+       CU_ASSERT_EQUAL(obj_hdr->encoded_object_length, 20);
+       CU_ASSERT_EQUAL(((struct pcep_object_lsp *)obj_hdr)->plsp_id, 0);
+       CU_ASSERT_TRUE(((struct pcep_object_lsp *)obj_hdr)->flag_d);
+       CU_ASSERT_TRUE(((struct pcep_object_lsp *)obj_hdr)->flag_a);
+       CU_ASSERT_FALSE(((struct pcep_object_lsp *)obj_hdr)->flag_s);
+       CU_ASSERT_FALSE(((struct pcep_object_lsp *)obj_hdr)->flag_r);
+       CU_ASSERT_FALSE(((struct pcep_object_lsp *)obj_hdr)->flag_c);
+
+       /* LSP TLV */
+       CU_ASSERT_TRUE(pcep_obj_has_tlv(obj_hdr));
+       CU_ASSERT_EQUAL(obj_hdr->tlv_list->num_entries, 1);
+       struct pcep_object_tlv_header *tlv =
+               (struct pcep_object_tlv_header *)obj_hdr->tlv_list->head->data;
+       CU_ASSERT_EQUAL(tlv->type, PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME);
+       CU_ASSERT_EQUAL(tlv->encoded_tlv_length, 8);
+
+       /* Endpoints object */
+       node = node->next_node;
+       obj_hdr = (struct pcep_object_header *)node->data;
+       CU_ASSERT_EQUAL(obj_hdr->object_class, PCEP_OBJ_CLASS_ENDPOINTS);
+       CU_ASSERT_EQUAL(obj_hdr->object_type, PCEP_OBJ_TYPE_ENDPOINT_IPV4);
+       CU_ASSERT_EQUAL(obj_hdr->encoded_object_length,
+                       pcep_object_get_length_by_hdr(obj_hdr));
+       CU_ASSERT_FALSE(pcep_obj_has_tlv(obj_hdr));
+
+       /* ERO object */
+       node = node->next_node;
+       obj_hdr = (struct pcep_object_header *)node->data;
+       CU_ASSERT_EQUAL(obj_hdr->object_class, PCEP_OBJ_CLASS_ERO);
+       CU_ASSERT_EQUAL(obj_hdr->object_type, PCEP_OBJ_TYPE_ERO);
+       CU_ASSERT_EQUAL(obj_hdr->encoded_object_length, 20);
+
+       /* ERO Subobjects */
+       double_linked_list *ero_subobj_list =
+               ((struct pcep_object_ro *)obj_hdr)->sub_objects;
+       CU_ASSERT_PTR_NOT_NULL(ero_subobj_list);
+       CU_ASSERT_EQUAL(ero_subobj_list->num_entries, 2);
+       double_linked_list_node *subobj_node = ero_subobj_list->head;
+       struct pcep_object_ro_subobj *subobj_hdr =
+               (struct pcep_object_ro_subobj *)subobj_node->data;
+       CU_ASSERT_EQUAL(subobj_hdr->ro_subobj_type, RO_SUBOBJ_TYPE_IPV4);
+       struct in_addr ero_subobj_ip;
+       inet_pton(AF_INET, "10.0.1.1", &ero_subobj_ip);
+       CU_ASSERT_EQUAL(
+               ((struct pcep_ro_subobj_ipv4 *)subobj_hdr)->ip_addr.s_addr,
+               ero_subobj_ip.s_addr);
+       CU_ASSERT_EQUAL(
+               ((struct pcep_ro_subobj_ipv4 *)subobj_hdr)->prefix_length, 24);
+
+       subobj_hdr =
+               (struct pcep_object_ro_subobj *)subobj_node->next_node->data;
+       CU_ASSERT_EQUAL(subobj_hdr->ro_subobj_type, RO_SUBOBJ_TYPE_IPV4);
+       inet_pton(AF_INET, "10.0.7.4", &ero_subobj_ip);
+       CU_ASSERT_EQUAL(
+               ((struct pcep_ro_subobj_ipv4 *)subobj_hdr)->ip_addr.s_addr,
+               ero_subobj_ip.s_addr);
+       CU_ASSERT_EQUAL(
+               ((struct pcep_ro_subobj_ipv4 *)subobj_hdr)->prefix_length, 24);
+
+       pcep_msg_free_message_list(msg_list);
+       close(fd);
+}
+
+
+void test_pcep_msg_read_pcep_initiate2()
+{
+       int fd = convert_hexstrs_to_binary(pcep_initiate2_hexbyte_strs,
+                                          pcep_initiate2_hexbyte_strs_length);
+       if(fd == -1){
+               CU_ASSERT_TRUE(fd>=0);
+               return;
+       }
+       double_linked_list *msg_list = pcep_msg_read(fd);
+       CU_ASSERT_PTR_NOT_NULL(msg_list);
+       CU_ASSERT_EQUAL(msg_list->num_entries, 1);
+
+       struct pcep_message *msg = (struct pcep_message *)msg_list->head->data;
+       CU_ASSERT_EQUAL(msg->obj_list->num_entries, 4);
+       CU_ASSERT_EQUAL(msg->msg_header->type, PCEP_TYPE_INITIATE);
+       CU_ASSERT_EQUAL(msg->encoded_message_length,
+                       pcep_initiate2_hexbyte_strs_length);
+
+       /* Verify each of the object types */
+
+       /* SRP object */
+       double_linked_list_node *node = msg->obj_list->head;
+       struct pcep_object_header *obj_hdr =
+               (struct pcep_object_header *)node->data;
+       CU_ASSERT_EQUAL(obj_hdr->object_class, PCEP_OBJ_CLASS_SRP);
+       CU_ASSERT_EQUAL(obj_hdr->object_type, PCEP_OBJ_TYPE_SRP);
+       CU_ASSERT_EQUAL(obj_hdr->encoded_object_length, 20);
+       CU_ASSERT_TRUE(pcep_obj_has_tlv(obj_hdr));
+       /* TODO test the TLVs */
+
+       /* LSP object and its TLV*/
+       node = node->next_node;
+       obj_hdr = (struct pcep_object_header *)node->data;
+       CU_ASSERT_EQUAL(obj_hdr->object_class, PCEP_OBJ_CLASS_LSP);
+       CU_ASSERT_EQUAL(obj_hdr->object_type, PCEP_OBJ_TYPE_LSP);
+       CU_ASSERT_EQUAL(obj_hdr->encoded_object_length, 20);
+
+       /* LSP TLV */
+       CU_ASSERT_TRUE(pcep_obj_has_tlv(obj_hdr));
+       CU_ASSERT_EQUAL(obj_hdr->tlv_list->num_entries, 1);
+       struct pcep_object_tlv_header *tlv =
+               (struct pcep_object_tlv_header *)obj_hdr->tlv_list->head->data;
+       CU_ASSERT_EQUAL(tlv->type, PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME);
+       CU_ASSERT_EQUAL(tlv->encoded_tlv_length, 8);
+
+       /* Endpoints object */
+       node = node->next_node;
+       obj_hdr = (struct pcep_object_header *)node->data;
+       CU_ASSERT_EQUAL(obj_hdr->object_class, PCEP_OBJ_CLASS_ENDPOINTS);
+       CU_ASSERT_EQUAL(obj_hdr->object_type, PCEP_OBJ_TYPE_ENDPOINT_IPV4);
+       CU_ASSERT_EQUAL(obj_hdr->encoded_object_length,
+                       pcep_object_get_length_by_hdr(obj_hdr));
+       CU_ASSERT_FALSE(pcep_obj_has_tlv(obj_hdr));
+
+       /* ERO object */
+       node = node->next_node;
+       obj_hdr = (struct pcep_object_header *)node->data;
+       CU_ASSERT_EQUAL(obj_hdr->object_class, PCEP_OBJ_CLASS_ERO);
+       CU_ASSERT_EQUAL(obj_hdr->object_type, PCEP_OBJ_TYPE_ERO);
+       CU_ASSERT_EQUAL(obj_hdr->encoded_object_length, 16);
+
+       /* ERO Subobjects */
+       double_linked_list *ero_subobj_list =
+               ((struct pcep_object_ro *)obj_hdr)->sub_objects;
+       CU_ASSERT_PTR_NOT_NULL(ero_subobj_list);
+       CU_ASSERT_EQUAL(ero_subobj_list->num_entries, 0);
+       double_linked_list_node *subobj_node = ero_subobj_list->head;
+       CU_ASSERT_PTR_NULL(subobj_node);
+       /* We no longer support draft07 SR sub-object type=5, and only support
+       type=36 struct pcep_object_ro_subobj *subobj_hdr = (struct
+       pcep_object_ro_subobj *) subobj_node->data;
+       CU_ASSERT_EQUAL(subobj_hdr->ro_subobj_type, RO_SUBOBJ_TYPE_SR);
+       struct pcep_ro_subobj_sr *subobj_sr = (struct pcep_ro_subobj_sr *)
+       subobj_hdr; CU_ASSERT_EQUAL(subobj_sr->nai_type,
+       PCEP_SR_SUBOBJ_NAI_IPV4_NODE); CU_ASSERT_TRUE(subobj_sr->flag_m);
+       CU_ASSERT_FALSE(subobj_sr->flag_c);
+       CU_ASSERT_FALSE(subobj_sr->flag_s);
+       CU_ASSERT_FALSE(subobj_sr->flag_f);
+       CU_ASSERT_EQUAL(subobj_sr->sid, 65576960);
+       CU_ASSERT_EQUAL(*((uint32_t *) subobj_sr->nai_list->head->data),
+       0x01010101);
+       */
+
+       pcep_msg_free_message_list(msg_list);
+       close(fd);
+}
+
+void test_pcep_msg_read_pcep_open()
+{
+       int fd = convert_hexstrs_to_binary(pcep_open_odl_hexbyte_strs,
+                                          pcep_open_hexbyte_strs_length);
+       if(fd == -1){
+               CU_ASSERT_TRUE(fd>=0);
+               return;
+       }
+       double_linked_list *msg_list = pcep_msg_read(fd);
+       CU_ASSERT_PTR_NOT_NULL(msg_list);
+       CU_ASSERT_EQUAL(msg_list->num_entries, 1);
+
+       struct pcep_message *msg = (struct pcep_message *)msg_list->head->data;
+       CU_ASSERT_EQUAL(msg->obj_list->num_entries, 1);
+       CU_ASSERT_EQUAL(msg->msg_header->type, PCEP_TYPE_OPEN);
+       CU_ASSERT_EQUAL(msg->encoded_message_length,
+                       pcep_open_hexbyte_strs_length);
+
+       /* Verify the Open message */
+       struct pcep_object_header *obj_hdr =
+               (struct pcep_object_header *)msg->obj_list->head->data;
+       CU_ASSERT_EQUAL(obj_hdr->object_class, PCEP_OBJ_CLASS_OPEN);
+       CU_ASSERT_EQUAL(obj_hdr->object_type, PCEP_OBJ_TYPE_OPEN);
+       CU_ASSERT_EQUAL(obj_hdr->encoded_object_length, 24);
+       CU_ASSERT_TRUE(pcep_obj_has_tlv(obj_hdr));
+
+       /* Open TLV: Stateful PCE Capability */
+       CU_ASSERT_EQUAL(obj_hdr->tlv_list->num_entries, 2);
+       double_linked_list_node *tlv_node = obj_hdr->tlv_list->head;
+       struct pcep_object_tlv_header *tlv =
+               (struct pcep_object_tlv_header *)tlv_node->data;
+       CU_ASSERT_EQUAL(tlv->type, PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY);
+       CU_ASSERT_EQUAL(tlv->encoded_tlv_length, 4);
+
+       /* Open TLV: SR PCE Capability */
+       tlv_node = tlv_node->next_node;
+       tlv = (struct pcep_object_tlv_header *)tlv_node->data;
+       CU_ASSERT_EQUAL(tlv->type, PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY);
+       CU_ASSERT_EQUAL(tlv->encoded_tlv_length, 4);
+
+       pcep_msg_free_message_list(msg_list);
+       close(fd);
+}
+
+void test_pcep_msg_read_pcep_update()
+{
+       int fd = convert_hexstrs_to_binary(pcep_update_hexbyte_strs,
+                                          pcep_update_hexbyte_strs_length);
+       if(fd == -1){
+               CU_ASSERT_TRUE(fd>=0);
+               return;
+       }
+       double_linked_list *msg_list = pcep_msg_read(fd);
+       CU_ASSERT_PTR_NOT_NULL(msg_list);
+       CU_ASSERT_EQUAL(msg_list->num_entries, 1);
+
+       struct pcep_message *msg = (struct pcep_message *)msg_list->head->data;
+       CU_ASSERT_EQUAL(msg->obj_list->num_entries, 3);
+
+       CU_ASSERT_EQUAL(msg->msg_header->type, PCEP_TYPE_UPDATE);
+       CU_ASSERT_EQUAL(msg->encoded_message_length,
+                       pcep_update_hexbyte_strs_length);
+
+       /* Verify each of the object types */
+
+       double_linked_list_node *node = msg->obj_list->head;
+
+       /* SRP object */
+       struct pcep_object_header *obj_hdr =
+               (struct pcep_object_header *)node->data;
+       CU_ASSERT_EQUAL(obj_hdr->object_class, PCEP_OBJ_CLASS_SRP);
+       CU_ASSERT_EQUAL(obj_hdr->object_type, PCEP_OBJ_TYPE_SRP);
+       CU_ASSERT_EQUAL(obj_hdr->encoded_object_length, 20);
+       CU_ASSERT_TRUE(pcep_obj_has_tlv(obj_hdr));
+
+       /* SRP TLV */
+       CU_ASSERT_EQUAL(obj_hdr->tlv_list->num_entries, 1);
+       struct pcep_object_tlv_header *tlv =
+               (struct pcep_object_tlv_header *)obj_hdr->tlv_list->head->data;
+       CU_ASSERT_EQUAL(tlv->type, PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE);
+       CU_ASSERT_EQUAL(tlv->encoded_tlv_length, 4);
+       /* TODO verify the path setup type */
+
+       /* LSP object */
+       node = node->next_node;
+       obj_hdr = (struct pcep_object_header *)node->data;
+       CU_ASSERT_EQUAL(obj_hdr->object_class, PCEP_OBJ_CLASS_LSP);
+       CU_ASSERT_EQUAL(obj_hdr->object_type, PCEP_OBJ_TYPE_LSP);
+       CU_ASSERT_EQUAL(obj_hdr->encoded_object_length,
+                       pcep_object_get_length_by_hdr(obj_hdr));
+       CU_ASSERT_FALSE(pcep_obj_has_tlv(obj_hdr));
+
+       /* ERO object */
+       node = node->next_node;
+       obj_hdr = (struct pcep_object_header *)node->data;
+       CU_ASSERT_EQUAL(obj_hdr->object_class, PCEP_OBJ_CLASS_ERO);
+       CU_ASSERT_EQUAL(obj_hdr->object_type, PCEP_OBJ_TYPE_ERO);
+       CU_ASSERT_EQUAL(obj_hdr->encoded_object_length, 16);
+
+       /* ERO Subobjects */
+       double_linked_list *ero_subobj_list =
+               ((struct pcep_object_ro *)obj_hdr)->sub_objects;
+       CU_ASSERT_PTR_NOT_NULL(ero_subobj_list);
+       CU_ASSERT_EQUAL(ero_subobj_list->num_entries, 0);
+       double_linked_list_node *subobj_node = ero_subobj_list->head;
+       CU_ASSERT_PTR_NULL(subobj_node);
+       /* We no longer support draft07 SR sub-object type=5, and only support
+       type=36 struct pcep_object_ro_subobj *subobj_hdr = (struct
+       pcep_object_ro_subobj *) subobj_node->data;
+       CU_ASSERT_EQUAL(subobj_hdr->ro_subobj_type, RO_SUBOBJ_TYPE_SR);
+       struct pcep_ro_subobj_sr *subobj_sr = (struct pcep_ro_subobj_sr *)
+       subobj_hdr; CU_ASSERT_EQUAL(subobj_sr->nai_type,
+       PCEP_SR_SUBOBJ_NAI_IPV4_NODE); CU_ASSERT_TRUE(subobj_sr->flag_m);
+       CU_ASSERT_FALSE(subobj_sr->flag_c);
+       CU_ASSERT_FALSE(subobj_sr->flag_s);
+       CU_ASSERT_FALSE(subobj_sr->flag_f);
+       CU_ASSERT_EQUAL(subobj_sr->sid, 65576960);
+       CU_ASSERT_EQUAL(*((uint32_t *) subobj_sr->nai_list->head->data),
+       0x01010101);
+       */
+
+       pcep_msg_free_message_list(msg_list);
+       close(fd);
+}
+
+void test_pcep_msg_read_pcep_open_initiate()
+{
+       int fd = convert_hexstrs_to_binary(
+               pcep_open_initiate_odl_hexbyte_strs,
+               pcep_open_initiate_hexbyte_strs_length);
+       if(fd == -1){
+               CU_ASSERT_TRUE(fd>=0);
+               return;
+       }
+       double_linked_list *msg_list = pcep_msg_read(fd);
+       CU_ASSERT_PTR_NOT_NULL(msg_list);
+       CU_ASSERT_EQUAL(msg_list->num_entries, 2);
+
+       struct pcep_message *msg = (struct pcep_message *)msg_list->head->data;
+       CU_ASSERT_EQUAL(msg->obj_list->num_entries, 1);
+       CU_ASSERT_EQUAL(msg->msg_header->type, PCEP_TYPE_OPEN);
+       CU_ASSERT_EQUAL(msg->encoded_message_length,
+                       pcep_open_hexbyte_strs_length);
+
+       msg = (struct pcep_message *)msg_list->head->next_node->data;
+       CU_ASSERT_EQUAL(msg->obj_list->num_entries, 4);
+       CU_ASSERT_EQUAL(msg->msg_header->type, PCEP_TYPE_INITIATE);
+       CU_ASSERT_EQUAL(msg->encoded_message_length,
+                       pcep_initiate2_hexbyte_strs_length);
+
+       pcep_msg_free_message_list(msg_list);
+       close(fd);
+}
+
+void test_pcep_msg_read_pcep_open_cisco_pce()
+{
+       int fd = convert_hexstrs_to_binary(
+               pcep_open_cisco_pce_hexbyte_strs,
+               pcep_open_cisco_pce_hexbyte_strs_length);
+       if(fd == -1){
+               CU_ASSERT_TRUE(fd>=0);
+               return;
+       }
+       double_linked_list *msg_list = pcep_msg_read(fd);
+       CU_ASSERT_PTR_NOT_NULL(msg_list);
+       CU_ASSERT_EQUAL(msg_list->num_entries, 1);
+
+       struct pcep_message *msg = (struct pcep_message *)msg_list->head->data;
+       CU_ASSERT_EQUAL(msg->msg_header->type, PCEP_TYPE_OPEN);
+       CU_ASSERT_EQUAL(msg->encoded_message_length,
+                       pcep_open_hexbyte_strs_length);
+       CU_ASSERT_EQUAL(msg->obj_list->num_entries, 1);
+
+       /* Open object */
+       struct pcep_object_open *open =
+               (struct pcep_object_open *)msg->obj_list->head->data;
+       CU_ASSERT_EQUAL(open->header.object_class, PCEP_OBJ_CLASS_OPEN);
+       CU_ASSERT_EQUAL(open->header.object_type, PCEP_OBJ_TYPE_OPEN);
+       CU_ASSERT_EQUAL(open->header.encoded_object_length, 24);
+       CU_ASSERT_EQUAL(open->open_deadtimer, 120);
+       CU_ASSERT_EQUAL(open->open_keepalive, 60);
+       CU_ASSERT_EQUAL(open->open_sid, 0);
+       CU_ASSERT_EQUAL(open->open_version, 1);
+       CU_ASSERT_PTR_NOT_NULL(open->header.tlv_list);
+       CU_ASSERT_EQUAL(open->header.tlv_list->num_entries, 2);
+
+       /* Stateful PCE Capability TLV */
+       double_linked_list_node *tlv_node = open->header.tlv_list->head;
+       struct pcep_object_tlv_stateful_pce_capability *pce_cap_tlv =
+               (struct pcep_object_tlv_stateful_pce_capability *)
+                       tlv_node->data;
+       CU_ASSERT_EQUAL(pce_cap_tlv->header.type,
+                       PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY);
+       CU_ASSERT_EQUAL(pce_cap_tlv->header.encoded_tlv_length, 4);
+       CU_ASSERT_TRUE(pce_cap_tlv->flag_u_lsp_update_capability);
+       CU_ASSERT_TRUE(pce_cap_tlv->flag_i_lsp_instantiation_capability);
+       CU_ASSERT_FALSE(pce_cap_tlv->flag_s_include_db_version);
+       CU_ASSERT_FALSE(pce_cap_tlv->flag_t_triggered_resync);
+       CU_ASSERT_FALSE(pce_cap_tlv->flag_d_delta_lsp_sync);
+       CU_ASSERT_FALSE(pce_cap_tlv->flag_f_triggered_initial_sync);
+
+       /* SR PCE Capability TLV */
+       tlv_node = tlv_node->next_node;
+       struct pcep_object_tlv_sr_pce_capability *sr_pce_cap_tlv =
+               (struct pcep_object_tlv_sr_pce_capability *)tlv_node->data;
+       CU_ASSERT_EQUAL(sr_pce_cap_tlv->header.type,
+                       PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY);
+       CU_ASSERT_EQUAL(sr_pce_cap_tlv->header.encoded_tlv_length, 4);
+       CU_ASSERT_FALSE(sr_pce_cap_tlv->flag_n);
+       CU_ASSERT_FALSE(sr_pce_cap_tlv->flag_x);
+       CU_ASSERT_EQUAL(sr_pce_cap_tlv->max_sid_depth, 10);
+
+       pcep_msg_free_message_list(msg_list);
+       close(fd);
+}
+
+void test_pcep_msg_read_pcep_update_cisco_pce()
+{
+       int fd = convert_hexstrs_to_binary(
+               pcep_update_cisco_pce_hexbyte_strs,
+               pcep_update_cisco_pce_hexbyte_strs_length);
+       if(fd == -1){
+               CU_ASSERT_TRUE(fd>=0);
+               return;
+       }
+       double_linked_list *msg_list = pcep_msg_read(fd);
+       CU_ASSERT_PTR_NOT_NULL(msg_list);
+       CU_ASSERT_EQUAL(msg_list->num_entries, 1);
+
+       struct pcep_message *msg = (struct pcep_message *)msg_list->head->data;
+       CU_ASSERT_EQUAL(msg->msg_header->type, PCEP_TYPE_UPDATE);
+       CU_ASSERT_EQUAL(msg->encoded_message_length,
+                       pcep_update_cisco_pce_hexbyte_strs_length);
+       CU_ASSERT_EQUAL(msg->obj_list->num_entries, 4);
+
+       /* SRP object */
+       double_linked_list_node *obj_node = msg->obj_list->head;
+       struct pcep_object_srp *srp = (struct pcep_object_srp *)obj_node->data;
+       CU_ASSERT_EQUAL(srp->header.object_class, PCEP_OBJ_CLASS_SRP);
+       CU_ASSERT_EQUAL(srp->header.object_type, PCEP_OBJ_TYPE_SRP);
+       CU_ASSERT_EQUAL(srp->header.encoded_object_length, 20);
+       CU_ASSERT_PTR_NOT_NULL(srp->header.tlv_list);
+       CU_ASSERT_EQUAL(srp->header.tlv_list->num_entries, 1);
+       CU_ASSERT_EQUAL(srp->srp_id_number, 1);
+       CU_ASSERT_FALSE(srp->flag_lsp_remove);
+
+       /* SRP Path Setup Type TLV */
+       double_linked_list_node *tlv_node = srp->header.tlv_list->head;
+       struct pcep_object_tlv_path_setup_type *pst_tlv =
+               (struct pcep_object_tlv_path_setup_type *)tlv_node->data;
+       CU_ASSERT_EQUAL(pst_tlv->header.type,
+                       PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE);
+       CU_ASSERT_EQUAL(pst_tlv->header.encoded_tlv_length, 4);
+       CU_ASSERT_EQUAL(pst_tlv->path_setup_type, 1);
+
+       /* LSP object */
+       obj_node = obj_node->next_node;
+       struct pcep_object_lsp *lsp = (struct pcep_object_lsp *)obj_node->data;
+       CU_ASSERT_EQUAL(lsp->header.object_class, PCEP_OBJ_CLASS_LSP);
+       CU_ASSERT_EQUAL(lsp->header.object_type, PCEP_OBJ_TYPE_LSP);
+       CU_ASSERT_EQUAL(lsp->header.encoded_object_length, 24);
+       CU_ASSERT_PTR_NOT_NULL(lsp->header.tlv_list);
+       CU_ASSERT_EQUAL(lsp->header.tlv_list->num_entries, 1);
+       CU_ASSERT_EQUAL(lsp->plsp_id, 524303);
+       CU_ASSERT_EQUAL(lsp->operational_status, PCEP_LSP_OPERATIONAL_DOWN);
+       CU_ASSERT_TRUE(lsp->flag_a);
+       CU_ASSERT_TRUE(lsp->flag_c);
+       CU_ASSERT_TRUE(lsp->flag_d);
+       CU_ASSERT_FALSE(lsp->flag_r);
+       CU_ASSERT_FALSE(lsp->flag_s);
+
+       /* LSP Vendor Info TLV */
+       tlv_node = lsp->header.tlv_list->head;
+       struct pcep_object_tlv_vendor_info *vendor_tlv =
+               (struct pcep_object_tlv_vendor_info *)tlv_node->data;
+       CU_ASSERT_EQUAL(vendor_tlv->header.type, PCEP_OBJ_TLV_TYPE_VENDOR_INFO);
+       CU_ASSERT_EQUAL(vendor_tlv->header.encoded_tlv_length, 12);
+       CU_ASSERT_EQUAL(vendor_tlv->enterprise_number, 9);
+       CU_ASSERT_EQUAL(vendor_tlv->enterprise_specific_info, 0x00030004);
+
+       /* ERO object */
+       obj_node = obj_node->next_node;
+       struct pcep_object_ro *ero = (struct pcep_object_ro *)obj_node->data;
+       CU_ASSERT_EQUAL(ero->header.object_class, PCEP_OBJ_CLASS_ERO);
+       CU_ASSERT_EQUAL(ero->header.object_type, PCEP_OBJ_TYPE_ERO);
+       CU_ASSERT_EQUAL(ero->header.encoded_object_length, 40);
+       CU_ASSERT_PTR_NULL(ero->header.tlv_list);
+       CU_ASSERT_PTR_NOT_NULL(ero->sub_objects);
+       CU_ASSERT_EQUAL(ero->sub_objects->num_entries, 3);
+
+       /* ERO Subobjects */
+       double_linked_list_node *ero_subobj_node = ero->sub_objects->head;
+       struct pcep_ro_subobj_sr *sr_subobj_ipv4_node =
+               (struct pcep_ro_subobj_sr *)ero_subobj_node->data;
+       CU_ASSERT_EQUAL(sr_subobj_ipv4_node->ro_subobj.ro_subobj_type,
+                       RO_SUBOBJ_TYPE_SR);
+       CU_ASSERT_FALSE(sr_subobj_ipv4_node->ro_subobj.flag_subobj_loose_hop);
+       CU_ASSERT_EQUAL(sr_subobj_ipv4_node->nai_type,
+                       PCEP_SR_SUBOBJ_NAI_IPV4_NODE);
+       CU_ASSERT_TRUE(sr_subobj_ipv4_node->flag_m);
+       CU_ASSERT_FALSE(sr_subobj_ipv4_node->flag_c);
+       CU_ASSERT_FALSE(sr_subobj_ipv4_node->flag_f);
+       CU_ASSERT_FALSE(sr_subobj_ipv4_node->flag_s);
+       CU_ASSERT_EQUAL(sr_subobj_ipv4_node->sid, 73748480);
+       CU_ASSERT_EQUAL(
+               *((uint32_t *)sr_subobj_ipv4_node->nai_list->head->data),
+               htonl(0x0a0a0a05));
+
+       ero_subobj_node = ero_subobj_node->next_node;
+       sr_subobj_ipv4_node = (struct pcep_ro_subobj_sr *)ero_subobj_node->data;
+       CU_ASSERT_EQUAL(sr_subobj_ipv4_node->ro_subobj.ro_subobj_type,
+                       RO_SUBOBJ_TYPE_SR);
+       CU_ASSERT_FALSE(sr_subobj_ipv4_node->ro_subobj.flag_subobj_loose_hop);
+       CU_ASSERT_EQUAL(sr_subobj_ipv4_node->nai_type,
+                       PCEP_SR_SUBOBJ_NAI_IPV4_NODE);
+       CU_ASSERT_TRUE(sr_subobj_ipv4_node->flag_m);
+       CU_ASSERT_FALSE(sr_subobj_ipv4_node->flag_c);
+       CU_ASSERT_FALSE(sr_subobj_ipv4_node->flag_f);
+       CU_ASSERT_FALSE(sr_subobj_ipv4_node->flag_s);
+       CU_ASSERT_EQUAL(sr_subobj_ipv4_node->sid, 73736192);
+       CU_ASSERT_EQUAL(
+               *((uint32_t *)sr_subobj_ipv4_node->nai_list->head->data),
+               htonl(0x0a0a0a02));
+
+       ero_subobj_node = ero_subobj_node->next_node;
+       sr_subobj_ipv4_node = (struct pcep_ro_subobj_sr *)ero_subobj_node->data;
+       CU_ASSERT_EQUAL(sr_subobj_ipv4_node->ro_subobj.ro_subobj_type,
+                       RO_SUBOBJ_TYPE_SR);
+       CU_ASSERT_FALSE(sr_subobj_ipv4_node->ro_subobj.flag_subobj_loose_hop);
+       CU_ASSERT_EQUAL(sr_subobj_ipv4_node->nai_type,
+                       PCEP_SR_SUBOBJ_NAI_IPV4_NODE);
+       CU_ASSERT_TRUE(sr_subobj_ipv4_node->flag_m);
+       CU_ASSERT_FALSE(sr_subobj_ipv4_node->flag_c);
+       CU_ASSERT_FALSE(sr_subobj_ipv4_node->flag_f);
+       CU_ASSERT_FALSE(sr_subobj_ipv4_node->flag_s);
+       CU_ASSERT_EQUAL(sr_subobj_ipv4_node->sid, 73732096);
+       CU_ASSERT_EQUAL(
+               *((uint32_t *)sr_subobj_ipv4_node->nai_list->head->data),
+               htonl(0x0a0a0a01));
+
+       /* Metric object */
+       obj_node = obj_node->next_node;
+       struct pcep_object_metric *metric =
+               (struct pcep_object_metric *)obj_node->data;
+       CU_ASSERT_EQUAL(metric->header.object_class, PCEP_OBJ_CLASS_METRIC);
+       CU_ASSERT_EQUAL(metric->header.object_type, PCEP_OBJ_TYPE_METRIC);
+       CU_ASSERT_EQUAL(metric->header.encoded_object_length, 12);
+       CU_ASSERT_PTR_NULL(metric->header.tlv_list);
+       CU_ASSERT_FALSE(metric->flag_b);
+       CU_ASSERT_FALSE(metric->flag_c);
+       CU_ASSERT_EQUAL(metric->type, PCEP_METRIC_TE);
+       CU_ASSERT_EQUAL(metric->value, 30.0);
+
+       pcep_msg_free_message_list(msg_list);
+       close(fd);
+}
+
+void test_pcep_msg_read_pcep_report_cisco_pcc()
+{
+       int fd = convert_hexstrs_to_binary(
+               pcep_report_cisco_pcc_hexbyte_strs,
+               pcep_report_cisco_pcc_hexbyte_strs_length);
+       if(fd == -1){
+               CU_ASSERT_TRUE(fd>=0);
+               return;
+       }
+       double_linked_list *msg_list = pcep_msg_read(fd);
+       CU_ASSERT_PTR_NOT_NULL(msg_list);
+       CU_ASSERT_EQUAL(msg_list->num_entries, 1);
+
+       struct pcep_message *msg = (struct pcep_message *)msg_list->head->data;
+       CU_ASSERT_EQUAL(msg->msg_header->type, PCEP_TYPE_REPORT);
+       CU_ASSERT_EQUAL(msg->encoded_message_length,
+                       pcep_report_cisco_pcc_hexbyte_strs_length);
+       CU_ASSERT_EQUAL(msg->obj_list->num_entries, 8);
+
+       /* SRP object */
+       double_linked_list_node *obj_node = msg->obj_list->head;
+       struct pcep_object_srp *srp = (struct pcep_object_srp *)obj_node->data;
+       CU_ASSERT_EQUAL(srp->header.object_class, PCEP_OBJ_CLASS_SRP);
+       CU_ASSERT_EQUAL(srp->header.object_type, PCEP_OBJ_TYPE_SRP);
+       CU_ASSERT_EQUAL(srp->header.encoded_object_length, 20);
+       CU_ASSERT_PTR_NOT_NULL(srp->header.tlv_list);
+       CU_ASSERT_EQUAL(srp->header.tlv_list->num_entries, 1);
+       CU_ASSERT_EQUAL(srp->srp_id_number, 0);
+       CU_ASSERT_FALSE(srp->flag_lsp_remove);
+
+       /* SRP Path Setup Type TLV */
+       double_linked_list_node *tlv_node = srp->header.tlv_list->head;
+       struct pcep_object_tlv_path_setup_type *pst_tlv =
+               (struct pcep_object_tlv_path_setup_type *)tlv_node->data;
+       CU_ASSERT_EQUAL(pst_tlv->header.type,
+                       PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE);
+       CU_ASSERT_EQUAL(pst_tlv->header.encoded_tlv_length, 4);
+       CU_ASSERT_EQUAL(pst_tlv->path_setup_type, 1);
+
+       /* LSP object */
+       obj_node = obj_node->next_node;
+       struct pcep_object_lsp *lsp = (struct pcep_object_lsp *)obj_node->data;
+       CU_ASSERT_EQUAL(lsp->header.object_class, PCEP_OBJ_CLASS_LSP);
+       CU_ASSERT_EQUAL(lsp->header.object_type, PCEP_OBJ_TYPE_LSP);
+       CU_ASSERT_EQUAL(lsp->header.encoded_object_length, 60);
+       CU_ASSERT_PTR_NOT_NULL(lsp->header.tlv_list);
+       /* The TLV with ID 65505 is not recognized, and its not in the list */
+       CU_ASSERT_EQUAL(lsp->header.tlv_list->num_entries, 2);
+       CU_ASSERT_EQUAL(lsp->plsp_id, 524303);
+       CU_ASSERT_EQUAL(lsp->operational_status, PCEP_LSP_OPERATIONAL_DOWN);
+       CU_ASSERT_TRUE(lsp->flag_a);
+       CU_ASSERT_TRUE(lsp->flag_d);
+       CU_ASSERT_FALSE(lsp->flag_c);
+       CU_ASSERT_FALSE(lsp->flag_r);
+       CU_ASSERT_FALSE(lsp->flag_s);
+
+       /* LSP IPv4 LSP Identifier TLV */
+       tlv_node = lsp->header.tlv_list->head;
+       struct pcep_object_tlv_ipv4_lsp_identifier *ipv4_lsp_id =
+               (struct pcep_object_tlv_ipv4_lsp_identifier *)tlv_node->data;
+       CU_ASSERT_EQUAL(ipv4_lsp_id->header.type,
+                       PCEP_OBJ_TLV_TYPE_IPV4_LSP_IDENTIFIERS);
+       CU_ASSERT_EQUAL(ipv4_lsp_id->header.encoded_tlv_length, 16);
+       CU_ASSERT_EQUAL(ipv4_lsp_id->ipv4_tunnel_sender.s_addr,
+                       htonl(0x0a0a0a06));
+       CU_ASSERT_EQUAL(ipv4_lsp_id->ipv4_tunnel_endpoint.s_addr,
+                       htonl(0x0a0a0a01));
+       CU_ASSERT_EQUAL(ipv4_lsp_id->extended_tunnel_id.s_addr,
+                       htonl(0x0a0a0a06));
+       CU_ASSERT_EQUAL(ipv4_lsp_id->tunnel_id, 15);
+       CU_ASSERT_EQUAL(ipv4_lsp_id->lsp_id, 2);
+
+       /* LSP Symbolic Path Name TLV */
+       tlv_node = tlv_node->next_node;
+       struct pcep_object_tlv_symbolic_path_name *sym_path_name =
+               (struct pcep_object_tlv_symbolic_path_name *)tlv_node->data;
+       CU_ASSERT_EQUAL(sym_path_name->header.type,
+                       PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME);
+       CU_ASSERT_EQUAL(sym_path_name->header.encoded_tlv_length, 13);
+       CU_ASSERT_EQUAL(sym_path_name->symbolic_path_name_length, 13);
+       CU_ASSERT_EQUAL(
+               strncmp(sym_path_name->symbolic_path_name, "cfg_R6-to-R1", 13),
+               0);
+
+       /* ERO object */
+       obj_node = obj_node->next_node;
+       struct pcep_object_ro *ero = (struct pcep_object_ro *)obj_node->data;
+       CU_ASSERT_EQUAL(ero->header.object_class, PCEP_OBJ_CLASS_ERO);
+       CU_ASSERT_EQUAL(ero->header.object_type, PCEP_OBJ_TYPE_ERO);
+       CU_ASSERT_EQUAL(ero->header.encoded_object_length, 4);
+       CU_ASSERT_PTR_NULL(ero->header.tlv_list);
+       CU_ASSERT_PTR_NOT_NULL(ero->sub_objects);
+       CU_ASSERT_EQUAL(ero->sub_objects->num_entries, 0);
+
+       /* LSPA object */
+       obj_node = obj_node->next_node;
+       struct pcep_object_lspa *lspa =
+               (struct pcep_object_lspa *)obj_node->data;
+       CU_ASSERT_EQUAL(lspa->header.object_class, PCEP_OBJ_CLASS_LSPA);
+       CU_ASSERT_EQUAL(lspa->header.object_type, PCEP_OBJ_TYPE_LSPA);
+       CU_ASSERT_EQUAL(lspa->header.encoded_object_length, 20);
+       CU_ASSERT_PTR_NULL(lspa->header.tlv_list);
+       CU_ASSERT_TRUE(lspa->flag_local_protection);
+       CU_ASSERT_EQUAL(lspa->holding_priority, 7);
+       CU_ASSERT_EQUAL(lspa->setup_priority, 7);
+       CU_ASSERT_EQUAL(lspa->lspa_include_all, 0);
+       CU_ASSERT_EQUAL(lspa->lspa_include_any, 0);
+       CU_ASSERT_EQUAL(lspa->lspa_exclude_any, 0);
+
+       /* Bandwidth object 1 */
+       obj_node = obj_node->next_node;
+       struct pcep_object_bandwidth *bandwidth =
+               (struct pcep_object_bandwidth *)obj_node->data;
+       CU_ASSERT_EQUAL(bandwidth->header.object_class,
+                       PCEP_OBJ_CLASS_BANDWIDTH);
+       CU_ASSERT_EQUAL(bandwidth->header.object_type,
+                       PCEP_OBJ_TYPE_BANDWIDTH_REQ);
+       CU_ASSERT_EQUAL(bandwidth->header.encoded_object_length, 8);
+       CU_ASSERT_EQUAL(bandwidth->bandwidth, 0);
+
+       /* Bandwidth object 2 */
+       obj_node = obj_node->next_node;
+       bandwidth = (struct pcep_object_bandwidth *)obj_node->data;
+       CU_ASSERT_EQUAL(bandwidth->header.object_class,
+                       PCEP_OBJ_CLASS_BANDWIDTH);
+       CU_ASSERT_EQUAL(bandwidth->header.object_type,
+                       PCEP_OBJ_TYPE_BANDWIDTH_CISCO);
+       CU_ASSERT_EQUAL(bandwidth->header.encoded_object_length, 8);
+       CU_ASSERT_EQUAL(bandwidth->bandwidth, 0);
+
+       /* Metric object 1 */
+       obj_node = obj_node->next_node;
+       struct pcep_object_metric *metric =
+               (struct pcep_object_metric *)obj_node->data;
+       CU_ASSERT_EQUAL(metric->header.object_class, PCEP_OBJ_CLASS_METRIC);
+       CU_ASSERT_EQUAL(metric->header.object_type, PCEP_OBJ_TYPE_METRIC);
+       CU_ASSERT_EQUAL(metric->header.encoded_object_length, 12);
+       CU_ASSERT_PTR_NULL(metric->header.tlv_list);
+       CU_ASSERT_FALSE(metric->flag_b);
+       CU_ASSERT_FALSE(metric->flag_c);
+       CU_ASSERT_EQUAL(metric->type, PCEP_METRIC_TE);
+       CU_ASSERT_EQUAL(metric->value, 0);
+
+       /* Metric object 2 */
+       obj_node = obj_node->next_node;
+       metric = (struct pcep_object_metric *)obj_node->data;
+       CU_ASSERT_EQUAL(metric->header.object_class, PCEP_OBJ_CLASS_METRIC);
+       CU_ASSERT_EQUAL(metric->header.object_type, PCEP_OBJ_TYPE_METRIC);
+       CU_ASSERT_EQUAL(metric->header.encoded_object_length, 12);
+       CU_ASSERT_PTR_NULL(metric->header.tlv_list);
+       CU_ASSERT_TRUE(metric->flag_b);
+       CU_ASSERT_FALSE(metric->flag_c);
+       CU_ASSERT_EQUAL(metric->type, PCEP_METRIC_AGGREGATE_BW);
+       CU_ASSERT_EQUAL(metric->value, 16.0);
+
+       pcep_msg_free_message_list(msg_list);
+       close(fd);
+}
+
+void test_pcep_msg_read_pcep_initiate_cisco_pcc()
+{
+       int fd = convert_hexstrs_to_binary(
+               pcep_initiate_cisco_pcc_hexbyte_strs,
+               pcep_initiate_cisco_pcc_hexbyte_strs_length);
+       if(fd == -1){
+               CU_ASSERT_TRUE(fd>=0);
+               return;
+       }
+       double_linked_list *msg_list = pcep_msg_read(fd);
+       CU_ASSERT_PTR_NOT_NULL(msg_list);
+       CU_ASSERT_EQUAL(msg_list->num_entries, 1);
+
+       struct pcep_message *msg = (struct pcep_message *)msg_list->head->data;
+       CU_ASSERT_EQUAL(msg->msg_header->type, PCEP_TYPE_INITIATE);
+       CU_ASSERT_EQUAL(msg->encoded_message_length,
+                       pcep_initiate_cisco_pcc_hexbyte_strs_length);
+       CU_ASSERT_EQUAL(msg->obj_list->num_entries, 6);
+
+       /* SRP object */
+       double_linked_list_node *obj_node = msg->obj_list->head;
+       struct pcep_object_srp *srp = (struct pcep_object_srp *)obj_node->data;
+       CU_ASSERT_EQUAL(srp->header.object_class, PCEP_OBJ_CLASS_SRP);
+       CU_ASSERT_EQUAL(srp->header.object_type, PCEP_OBJ_TYPE_SRP);
+       CU_ASSERT_EQUAL(srp->header.encoded_object_length, 20);
+       CU_ASSERT_PTR_NOT_NULL(srp->header.tlv_list);
+       CU_ASSERT_EQUAL(srp->header.tlv_list->num_entries, 1);
+       CU_ASSERT_EQUAL(srp->srp_id_number, 1);
+       CU_ASSERT_FALSE(srp->flag_lsp_remove);
+
+       /* LSP object */
+       obj_node = obj_node->next_node;
+       struct pcep_object_lsp *lsp = (struct pcep_object_lsp *)obj_node->data;
+       CU_ASSERT_EQUAL(lsp->header.object_class, PCEP_OBJ_CLASS_LSP);
+       CU_ASSERT_EQUAL(lsp->header.object_type, PCEP_OBJ_TYPE_LSP);
+       CU_ASSERT_EQUAL(lsp->header.encoded_object_length, 48);
+       CU_ASSERT_PTR_NOT_NULL(lsp->header.tlv_list);
+       CU_ASSERT_EQUAL(lsp->header.tlv_list->num_entries, 2);
+       CU_ASSERT_EQUAL(lsp->plsp_id, 0);
+       CU_ASSERT_EQUAL(lsp->operational_status, PCEP_LSP_OPERATIONAL_DOWN);
+       CU_ASSERT_TRUE(lsp->flag_a);
+       CU_ASSERT_TRUE(lsp->flag_d);
+       CU_ASSERT_TRUE(lsp->flag_c);
+       CU_ASSERT_FALSE(lsp->flag_r);
+       CU_ASSERT_FALSE(lsp->flag_s);
+
+       /* Endpoint object */
+       obj_node = obj_node->next_node;
+       struct pcep_object_endpoints_ipv4 *endpoint =
+               (struct pcep_object_endpoints_ipv4 *)obj_node->data;
+       CU_ASSERT_EQUAL(endpoint->header.object_class,
+                       PCEP_OBJ_CLASS_ENDPOINTS);
+       CU_ASSERT_EQUAL(endpoint->header.object_type,
+                       PCEP_OBJ_TYPE_ENDPOINT_IPV4);
+       CU_ASSERT_EQUAL(endpoint->header.encoded_object_length, 12);
+       CU_ASSERT_PTR_NULL(endpoint->header.tlv_list);
+       CU_ASSERT_EQUAL(endpoint->src_ipv4.s_addr, htonl(0x0a0a0a0a));
+       CU_ASSERT_EQUAL(endpoint->dst_ipv4.s_addr, htonl(0x0a0a0a04));
+
+       /* Inter-Layer object */
+       obj_node = obj_node->next_node;
+       struct pcep_object_inter_layer *inter_layer =
+               (struct pcep_object_inter_layer *)obj_node->data;
+       CU_ASSERT_EQUAL(inter_layer->header.object_class,
+                       PCEP_OBJ_CLASS_INTER_LAYER);
+       CU_ASSERT_EQUAL(inter_layer->header.object_type,
+                       PCEP_OBJ_TYPE_INTER_LAYER);
+       CU_ASSERT_EQUAL(inter_layer->header.encoded_object_length, 8);
+       CU_ASSERT_PTR_NULL(inter_layer->header.tlv_list);
+       CU_ASSERT_TRUE(inter_layer->flag_i);
+       CU_ASSERT_FALSE(inter_layer->flag_m);
+       CU_ASSERT_TRUE(inter_layer->flag_t);
+
+       /* Switch-Layer object */
+       obj_node = obj_node->next_node;
+       struct pcep_object_switch_layer *switch_layer =
+               (struct pcep_object_switch_layer *)obj_node->data;
+       CU_ASSERT_EQUAL(switch_layer->header.object_class,
+                       PCEP_OBJ_CLASS_SWITCH_LAYER);
+       CU_ASSERT_EQUAL(switch_layer->header.object_type,
+                       PCEP_OBJ_TYPE_SWITCH_LAYER);
+       CU_ASSERT_EQUAL(switch_layer->header.encoded_object_length, 8);
+       CU_ASSERT_PTR_NULL(switch_layer->header.tlv_list);
+       CU_ASSERT_PTR_NOT_NULL(switch_layer->switch_layer_rows);
+       CU_ASSERT_EQUAL(switch_layer->switch_layer_rows->num_entries, 1);
+       struct pcep_object_switch_layer_row *switch_layer_row =
+               (struct pcep_object_switch_layer_row *)
+                       switch_layer->switch_layer_rows->head->data;
+       CU_ASSERT_EQUAL(switch_layer_row->lsp_encoding_type, 0);
+       CU_ASSERT_EQUAL(switch_layer_row->switching_type, 0);
+       CU_ASSERT_FALSE(switch_layer_row->flag_i);
+
+       /* ERO object */
+       obj_node = obj_node->next_node;
+       struct pcep_object_ro *ero = (struct pcep_object_ro *)obj_node->data;
+       CU_ASSERT_EQUAL(ero->header.object_class, PCEP_OBJ_CLASS_ERO);
+       CU_ASSERT_EQUAL(ero->header.object_type, PCEP_OBJ_TYPE_ERO);
+       CU_ASSERT_EQUAL(ero->header.encoded_object_length, 4);
+       CU_ASSERT_PTR_NULL(ero->header.tlv_list);
+
+       pcep_msg_free_message_list(msg_list);
+       close(fd);
+}
+
+void test_validate_message_header()
+{
+       uint8_t pcep_message_invalid_version[] = {0x40, 0x01, 0x04, 0x00};
+       uint8_t pcep_message_invalid_flags[] = {0x22, 0x01, 0x04, 0x00};
+       uint8_t pcep_message_invalid_length[] = {0x20, 0x01, 0x00, 0x00};
+       uint8_t pcep_message_invalid_type[] = {0x20, 0xff, 0x04, 0x00};
+       uint8_t pcep_message_valid[] = {0x20, 0x01, 0x00, 0x04};
+
+       /* Verify invalid message header version */
+       CU_ASSERT_TRUE(
+               pcep_decode_validate_msg_header(pcep_message_invalid_version)
+               < 0);
+
+       /* Verify invalid message header flags */
+       CU_ASSERT_TRUE(
+               pcep_decode_validate_msg_header(pcep_message_invalid_flags)
+               < 0);
+
+       /* Verify invalid message header lengths */
+       CU_ASSERT_TRUE(
+               pcep_decode_validate_msg_header(pcep_message_invalid_length)
+               < 0);
+       pcep_message_invalid_length[3] = 0x05;
+       CU_ASSERT_TRUE(
+               pcep_decode_validate_msg_header(pcep_message_invalid_length)
+               < 0);
+
+       /* Verify invalid message header types */
+       CU_ASSERT_TRUE(
+               pcep_decode_validate_msg_header(pcep_message_invalid_type) < 0);
+       pcep_message_invalid_type[1] = 0x00;
+       CU_ASSERT_TRUE(
+               pcep_decode_validate_msg_header(pcep_message_invalid_type) < 0);
+
+       /* Verify a valid message header */
+       CU_ASSERT_EQUAL(pcep_decode_validate_msg_header(pcep_message_valid), 4);
+}
+
+/* Internal util function */
+struct pcep_message *create_message(uint8_t msg_type, uint8_t obj1_class,
+                                   uint8_t obj2_class, uint8_t obj3_class,
+                                   uint8_t obj4_class)
+{
+       struct pcep_message *msg =
+               pceplib_malloc(PCEPLIB_MESSAGES, sizeof(struct pcep_message));
+       msg->obj_list = dll_initialize();
+       msg->msg_header = pceplib_malloc(PCEPLIB_MESSAGES,
+                                        sizeof(struct pcep_message_header));
+       msg->msg_header->type = msg_type;
+       msg->encoded_message = NULL;
+
+       if (obj1_class > 0) {
+               struct pcep_object_header *obj_hdr = pceplib_malloc(
+                       PCEPLIB_MESSAGES, sizeof(struct pcep_object_header));
+               obj_hdr->object_class = obj1_class;
+               obj_hdr->tlv_list = NULL;
+               dll_append(msg->obj_list, obj_hdr);
+       }
+
+       if (obj2_class > 0) {
+               struct pcep_object_header *obj_hdr = pceplib_malloc(
+                       PCEPLIB_MESSAGES, sizeof(struct pcep_object_header));
+               obj_hdr->object_class = obj2_class;
+               obj_hdr->tlv_list = NULL;
+               dll_append(msg->obj_list, obj_hdr);
+       }
+
+       if (obj3_class > 0) {
+               struct pcep_object_header *obj_hdr = pceplib_malloc(
+                       PCEPLIB_MESSAGES, sizeof(struct pcep_object_header));
+               obj_hdr->object_class = obj3_class;
+               obj_hdr->tlv_list = NULL;
+               dll_append(msg->obj_list, obj_hdr);
+       }
+
+       if (obj4_class > 0) {
+               struct pcep_object_header *obj_hdr = pceplib_malloc(
+                       PCEPLIB_MESSAGES, sizeof(struct pcep_object_header));
+               obj_hdr->object_class = obj4_class;
+               obj_hdr->tlv_list = NULL;
+               dll_append(msg->obj_list, obj_hdr);
+       }
+
+       return msg;
+}
+
+void test_validate_message_objects()
+{
+       /* Valid Open message */
+       struct pcep_message *msg =
+               create_message(PCEP_TYPE_OPEN, PCEP_OBJ_CLASS_OPEN, 0, 0, 0);
+       CU_ASSERT_TRUE(validate_message_objects(msg));
+       pcep_msg_free_message(msg);
+
+       /* Valid KeepAlive message */
+       msg = create_message(PCEP_TYPE_KEEPALIVE, 0, 0, 0, 0);
+       CU_ASSERT_TRUE(validate_message_objects(msg));
+       pcep_msg_free_message(msg);
+
+       /* Valid PcReq message */
+       /* Using object_class=255 to verify it can take any object */
+       msg = create_message(PCEP_TYPE_PCREQ, PCEP_OBJ_CLASS_RP,
+                            PCEP_OBJ_CLASS_ENDPOINTS, any_obj_class, 0);
+       CU_ASSERT_TRUE(validate_message_objects(msg));
+       pcep_msg_free_message(msg);
+
+       /* Valid PcRep message */
+       msg = create_message(PCEP_TYPE_PCREP, PCEP_OBJ_CLASS_RP, any_obj_class,
+                            0, 0);
+       CU_ASSERT_TRUE(validate_message_objects(msg));
+       pcep_msg_free_message(msg);
+
+       /* Valid Notify message */
+       msg = create_message(PCEP_TYPE_PCNOTF, PCEP_OBJ_CLASS_NOTF,
+                            any_obj_class, 0, 0);
+       CU_ASSERT_TRUE(validate_message_objects(msg));
+       pcep_msg_free_message(msg);
+
+       /* Valid Error message */
+       msg = create_message(PCEP_TYPE_ERROR, PCEP_OBJ_CLASS_ERROR,
+                            any_obj_class, 0, 0);
+       CU_ASSERT_TRUE(validate_message_objects(msg));
+       pcep_msg_free_message(msg);
+
+       /* Valid Close message */
+       msg = create_message(PCEP_TYPE_CLOSE, PCEP_OBJ_CLASS_CLOSE, 0, 0, 0);
+       CU_ASSERT_TRUE(validate_message_objects(msg));
+       pcep_msg_free_message(msg);
+
+       /* Valid Report message */
+       msg = create_message(PCEP_TYPE_REPORT, PCEP_OBJ_CLASS_SRP,
+                            PCEP_OBJ_CLASS_LSP, any_obj_class, any_obj_class);
+       CU_ASSERT_TRUE(validate_message_objects(msg));
+       pcep_msg_free_message(msg);
+
+       /* Valid Update message */
+       msg = create_message(PCEP_TYPE_UPDATE, PCEP_OBJ_CLASS_SRP,
+                            PCEP_OBJ_CLASS_LSP, any_obj_class, any_obj_class);
+       CU_ASSERT_TRUE(validate_message_objects(msg));
+       pcep_msg_free_message(msg);
+
+       /* Valid Initiate message */
+       msg = create_message(PCEP_TYPE_INITIATE, PCEP_OBJ_CLASS_SRP,
+                            PCEP_OBJ_CLASS_LSP, any_obj_class, any_obj_class);
+       CU_ASSERT_TRUE(validate_message_objects(msg));
+       pcep_msg_free_message(msg);
+}
+
+void test_validate_message_objects_invalid()
+{
+       /* unsupported message ID = 0
+        * {NO_OBJECT, NO_OBJECT, NO_OBJECT, NO_OBJECT} */
+       struct pcep_message *msg = create_message(0, any_obj_class, 0, 0, 0);
+       CU_ASSERT_FALSE(validate_message_objects(msg));
+       pcep_msg_free_message(msg);
+
+       /* Open message
+        * {PCEP_OBJ_CLASS_OPEN, NO_OBJECT, NO_OBJECT, NO_OBJECT} */
+       msg = create_message(PCEP_TYPE_OPEN, 0, 0, 0, 0);
+       CU_ASSERT_FALSE(validate_message_objects(msg));
+       pcep_msg_free_message(msg);
+
+       msg = create_message(PCEP_TYPE_OPEN, any_obj_class, 0, 0, 0);
+       CU_ASSERT_FALSE(validate_message_objects(msg));
+       pcep_msg_free_message(msg);
+
+       msg = create_message(PCEP_TYPE_OPEN, PCEP_OBJ_CLASS_OPEN, any_obj_class,
+                            0, 0);
+       CU_ASSERT_FALSE(validate_message_objects(msg));
+       pcep_msg_free_message(msg);
+
+       /* KeepAlive message
+        * {NO_OBJECT, NO_OBJECT, NO_OBJECT, NO_OBJECT} */
+       msg = create_message(PCEP_TYPE_KEEPALIVE, any_obj_class, 0, 0, 0);
+       CU_ASSERT_FALSE(validate_message_objects(msg));
+       pcep_msg_free_message(msg);
+
+       /* PcReq message
+        * {PCEP_OBJ_CLASS_RP, PCEP_OBJ_CLASS_ENDPOINTS, ANY_OBJECT, ANY_OBJECT}
+        */
+       msg = create_message(PCEP_TYPE_PCREQ, 0, 0, 0, 0);
+       CU_ASSERT_FALSE(validate_message_objects(msg));
+       pcep_msg_free_message(msg);
+
+       msg = create_message(PCEP_TYPE_PCREQ, PCEP_OBJ_CLASS_RP, any_obj_class,
+                            0, 0);
+       CU_ASSERT_FALSE(validate_message_objects(msg));
+       pcep_msg_free_message(msg);
+
+       /* PcRep message
+        * {PCEP_OBJ_CLASS_RP, ANY_OBJECT, ANY_OBJECT, ANY_OBJECT} */
+       msg = create_message(PCEP_TYPE_PCREP, 0, 0, 0, 0);
+       CU_ASSERT_FALSE(validate_message_objects(msg));
+       pcep_msg_free_message(msg);
+
+       msg = create_message(PCEP_TYPE_PCREP, any_obj_class, 0, 0, 0);
+       CU_ASSERT_FALSE(validate_message_objects(msg));
+       pcep_msg_free_message(msg);
+
+       /* Notify message
+        * {PCEP_OBJ_CLASS_NOTF, ANY_OBJECT, ANY_OBJECT, ANY_OBJECT} */
+       msg = create_message(PCEP_TYPE_PCNOTF, 0, 0, 0, 0);
+       CU_ASSERT_FALSE(validate_message_objects(msg));
+       pcep_msg_free_message(msg);
+
+       msg = create_message(PCEP_TYPE_PCNOTF, any_obj_class, 0, 0, 0);
+       CU_ASSERT_FALSE(validate_message_objects(msg));
+       pcep_msg_free_message(msg);
+
+       /* Error message
+        * {PCEP_OBJ_CLASS_ERROR, ANY_OBJECT, ANY_OBJECT, ANY_OBJECT} */
+       msg = create_message(PCEP_TYPE_ERROR, 0, 0, 0, 0);
+       CU_ASSERT_FALSE(validate_message_objects(msg));
+       pcep_msg_free_message(msg);
+
+       msg = create_message(PCEP_TYPE_ERROR, any_obj_class, 0, 0, 0);
+       CU_ASSERT_FALSE(validate_message_objects(msg));
+       pcep_msg_free_message(msg);
+
+       /* Close message
+        * {PCEP_OBJ_CLASS_CLOSE, NO_OBJECT, NO_OBJECT, NO_OBJECT} */
+       msg = create_message(PCEP_TYPE_CLOSE, 0, 0, 0, 0);
+       CU_ASSERT_FALSE(validate_message_objects(msg));
+       pcep_msg_free_message(msg);
+
+       msg = create_message(PCEP_TYPE_CLOSE, any_obj_class, 0, 0, 0);
+       CU_ASSERT_FALSE(validate_message_objects(msg));
+       pcep_msg_free_message(msg);
+
+       /* unsupported message ID = 8
+        * {NO_OBJECT, NO_OBJECT, NO_OBJECT, NO_OBJECT} */
+       msg = create_message(8, any_obj_class, 0, 0, 0);
+       CU_ASSERT_FALSE(validate_message_objects(msg));
+       pcep_msg_free_message(msg);
+
+       /* unsupported message ID = 9
+        * {NO_OBJECT, NO_OBJECT, NO_OBJECT, NO_OBJECT} */
+       msg = create_message(9, any_obj_class, 0, 0, 0);
+       CU_ASSERT_FALSE(validate_message_objects(msg));
+       pcep_msg_free_message(msg);
+
+       /* Report message
+        * {PCEP_OBJ_CLASS_SRP, PCEP_OBJ_CLASS_LSP, ANY_OBJECT, ANY_OBJECT} */
+       msg = create_message(PCEP_TYPE_REPORT, 0, 0, 0, 0);
+       CU_ASSERT_FALSE(validate_message_objects(msg));
+       pcep_msg_free_message(msg);
+
+       msg = create_message(PCEP_TYPE_REPORT, any_obj_class, 0, 0, 0);
+       CU_ASSERT_FALSE(validate_message_objects(msg));
+       pcep_msg_free_message(msg);
+
+       msg = create_message(PCEP_TYPE_REPORT, PCEP_OBJ_CLASS_SRP, 0, 0, 0);
+       CU_ASSERT_FALSE(validate_message_objects(msg));
+       pcep_msg_free_message(msg);
+
+       msg = create_message(PCEP_TYPE_REPORT, PCEP_OBJ_CLASS_SRP,
+                            any_obj_class, 0, 0);
+       CU_ASSERT_FALSE(validate_message_objects(msg));
+       pcep_msg_free_message(msg);
+
+       /* Update message
+        * {PCEP_OBJ_CLASS_SRP, PCEP_OBJ_CLASS_LSP, ANY_OBJECT, ANY_OBJECT} */
+       msg = create_message(PCEP_TYPE_UPDATE, 0, 0, 0, 0);
+       CU_ASSERT_FALSE(validate_message_objects(msg));
+       pcep_msg_free_message(msg);
+
+       msg = create_message(PCEP_TYPE_UPDATE, any_obj_class, 0, 0, 0);
+       CU_ASSERT_FALSE(validate_message_objects(msg));
+       pcep_msg_free_message(msg);
+
+       msg = create_message(PCEP_TYPE_UPDATE, PCEP_OBJ_CLASS_SRP, 0, 0, 0);
+       CU_ASSERT_FALSE(validate_message_objects(msg));
+       pcep_msg_free_message(msg);
+
+       msg = create_message(PCEP_TYPE_UPDATE, PCEP_OBJ_CLASS_SRP,
+                            any_obj_class, 0, 0);
+       CU_ASSERT_FALSE(validate_message_objects(msg));
+       pcep_msg_free_message(msg);
+
+       /* Initiate message
+        * {PCEP_OBJ_CLASS_SRP, PCEP_OBJ_CLASS_LSP, ANY_OBJECT, ANY_OBJECT} */
+       msg = create_message(PCEP_TYPE_INITIATE, 0, 0, 0, 0);
+       CU_ASSERT_FALSE(validate_message_objects(msg));
+       pcep_msg_free_message(msg);
+
+       msg = create_message(PCEP_TYPE_INITIATE, any_obj_class, 0, 0, 0);
+       CU_ASSERT_FALSE(validate_message_objects(msg));
+       pcep_msg_free_message(msg);
+
+       msg = create_message(PCEP_TYPE_INITIATE, PCEP_OBJ_CLASS_SRP, 0, 0, 0);
+       CU_ASSERT_FALSE(validate_message_objects(msg));
+       pcep_msg_free_message(msg);
+
+       msg = create_message(PCEP_TYPE_INITIATE, PCEP_OBJ_CLASS_SRP,
+                            any_obj_class, 0, 0);
+       CU_ASSERT_FALSE(validate_message_objects(msg));
+       pcep_msg_free_message(msg);
+}
diff --git a/pceplib/test/pcep_msg_tools_test.h b/pceplib/test/pcep_msg_tools_test.h
new file mode 100644 (file)
index 0000000..dc66390
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Javier Garcia <javier.garcia@voltanet.io>
+ *
+ */
+
+/*
+ *  Timer definitions to be used internally by the pcep_timers library.
+ */
+
+#ifndef PCEP_MSG_TOOLS_TEST_H_
+#define PCEP_MSG_TOOLS_TEST_H_
+
+
+int pcep_tools_test_suite_setup(void);
+int pcep_tools_test_suite_teardown(void);
+void pcep_tools_test_setup(void);
+void pcep_tools_test_teardown(void);
+void test_pcep_msg_read_pcep_initiate(void);
+void test_pcep_msg_read_pcep_initiate2(void);
+void test_pcep_msg_read_pcep_update(void);
+void test_pcep_msg_read_pcep_open(void);
+void test_pcep_msg_read_pcep_open_initiate(void);
+void test_validate_message_header(void);
+void test_validate_message_objects(void);
+void test_validate_message_objects_invalid(void);
+void test_pcep_msg_read_pcep_open_cisco_pce(void);
+void test_pcep_msg_read_pcep_update_cisco_pce(void);
+void test_pcep_msg_read_pcep_report_cisco_pcc(void);
+void test_pcep_msg_read_pcep_initiate_cisco_pcc(void);
+
+#endif /* PCEPTIMERINTERNALS_H_ */
diff --git a/pceplib/test/pcep_pcc_api_test.c b/pceplib/test/pcep_pcc_api_test.c
new file mode 100644 (file)
index 0000000..c227dc1
--- /dev/null
@@ -0,0 +1,285 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <netdb.h> // gethostbyname
+#include <pthread.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <CUnit/CUnit.h>
+
+#include "pcep_pcc_api.h"
+#include "pcep_pcc_api_test.h"
+#include "pcep_socket_comm_mock.h"
+#include "pcep_utils_memory.h"
+
+extern pcep_event_queue *session_logic_event_queue_;
+extern const char MESSAGE_RECEIVED_STR[];
+extern const char UNKNOWN_EVENT_STR[];
+
+/*
+ * Test suite setup and teardown called before AND after the test suite.
+ */
+
+int pcep_pcc_api_test_suite_setup()
+{
+       pceplib_memory_reset();
+       return 0;
+}
+
+int pcep_pcc_api_test_suite_teardown()
+{
+       printf("\n");
+       pceplib_memory_dump();
+       return 0;
+}
+
+/*
+ * Test case setup and teardown called before AND after each test.
+ */
+
+void pcep_pcc_api_test_setup()
+{
+       setup_mock_socket_comm_info();
+}
+
+
+void pcep_pcc_api_test_teardown()
+{
+       teardown_mock_socket_comm_info();
+}
+
+/*
+ * Unit test cases
+ */
+
+void test_initialize_pcc()
+{
+       CU_ASSERT_TRUE(initialize_pcc());
+       /* Give the PCC time to initialize */
+       sleep(1);
+       CU_ASSERT_TRUE(destroy_pcc());
+}
+
+void test_connect_pce()
+{
+       pcep_configuration *config = create_default_pcep_configuration();
+       struct hostent *host_info = gethostbyname("localhost");
+       struct in_addr dest_address;
+       memcpy(&dest_address, host_info->h_addr, host_info->h_length);
+       mock_socket_comm_info *mock_info = get_mock_socket_comm_info();
+       mock_info->send_message_save_message = true;
+
+       initialize_pcc();
+
+       pcep_session *session = connect_pce(config, &dest_address);
+
+       CU_ASSERT_PTR_NOT_NULL(session);
+       CU_ASSERT_EQUAL(mock_info->sent_message_list->num_entries, 1);
+       /* What gets saved in the mock is the msg byte buffer. The msg struct
+        * was deleted when it was sent. Instead of inspecting the msg byte
+        * buffer, lets just decode it. */
+       uint8_t *encoded_msg =
+               dll_delete_first_node(mock_info->sent_message_list);
+       CU_ASSERT_PTR_NOT_NULL(encoded_msg);
+       struct pcep_message *open_msg = pcep_decode_message(encoded_msg);
+       CU_ASSERT_PTR_NOT_NULL(open_msg);
+       CU_ASSERT_EQUAL(open_msg->msg_header->type, PCEP_TYPE_OPEN);
+
+       pcep_msg_free_message(open_msg);
+       destroy_pcep_session(session);
+       destroy_pcep_configuration(config);
+       pceplib_free(PCEPLIB_MESSAGES, encoded_msg);
+
+       destroy_pcc();
+}
+
+void test_connect_pce_ipv6()
+{
+       pcep_configuration *config = create_default_pcep_configuration();
+       struct in6_addr dest_address;
+       dest_address.__in6_u.__u6_addr32[0] = 0;
+       dest_address.__in6_u.__u6_addr32[1] = 0;
+       dest_address.__in6_u.__u6_addr32[2] = 0;
+       dest_address.__in6_u.__u6_addr32[3] = htonl(1);
+       mock_socket_comm_info *mock_info = get_mock_socket_comm_info();
+       mock_info->send_message_save_message = true;
+
+       initialize_pcc();
+
+       pcep_session *session = connect_pce_ipv6(config, &dest_address);
+
+       CU_ASSERT_PTR_NOT_NULL(session);
+       CU_ASSERT_TRUE(session->socket_comm_session->is_ipv6);
+       CU_ASSERT_EQUAL(mock_info->sent_message_list->num_entries, 1);
+       /* What gets saved in the mock is the msg byte buffer. The msg struct
+        * was deleted when it was sent. Instead of inspecting the msg byte
+        * buffer, lets just decode it. */
+       uint8_t *encoded_msg =
+               dll_delete_first_node(mock_info->sent_message_list);
+       CU_ASSERT_PTR_NOT_NULL(encoded_msg);
+       struct pcep_message *open_msg = pcep_decode_message(encoded_msg);
+       CU_ASSERT_PTR_NOT_NULL(open_msg);
+       CU_ASSERT_EQUAL(open_msg->msg_header->type, PCEP_TYPE_OPEN);
+
+       pcep_msg_free_message(open_msg);
+       destroy_pcep_session(session);
+       destroy_pcep_configuration(config);
+       pceplib_free(PCEPLIB_MESSAGES, encoded_msg);
+
+       destroy_pcc();
+}
+
+void test_connect_pce_with_src_ip()
+{
+       pcep_configuration *config = create_default_pcep_configuration();
+       struct hostent *host_info = gethostbyname("localhost");
+       struct in_addr dest_address;
+       memcpy(&dest_address, host_info->h_addr, host_info->h_length);
+       mock_socket_comm_info *mock_info = get_mock_socket_comm_info();
+       mock_info->send_message_save_message = true;
+       config->src_ip.src_ipv4.s_addr = 0x0a0a0102;
+
+       initialize_pcc();
+
+       pcep_session *session = connect_pce(config, &dest_address);
+
+       CU_ASSERT_PTR_NOT_NULL(session);
+       CU_ASSERT_EQUAL(mock_info->sent_message_list->num_entries, 1);
+       uint8_t *encoded_msg =
+               dll_delete_first_node(mock_info->sent_message_list);
+       CU_ASSERT_PTR_NOT_NULL(encoded_msg);
+       struct pcep_message *open_msg = pcep_decode_message(encoded_msg);
+       CU_ASSERT_PTR_NOT_NULL(open_msg);
+       CU_ASSERT_EQUAL(open_msg->msg_header->type, PCEP_TYPE_OPEN);
+
+       pcep_msg_free_message(open_msg);
+       destroy_pcep_session(session);
+       destroy_pcep_configuration(config);
+       pceplib_free(PCEPLIB_MESSAGES, encoded_msg);
+
+       destroy_pcc();
+}
+
+void test_disconnect_pce()
+{
+       pcep_configuration *config = create_default_pcep_configuration();
+       struct hostent *host_info = gethostbyname("localhost");
+       struct in_addr dest_address;
+       memcpy(&dest_address, host_info->h_addr, host_info->h_length);
+       mock_socket_comm_info *mock_info = get_mock_socket_comm_info();
+       mock_info->send_message_save_message = true;
+
+       initialize_pcc();
+
+       pcep_session *session = connect_pce(config, &dest_address);
+       disconnect_pce(session);
+
+       CU_ASSERT_EQUAL(mock_info->sent_message_list->num_entries, 2);
+
+       /* First there should be an open message from connect_pce() */
+       uint8_t *encoded_msg =
+               dll_delete_first_node(mock_info->sent_message_list);
+       CU_ASSERT_PTR_NOT_NULL(encoded_msg);
+       struct pcep_message *msg = pcep_decode_message(encoded_msg);
+       CU_ASSERT_PTR_NOT_NULL(msg);
+       CU_ASSERT_EQUAL(msg->msg_header->type, PCEP_TYPE_OPEN);
+       pcep_msg_free_message(msg);
+       pceplib_free(PCEPLIB_MESSAGES, encoded_msg);
+
+       /* Then there should be a close message from disconnect_pce() */
+       encoded_msg = dll_delete_first_node(mock_info->sent_message_list);
+       CU_ASSERT_PTR_NOT_NULL(encoded_msg);
+       msg = pcep_decode_message(encoded_msg);
+       CU_ASSERT_PTR_NOT_NULL(msg);
+       CU_ASSERT_EQUAL(msg->msg_header->type, PCEP_TYPE_CLOSE);
+
+       pcep_msg_free_message(msg);
+       destroy_pcep_session(session);
+       destroy_pcep_configuration(config);
+       pceplib_free(PCEPLIB_MESSAGES, encoded_msg);
+
+       destroy_pcc();
+}
+
+
+void test_send_message()
+{
+       pcep_configuration *config = create_default_pcep_configuration();
+       struct hostent *host_info = gethostbyname("localhost");
+       struct in_addr dest_address;
+
+       initialize_pcc();
+
+       memcpy(&dest_address, host_info->h_addr, host_info->h_length);
+       pcep_session *session = connect_pce(config, &dest_address);
+       verify_socket_comm_times_called(0, 0, 1, 1, 0, 0, 0);
+
+       struct pcep_message *msg = pcep_msg_create_keepalive();
+       send_message(session, msg, false);
+
+       verify_socket_comm_times_called(0, 0, 1, 2, 0, 0, 0);
+
+       pcep_msg_free_message(msg);
+       destroy_pcep_session(session);
+       destroy_pcep_configuration(config);
+
+       destroy_pcc();
+}
+
+void test_event_queue()
+{
+       /* This initializes the event_queue */
+       CU_ASSERT_TRUE(initialize_pcc());
+
+       /* Verify correct behavior when the queue is empty */
+       CU_ASSERT_TRUE(event_queue_is_empty());
+       CU_ASSERT_EQUAL(event_queue_num_events_available(), 0);
+       CU_ASSERT_PTR_NULL(event_queue_get_event());
+       destroy_pcep_event(NULL);
+
+       /* Create an empty event and put it on the queue */
+       pcep_event *event = pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_event));
+       memset(event, 0, sizeof(pcep_event));
+       pthread_mutex_lock(&session_logic_event_queue_->event_queue_mutex);
+       queue_enqueue(session_logic_event_queue_->event_queue, event);
+       pthread_mutex_unlock(&session_logic_event_queue_->event_queue_mutex);
+
+       /* Verify correct behavior when there is an entry in the queue */
+       CU_ASSERT_FALSE(event_queue_is_empty());
+       CU_ASSERT_EQUAL(event_queue_num_events_available(), 1);
+       pcep_event *queued_event = event_queue_get_event();
+       CU_ASSERT_PTR_NOT_NULL(queued_event);
+       CU_ASSERT_PTR_EQUAL(event, queued_event);
+       destroy_pcep_event(queued_event);
+
+       CU_ASSERT_TRUE(destroy_pcc());
+}
+
+void test_get_event_type_str()
+{
+       CU_ASSERT_EQUAL(strcmp(get_event_type_str(MESSAGE_RECEIVED),
+                              MESSAGE_RECEIVED_STR),
+                       0);
+       CU_ASSERT_EQUAL(strcmp(get_event_type_str(1000), UNKNOWN_EVENT_STR), 0);
+}
diff --git a/pceplib/test/pcep_pcc_api_test.h b/pceplib/test/pcep_pcc_api_test.h
new file mode 100644 (file)
index 0000000..d3db96e
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Javier Garcia <javier.garcia@voltanet.io>
+ *
+ */
+
+/*
+ *  Timer definitions to be used internally by the pcep_timers library.
+ */
+
+#ifndef PCEP_PCC_API_TEST_
+#define PCEP_PCC_API_TEST_
+
+int pcep_pcc_api_test_suite_setup(void);
+int pcep_pcc_api_test_suite_teardown(void);
+void pcep_pcc_api_test_setup(void);
+void pcep_pcc_api_test_teardown(void);
+void test_initialize_pcc(void);
+void test_connect_pce(void);
+void test_connect_pce_ipv6(void);
+void test_connect_pce_with_src_ip(void);
+void test_disconnect_pce(void);
+void test_send_message(void);
+void test_event_queue(void);
+void test_get_event_type_str(void);
+
+#endif /* PCEPTIMERINTERNALS_H_ */
diff --git a/pceplib/test/pcep_pcc_api_tests.c b/pceplib/test/pcep_pcc_api_tests.c
new file mode 100644 (file)
index 0000000..04895d6
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <CUnit/Basic.h>
+#include <CUnit/CUnit.h>
+#include <CUnit/TestDB.h>
+
+#include "pcep_pcc_api_test.h"
+
+int main(int argc, char **argv)
+{
+       /* Unused parameters cause compilation warnings */
+       (void)argc;
+       (void)argv;
+
+       CU_initialize_registry();
+
+       /*
+        * Tests defined in pcep_socket_comm_test.c
+        */
+       CU_pSuite test_pcc_api_suite = CU_add_suite_with_setup_and_teardown(
+               "PCEP PCC API Test Suite",
+               pcep_pcc_api_test_suite_setup, // suite setup and cleanup
+                                              // function pointers
+               pcep_pcc_api_test_suite_teardown,
+               pcep_pcc_api_test_setup,     // test case setup function pointer
+               pcep_pcc_api_test_teardown); // test case teardown function
+                                            // pointer
+
+       CU_add_test(test_pcc_api_suite, "test_initialize_pcc",
+                   test_initialize_pcc);
+       CU_add_test(test_pcc_api_suite, "test_connect_pce", test_connect_pce);
+       CU_add_test(test_pcc_api_suite, "test_connect_pce_ipv6",
+                   test_connect_pce_ipv6);
+       CU_add_test(test_pcc_api_suite, "test_connect_pce_with_src_ip",
+                   test_connect_pce_with_src_ip);
+       CU_add_test(test_pcc_api_suite, "test_disconnect_pce",
+                   test_disconnect_pce);
+       CU_add_test(test_pcc_api_suite, "test_send_message", test_send_message);
+       CU_add_test(test_pcc_api_suite, "test_event_queue", test_event_queue);
+       CU_add_test(test_pcc_api_suite, "test_get_event_type_str",
+                   test_get_event_type_str);
+
+       /*
+        * Run the tests and cleanup.
+        */
+       CU_basic_set_mode(CU_BRM_VERBOSE);
+       CU_basic_run_tests();
+       CU_FailureRecord *failure_record = CU_get_failure_list();
+       if (failure_record != NULL) {
+               printf("\nFailed tests:\n\t [Suite] [Test] [File:line-number]\n");
+               do {
+                       printf("\t [%s] [%s] [%s:%d]\n",
+                              failure_record->pSuite->pName,
+                              failure_record->pTest->pName,
+                              failure_record->strFileName,
+                              failure_record->uiLineNumber);
+                       failure_record = failure_record->pNext;
+
+               } while (failure_record != NULL);
+       }
+
+       CU_pRunSummary run_summary = CU_get_run_summary();
+       int result = run_summary->nTestsFailed;
+       CU_cleanup_registry();
+
+       return result;
+}
diff --git a/pceplib/test/pcep_pcc_api_tests_valgrind.sh b/pceplib/test/pcep_pcc_api_tests_valgrind.sh
new file mode 100755 (executable)
index 0000000..74494b7
--- /dev/null
@@ -0,0 +1,2 @@
+source pceplib/test/pcep_tests_valgrind.sh
+valgrind_test pceplib/test/pcep_pcc_api_tests
diff --git a/pceplib/test/pcep_session_logic_loop_test.c b/pceplib/test/pcep_session_logic_loop_test.c
new file mode 100644 (file)
index 0000000..3a40f59
--- /dev/null
@@ -0,0 +1,235 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <CUnit/CUnit.h>
+
+#include "pcep_msg_encoding.h"
+#include "pcep_session_logic.h"
+#include "pcep_session_logic_internals.h"
+#include "pcep_timers.h"
+#include "pcep_utils_ordered_list.h"
+#include "pcep_utils_memory.h"
+#include "pcep_session_logic_loop_test.h"
+
+
+extern pcep_session_logic_handle *session_logic_handle_;
+extern pcep_event_queue *session_logic_event_queue_;
+
+/*
+ * Test suite setup and teardown called before AND after the test suite.
+ */
+
+int pcep_session_logic_loop_test_suite_setup(void)
+{
+       pceplib_memory_reset();
+       return 0;
+}
+
+int pcep_session_logic_loop_test_suite_teardown(void)
+{
+       printf("\n");
+       pceplib_memory_dump();
+       return 0;
+}
+
+
+/*
+ * Test case setup and teardown called before AND after each test.
+ */
+
+void pcep_session_logic_loop_test_setup()
+{
+       /* We need to setup the session_logic_handle_ without starting the
+        * thread */
+       session_logic_handle_ = pceplib_malloc(
+               PCEPLIB_INFRA, sizeof(pcep_session_logic_handle));
+       memset(session_logic_handle_, 0, sizeof(pcep_session_logic_handle));
+       session_logic_handle_->active = true;
+       session_logic_handle_->session_list =
+               ordered_list_initialize(pointer_compare_function);
+       session_logic_handle_->session_event_queue = queue_initialize();
+       pthread_cond_init(&(session_logic_handle_->session_logic_cond_var),
+                         NULL);
+       pthread_mutex_init(&(session_logic_handle_->session_logic_mutex), NULL);
+       pthread_mutex_init(&(session_logic_handle_->session_list_mutex), NULL);
+
+       pthread_mutex_lock(&(session_logic_handle_->session_logic_mutex));
+       session_logic_handle_->session_logic_condition = true;
+       pthread_cond_signal(&(session_logic_handle_->session_logic_cond_var));
+       pthread_mutex_unlock(&(session_logic_handle_->session_logic_mutex));
+
+       session_logic_event_queue_ =
+               pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_event_queue));
+       memset(session_logic_event_queue_, 0, sizeof(pcep_event_queue));
+       session_logic_event_queue_->event_queue = queue_initialize();
+}
+
+
+void pcep_session_logic_loop_test_teardown()
+{
+       ordered_list_destroy(session_logic_handle_->session_list);
+       queue_destroy(session_logic_handle_->session_event_queue);
+       pthread_mutex_unlock(&(session_logic_handle_->session_logic_mutex));
+       pthread_mutex_destroy(&(session_logic_handle_->session_logic_mutex));
+       pthread_mutex_destroy(&(session_logic_handle_->session_list_mutex));
+       pceplib_free(PCEPLIB_INFRA, session_logic_handle_);
+       session_logic_handle_ = NULL;
+
+       queue_destroy(session_logic_event_queue_->event_queue);
+       pceplib_free(PCEPLIB_INFRA, session_logic_event_queue_);
+       session_logic_event_queue_ = NULL;
+}
+
+
+/*
+ * Test cases
+ */
+
+void test_session_logic_loop_null_data()
+{
+       /* Just testing that it does not core dump */
+       session_logic_loop(NULL);
+}
+
+
+void test_session_logic_loop_inactive()
+{
+       session_logic_handle_->active = false;
+
+       session_logic_loop(session_logic_handle_);
+}
+
+
+void test_session_logic_msg_ready_handler()
+{
+       /* Just testing that it does not core dump */
+       CU_ASSERT_EQUAL(session_logic_msg_ready_handler(NULL, 0), -1);
+
+       /* Read from an empty file should return 0, thus
+        * session_logic_msg_ready_handler returns -1 */
+       mode_t oldumask;
+       oldumask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH);
+       /* Set umask before anything for security */
+       umask(0027);
+       char tmpfile[] = "/tmp/pceplib_XXXXXX";
+       int fd = mkstemp(tmpfile);
+       umask(oldumask);
+       if (fd == -1){
+               CU_ASSERT_TRUE(fd>=0);
+               return;
+       }
+       pcep_session session;
+       memset(&session, 0, sizeof(pcep_session));
+       session.session_id = 100;
+       CU_ASSERT_EQUAL(session_logic_msg_ready_handler(&session, fd), 0);
+       CU_ASSERT_EQUAL(session_logic_handle_->session_event_queue->num_entries,
+                       1);
+       pcep_event *e = queue_dequeue(session_logic_event_queue_->event_queue);
+       CU_ASSERT_EQUAL(PCE_CLOSED_SOCKET, e->event_type);
+       pceplib_free(PCEPLIB_INFRA, e);
+       pcep_session_event *socket_event = (pcep_session_event *)queue_dequeue(
+               session_logic_handle_->session_event_queue);
+       CU_ASSERT_PTR_NOT_NULL(socket_event);
+       CU_ASSERT_TRUE(socket_event->socket_closed);
+       pceplib_free(PCEPLIB_INFRA, socket_event);
+
+       /* A pcep_session_event should be created */
+       struct pcep_versioning *versioning = create_default_pcep_versioning();
+       struct pcep_message *keep_alive_msg = pcep_msg_create_keepalive();
+       pcep_encode_message(keep_alive_msg, versioning);
+       int retval = write(fd, (char *)keep_alive_msg->encoded_message,
+                          keep_alive_msg->encoded_message_length);
+       CU_ASSERT_TRUE(retval > 0);
+       lseek(fd, 0, SEEK_SET);
+       CU_ASSERT_EQUAL(session_logic_msg_ready_handler(&session, fd),
+                       keep_alive_msg->encoded_message_length);
+       CU_ASSERT_EQUAL(session_logic_handle_->session_event_queue->num_entries,
+                       1);
+       socket_event = (pcep_session_event *)queue_dequeue(
+               session_logic_handle_->session_event_queue);
+       CU_ASSERT_PTR_NOT_NULL(socket_event);
+       CU_ASSERT_FALSE(socket_event->socket_closed);
+       CU_ASSERT_PTR_EQUAL(socket_event->session, &session);
+       CU_ASSERT_EQUAL(socket_event->expired_timer_id, TIMER_ID_NOT_SET);
+       CU_ASSERT_PTR_NOT_NULL(socket_event->received_msg_list);
+       pcep_msg_free_message_list(socket_event->received_msg_list);
+       pcep_msg_free_message(keep_alive_msg);
+       destroy_pcep_versioning(versioning);
+       pceplib_free(PCEPLIB_INFRA, socket_event);
+       close(fd);
+}
+
+
+void test_session_logic_conn_except_notifier()
+{
+       /* Just testing that it does not core dump */
+       session_logic_conn_except_notifier(NULL, 1);
+
+       /* A pcep_session_event should be created */
+       pcep_session session;
+       memset(&session, 0, sizeof(pcep_session));
+       session.session_id = 100;
+       session_logic_conn_except_notifier(&session, 10);
+       CU_ASSERT_EQUAL(session_logic_handle_->session_event_queue->num_entries,
+                       1);
+       pcep_session_event *socket_event = (pcep_session_event *)queue_dequeue(
+               session_logic_handle_->session_event_queue);
+       CU_ASSERT_PTR_NOT_NULL_FATAL(socket_event);
+       CU_ASSERT_TRUE(socket_event->socket_closed);
+       CU_ASSERT_PTR_EQUAL(socket_event->session, &session);
+       CU_ASSERT_EQUAL(socket_event->expired_timer_id, TIMER_ID_NOT_SET);
+       CU_ASSERT_PTR_NULL(socket_event->received_msg_list);
+
+       pceplib_free(PCEPLIB_INFRA, socket_event);
+}
+
+
+void test_session_logic_timer_expire_handler()
+{
+       /* Just testing that it does not core dump */
+       session_logic_timer_expire_handler(NULL, 42);
+
+       /* A pcep_session_event should be created */
+       pcep_session session;
+       memset(&session, 0, sizeof(pcep_session));
+       session.session_id = 100;
+       session_logic_timer_expire_handler(&session, 42);
+       CU_ASSERT_EQUAL(session_logic_handle_->session_event_queue->num_entries,
+                       1);
+       pcep_session_event *socket_event = (pcep_session_event *)queue_dequeue(
+               session_logic_handle_->session_event_queue);
+       CU_ASSERT_PTR_NOT_NULL_FATAL(socket_event);
+       CU_ASSERT_FALSE(socket_event->socket_closed);
+       CU_ASSERT_PTR_EQUAL(socket_event->session, &session);
+       CU_ASSERT_EQUAL(socket_event->expired_timer_id, 42);
+       CU_ASSERT_PTR_NULL(socket_event->received_msg_list);
+
+       pceplib_free(PCEPLIB_INFRA, socket_event);
+}
diff --git a/pceplib/test/pcep_session_logic_loop_test.h b/pceplib/test/pcep_session_logic_loop_test.h
new file mode 100644 (file)
index 0000000..ae3c3e3
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Javier Garcia <javier.garcia@voltanet.io>
+ *
+ */
+
+/*
+ *  Timer definitions to be used internally by the pcep_timers library.
+ */
+
+#ifndef PCEP_SESSION_LOGIC_LOOP_TEST_H_
+#define PCEP_SESSION_LOGIC_LOOP_TEST_H_
+
+int pcep_session_logic_loop_test_suite_setup(void);
+int pcep_session_logic_loop_test_suite_teardown(void);
+void pcep_session_logic_loop_test_setup(void);
+void pcep_session_logic_loop_test_teardown(void);
+void test_session_logic_loop_null_data(void);
+void test_session_logic_loop_inactive(void);
+void test_session_logic_msg_ready_handler(void);
+void test_session_logic_conn_except_notifier(void);
+void test_session_logic_timer_expire_handler(void);
+
+#endif /* PCEPTIMERINTERNALS_H_ */
diff --git a/pceplib/test/pcep_session_logic_states_test.c b/pceplib/test/pcep_session_logic_states_test.c
new file mode 100644 (file)
index 0000000..f75c16e
--- /dev/null
@@ -0,0 +1,919 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <CUnit/CUnit.h>
+
+#include "pcep_socket_comm_mock.h"
+#include "pcep_session_logic.h"
+#include "pcep_session_logic_internals.h"
+#include "pcep_timers.h"
+#include "pcep_utils_ordered_list.h"
+#include "pcep_utils_double_linked_list.h"
+#include "pcep_utils_memory.h"
+#include "pcep_msg_objects.h"
+#include "pcep_msg_tools.h"
+#include "pcep_session_logic_states_test.h"
+
+/* Functions being tested */
+extern pcep_session_logic_handle *session_logic_handle_;
+extern pcep_event_queue *session_logic_event_queue_;
+
+static pcep_session_event event;
+static pcep_session session;
+/* A message list is a dll of struct pcep_messages_list_node items */
+static double_linked_list *msg_list;
+struct pcep_message *message;
+static bool free_msg_list;
+static bool msg_enqueued;
+/* Forward declaration */
+void destroy_message_for_test(void);
+void create_message_for_test(uint8_t msg_type, bool free_msg_list_at_teardown,
+                            bool was_msg_enqueued);
+void test_handle_timer_event_open_keep_alive(void);
+
+/*
+ * Test suite setup and teardown called before AND after the test suite.
+ */
+
+int pcep_session_logic_states_test_suite_setup(void)
+{
+       pceplib_memory_reset();
+       return 0;
+}
+
+int pcep_session_logic_states_test_suite_teardown(void)
+{
+       printf("\n");
+       pceplib_memory_dump();
+       return 0;
+}
+
+/*
+ * Test case setup and teardown called before AND after each test.
+ */
+
+void pcep_session_logic_states_test_setup()
+{
+       session_logic_handle_ = pceplib_malloc(
+               PCEPLIB_INFRA, sizeof(pcep_session_logic_handle));
+       memset(session_logic_handle_, 0, sizeof(pcep_session_logic_handle));
+
+       session_logic_event_queue_ =
+               pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_event_queue));
+       memset(session_logic_event_queue_, 0, sizeof(pcep_event_queue));
+       session_logic_event_queue_->event_queue = queue_initialize();
+
+       memset(&session, 0, sizeof(pcep_session));
+       session.pcc_config.keep_alive_seconds = 5;
+       session.pcc_config.keep_alive_pce_negotiated_timer_seconds = 5;
+       session.pcc_config.min_keep_alive_seconds = 1;
+       session.pcc_config.max_keep_alive_seconds = 10;
+       session.pcc_config.dead_timer_seconds = 5;
+       session.pcc_config.dead_timer_pce_negotiated_seconds = 5;
+       session.pcc_config.min_dead_timer_seconds = 1;
+       session.pcc_config.max_dead_timer_seconds = 10;
+       session.pcc_config.max_unknown_messages = 2;
+       memcpy(&session.pce_config, &session.pcc_config,
+              sizeof(pcep_configuration));
+       session.num_unknown_messages_time_queue = queue_initialize();
+
+       memset(&event, 0, sizeof(pcep_session_event));
+       event.socket_closed = false;
+       event.session = &session;
+
+       setup_mock_socket_comm_info();
+       free_msg_list = false;
+       msg_enqueued = false;
+}
+
+
+void pcep_session_logic_states_test_teardown()
+{
+       destroy_message_for_test();
+       pceplib_free(PCEPLIB_INFRA, session_logic_handle_);
+       queue_destroy(session_logic_event_queue_->event_queue);
+       pceplib_free(PCEPLIB_INFRA, session_logic_event_queue_);
+       session_logic_handle_ = NULL;
+       session_logic_event_queue_ = NULL;
+       queue_destroy_with_data(session.num_unknown_messages_time_queue);
+       teardown_mock_socket_comm_info();
+}
+
+void create_message_for_test(uint8_t msg_type, bool free_msg_list_at_teardown,
+                            bool was_msg_enqueued)
+{
+       /* See the comments in destroy_message_for_test() about these 2
+        * variables */
+       free_msg_list = free_msg_list_at_teardown;
+       msg_enqueued = was_msg_enqueued;
+
+       message = pceplib_malloc(PCEPLIB_MESSAGES, sizeof(struct pcep_message));
+       memset(message, 0, sizeof(struct pcep_message));
+
+       message->msg_header = pceplib_malloc(
+               PCEPLIB_MESSAGES, sizeof(struct pcep_message_header));
+       memset(message->msg_header, 0, sizeof(struct pcep_message_header));
+       message->obj_list = dll_initialize();
+       message->msg_header->type = msg_type;
+
+       msg_list = dll_initialize();
+       dll_append(msg_list, message);
+       event.received_msg_list = msg_list;
+}
+
+void destroy_message_for_test()
+{
+       /* Some test cases internally free the message list, so we dont
+        * want to double free it */
+       if (free_msg_list == true) {
+               /* This will destroy both the msg_list and the obj_list */
+               pcep_msg_free_message_list(msg_list);
+       }
+
+       /* Some tests cause the message to be enqueued and dont delete it,
+        * so we have to delete it here */
+       if (msg_enqueued == true) {
+               pcep_msg_free_message(message);
+       }
+}
+
+/*
+ * Test cases
+ */
+
+void test_handle_timer_event_dead_timer()
+{
+       /* Dead Timer expired */
+       event.expired_timer_id = session.timer_id_dead_timer = 100;
+
+       handle_timer_event(&event);
+
+       CU_ASSERT_EQUAL(session.timer_id_dead_timer, TIMER_ID_NOT_SET);
+       CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_INITIALIZED);
+       CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+                       1);
+
+       pcep_event *e = queue_dequeue(session_logic_event_queue_->event_queue);
+       CU_ASSERT_EQUAL(PCE_DEAD_TIMER_EXPIRED, e->event_type);
+       pceplib_free(PCEPLIB_INFRA, e);
+
+       /* verify_socket_comm_times_called(
+        *     initialized, teardown, connect, send_message, close_after_write,
+        * close, destroy); */
+       verify_socket_comm_times_called(0, 0, 0, 1, 1, 0, 0);
+}
+
+
+void test_handle_timer_event_keep_alive()
+{
+       /* Keep Alive timer expired */
+       event.expired_timer_id = session.timer_id_keep_alive = 200;
+
+       handle_timer_event(&event);
+
+       CU_ASSERT_EQUAL(session.timer_id_keep_alive, TIMER_ID_NOT_SET);
+       verify_socket_comm_times_called(0, 0, 0, 1, 0, 0, 0);
+}
+
+
+void test_handle_timer_event_open_keep_wait()
+{
+       /* Open Keep Wait timer expired */
+       event.expired_timer_id = session.timer_id_open_keep_wait = 300;
+       session.session_state = SESSION_STATE_PCEP_CONNECTING;
+       handle_timer_event(&event);
+
+       CU_ASSERT_EQUAL(session.timer_id_open_keep_wait, TIMER_ID_NOT_SET);
+       CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_INITIALIZED);
+       CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+                       1);
+       verify_socket_comm_times_called(0, 0, 0, 0, 1, 0, 0);
+
+       pcep_event *e = queue_dequeue(session_logic_event_queue_->event_queue);
+       CU_ASSERT_EQUAL(PCE_OPEN_KEEP_WAIT_TIMER_EXPIRED, e->event_type);
+       pceplib_free(PCEPLIB_INFRA, e);
+
+       /* If the state is not SESSION_STATE_PCEP_CONNECTED, then nothing should
+        * happen */
+       reset_mock_socket_comm_info();
+       session.session_state = SESSION_STATE_UNKNOWN;
+       event.expired_timer_id = session.timer_id_open_keep_wait = 300;
+       handle_timer_event(&event);
+
+       CU_ASSERT_EQUAL(session.timer_id_open_keep_wait, 300);
+       CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_UNKNOWN);
+       verify_socket_comm_times_called(0, 0, 0, 0, 0, 0, 0);
+}
+
+
+void test_handle_timer_event_open_keep_alive()
+{
+       /* Open Keep Alive timer expired, but the Keep Alive should not be sent
+        * since the PCE Open has not been received yet */
+       event.expired_timer_id = session.timer_id_open_keep_alive = 300;
+       session.session_state = SESSION_STATE_PCEP_CONNECTING;
+       session.pce_open_keep_alive_sent = false;
+       session.pce_open_received = false;
+       handle_timer_event(&event);
+
+       CU_ASSERT_EQUAL(session.timer_id_open_keep_alive, TIMER_ID_NOT_SET);
+       CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_PCEP_CONNECTING);
+       CU_ASSERT_FALSE(session.pce_open_keep_alive_sent);
+
+       /* Open Keep Alive timer expired, the Keep Alive should be sent,
+        * but the session should not be connected, since the PCC Open
+        * has not been accepted yet */
+       event.expired_timer_id = session.timer_id_open_keep_alive = 300;
+       session.session_state = SESSION_STATE_PCEP_CONNECTING;
+       session.pce_open_keep_alive_sent = false;
+       session.pce_open_received = true;
+       session.pce_open_rejected = false;
+       session.pcc_open_accepted = false;
+       handle_timer_event(&event);
+
+       CU_ASSERT_EQUAL(session.timer_id_open_keep_alive, TIMER_ID_NOT_SET);
+       CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_PCEP_CONNECTING);
+       CU_ASSERT_TRUE(session.pce_open_keep_alive_sent);
+
+       /* Open Keep Alive timer expired, the Keep Alive should be sent,
+        * and the session is connected */
+       event.expired_timer_id = session.timer_id_open_keep_alive = 300;
+       session.session_state = SESSION_STATE_PCEP_CONNECTING;
+       session.pce_open_keep_alive_sent = false;
+       session.pce_open_received = true;
+       session.pce_open_rejected = false;
+       session.pcc_open_accepted = true;
+       handle_timer_event(&event);
+
+       CU_ASSERT_EQUAL(session.timer_id_open_keep_alive, TIMER_ID_NOT_SET);
+       CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_PCEP_CONNECTED);
+       CU_ASSERT_FALSE(session.pce_open_keep_alive_sent);
+}
+
+
+void test_handle_socket_comm_event_null_params()
+{
+       /* Verify it doesnt core dump */
+       handle_socket_comm_event(NULL);
+       verify_socket_comm_times_called(0, 0, 0, 0, 0, 0, 0);
+       reset_mock_socket_comm_info();
+
+       event.received_msg_list = NULL;
+       handle_socket_comm_event(&event);
+       verify_socket_comm_times_called(0, 0, 0, 0, 0, 0, 0);
+}
+
+
+void test_handle_socket_comm_event_close()
+{
+       event.socket_closed = true;
+       handle_socket_comm_event(&event);
+
+       CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_INITIALIZED);
+       CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+                       1);
+       verify_socket_comm_times_called(0, 0, 0, 0, 0, 1, 0);
+
+       pcep_event *e = queue_dequeue(session_logic_event_queue_->event_queue);
+       CU_ASSERT_EQUAL(PCE_CLOSED_SOCKET, e->event_type);
+       pceplib_free(PCEPLIB_INFRA, e);
+}
+
+
+void test_handle_socket_comm_event_open()
+{
+       /*
+        * Test when a PCE Open is received, but the PCC Open has not been
+        * accepted yet
+        */
+       create_message_for_test(PCEP_TYPE_OPEN, false, true);
+       struct pcep_object_open *open_object =
+               pcep_obj_create_open(1, 1, 1, NULL);
+       dll_append(message->obj_list, open_object);
+       session.pcc_open_accepted = false;
+       session.pce_open_received = false;
+       session.pce_open_accepted = false;
+       session.timer_id_open_keep_alive = 100;
+       session.session_state = SESSION_STATE_PCEP_CONNECTING;
+
+       handle_socket_comm_event(&event);
+
+       CU_ASSERT_TRUE(session.pce_open_received);
+       CU_ASSERT_TRUE(session.pce_open_accepted);
+       CU_ASSERT_FALSE(session.pce_open_rejected);
+       CU_ASSERT_FALSE(session.pce_open_keep_alive_sent);
+       CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_PCEP_CONNECTING);
+       CU_ASSERT_NOT_EQUAL(session.timer_id_open_keep_alive, 100);
+       /* A keep alive response should NOT be sent yet */
+       verify_socket_comm_times_called(0, 0, 0, 0, 0, 0, 0);
+       CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+                       1);
+       pcep_event *e = queue_dequeue(session_logic_event_queue_->event_queue);
+       CU_ASSERT_EQUAL(MESSAGE_RECEIVED, e->event_type);
+       CU_ASSERT_EQUAL(PCEP_TYPE_OPEN, e->message->msg_header->type);
+       pceplib_free(PCEPLIB_INFRA, e);
+       destroy_message_for_test();
+
+       /*
+        * Test when a PCE Open is received, and the PCC Open has been accepted
+        */
+       create_message_for_test(PCEP_TYPE_OPEN, false, true);
+       reset_mock_socket_comm_info();
+       open_object = pcep_obj_create_open(1, 1, 1, NULL);
+       dll_append(message->obj_list, open_object);
+       session.pcc_open_accepted = true;
+       session.pce_open_received = false;
+       session.pce_open_accepted = false;
+       session.session_state = SESSION_STATE_PCEP_CONNECTING;
+
+       handle_socket_comm_event(&event);
+
+       CU_ASSERT_TRUE(session.pce_open_received);
+       CU_ASSERT_TRUE(session.pce_open_accepted);
+       CU_ASSERT_FALSE(session.pce_open_rejected);
+       CU_ASSERT_TRUE(session.pce_open_keep_alive_sent);
+       CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_PCEP_CONNECTED);
+       /* A keep alive response should be sent, accepting the Open */
+       verify_socket_comm_times_called(0, 0, 0, 1, 0, 0, 0);
+       CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+                       2);
+       e = queue_dequeue(session_logic_event_queue_->event_queue);
+       CU_ASSERT_EQUAL(MESSAGE_RECEIVED, e->event_type);
+       CU_ASSERT_EQUAL(PCEP_TYPE_OPEN, e->message->msg_header->type);
+       pceplib_free(PCEPLIB_INFRA, e);
+       e = queue_dequeue(session_logic_event_queue_->event_queue);
+       CU_ASSERT_EQUAL(PCC_CONNECTED_TO_PCE, e->event_type);
+       pceplib_free(PCEPLIB_INFRA, e);
+       destroy_message_for_test();
+
+       /*
+        * Send a 2nd Open, an error should be sent
+        */
+       create_message_for_test(PCEP_TYPE_OPEN, false, false);
+       reset_mock_socket_comm_info();
+       mock_socket_comm_info *mock_info = get_mock_socket_comm_info();
+       mock_info->send_message_save_message = true;
+
+       handle_socket_comm_event(&event);
+
+       CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+                       0);
+       verify_socket_comm_times_called(0, 0, 0, 1, 0, 0, 0);
+       /* What gets saved in the mock is the msg byte buffer. The msg struct
+        * was deleted when it was sent. Instead of inspecting the msg byte
+        * buffer, lets just decode it. */
+       uint8_t *encoded_msg =
+               dll_delete_first_node(mock_info->sent_message_list);
+       CU_ASSERT_PTR_NOT_NULL(encoded_msg);
+       struct pcep_message *msg = pcep_decode_message(encoded_msg);
+       CU_ASSERT_PTR_NOT_NULL(msg);
+       CU_ASSERT_EQUAL(PCEP_TYPE_ERROR, msg->msg_header->type);
+       /* Verify the error object */
+       CU_ASSERT_EQUAL(1, msg->obj_list->num_entries);
+       struct pcep_object_error *error_obj = msg->obj_list->head->data;
+       CU_ASSERT_EQUAL(PCEP_OBJ_CLASS_ERROR, error_obj->header.object_class);
+       CU_ASSERT_EQUAL(PCEP_OBJ_TYPE_ERROR, error_obj->header.object_type);
+       CU_ASSERT_EQUAL(PCEP_ERRT_ATTEMPT_TO_ESTABLISH_2ND_PCEP_SESSION,
+                       error_obj->error_type);
+       CU_ASSERT_EQUAL(PCEP_ERRV_RECVD_INVALID_OPEN_MSG,
+                       error_obj->error_value);
+       pcep_msg_free_message(msg);
+       pceplib_free(PCEPLIB_MESSAGES, encoded_msg);
+}
+
+
+void test_handle_socket_comm_event_open_error()
+{
+       /* Test when the PCE rejects the PCC Open with an Error
+        * that a "corrected" Open message is sent. */
+
+       create_message_for_test(PCEP_TYPE_ERROR, false, true);
+       struct pcep_object_error *error_object = pcep_obj_create_error(
+               PCEP_ERRT_SESSION_FAILURE, PCEP_ERRV_UNACCEPTABLE_OPEN_MSG_NEG);
+       struct pcep_object_open *error_open_object =
+               pcep_obj_create_open(1, 1, 1, NULL);
+       /* The configured [Keep-alive, Dead-timer] values are [5, 5],
+        * this error open object will request they be changed to [10, 10] */
+       error_open_object->open_keepalive = 10;
+       error_open_object->open_deadtimer = 10;
+       dll_append(message->obj_list, error_object);
+       dll_append(message->obj_list, error_open_object);
+       session.session_state = SESSION_STATE_PCEP_CONNECTING;
+       mock_socket_comm_info *mock_info = get_mock_socket_comm_info();
+       mock_info->send_message_save_message = true;
+
+       handle_socket_comm_event(&event);
+
+       CU_ASSERT_TRUE(session.pcc_open_rejected);
+       CU_ASSERT_FALSE(session.pce_open_keep_alive_sent);
+       CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_PCEP_CONNECTING);
+       /* Another Open should be sent */
+       verify_socket_comm_times_called(0, 0, 0, 1, 0, 0, 0);
+       CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+                       2);
+
+       pcep_event *e = queue_dequeue(session_logic_event_queue_->event_queue);
+       CU_ASSERT_EQUAL(PCC_SENT_INVALID_OPEN, e->event_type);
+       pceplib_free(PCEPLIB_INFRA, e);
+
+       e = queue_dequeue(session_logic_event_queue_->event_queue);
+       CU_ASSERT_EQUAL(MESSAGE_RECEIVED, e->event_type);
+       CU_ASSERT_EQUAL(PCEP_TYPE_ERROR, e->message->msg_header->type);
+       pceplib_free(PCEPLIB_INFRA, e);
+
+       /* Check the Corrected Open Message */
+
+       /* What gets saved in the mock is the msg byte buffer. The msg struct
+        * was deleted when it was sent. Instead of inspecting the msg byte
+        * buffer, lets just decode it. */
+       uint8_t *encoded_msg =
+               dll_delete_first_node(mock_info->sent_message_list);
+       CU_ASSERT_PTR_NOT_NULL(encoded_msg);
+       struct pcep_message *open_msg_corrected =
+               pcep_decode_message(encoded_msg);
+       CU_ASSERT_PTR_NOT_NULL(open_msg_corrected);
+       struct pcep_object_open *open_object_corrected =
+               (struct pcep_object_open *)pcep_obj_get(
+                       open_msg_corrected->obj_list, PCEP_OBJ_CLASS_OPEN);
+       CU_ASSERT_PTR_NOT_NULL(open_object_corrected);
+       /* Verify the Keep-alive and Dead timers have been negotiated */
+       CU_ASSERT_EQUAL(error_open_object->open_keepalive,
+                       open_object_corrected->open_keepalive);
+       CU_ASSERT_EQUAL(error_open_object->open_deadtimer,
+                       open_object_corrected->open_deadtimer);
+       CU_ASSERT_EQUAL(session.pcc_config.dead_timer_pce_negotiated_seconds,
+                       open_object_corrected->open_deadtimer);
+       CU_ASSERT_EQUAL(
+               session.pcc_config.keep_alive_pce_negotiated_timer_seconds,
+               open_object_corrected->open_keepalive);
+       CU_ASSERT_NOT_EQUAL(
+               session.pcc_config.dead_timer_pce_negotiated_seconds,
+               session.pcc_config.dead_timer_seconds);
+       CU_ASSERT_NOT_EQUAL(
+               session.pcc_config.keep_alive_pce_negotiated_timer_seconds,
+               session.pcc_config.keep_alive_seconds);
+
+       pcep_msg_free_message(open_msg_corrected);
+       pceplib_free(PCEPLIB_MESSAGES, encoded_msg);
+}
+
+
+void test_handle_socket_comm_event_keep_alive()
+{
+       /* Test when a Keep Alive is received, but the PCE Open has not been
+        * received yet */
+       create_message_for_test(PCEP_TYPE_KEEPALIVE, false, false);
+       session.session_state = SESSION_STATE_PCEP_CONNECTING;
+       session.timer_id_dead_timer = 100;
+       session.timer_id_open_keep_wait = 200;
+       session.pce_open_accepted = false;
+       session.pce_open_received = false;
+       session.pcc_open_accepted = false;
+
+       handle_socket_comm_event(&event);
+
+       CU_ASSERT_TRUE(session.pcc_open_accepted);
+       CU_ASSERT_FALSE(session.pce_open_keep_alive_sent);
+       CU_ASSERT_FALSE(session.pcc_open_rejected);
+       CU_ASSERT_FALSE(session.pce_open_accepted);
+       CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_PCEP_CONNECTING);
+       CU_ASSERT_EQUAL(session.timer_id_open_keep_wait, TIMER_ID_NOT_SET);
+       CU_ASSERT_EQUAL(session.timer_id_dead_timer, 100);
+       verify_socket_comm_times_called(0, 0, 0, 0, 0, 0, 0);
+       CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+                       0);
+
+       /* Test when a Keep Alive is received, and the PCE Open has been
+        * received and accepted */
+       create_message_for_test(PCEP_TYPE_KEEPALIVE, false, false);
+       session.session_state = SESSION_STATE_PCEP_CONNECTING;
+       session.timer_id_dead_timer = 100;
+       session.timer_id_open_keep_wait = 200;
+       session.pce_open_received = true;
+       session.pce_open_accepted = true;
+       session.pcc_open_accepted = false;
+
+       handle_socket_comm_event(&event);
+
+       CU_ASSERT_TRUE(session.pcc_open_accepted);
+       CU_ASSERT_TRUE(session.pce_open_keep_alive_sent);
+       CU_ASSERT_FALSE(session.pcc_open_rejected);
+       CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_PCEP_CONNECTED);
+       CU_ASSERT_EQUAL(session.timer_id_open_keep_wait, TIMER_ID_NOT_SET);
+       CU_ASSERT_EQUAL(session.timer_id_dead_timer, 100);
+       verify_socket_comm_times_called(0, 0, 0, 1, 0, 0, 0);
+
+       /* Test when a Keep Alive is received, and the PCE Open has been
+        * received and rejected */
+       create_message_for_test(PCEP_TYPE_KEEPALIVE, false, false);
+       session.session_state = SESSION_STATE_PCEP_CONNECTING;
+       session.timer_id_dead_timer = 100;
+       session.timer_id_open_keep_wait = 200;
+       session.pce_open_received = true;
+       session.pce_open_accepted = false;
+       session.pce_open_rejected = true;
+       session.pce_open_keep_alive_sent = false;
+       session.pcc_open_accepted = true;
+
+       handle_socket_comm_event(&event);
+
+       CU_ASSERT_TRUE(session.pcc_open_accepted);
+       CU_ASSERT_FALSE(session.pce_open_keep_alive_sent);
+       CU_ASSERT_FALSE(session.pcc_open_rejected);
+       CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_PCEP_CONNECTING);
+       CU_ASSERT_EQUAL(session.timer_id_open_keep_wait, TIMER_ID_NOT_SET);
+       CU_ASSERT_EQUAL(session.timer_id_dead_timer, 100);
+       verify_socket_comm_times_called(0, 0, 0, 1, 0, 0, 0);
+
+       /* The session is considered connected, when both the
+        * PCE and PCC Open messages have been accepted */
+       pcep_event *e = queue_dequeue(session_logic_event_queue_->event_queue);
+       CU_ASSERT_EQUAL(PCC_CONNECTED_TO_PCE, e->event_type);
+       pceplib_free(PCEPLIB_INFRA, e);
+}
+
+
+void test_handle_socket_comm_event_pcrep()
+{
+       create_message_for_test(PCEP_TYPE_PCREP, false, true);
+       struct pcep_object_rp *rp =
+               pcep_obj_create_rp(1, true, true, true, true, 1, NULL);
+       dll_append(message->obj_list, rp);
+
+       handle_socket_comm_event(&event);
+
+       CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+                       1);
+       verify_socket_comm_times_called(0, 0, 0, 0, 0, 0, 0);
+       pcep_event *e = queue_dequeue(session_logic_event_queue_->event_queue);
+       CU_ASSERT_EQUAL(MESSAGE_RECEIVED, e->event_type);
+       pceplib_free(PCEPLIB_INFRA, e);
+}
+
+
+void test_handle_socket_comm_event_pcreq()
+{
+       create_message_for_test(PCEP_TYPE_PCREQ, false, false);
+       mock_socket_comm_info *mock_info = get_mock_socket_comm_info();
+       mock_info->send_message_save_message = true;
+
+       handle_socket_comm_event(&event);
+
+       /* The PCC does not support receiving PcReq messages, so an error should
+        * be sent */
+       CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+                       0);
+       verify_socket_comm_times_called(0, 0, 0, 1, 0, 0, 0);
+       uint8_t *encoded_msg =
+               dll_delete_first_node(mock_info->sent_message_list);
+       CU_ASSERT_PTR_NOT_NULL(encoded_msg);
+       struct pcep_message *error_msg = pcep_decode_message(encoded_msg);
+       CU_ASSERT_PTR_NOT_NULL(error_msg);
+       CU_ASSERT_EQUAL(PCEP_TYPE_ERROR, error_msg->msg_header->type);
+       /* Verify the error object */
+       CU_ASSERT_EQUAL(1, error_msg->obj_list->num_entries);
+       struct pcep_object_error *obj = error_msg->obj_list->head->data;
+       CU_ASSERT_EQUAL(PCEP_OBJ_CLASS_ERROR, obj->header.object_class);
+       CU_ASSERT_EQUAL(PCEP_OBJ_TYPE_ERROR, obj->header.object_type);
+       CU_ASSERT_EQUAL(PCEP_ERRT_CAPABILITY_NOT_SUPPORTED, obj->error_type);
+       CU_ASSERT_EQUAL(PCEP_ERRV_UNASSIGNED, obj->error_value);
+       pcep_msg_free_message(error_msg);
+       pceplib_free(PCEPLIB_MESSAGES, encoded_msg);
+}
+
+
+void test_handle_socket_comm_event_report()
+{
+       create_message_for_test(PCEP_TYPE_REPORT, false, false);
+       mock_socket_comm_info *mock_info = get_mock_socket_comm_info();
+       mock_info->send_message_save_message = true;
+
+       handle_socket_comm_event(&event);
+
+       /* The PCC does not support receiving Report messages, so an error
+        * should be sent */
+       CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+                       0);
+       verify_socket_comm_times_called(0, 0, 0, 1, 0, 0, 0);
+       uint8_t *encoded_msg =
+               dll_delete_first_node(mock_info->sent_message_list);
+       CU_ASSERT_PTR_NOT_NULL(encoded_msg);
+       struct pcep_message *error_msg = pcep_decode_message(encoded_msg);
+       CU_ASSERT_PTR_NOT_NULL(error_msg);
+       CU_ASSERT_EQUAL(PCEP_TYPE_ERROR, error_msg->msg_header->type);
+       /* Verify the error object */
+       CU_ASSERT_EQUAL(1, error_msg->obj_list->num_entries);
+       struct pcep_object_error *obj = error_msg->obj_list->head->data;
+       CU_ASSERT_EQUAL(PCEP_OBJ_CLASS_ERROR, obj->header.object_class);
+       CU_ASSERT_EQUAL(PCEP_OBJ_TYPE_ERROR, obj->header.object_type);
+       CU_ASSERT_EQUAL(PCEP_ERRT_CAPABILITY_NOT_SUPPORTED, obj->error_type);
+       CU_ASSERT_EQUAL(PCEP_ERRV_UNASSIGNED, obj->error_value);
+       pcep_msg_free_message(error_msg);
+       pceplib_free(PCEPLIB_MESSAGES, encoded_msg);
+}
+
+
+void test_handle_socket_comm_event_update()
+{
+       create_message_for_test(PCEP_TYPE_UPDATE, false, true);
+       struct pcep_object_srp *srp = pcep_obj_create_srp(false, 100, NULL);
+       struct pcep_object_lsp *lsp =
+               pcep_obj_create_lsp(100, PCEP_LSP_OPERATIONAL_UP, true, true,
+                                   true, true, true, NULL);
+       double_linked_list *ero_subobj_list = dll_initialize();
+       dll_append(ero_subobj_list, pcep_obj_create_ro_subobj_asn(0x0102));
+       struct pcep_object_ro *ero = pcep_obj_create_ero(ero_subobj_list);
+       struct pcep_object_metric *metric =
+               pcep_obj_create_metric(PCEP_METRIC_TE, false, true, 16.0);
+       dll_append(message->obj_list, srp);
+       dll_append(message->obj_list, lsp);
+       dll_append(message->obj_list, ero);
+       dll_append(message->obj_list, metric);
+       mock_socket_comm_info *mock_info = get_mock_socket_comm_info();
+       mock_info->send_message_save_message = true;
+
+       handle_socket_comm_event(&event);
+
+       CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+                       1);
+       verify_socket_comm_times_called(0, 0, 0, 0, 0, 0, 0);
+       pcep_event *e = queue_dequeue(session_logic_event_queue_->event_queue);
+       CU_ASSERT_EQUAL(MESSAGE_RECEIVED, e->event_type);
+       CU_ASSERT_EQUAL(PCEP_TYPE_UPDATE, e->message->msg_header->type);
+       pceplib_free(PCEPLIB_INFRA, e);
+}
+
+
+void test_handle_socket_comm_event_initiate()
+{
+       create_message_for_test(PCEP_TYPE_INITIATE, false, true);
+       struct pcep_object_srp *srp = pcep_obj_create_srp(false, 100, NULL);
+       struct pcep_object_lsp *lsp =
+               pcep_obj_create_lsp(100, PCEP_LSP_OPERATIONAL_UP, true, true,
+                                   true, true, true, NULL);
+       dll_append(message->obj_list, srp);
+       dll_append(message->obj_list, lsp);
+       mock_socket_comm_info *mock_info = get_mock_socket_comm_info();
+       mock_info->send_message_save_message = true;
+
+       handle_socket_comm_event(&event);
+
+       CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+                       1);
+       verify_socket_comm_times_called(0, 0, 0, 0, 0, 0, 0);
+       pcep_event *e = queue_dequeue(session_logic_event_queue_->event_queue);
+       CU_ASSERT_EQUAL(MESSAGE_RECEIVED, e->event_type);
+       CU_ASSERT_EQUAL(PCEP_TYPE_INITIATE, e->message->msg_header->type);
+       pceplib_free(PCEPLIB_INFRA, e);
+}
+
+
+void test_handle_socket_comm_event_notify()
+{
+       create_message_for_test(PCEP_TYPE_PCNOTF, false, true);
+       handle_socket_comm_event(&event);
+
+       CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+                       1);
+       verify_socket_comm_times_called(0, 0, 0, 0, 0, 0, 0);
+       pcep_event *e = queue_dequeue(session_logic_event_queue_->event_queue);
+       CU_ASSERT_EQUAL(MESSAGE_RECEIVED, e->event_type);
+       CU_ASSERT_EQUAL(PCEP_TYPE_PCNOTF, e->message->msg_header->type);
+       pceplib_free(PCEPLIB_INFRA, e);
+}
+
+
+void test_handle_socket_comm_event_error()
+{
+       create_message_for_test(PCEP_TYPE_ERROR, false, true);
+       handle_socket_comm_event(&event);
+
+       CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+                       1);
+       verify_socket_comm_times_called(0, 0, 0, 0, 0, 0, 0);
+       pcep_event *e = queue_dequeue(session_logic_event_queue_->event_queue);
+       CU_ASSERT_EQUAL(MESSAGE_RECEIVED, e->event_type);
+       CU_ASSERT_EQUAL(PCEP_TYPE_ERROR, e->message->msg_header->type);
+       pceplib_free(PCEPLIB_INFRA, e);
+}
+
+
+void test_handle_socket_comm_event_unknown_msg()
+{
+       create_message_for_test(13, false, false);
+       mock_socket_comm_info *mock_info = get_mock_socket_comm_info();
+       mock_info->send_message_save_message = true;
+
+       handle_socket_comm_event(&event);
+
+       /* Sending an unsupported message type, so an error should be sent,
+        * but the connection should remain open, since max_unknown_messages = 2
+        */
+       CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+                       0);
+       verify_socket_comm_times_called(0, 0, 0, 1, 0, 0, 0);
+       uint8_t *encoded_msg =
+               dll_delete_first_node(mock_info->sent_message_list);
+       CU_ASSERT_PTR_NOT_NULL(encoded_msg);
+       struct pcep_message *msg = pcep_decode_message(encoded_msg);
+       CU_ASSERT_PTR_NOT_NULL(msg);
+       CU_ASSERT_EQUAL(PCEP_TYPE_ERROR, msg->msg_header->type);
+       /* Verify the error object */
+       CU_ASSERT_EQUAL(1, msg->obj_list->num_entries);
+       struct pcep_object_error *error_obj = msg->obj_list->head->data;
+       CU_ASSERT_EQUAL(PCEP_OBJ_CLASS_ERROR, error_obj->header.object_class);
+       CU_ASSERT_EQUAL(PCEP_OBJ_TYPE_ERROR, error_obj->header.object_type);
+       CU_ASSERT_EQUAL(PCEP_ERRT_CAPABILITY_NOT_SUPPORTED,
+                       error_obj->error_type);
+       CU_ASSERT_EQUAL(PCEP_ERRV_UNASSIGNED, error_obj->error_value);
+       pcep_msg_free_message(msg);
+       pceplib_free(PCEPLIB_MESSAGES, encoded_msg);
+       destroy_message_for_test();
+
+       /* Send another unsupported message type, an error should be sent and
+        * the connection should be closed, since max_unknown_messages = 2 */
+       create_message_for_test(13, false, false);
+       reset_mock_socket_comm_info();
+       mock_info = get_mock_socket_comm_info();
+       mock_info->send_message_save_message = true;
+
+       handle_socket_comm_event(&event);
+
+       verify_socket_comm_times_called(0, 0, 0, 2, 1, 0, 0);
+       CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+                       1);
+       pcep_event *e = queue_dequeue(session_logic_event_queue_->event_queue);
+       CU_ASSERT_EQUAL(PCC_RCVD_MAX_UNKOWN_MSGS, e->event_type);
+       pceplib_free(PCEPLIB_INFRA, e);
+
+       /* Verify the error message */
+       encoded_msg = dll_delete_first_node(mock_info->sent_message_list);
+       CU_ASSERT_PTR_NOT_NULL(encoded_msg);
+       msg = pcep_decode_message(encoded_msg);
+       CU_ASSERT_PTR_NOT_NULL(msg);
+       CU_ASSERT_EQUAL(PCEP_TYPE_ERROR, msg->msg_header->type);
+       /* Verify the error object */
+       CU_ASSERT_EQUAL(1, msg->obj_list->num_entries);
+       error_obj = msg->obj_list->head->data;
+       CU_ASSERT_EQUAL(PCEP_OBJ_CLASS_ERROR, error_obj->header.object_class);
+       CU_ASSERT_EQUAL(PCEP_OBJ_TYPE_ERROR, error_obj->header.object_type);
+       CU_ASSERT_EQUAL(PCEP_ERRT_CAPABILITY_NOT_SUPPORTED,
+                       error_obj->error_type);
+       CU_ASSERT_EQUAL(PCEP_ERRV_UNASSIGNED, error_obj->error_value);
+       pcep_msg_free_message(msg);
+       pceplib_free(PCEPLIB_MESSAGES, encoded_msg);
+
+       /* Verify the Close message */
+       encoded_msg = dll_delete_first_node(mock_info->sent_message_list);
+       CU_ASSERT_PTR_NOT_NULL(encoded_msg);
+       msg = pcep_decode_message(encoded_msg);
+       CU_ASSERT_PTR_NOT_NULL(msg);
+       CU_ASSERT_EQUAL(PCEP_TYPE_CLOSE, msg->msg_header->type);
+       /* Verify the error object */
+       CU_ASSERT_EQUAL(1, msg->obj_list->num_entries);
+       struct pcep_object_close *close_obj = msg->obj_list->head->data;
+       CU_ASSERT_EQUAL(PCEP_OBJ_CLASS_CLOSE, close_obj->header.object_class);
+       CU_ASSERT_EQUAL(PCEP_OBJ_TYPE_CLOSE, close_obj->header.object_type);
+       CU_ASSERT_EQUAL(PCEP_CLOSE_REASON_UNREC_MSG, close_obj->reason);
+       pcep_msg_free_message(msg);
+       pceplib_free(PCEPLIB_MESSAGES, encoded_msg);
+}
+
+
+void test_connection_failure(void)
+{
+       /*
+        * Test when 2 invalid Open messages are received that a
+        * PCC_CONNECTION_FAILURE event is generated.
+        */
+       create_message_for_test(PCEP_TYPE_OPEN, false, false);
+       reset_mock_socket_comm_info();
+       struct pcep_object_open *open_object =
+               pcep_obj_create_open(1, 1, 1, NULL);
+       /* Make the Open message invalid */
+       open_object->open_deadtimer =
+               session.pcc_config.max_dead_timer_seconds + 1;
+       dll_append(message->obj_list, open_object);
+       session.pce_open_received = false;
+       session.pce_open_accepted = false;
+       session.pce_open_rejected = false;
+       session.session_state = SESSION_STATE_PCEP_CONNECTING;
+
+       handle_socket_comm_event(&event);
+
+       CU_ASSERT_TRUE(session.pce_open_received);
+       CU_ASSERT_TRUE(session.pce_open_rejected);
+       CU_ASSERT_FALSE(session.pce_open_accepted);
+       CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_PCEP_CONNECTING);
+       /* An error response should be sent, rejecting the Open */
+       verify_socket_comm_times_called(0, 0, 0, 1, 0, 0, 0);
+       CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+                       1);
+       pcep_event *e = queue_dequeue(session_logic_event_queue_->event_queue);
+       CU_ASSERT_EQUAL(PCC_RCVD_INVALID_OPEN, e->event_type);
+       pceplib_free(PCEPLIB_INFRA, e);
+       destroy_message_for_test();
+
+       /* Send the same erroneous Open again */
+       create_message_for_test(PCEP_TYPE_OPEN, false, false);
+       reset_mock_socket_comm_info();
+       open_object = pcep_obj_create_open(1, 1, 1, NULL);
+       /* Make the Open message invalid */
+       open_object->open_deadtimer =
+               session.pcc_config.max_dead_timer_seconds + 1;
+       dll_append(message->obj_list, open_object);
+
+       handle_socket_comm_event(&event);
+
+       CU_ASSERT_TRUE(session.pce_open_received);
+       CU_ASSERT_TRUE(session.pce_open_rejected);
+       CU_ASSERT_FALSE(session.pce_open_accepted);
+       CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_INITIALIZED);
+       /* An error response should be sent, rejecting the Open */
+       verify_socket_comm_times_called(0, 0, 0, 1, 1, 0, 0);
+       CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+                       2);
+       e = queue_dequeue(session_logic_event_queue_->event_queue);
+       CU_ASSERT_EQUAL(PCC_RCVD_INVALID_OPEN, e->event_type);
+       pceplib_free(PCEPLIB_INFRA, e);
+       e = queue_dequeue(session_logic_event_queue_->event_queue);
+       CU_ASSERT_EQUAL(PCC_CONNECTION_FAILURE, e->event_type);
+       pceplib_free(PCEPLIB_INFRA, e);
+
+       destroy_message_for_test();
+
+       /*
+        * Test when 2 invalid Open messages are sent that a
+        * PCC_CONNECTION_FAILURE event is generated.
+        */
+       create_message_for_test(PCEP_TYPE_ERROR, false, false);
+       reset_mock_socket_comm_info();
+       struct pcep_object_error *error_object = pcep_obj_create_error(
+               PCEP_ERRT_SESSION_FAILURE, PCEP_ERRV_UNACCEPTABLE_OPEN_MSG_NEG);
+       dll_append(message->obj_list, error_object);
+       session.pcc_open_accepted = false;
+       session.pcc_open_rejected = false;
+       session.session_state = SESSION_STATE_PCEP_CONNECTING;
+
+       handle_socket_comm_event(&event);
+
+       CU_ASSERT_TRUE(session.pcc_open_rejected);
+       CU_ASSERT_FALSE(session.pcc_open_accepted);
+       CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_PCEP_CONNECTING);
+       /* Another Open should be sent */
+       verify_socket_comm_times_called(0, 0, 0, 1, 0, 0, 0);
+       CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+                       2);
+       e = queue_dequeue(session_logic_event_queue_->event_queue);
+       CU_ASSERT_EQUAL(PCC_SENT_INVALID_OPEN, e->event_type);
+       pceplib_free(PCEPLIB_INFRA, e);
+       e = queue_dequeue(session_logic_event_queue_->event_queue);
+       CU_ASSERT_EQUAL(MESSAGE_RECEIVED, e->event_type);
+       CU_ASSERT_EQUAL(PCEP_TYPE_ERROR, e->message->msg_header->type);
+       pceplib_free(PCEPLIB_INFRA, e);
+       destroy_message_for_test();
+
+       /* Send a socket close while connecting, which should
+        * generate a PCC_CONNECTION_FAILURE event */
+       reset_mock_socket_comm_info();
+       event.socket_closed = true;
+       event.received_msg_list = NULL;
+
+       handle_socket_comm_event(&event);
+
+       CU_ASSERT_TRUE(session.pcc_open_rejected);
+       CU_ASSERT_FALSE(session.pcc_open_accepted);
+       CU_ASSERT_EQUAL(session.session_state, SESSION_STATE_INITIALIZED);
+       verify_socket_comm_times_called(0, 0, 0, 0, 0, 1, 0);
+       CU_ASSERT_EQUAL(session_logic_event_queue_->event_queue->num_entries,
+                       2);
+       e = queue_dequeue(session_logic_event_queue_->event_queue);
+       CU_ASSERT_EQUAL(PCE_CLOSED_SOCKET, e->event_type);
+       pceplib_free(PCEPLIB_INFRA, e);
+       e = queue_dequeue(session_logic_event_queue_->event_queue);
+       CU_ASSERT_EQUAL(PCC_CONNECTION_FAILURE, e->event_type);
+       pceplib_free(PCEPLIB_INFRA, e);
+}
diff --git a/pceplib/test/pcep_session_logic_states_test.h b/pceplib/test/pcep_session_logic_states_test.h
new file mode 100644 (file)
index 0000000..e42b501
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Javier Garcia <javier.garcia@voltanet.io>
+ *
+ */
+
+/*
+ *  Timer definitions to be used internally by the pcep_timers library.
+ */
+
+#ifndef PCEP_SESSION_LOGIC_STATES_TEST_H
+#define PCEP_SESSION_LOGIC_STATES_TEST_H
+
+int pcep_session_logic_states_test_suite_setup(void);
+int pcep_session_logic_states_test_suite_teardown(void);
+void pcep_session_logic_states_test_setup(void);
+void pcep_session_logic_states_test_teardown(void);
+void test_handle_timer_event_dead_timer(void);
+void test_handle_timer_event_keep_alive(void);
+void test_handle_timer_event_open_keep_wait(void);
+void test_handle_socket_comm_event_null_params(void);
+void test_handle_socket_comm_event_close(void);
+void test_handle_socket_comm_event_open(void);
+void test_handle_socket_comm_event_open_error(void);
+void test_handle_socket_comm_event_keep_alive(void);
+void test_handle_socket_comm_event_pcrep(void);
+void test_handle_socket_comm_event_pcreq(void);
+void test_handle_socket_comm_event_report(void);
+void test_handle_socket_comm_event_update(void);
+void test_handle_socket_comm_event_initiate(void);
+void test_handle_socket_comm_event_notify(void);
+void test_handle_socket_comm_event_error(void);
+void test_handle_socket_comm_event_unknown_msg(void);
+void test_connection_failure(void);
+
+#endif /* PCEPTIMERINTERNALS_H_ */
diff --git a/pceplib/test/pcep_session_logic_test.c b/pceplib/test/pcep_session_logic_test.c
new file mode 100644 (file)
index 0000000..66db4fb
--- /dev/null
@@ -0,0 +1,360 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <CUnit/CUnit.h>
+
+#include "pcep_socket_comm_mock.h"
+#include "pcep_session_logic.h"
+#include "pcep_session_logic_test.h"
+
+/*
+ * Test suite setup and teardown called before AND after the test suite.
+ */
+
+int pcep_session_logic_test_suite_setup(void)
+{
+       pceplib_memory_reset();
+       return 0;
+}
+
+int pcep_session_logic_test_suite_teardown(void)
+{
+       printf("\n");
+       pceplib_memory_dump();
+       return 0;
+}
+
+/*
+ * Test case setup and teardown called before AND after each test.
+ */
+
+void pcep_session_logic_test_setup()
+{
+       setup_mock_socket_comm_info();
+}
+
+
+void pcep_session_logic_test_teardown()
+{
+       stop_session_logic();
+       teardown_mock_socket_comm_info();
+}
+
+
+/*
+ * Test cases
+ */
+
+void test_run_stop_session_logic()
+{
+       CU_ASSERT_TRUE(run_session_logic());
+       CU_ASSERT_TRUE(stop_session_logic());
+}
+
+
+void test_run_session_logic_twice()
+{
+       CU_ASSERT_TRUE(run_session_logic());
+       CU_ASSERT_FALSE(run_session_logic());
+}
+
+
+void test_session_logic_without_run()
+{
+       /* Verify the functions that depend on run_session_logic() being called
+        */
+       CU_ASSERT_FALSE(stop_session_logic());
+}
+
+
+void test_create_pcep_session_null_params()
+{
+       pcep_configuration config;
+       struct in_addr pce_ip;
+
+       CU_ASSERT_PTR_NULL(create_pcep_session(NULL, NULL));
+       CU_ASSERT_PTR_NULL(create_pcep_session(NULL, &pce_ip));
+       CU_ASSERT_PTR_NULL(create_pcep_session(&config, NULL));
+}
+
+
+void test_create_destroy_pcep_session()
+{
+       pcep_session *session;
+       pcep_configuration config;
+       struct in_addr pce_ip;
+
+       run_session_logic();
+
+       memset(&config, 0, sizeof(pcep_configuration));
+       config.keep_alive_seconds = 5;
+       config.dead_timer_seconds = 5;
+       config.request_time_seconds = 5;
+       config.max_unknown_messages = 5;
+       config.max_unknown_requests = 5;
+       inet_pton(AF_INET, "127.0.0.1", &(pce_ip));
+
+       mock_socket_comm_info *mock_info = get_mock_socket_comm_info();
+       mock_info->send_message_save_message = true;
+       session = create_pcep_session(&config, &pce_ip);
+       CU_ASSERT_PTR_NOT_NULL(session);
+       /* What gets saved in the mock is the msg byte buffer. The msg struct
+        * was deleted when it was sent. Instead of inspecting the msg byte
+        * buffer, lets just decode it. */
+       uint8_t *encoded_msg =
+               dll_delete_first_node(mock_info->sent_message_list);
+       CU_ASSERT_PTR_NOT_NULL(encoded_msg);
+       struct pcep_message *open_msg = pcep_decode_message(encoded_msg);
+       CU_ASSERT_PTR_NOT_NULL(open_msg);
+       /* Should be an Open, with no TLVs: length = 12 */
+       CU_ASSERT_EQUAL(open_msg->msg_header->type, PCEP_TYPE_OPEN);
+       CU_ASSERT_EQUAL(open_msg->encoded_message_length, 12);
+       destroy_pcep_session(session);
+       pcep_msg_free_message(open_msg);
+       pceplib_free(PCEPLIB_MESSAGES, encoded_msg);
+
+       stop_session_logic();
+}
+
+
+void test_create_destroy_pcep_session_ipv6()
+{
+       pcep_session *session;
+       pcep_configuration config;
+       struct in6_addr pce_ip;
+
+       run_session_logic();
+
+       memset(&config, 0, sizeof(pcep_configuration));
+       config.keep_alive_seconds = 5;
+       config.dead_timer_seconds = 5;
+       config.request_time_seconds = 5;
+       config.max_unknown_messages = 5;
+       config.max_unknown_requests = 5;
+       config.is_src_ipv6 = true;
+       inet_pton(AF_INET6, "::1", &pce_ip);
+
+       mock_socket_comm_info *mock_info = get_mock_socket_comm_info();
+       mock_info->send_message_save_message = true;
+       session = create_pcep_session_ipv6(&config, &pce_ip);
+       CU_ASSERT_PTR_NOT_NULL(session);
+       CU_ASSERT_TRUE(session->socket_comm_session->is_ipv6);
+       /* What gets saved in the mock is the msg byte buffer. The msg struct
+        * was deleted when it was sent. Instead of inspecting the msg byte
+        * buffer, lets just decode it. */
+       uint8_t *encoded_msg =
+               dll_delete_first_node(mock_info->sent_message_list);
+       CU_ASSERT_PTR_NOT_NULL(encoded_msg);
+       struct pcep_message *open_msg = pcep_decode_message(encoded_msg);
+       CU_ASSERT_PTR_NOT_NULL(open_msg);
+       /* Should be an Open, with no TLVs: length = 12 */
+       CU_ASSERT_EQUAL(open_msg->msg_header->type, PCEP_TYPE_OPEN);
+       CU_ASSERT_EQUAL(open_msg->encoded_message_length, 12);
+       destroy_pcep_session(session);
+       pcep_msg_free_message(open_msg);
+       pceplib_free(PCEPLIB_MESSAGES, encoded_msg);
+
+       stop_session_logic();
+}
+
+
+void test_create_pcep_session_open_tlvs()
+{
+       pcep_session *session;
+       struct in_addr pce_ip;
+       struct pcep_message *open_msg;
+       struct pcep_object_header *open_obj;
+       pcep_configuration config;
+       memset(&config, 0, sizeof(pcep_configuration));
+       config.pcep_msg_versioning = create_default_pcep_versioning();
+       inet_pton(AF_INET, "127.0.0.1", &(pce_ip));
+
+       run_session_logic();
+
+       /* Verify the created Open message only has 1 TLV:
+        *   pcep_tlv_create_stateful_pce_capability() */
+       mock_socket_comm_info *mock_info = get_mock_socket_comm_info();
+       mock_info->send_message_save_message = true;
+       config.support_stateful_pce_lsp_update = true;
+       config.pcep_msg_versioning->draft_ietf_pce_segment_routing_07 = false;
+       config.support_sr_te_pst = false;
+
+       session = create_pcep_session(&config, &pce_ip);
+       CU_ASSERT_PTR_NOT_NULL(session);
+       /* Get and verify the Open Message */
+       uint8_t *encoded_msg =
+               dll_delete_first_node(mock_info->sent_message_list);
+       CU_ASSERT_PTR_NOT_NULL(encoded_msg);
+       open_msg = pcep_decode_message(encoded_msg);
+       CU_ASSERT_PTR_NOT_NULL(open_msg);
+       /* Get and verify the Open Message objects */
+       CU_ASSERT_PTR_NOT_NULL(open_msg->obj_list);
+       CU_ASSERT_TRUE(open_msg->obj_list->num_entries > 0);
+       /* Get and verify the Open object */
+       open_obj = pcep_obj_get(open_msg->obj_list, PCEP_OBJ_CLASS_OPEN);
+       CU_ASSERT_PTR_NOT_NULL(open_obj);
+       /* Get and verify the Open object TLVs */
+       CU_ASSERT_PTR_NOT_NULL(open_obj->tlv_list);
+       CU_ASSERT_EQUAL(open_obj->tlv_list->num_entries, 1);
+       CU_ASSERT_EQUAL(((struct pcep_object_tlv_header *)
+                                open_obj->tlv_list->head->data)
+                               ->type,
+                       PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY);
+
+       destroy_pcep_session(session);
+       pcep_msg_free_message(open_msg);
+       pceplib_free(PCEPLIB_MESSAGES, encoded_msg);
+
+       /* Verify the created Open message only has 2 TLVs:
+        *   pcep_tlv_create_stateful_pce_capability()
+        *   pcep_tlv_create_lsp_db_version() */
+       reset_mock_socket_comm_info();
+       mock_info->send_message_save_message = true;
+       config.support_include_db_version = true;
+       config.lsp_db_version = 100;
+
+       session = create_pcep_session(&config, &pce_ip);
+       CU_ASSERT_PTR_NOT_NULL(session);
+       /* Get and verify the Open Message */
+       encoded_msg = dll_delete_first_node(mock_info->sent_message_list);
+       CU_ASSERT_PTR_NOT_NULL(encoded_msg);
+       open_msg = pcep_decode_message(encoded_msg);
+       CU_ASSERT_PTR_NOT_NULL(open_msg);
+       /* Get and verify the Open Message objects */
+       CU_ASSERT_PTR_NOT_NULL(open_msg->obj_list);
+       CU_ASSERT_TRUE(open_msg->obj_list->num_entries > 0);
+       /* Get and verify the Open object */
+       open_obj = pcep_obj_get(open_msg->obj_list, PCEP_OBJ_CLASS_OPEN);
+       CU_ASSERT_PTR_NOT_NULL(open_obj);
+       /* Get and verify the Open object TLVs */
+       CU_ASSERT_PTR_NOT_NULL(open_obj->tlv_list);
+       CU_ASSERT_EQUAL(open_obj->tlv_list->num_entries, 2);
+       CU_ASSERT_EQUAL(((struct pcep_object_tlv_header *)
+                                open_obj->tlv_list->head->data)
+                               ->type,
+                       PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY);
+       CU_ASSERT_EQUAL(((struct pcep_object_tlv_header *)
+                                open_obj->tlv_list->head->next_node->data)
+                               ->type,
+                       PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION);
+
+       destroy_pcep_session(session);
+       pcep_msg_free_message(open_msg);
+       pceplib_free(PCEPLIB_MESSAGES, encoded_msg);
+
+
+       /* Verify the created Open message only has 4 TLVs:
+        *   pcep_tlv_create_stateful_pce_capability()
+        *   pcep_tlv_create_lsp_db_version()
+        *   pcep_tlv_create_sr_pce_capability()
+        *   pcep_tlv_create_path_setup_type_capability() */
+       reset_mock_socket_comm_info();
+       mock_info->send_message_save_message = true;
+       config.support_sr_te_pst = true;
+
+       session = create_pcep_session(&config, &pce_ip);
+       CU_ASSERT_PTR_NOT_NULL(session);
+       /* Get and verify the Open Message */
+       encoded_msg = dll_delete_first_node(mock_info->sent_message_list);
+       CU_ASSERT_PTR_NOT_NULL(encoded_msg);
+       open_msg = pcep_decode_message(encoded_msg);
+       CU_ASSERT_PTR_NOT_NULL(open_msg);
+       /* Get and verify the Open Message objects */
+       CU_ASSERT_PTR_NOT_NULL(open_msg->obj_list);
+       CU_ASSERT_TRUE(open_msg->obj_list->num_entries > 0);
+       /* Get and verify the Open object */
+       open_obj = pcep_obj_get(open_msg->obj_list, PCEP_OBJ_CLASS_OPEN);
+       CU_ASSERT_PTR_NOT_NULL(open_obj);
+       /* Get and verify the Open object TLVs */
+       CU_ASSERT_PTR_NOT_NULL(open_obj->tlv_list);
+       CU_ASSERT_EQUAL(open_obj->tlv_list->num_entries, 3);
+       double_linked_list_node *tlv_node = open_obj->tlv_list->head;
+       CU_ASSERT_EQUAL(((struct pcep_object_tlv_header *)tlv_node->data)->type,
+                       PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY);
+       tlv_node = tlv_node->next_node;
+       CU_ASSERT_EQUAL(((struct pcep_object_tlv_header *)tlv_node->data)->type,
+                       PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION);
+       tlv_node = tlv_node->next_node;
+       CU_ASSERT_EQUAL(((struct pcep_object_tlv_header *)tlv_node->data)->type,
+                       PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY);
+
+       destroy_pcep_session(session);
+       pcep_msg_free_message(open_msg);
+       pceplib_free(PCEPLIB_MESSAGES, encoded_msg);
+
+       /* Verify the created Open message only has 4 TLVs:
+        *   pcep_tlv_create_stateful_pce_capability()
+        *   pcep_tlv_create_lsp_db_version()
+        *   pcep_tlv_create_sr_pce_capability()
+        *   pcep_tlv_create_path_setup_type_capability() */
+       reset_mock_socket_comm_info();
+       mock_info->send_message_save_message = true;
+       config.pcep_msg_versioning->draft_ietf_pce_segment_routing_07 = true;
+
+       session = create_pcep_session(&config, &pce_ip);
+       CU_ASSERT_PTR_NOT_NULL(session);
+       /* Get and verify the Open Message */
+       encoded_msg = dll_delete_first_node(mock_info->sent_message_list);
+       CU_ASSERT_PTR_NOT_NULL(encoded_msg);
+       open_msg = pcep_decode_message(encoded_msg);
+       CU_ASSERT_PTR_NOT_NULL(open_msg);
+       /* Get and verify the Open Message objects */
+       CU_ASSERT_PTR_NOT_NULL(open_msg->obj_list);
+       CU_ASSERT_TRUE(open_msg->obj_list->num_entries > 0);
+       /* Get and verify the Open object */
+       open_obj = pcep_obj_get(open_msg->obj_list, PCEP_OBJ_CLASS_OPEN);
+       CU_ASSERT_PTR_NOT_NULL(open_obj);
+       /* Get and verify the Open object TLVs */
+       CU_ASSERT_PTR_NOT_NULL(open_obj->tlv_list);
+       CU_ASSERT_EQUAL(open_obj->tlv_list->num_entries, 4);
+       tlv_node = open_obj->tlv_list->head;
+       CU_ASSERT_EQUAL(((struct pcep_object_tlv_header *)tlv_node->data)->type,
+                       PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY);
+       tlv_node = tlv_node->next_node;
+       CU_ASSERT_EQUAL(((struct pcep_object_tlv_header *)tlv_node->data)->type,
+                       PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION);
+       tlv_node = tlv_node->next_node;
+       CU_ASSERT_EQUAL(((struct pcep_object_tlv_header *)tlv_node->data)->type,
+                       PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY);
+       tlv_node = tlv_node->next_node;
+       CU_ASSERT_EQUAL(((struct pcep_object_tlv_header *)tlv_node->data)->type,
+                       PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY);
+
+       destroy_pcep_versioning(config.pcep_msg_versioning);
+       destroy_pcep_session(session);
+       pcep_msg_free_message(open_msg);
+       pceplib_free(PCEPLIB_MESSAGES, encoded_msg);
+
+       stop_session_logic();
+}
+
+
+void test_destroy_pcep_session_null_session()
+{
+       /* Just testing that it does not core dump */
+       destroy_pcep_session(NULL);
+}
diff --git a/pceplib/test/pcep_session_logic_test.h b/pceplib/test/pcep_session_logic_test.h
new file mode 100644 (file)
index 0000000..6cc1963
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Javier Garcia <javier.garcia@voltanet.io>
+ *
+ */
+
+/*
+ *  Timer definitions to be used internally by the pcep_timers library.
+ */
+
+#ifndef PCEP_SESSION_LOGIC_TEST_H_
+#define PCEP_SESSION_LOGIC_TEST_H_
+
+int pcep_session_logic_test_suite_setup(void);
+int pcep_session_logic_test_suite_teardown(void);
+void pcep_session_logic_test_setup(void);
+void pcep_session_logic_test_teardown(void);
+void test_run_stop_session_logic(void);
+void test_run_session_logic_twice(void);
+void test_session_logic_without_run(void);
+void test_create_pcep_session_null_params(void);
+void test_create_destroy_pcep_session(void);
+void test_create_destroy_pcep_session_ipv6(void);
+void test_create_pcep_session_open_tlvs(void);
+void test_destroy_pcep_session_null_session(void);
+
+#endif /* PCEPTIMERINTERNALS_H_ */
diff --git a/pceplib/test/pcep_session_logic_tests.c b/pceplib/test/pcep_session_logic_tests.c
new file mode 100644 (file)
index 0000000..67bf6e2
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <CUnit/Basic.h>
+#include <CUnit/CUnit.h>
+#include <CUnit/TestDB.h>
+
+#include "pcep_session_logic_loop_test.h"
+#include "pcep_session_logic_states_test.h"
+#include "pcep_session_logic_test.h"
+
+
+int main(int argc, char **argv)
+{
+       /* Unused parameters cause compilation warnings */
+       (void)argc;
+       (void)argv;
+
+       CU_initialize_registry();
+
+       /*
+        * Tests defined in pcep_socket_comm_test.c
+        */
+       CU_pSuite test_session_logic_suite =
+               CU_add_suite_with_setup_and_teardown(
+                       "PCEP Session Logic Test Suite",
+                       pcep_session_logic_test_suite_setup, // suite setup and
+                                                            // cleanup function
+                                                            // pointers
+                       pcep_session_logic_test_suite_teardown,
+                       pcep_session_logic_test_setup,     // test case setup
+                                                          // function pointer
+                       pcep_session_logic_test_teardown); // test case teardown
+                                                          // function pointer
+
+       CU_add_test(test_session_logic_suite, "test_run_stop_session_logic",
+                   test_run_stop_session_logic);
+       CU_add_test(test_session_logic_suite, "test_run_session_logic_twice",
+                   test_run_session_logic_twice);
+       CU_add_test(test_session_logic_suite, "test_session_logic_without_run",
+                   test_session_logic_without_run);
+       CU_add_test(test_session_logic_suite,
+                   "test_create_pcep_session_null_params",
+                   test_create_pcep_session_null_params);
+       CU_add_test(test_session_logic_suite,
+                   "test_create_destroy_pcep_session",
+                   test_create_destroy_pcep_session);
+       CU_add_test(test_session_logic_suite,
+                   "test_create_destroy_pcep_session_ipv6",
+                   test_create_destroy_pcep_session_ipv6);
+       CU_add_test(test_session_logic_suite,
+                   "test_create_pcep_session_open_tlvs",
+                   test_create_pcep_session_open_tlvs);
+       CU_add_test(test_session_logic_suite,
+                   "test_destroy_pcep_session_null_session",
+                   test_destroy_pcep_session_null_session);
+
+       CU_pSuite test_session_logic_loop_suite =
+               CU_add_suite_with_setup_and_teardown(
+                       "PCEP Session Logic Loop Test Suite",
+                       pcep_session_logic_loop_test_suite_setup, // suite setup
+                                                                 // and cleanup
+                                                                 // function
+                                                                 // pointers
+                       pcep_session_logic_loop_test_suite_teardown,
+                       pcep_session_logic_loop_test_setup, // test case setup
+                                                           // function pointer
+                       pcep_session_logic_loop_test_teardown); // test case
+                                                               // teardown
+                                                               // function
+                                                               // pointer
+
+       CU_add_test(test_session_logic_loop_suite,
+                   "test_session_logic_loop_null_data",
+                   test_session_logic_loop_null_data);
+       CU_add_test(test_session_logic_loop_suite,
+                   "test_session_logic_loop_inactive",
+                   test_session_logic_loop_inactive);
+       CU_add_test(test_session_logic_loop_suite,
+                   "test_session_logic_msg_ready_handler",
+                   test_session_logic_msg_ready_handler);
+       CU_add_test(test_session_logic_loop_suite,
+                   "test_session_logic_conn_except_notifier",
+                   test_session_logic_conn_except_notifier);
+       CU_add_test(test_session_logic_loop_suite,
+                   "test_session_logic_timer_expire_handler",
+                   test_session_logic_timer_expire_handler);
+
+       CU_pSuite test_session_logic_states_suite =
+               CU_add_suite_with_setup_and_teardown(
+                       "PCEP Session Logic States Test Suite",
+                       pcep_session_logic_states_test_suite_setup, // suite
+                                                                   // setup and
+                                                                   // cleanup
+                                                                   // function
+                                                                   // pointers
+                       pcep_session_logic_states_test_suite_teardown,
+                       pcep_session_logic_states_test_setup, // test case setup
+                                                             // function
+                                                             // pointer
+                       pcep_session_logic_states_test_teardown); // test case
+                                                                 // teardown
+                                                                 // function
+                                                                 // pointer
+
+       CU_add_test(test_session_logic_states_suite,
+                   "test_handle_timer_event_dead_timer",
+                   test_handle_timer_event_dead_timer);
+       CU_add_test(test_session_logic_states_suite,
+                   "test_handle_timer_event_keep_alive",
+                   test_handle_timer_event_keep_alive);
+       CU_add_test(test_session_logic_states_suite,
+                   "test_handle_timer_event_open_keep_wait",
+                   test_handle_timer_event_open_keep_wait);
+       CU_add_test(test_session_logic_states_suite,
+                   "test_handle_socket_comm_event_null_params",
+                   test_handle_socket_comm_event_null_params);
+       CU_add_test(test_session_logic_states_suite,
+                   "test_handle_socket_comm_event_close",
+                   test_handle_socket_comm_event_close);
+       CU_add_test(test_session_logic_states_suite,
+                   "test_handle_socket_comm_event_open",
+                   test_handle_socket_comm_event_open);
+       CU_add_test(test_session_logic_states_suite,
+                   "test_handle_socket_comm_event_open_error",
+                   test_handle_socket_comm_event_open_error);
+       CU_add_test(test_session_logic_states_suite,
+                   "test_handle_socket_comm_event_keep_alive",
+                   test_handle_socket_comm_event_keep_alive);
+       CU_add_test(test_session_logic_states_suite,
+                   "test_handle_socket_comm_event_pcrep",
+                   test_handle_socket_comm_event_pcrep);
+       CU_add_test(test_session_logic_states_suite,
+                   "test_handle_socket_comm_event_pcreq",
+                   test_handle_socket_comm_event_pcreq);
+       CU_add_test(test_session_logic_states_suite,
+                   "test_handle_socket_comm_event_report",
+                   test_handle_socket_comm_event_report);
+       CU_add_test(test_session_logic_states_suite,
+                   "test_handle_socket_comm_event_update",
+                   test_handle_socket_comm_event_update);
+       CU_add_test(test_session_logic_states_suite,
+                   "test_handle_socket_comm_event_initiate",
+                   test_handle_socket_comm_event_initiate);
+       CU_add_test(test_session_logic_states_suite,
+                   "test_handle_socket_comm_event_notify",
+                   test_handle_socket_comm_event_notify);
+       CU_add_test(test_session_logic_states_suite,
+                   "test_handle_socket_comm_event_error",
+                   test_handle_socket_comm_event_error);
+       CU_add_test(test_session_logic_states_suite,
+                   "test_handle_socket_comm_event_unknown_msg",
+                   test_handle_socket_comm_event_unknown_msg);
+       CU_add_test(test_session_logic_states_suite, "test_connection_failure",
+                   test_connection_failure);
+
+       /*
+        * Run the tests and cleanup.
+        */
+       CU_basic_set_mode(CU_BRM_VERBOSE);
+       CU_basic_run_tests();
+       CU_FailureRecord *failure_record = CU_get_failure_list();
+       if (failure_record != NULL) {
+               printf("\nFailed tests:\n\t [Suite] [Test] [File:line-number]\n");
+               do {
+                       printf("\t [%s] [%s] [%s:%d]\n",
+                              failure_record->pSuite->pName,
+                              failure_record->pTest->pName,
+                              failure_record->strFileName,
+                              failure_record->uiLineNumber);
+                       failure_record = failure_record->pNext;
+
+               } while (failure_record != NULL);
+       }
+
+       CU_pRunSummary run_summary = CU_get_run_summary();
+       int result = run_summary->nTestsFailed;
+       CU_cleanup_registry();
+
+       return result;
+}
diff --git a/pceplib/test/pcep_session_logic_tests_valgrind.sh b/pceplib/test/pcep_session_logic_tests_valgrind.sh
new file mode 100755 (executable)
index 0000000..435bb3d
--- /dev/null
@@ -0,0 +1,2 @@
+source pceplib/test/pcep_tests_valgrind.sh
+valgrind_test pceplib/test/pcep_session_logic_tests
diff --git a/pceplib/test/pcep_socket_comm_loop_test.c b/pceplib/test/pcep_socket_comm_loop_test.c
new file mode 100644 (file)
index 0000000..94f0983
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <pthread.h>
+#include <stdlib.h>
+
+#include <CUnit/CUnit.h>
+
+#include "pcep_socket_comm_internals.h"
+#include "pcep_socket_comm_loop.h"
+#include "pcep_socket_comm_loop_test.h"
+#include "pcep_socket_comm.h"
+#include "pcep_utils_memory.h"
+
+void test_loop_conn_except_notifier(void *session_data, int socket_fd);
+
+/*
+ * Functions to be tested, implemented in pcep_socket_comm_loop.c
+ */
+
+typedef struct ready_to_read_handler_info_ {
+       bool handler_called;
+       bool except_handler_called;
+       void *data;
+       int socket_fd;
+       int bytes_read;
+
+} ready_to_read_handler_info;
+
+static ready_to_read_handler_info read_handler_info;
+static pcep_socket_comm_session *test_comm_session;
+static pcep_socket_comm_handle *test_socket_comm_handle = NULL;
+
+static int test_loop_message_ready_to_read_handler(void *session_data,
+                                                  int socket_fd)
+{
+       read_handler_info.handler_called = true;
+       read_handler_info.data = session_data;
+       read_handler_info.socket_fd = socket_fd;
+
+       return read_handler_info.bytes_read;
+}
+
+
+void test_loop_conn_except_notifier(void *session_data, int socket_fd)
+{
+       (void)session_data;
+       (void)socket_fd;
+       read_handler_info.except_handler_called = true;
+}
+
+
+/*
+ * Test case setup and teardown called before AND after each test.
+ */
+void pcep_socket_comm_loop_test_setup()
+{
+       test_socket_comm_handle =
+               pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_socket_comm_handle));
+       memset(test_socket_comm_handle, 0, sizeof(pcep_socket_comm_handle));
+       test_socket_comm_handle->active = false;
+       test_socket_comm_handle->read_list =
+               ordered_list_initialize(socket_fd_node_compare);
+       test_socket_comm_handle->write_list =
+               ordered_list_initialize(socket_fd_node_compare);
+       test_socket_comm_handle->session_list =
+               ordered_list_initialize(pointer_compare_function);
+       pthread_mutex_init(&test_socket_comm_handle->socket_comm_mutex, NULL);
+       test_socket_comm_handle->num_active_sessions = 0;
+
+       test_comm_session =
+               pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_socket_comm_session));
+       memset(test_comm_session, 0, sizeof(pcep_socket_comm_session));
+       test_comm_session->message_ready_to_read_handler =
+               test_loop_message_ready_to_read_handler;
+       ordered_list_add_node(test_socket_comm_handle->session_list,
+                             test_comm_session);
+
+       read_handler_info.handler_called = false;
+       read_handler_info.except_handler_called = false;
+       read_handler_info.data = NULL;
+       read_handler_info.socket_fd = -1;
+       read_handler_info.bytes_read = 0;
+}
+
+
+void pcep_socket_comm_loop_test_teardown()
+{
+       pthread_mutex_destroy(&test_socket_comm_handle->socket_comm_mutex);
+       ordered_list_destroy(test_socket_comm_handle->read_list);
+       ordered_list_destroy(test_socket_comm_handle->write_list);
+       ordered_list_destroy(test_socket_comm_handle->session_list);
+       pceplib_free(PCEPLIB_INFRA, test_socket_comm_handle);
+       test_socket_comm_handle = NULL;
+
+       if (test_comm_session != NULL) {
+               pceplib_free(PCEPLIB_INFRA, test_comm_session);
+               test_comm_session = NULL;
+       }
+}
+
+
+/*
+ * Test cases
+ */
+
+void test_socket_comm_loop_null_handle()
+{
+       /* Verify that socket_comm_loop() correctly handles a NULL
+        * timers_context */
+       socket_comm_loop(NULL);
+}
+
+
+void test_socket_comm_loop_not_active()
+{
+       /* Verify that event_loop() correctly handles an inactive flag */
+       pcep_socket_comm_handle handle;
+       handle.active = false;
+       socket_comm_loop(&handle);
+}
+
+
+void test_handle_reads_no_read()
+{
+       CU_ASSERT_PTR_NULL(test_socket_comm_handle->read_list->head);
+
+       handle_reads(test_socket_comm_handle);
+
+       CU_ASSERT_FALSE(read_handler_info.handler_called);
+       CU_ASSERT_FALSE(read_handler_info.except_handler_called);
+       CU_ASSERT_PTR_NULL(test_socket_comm_handle->read_list->head);
+}
+
+
+void test_handle_reads_read_message()
+{
+       /* Setup the comm session so that it can read.
+        * It should read 100 bytes, which simulates a successful read */
+       test_comm_session->socket_fd = 10;
+       read_handler_info.bytes_read = 100;
+       FD_SET(test_comm_session->socket_fd,
+              &test_socket_comm_handle->read_master_set);
+       ordered_list_add_node(test_socket_comm_handle->read_list,
+                             test_comm_session);
+
+       handle_reads(test_socket_comm_handle);
+
+       CU_ASSERT_TRUE(read_handler_info.handler_called);
+       CU_ASSERT_FALSE(read_handler_info.except_handler_called);
+       CU_ASSERT_EQUAL(test_comm_session->received_bytes,
+                       read_handler_info.bytes_read);
+}
+
+
+void test_handle_reads_read_message_close()
+{
+       /* Setup the comm session so that it can read.
+        * It should read 0 bytes, which simulates that the socket closed */
+       test_comm_session->socket_fd = 11;
+       read_handler_info.bytes_read = 0;
+       FD_SET(test_comm_session->socket_fd,
+              &test_socket_comm_handle->read_master_set);
+       ordered_list_add_node(test_socket_comm_handle->read_list,
+                             test_comm_session);
+
+       handle_reads(test_socket_comm_handle);
+
+       CU_ASSERT_TRUE(read_handler_info.handler_called);
+       CU_ASSERT_FALSE(read_handler_info.except_handler_called);
+       CU_ASSERT_EQUAL(test_comm_session->received_bytes,
+                       read_handler_info.bytes_read);
+       CU_ASSERT_PTR_NULL(test_socket_comm_handle->read_list->head);
+}
diff --git a/pceplib/test/pcep_socket_comm_loop_test.h b/pceplib/test/pcep_socket_comm_loop_test.h
new file mode 100644 (file)
index 0000000..d2e3f21
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Javier Garcia <javier.garcia@voltanet.io>
+ *
+ */
+
+/*
+ *  Timer definitions to be used internally by the pcep_timers library.
+ */
+
+#ifndef PCEP_SOCKET_COMM_LOOP_TEST_H_
+#define PCEP_SOCKET_COMM_LOOP_TEST_H_
+
+void pcep_socket_comm_loop_test_setup(void);
+void pcep_socket_comm_loop_test_teardown(void);
+void test_socket_comm_loop_null_handle(void);
+void test_socket_comm_loop_not_active(void);
+void test_handle_reads_no_read(void);
+void test_handle_reads_read_message(void);
+void test_handle_reads_read_message_close(void);
+
+#endif /* PCEPTIMERINTERNALS_H_ */
diff --git a/pceplib/test/pcep_socket_comm_test.c b/pceplib/test/pcep_socket_comm_test.c
new file mode 100644 (file)
index 0000000..35afbcb
--- /dev/null
@@ -0,0 +1,308 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <netinet/in.h>
+
+#include <CUnit/CUnit.h>
+
+#include "pcep_socket_comm.h"
+#include "pcep_socket_comm_internals.h"
+#include "pcep_socket_comm_test.h"
+
+extern pcep_socket_comm_handle *socket_comm_handle_;
+
+static pcep_socket_comm_session *test_session = NULL;
+static struct in_addr test_host_ip;
+static struct in_addr test_src_ip;
+static struct in6_addr test_host_ipv6;
+static struct in6_addr test_src_ipv6;
+static short test_port = 4789;
+static short test_src_port = 4999;
+static uint32_t connect_timeout_millis = 500;
+
+/*
+ * Unit Test Basic pcep_socket_comm API usage.
+ * Testing sending messages, etc via sockets should be done
+ * with integration tests, not unit tests.
+ */
+
+/*
+ * Different socket_comm handler test implementations
+ */
+static void test_message_received_handler(void *session_data,
+                                         const char *message_data,
+                                         unsigned int message_length)
+{
+       (void)session_data;
+       (void)message_data;
+       (void)message_length;
+}
+
+static int test_message_ready_to_read_handler(void *session_data, int socket_fd)
+{
+       (void)session_data;
+       (void)socket_fd;
+       return 1;
+}
+
+static void test_message_sent_handler(void *session_data, int socket_fd)
+{
+       (void)session_data;
+       (void)socket_fd;
+       return;
+}
+
+static void test_connection_except_notifier(void *session_data, int socket_fd)
+{
+       (void)session_data;
+       (void)socket_fd;
+}
+
+
+/*
+ * Test case setup and teardown called before AND after each test.
+ */
+void pcep_socket_comm_test_setup()
+{
+       inet_pton(AF_INET, "127.0.0.1", &(test_host_ip));
+       inet_pton(AF_INET, "127.0.0.1", &(test_src_ip));
+       inet_pton(AF_INET6, "::1", &(test_host_ipv6));
+       inet_pton(AF_INET6, "::1", &(test_src_ipv6));
+}
+
+void pcep_socket_comm_test_teardown()
+{
+       socket_comm_session_teardown(test_session);
+       test_session = NULL;
+}
+
+
+/*
+ * Test cases
+ */
+
+void test_pcep_socket_comm_initialize()
+{
+       test_session = socket_comm_session_initialize(
+               test_message_received_handler, NULL, NULL,
+               test_connection_except_notifier, &test_host_ip, test_port,
+               connect_timeout_millis, NULL, false, NULL);
+       CU_ASSERT_PTR_NOT_NULL(test_session);
+       CU_ASSERT_FALSE(test_session->is_ipv6);
+}
+
+
+void test_pcep_socket_comm_initialize_ipv6()
+{
+       test_session = socket_comm_session_initialize_ipv6(
+               test_message_received_handler, NULL, NULL,
+               test_connection_except_notifier, &test_host_ipv6, test_port,
+               connect_timeout_millis, NULL, false, NULL);
+       CU_ASSERT_PTR_NOT_NULL(test_session);
+       CU_ASSERT_TRUE(test_session->is_ipv6);
+}
+
+
+void test_pcep_socket_comm_initialize_with_src()
+{
+       /* Test that INADDR_ANY will be used when src_ip is NULL */
+       test_session = socket_comm_session_initialize_with_src(
+               test_message_received_handler, NULL, NULL,
+               test_connection_except_notifier, NULL, 0, &test_host_ip,
+               test_port, connect_timeout_millis, NULL, false, NULL);
+       CU_ASSERT_PTR_NOT_NULL(test_session);
+       CU_ASSERT_EQUAL(
+               test_session->src_sock_addr.src_sock_addr_ipv4.sin_addr.s_addr,
+               INADDR_ANY);
+       CU_ASSERT_FALSE(test_session->is_ipv6);
+
+       socket_comm_session_teardown(test_session);
+       test_session = socket_comm_session_initialize_with_src(
+               test_message_received_handler, NULL, NULL,
+               test_connection_except_notifier, &test_src_ip, test_src_port,
+               &test_host_ip, test_port, connect_timeout_millis, NULL, false,
+               NULL);
+       CU_ASSERT_PTR_NOT_NULL(test_session);
+       CU_ASSERT_EQUAL(
+               test_session->src_sock_addr.src_sock_addr_ipv4.sin_addr.s_addr,
+               test_src_ip.s_addr);
+       CU_ASSERT_EQUAL(test_session->src_sock_addr.src_sock_addr_ipv4.sin_port,
+                       ntohs(test_src_port));
+       CU_ASSERT_FALSE(test_session->is_ipv6);
+}
+
+
+void test_pcep_socket_comm_initialize_with_src_ipv6()
+{
+       /* Test that INADDR6_ANY will be used when src_ip is NULL */
+       test_session = socket_comm_session_initialize_with_src_ipv6(
+               test_message_received_handler, NULL, NULL,
+               test_connection_except_notifier, NULL, 0, &test_host_ipv6,
+               test_port, connect_timeout_millis, NULL, false, NULL);
+       CU_ASSERT_PTR_NOT_NULL(test_session);
+       CU_ASSERT_EQUAL(memcmp(&test_session->src_sock_addr.src_sock_addr_ipv6
+                                       .sin6_addr,
+                              &in6addr_any, sizeof(struct in6_addr)),
+                       0);
+       CU_ASSERT_TRUE(test_session->is_ipv6);
+
+       socket_comm_session_teardown(test_session);
+       test_session = socket_comm_session_initialize_with_src_ipv6(
+               test_message_received_handler, NULL, NULL,
+               test_connection_except_notifier, &test_src_ipv6, test_src_port,
+               &test_host_ipv6, test_port, connect_timeout_millis, NULL, false,
+               NULL);
+       CU_ASSERT_PTR_NOT_NULL(test_session);
+       CU_ASSERT_EQUAL(memcmp(&test_session->src_sock_addr.src_sock_addr_ipv6
+                                       .sin6_addr,
+                              &test_src_ipv6, sizeof(struct in6_addr)),
+                       0);
+       CU_ASSERT_EQUAL(
+               test_session->src_sock_addr.src_sock_addr_ipv6.sin6_port,
+               ntohs(test_src_port));
+       CU_ASSERT_TRUE(test_session->is_ipv6);
+}
+
+
+void test_pcep_socket_comm_initialize_tcpmd5()
+{
+       char tcp_md5_str[] = "hello";
+       int tcp_md5_strlen = strlen(tcp_md5_str);
+
+       test_session = socket_comm_session_initialize(
+               test_message_received_handler, NULL, NULL,
+               test_connection_except_notifier, &test_host_ip, test_port, 1,
+               tcp_md5_str, true, NULL);
+       CU_ASSERT_PTR_NOT_NULL(test_session);
+       CU_ASSERT_EQUAL(0, strncmp(tcp_md5_str,
+                                  test_session->tcp_authentication_str,
+                                  tcp_md5_strlen));
+       CU_ASSERT_TRUE(test_session->is_tcp_auth_md5);
+       CU_ASSERT_FALSE(socket_comm_session_connect_tcp(test_session));
+       /* This call does not work, it returns errno=92, Protocol not available
+       getsockopt(test_session->socket_fd, SOL_SOCKET, TCP_MD5SIG, &sig,
+       &siglen);*/
+
+       socket_comm_session_teardown(test_session);
+       test_session = socket_comm_session_initialize(
+               test_message_received_handler, NULL, NULL,
+               test_connection_except_notifier, &test_host_ip, test_port, 1,
+               tcp_md5_str, false, NULL);
+       CU_ASSERT_PTR_NOT_NULL(test_session);
+       CU_ASSERT_EQUAL(0, strncmp(tcp_md5_str,
+                                  test_session->tcp_authentication_str,
+                                  tcp_md5_strlen));
+       CU_ASSERT_FALSE(test_session->is_tcp_auth_md5);
+       CU_ASSERT_FALSE(socket_comm_session_connect_tcp(test_session));
+}
+
+
+void test_pcep_socket_comm_initialize_ipv6_tcpmd5()
+{
+       char tcp_md5_str[] = "hello";
+       int tcp_md5_strlen = strlen(tcp_md5_str);
+
+       test_session = socket_comm_session_initialize_ipv6(
+               test_message_received_handler, NULL, NULL,
+               test_connection_except_notifier, &test_host_ipv6, test_port, 1,
+               tcp_md5_str, true, NULL);
+       CU_ASSERT_PTR_NOT_NULL(test_session);
+       CU_ASSERT_EQUAL(0, strncmp(tcp_md5_str,
+                                  test_session->tcp_authentication_str,
+                                  tcp_md5_strlen));
+       CU_ASSERT_TRUE(test_session->is_tcp_auth_md5);
+       CU_ASSERT_FALSE(socket_comm_session_connect_tcp(test_session));
+       /* This call does not work, it returns errno=92, Protocol not available
+       getsockopt(test_session->socket_fd, SOL_SOCKET, TCP_MD5SIG, &sig,
+       &siglen);*/
+
+       socket_comm_session_teardown(test_session);
+       test_session = socket_comm_session_initialize_ipv6(
+               test_message_received_handler, NULL, NULL,
+               test_connection_except_notifier, &test_host_ipv6, test_port, 1,
+               tcp_md5_str, false, NULL);
+       CU_ASSERT_PTR_NOT_NULL(test_session);
+       CU_ASSERT_EQUAL(0, strncmp(tcp_md5_str,
+                                  test_session->tcp_authentication_str,
+                                  tcp_md5_strlen));
+       CU_ASSERT_FALSE(test_session->is_tcp_auth_md5);
+       CU_ASSERT_FALSE(socket_comm_session_connect_tcp(test_session));
+}
+
+
+void test_pcep_socket_comm_initialize_handlers()
+{
+       /* Verify incorrect handler usage is correctly handled */
+
+       /* Both receive handlers cannot be NULL */
+       test_session = socket_comm_session_initialize(
+               NULL, NULL, NULL, test_connection_except_notifier,
+               &test_host_ip, test_port, connect_timeout_millis, NULL, false,
+               NULL);
+       CU_ASSERT_PTR_NULL(test_session);
+
+       /* Both receive handlers cannot be set */
+       test_session = socket_comm_session_initialize(
+               test_message_received_handler,
+               test_message_ready_to_read_handler, test_message_sent_handler,
+               test_connection_except_notifier, &test_host_ip, test_port,
+               connect_timeout_millis, NULL, false, NULL);
+       CU_ASSERT_PTR_NULL(test_session);
+
+       /* Only one receive handler can be set */
+       test_session = socket_comm_session_initialize(
+               NULL, test_message_ready_to_read_handler,
+               test_message_sent_handler, test_connection_except_notifier,
+               &test_host_ip, test_port, connect_timeout_millis, NULL, false,
+               NULL);
+       CU_ASSERT_PTR_NOT_NULL(test_session);
+}
+
+
+void test_pcep_socket_comm_session_not_initialized()
+{
+       CU_ASSERT_FALSE(socket_comm_session_connect_tcp(NULL));
+       CU_ASSERT_FALSE(socket_comm_session_close_tcp(NULL));
+       CU_ASSERT_FALSE(socket_comm_session_close_tcp_after_write(NULL));
+       socket_comm_session_send_message(NULL, NULL, 0, true);
+       CU_ASSERT_FALSE(socket_comm_session_teardown(NULL));
+}
+
+
+void test_pcep_socket_comm_session_destroy()
+{
+       test_session = socket_comm_session_initialize(
+               test_message_received_handler, NULL, test_message_sent_handler,
+               test_connection_except_notifier, &test_host_ip, test_port,
+               connect_timeout_millis, NULL, false, NULL);
+       CU_ASSERT_PTR_NOT_NULL(test_session);
+       CU_ASSERT_PTR_NOT_NULL(socket_comm_handle_);
+       CU_ASSERT_EQUAL(socket_comm_handle_->num_active_sessions, 1);
+
+       CU_ASSERT_TRUE(socket_comm_session_teardown(test_session));
+       test_session = NULL;
+       CU_ASSERT_PTR_NOT_NULL(socket_comm_handle_);
+
+       CU_ASSERT_TRUE(destroy_socket_comm_loop());
+       CU_ASSERT_PTR_NULL(socket_comm_handle_);
+}
diff --git a/pceplib/test/pcep_socket_comm_test.h b/pceplib/test/pcep_socket_comm_test.h
new file mode 100644 (file)
index 0000000..f857af0
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Javier Garcia <javier.garcia@voltanet.io>
+ *
+ */
+
+/*
+ *  Timer definitions to be used internally by the pcep_timers library.
+ */
+
+#ifndef PCEP_SOCKET_COMM_TEST_H_
+#define PCEP_SOCKET_COMM_TEST_H_
+
+void pcep_socket_comm_test_teardown(void);
+void pcep_socket_comm_test_setup(void);
+void test_pcep_socket_comm_initialize(void);
+void test_pcep_socket_comm_initialize_ipv6(void);
+void test_pcep_socket_comm_initialize_with_src(void);
+void test_pcep_socket_comm_initialize_with_src_ipv6(void);
+void test_pcep_socket_comm_initialize_tcpmd5(void);
+void test_pcep_socket_comm_initialize_ipv6_tcpmd5(void);
+void test_pcep_socket_comm_initialize_handlers(void);
+void test_pcep_socket_comm_session_not_initialized(void);
+void test_pcep_socket_comm_session_destroy(void);
+
+#endif
diff --git a/pceplib/test/pcep_socket_comm_tests.c b/pceplib/test/pcep_socket_comm_tests.c
new file mode 100644 (file)
index 0000000..293678f
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <CUnit/Basic.h>
+#include <CUnit/CUnit.h>
+#include <CUnit/TestDB.h>
+
+#include "pcep_socket_comm_loop_test.h"
+#include "pcep_socket_comm_test.h"
+
+
+int main(int argc, char **argv)
+{
+       /* Unused parameters cause compilation warnings */
+       (void)argc;
+       (void)argv;
+
+       CU_initialize_registry();
+
+       /*
+        * Tests defined in pcep_socket_comm_test.c
+        */
+       CU_pSuite test_socket_comm_suite = CU_add_suite_with_setup_and_teardown(
+               "PCEP Socket Comm Test Suite", NULL,
+               NULL, // suite setup and cleanup function pointers
+               pcep_socket_comm_test_setup, // test case setup function pointer
+               pcep_socket_comm_test_teardown); // test case teardown function
+                                                // pointer
+
+       CU_add_test(test_socket_comm_suite, "test_pcep_socket_comm_initialize",
+                   test_pcep_socket_comm_initialize);
+       CU_add_test(test_socket_comm_suite,
+                   "test_pcep_socket_comm_initialize_ipv6",
+                   test_pcep_socket_comm_initialize_ipv6);
+       CU_add_test(test_socket_comm_suite,
+                   "test_pcep_socket_comm_initialize_with_src",
+                   test_pcep_socket_comm_initialize_with_src);
+       CU_add_test(test_socket_comm_suite,
+                   "test_pcep_socket_comm_initialize_with_src_ipv6",
+                   test_pcep_socket_comm_initialize_with_src_ipv6);
+       CU_add_test(test_socket_comm_suite,
+                   "test_pcep_socket_comm_initialize_tcpmd5",
+                   test_pcep_socket_comm_initialize_tcpmd5);
+       CU_add_test(test_socket_comm_suite,
+                   "test_pcep_socket_comm_initialize_ipv6_tcpmd5",
+                   test_pcep_socket_comm_initialize_ipv6_tcpmd5);
+       CU_add_test(test_socket_comm_suite,
+                   "test_pcep_socket_comm_initialize_handlers",
+                   test_pcep_socket_comm_initialize_handlers);
+       CU_add_test(test_socket_comm_suite,
+                   "test_pcep_socket_comm_session_not_initialized",
+                   test_pcep_socket_comm_session_not_initialized);
+       CU_add_test(test_socket_comm_suite,
+                   "test_pcep_socket_comm_session_destroy",
+                   test_pcep_socket_comm_session_destroy);
+
+       /*
+        * Tests defined in pcep_socket_comm_loop_test.c
+        */
+       CU_pSuite test_socket_comm_loop_suite =
+               CU_add_suite_with_setup_and_teardown(
+                       "PCEP Socket Comm Loop Test Suite", NULL, NULL,
+                       pcep_socket_comm_loop_test_setup, // suite setup
+                                                         // function pointer
+                       pcep_socket_comm_loop_test_teardown); // suite cleanup
+                                                             // function
+                                                             // pointer
+
+       CU_add_test(test_socket_comm_loop_suite,
+                   "test_socket_comm_loop_null_handle",
+                   test_socket_comm_loop_null_handle);
+       CU_add_test(test_socket_comm_loop_suite,
+                   "test_socket_comm_loop_not_active",
+                   test_socket_comm_loop_not_active);
+       CU_add_test(test_socket_comm_loop_suite, "test_handle_reads_no_read",
+                   test_handle_reads_no_read);
+       CU_add_test(test_socket_comm_loop_suite,
+                   "test_handle_reads_read_message",
+                   test_handle_reads_read_message);
+       CU_add_test(test_socket_comm_loop_suite,
+                   "test_handle_reads_read_message_close",
+                   test_handle_reads_read_message_close);
+
+       /*
+        * Run the tests and cleanup.
+        */
+       CU_basic_set_mode(CU_BRM_VERBOSE);
+       CU_basic_run_tests();
+       CU_FailureRecord *failure_record = CU_get_failure_list();
+       if (failure_record != NULL) {
+               printf("\nFailed tests:\n\t [Suite] [Test] [File:line-number]\n");
+               do {
+                       printf("\t [%s] [%s] [%s:%d]\n",
+                              failure_record->pSuite->pName,
+                              failure_record->pTest->pName,
+                              failure_record->strFileName,
+                              failure_record->uiLineNumber);
+                       failure_record = failure_record->pNext;
+
+               } while (failure_record != NULL);
+       }
+
+       CU_pRunSummary run_summary = CU_get_run_summary();
+       int result = run_summary->nTestsFailed;
+       CU_cleanup_registry();
+
+       return result;
+}
diff --git a/pceplib/test/pcep_socket_comm_tests_valgrind.sh b/pceplib/test/pcep_socket_comm_tests_valgrind.sh
new file mode 100755 (executable)
index 0000000..d9e95e4
--- /dev/null
@@ -0,0 +1,2 @@
+source pceplib/test/pcep_tests_valgrind.sh
+valgrind_test pceplib/test/pcep_socket_comm_tests
diff --git a/pceplib/test/pcep_tests_valgrind.sh b/pceplib/test/pcep_tests_valgrind.sh
new file mode 100755 (executable)
index 0000000..ca4772c
--- /dev/null
@@ -0,0 +1,15 @@
+#
+# Common function definition for PCEPlib valgrind tests
+#
+
+function valgrind_test()
+{
+    local test_suite=$1
+    [[ -z ${test_suite} ]]     && { echo "${FUNCNAME}(): test_suite not specified."; exit 1; }
+    [[ ! -x "${test_suite}" ]] && { echo "${test_suite} is not an executable file."; exit 1; }
+
+    G_SLICE=always-malloc
+    G_DEBUG=gc-friendly
+    VALGRIND="valgrind -v --tool=memcheck --leak-check=full --num-callers=40 --error-exitcode=1"
+    ${VALGRIND} --log-file=${test_suite}.val.log ./${test_suite} || ({ echo "Valgrind memory check error"; exit 1; })
+}
diff --git a/pceplib/test/pcep_timers_event_loop_test.c b/pceplib/test/pcep_timers_event_loop_test.c
new file mode 100644 (file)
index 0000000..ae63601
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <stdlib.h>
+
+#include <CUnit/CUnit.h>
+
+#include "pcep_timers.h"
+#include "pcep_utils_memory.h"
+#include "pcep_timers_event_loop.h"
+#include "pcep_timers_event_loop_test.h"
+
+
+typedef struct timer_expire_handler_info_ {
+       bool handler_called;
+       void *data;
+       int timerId;
+
+} timer_expire_handler_info;
+
+static pcep_timers_context *test_timers_context = NULL;
+static timer_expire_handler_info expire_handler_info;
+#define TEST_EVENT_LOOP_TIMER_ID 500
+
+
+/* Called when a timer expires */
+static void test_timer_expire_handler(void *data, int timerId)
+{
+       expire_handler_info.handler_called = true;
+       expire_handler_info.data = data;
+       expire_handler_info.timerId = timerId;
+}
+
+
+/* Test case setup called before each test.
+ * Declared in pcep_timers_tests.c */
+void pcep_timers_event_loop_test_setup()
+{
+       test_timers_context =
+               pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_timers_context));
+       memset(test_timers_context, 0, sizeof(pcep_timers_context));
+       if (pthread_mutex_init(&(test_timers_context->timer_list_lock), NULL)
+           != 0) {
+               fprintf(stderr,
+                       "ERROR initializing timers, cannot initialize the mutex\n");
+       }
+       test_timers_context->active = false;
+       test_timers_context->expire_handler = test_timer_expire_handler;
+       test_timers_context->timer_list =
+               ordered_list_initialize(timer_list_node_timer_id_compare);
+
+       expire_handler_info.handler_called = false;
+       expire_handler_info.data = NULL;
+       expire_handler_info.timerId = -1;
+}
+
+
+/* Test case teardown called after each test.
+ * Declared in pcep_timers_tests.c */
+void pcep_timers_event_loop_test_teardown()
+{
+       pthread_mutex_unlock(&test_timers_context->timer_list_lock);
+       pthread_mutex_destroy(&(test_timers_context->timer_list_lock));
+       ordered_list_destroy(test_timers_context->timer_list);
+       pceplib_free(PCEPLIB_INFRA, test_timers_context);
+       test_timers_context = NULL;
+}
+
+
+/*
+ * Test functions
+ */
+
+void test_walk_and_process_timers_no_timers()
+{
+       CU_ASSERT_EQUAL(test_timers_context->timer_list->num_entries, 0);
+       CU_ASSERT_PTR_NULL(test_timers_context->timer_list->head);
+
+       walk_and_process_timers(test_timers_context);
+
+       CU_ASSERT_FALSE(expire_handler_info.handler_called);
+       CU_ASSERT_EQUAL(test_timers_context->timer_list->num_entries, 0);
+       CU_ASSERT_PTR_NULL(test_timers_context->timer_list->head);
+}
+
+
+void test_walk_and_process_timers_timer_not_expired()
+{
+       pcep_timer timer;
+       timer.data = &timer;
+       // Set the timer to expire 100 seconds from now
+       timer.expire_time = time(NULL) + 100;
+       timer.timer_id = TEST_EVENT_LOOP_TIMER_ID;
+       ordered_list_add_node(test_timers_context->timer_list, &timer);
+
+       walk_and_process_timers(test_timers_context);
+
+       /* The timer should still be in the list, since it hasnt expired yet */
+       CU_ASSERT_FALSE(expire_handler_info.handler_called);
+       CU_ASSERT_EQUAL(test_timers_context->timer_list->num_entries, 1);
+       CU_ASSERT_PTR_NOT_NULL(test_timers_context->timer_list->head);
+}
+
+
+void test_walk_and_process_timers_timer_expired()
+{
+       /* We need to alloc it, since it will be free'd in
+        * walk_and_process_timers */
+       pcep_timer *timer = pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_timer));
+       timer->data = timer;
+       // Set the timer to expire 10 seconds ago
+       timer->expire_time = time(NULL) - 10;
+       pthread_mutex_lock(&test_timers_context->timer_list_lock);
+       timer->timer_id = TEST_EVENT_LOOP_TIMER_ID;
+       pthread_mutex_unlock(&test_timers_context->timer_list_lock);
+       ordered_list_add_node(test_timers_context->timer_list, timer);
+
+       walk_and_process_timers(test_timers_context);
+
+       /* Since the timer expired, the expire_handler should have been called
+        * and the timer should have been removed from the timer list */
+       CU_ASSERT_TRUE(expire_handler_info.handler_called);
+       CU_ASSERT_PTR_EQUAL(expire_handler_info.data, timer);
+       CU_ASSERT_EQUAL(expire_handler_info.timerId, TEST_EVENT_LOOP_TIMER_ID);
+       CU_ASSERT_EQUAL(test_timers_context->timer_list->num_entries, 0);
+       CU_ASSERT_PTR_NULL(test_timers_context->timer_list->head);
+}
+
+void test_event_loop_null_handle()
+{
+       /* Verify that event_loop() correctly handles a NULL timers_context */
+       event_loop(NULL);
+}
+
+
+void test_event_loop_not_active()
+{
+       /* Verify that event_loop() correctly handles an inactive timers_context
+        * flag */
+       test_timers_context->active = false;
+       event_loop(test_timers_context);
+}
diff --git a/pceplib/test/pcep_timers_event_loop_test.h b/pceplib/test/pcep_timers_event_loop_test.h
new file mode 100644 (file)
index 0000000..19fd264
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Javier Garcia <javier.garcia@voltanet.io>
+ *
+ */
+
+/*
+ *  Timer definitions to be used internally by the pcep_timers library.
+ */
+
+#ifndef PCEP_TIMERS_EVENT_LOOP_TEST_H_
+#define PCEP_TIMERS_EVENT_LOOP_TEST_H_
+
+void pcep_timers_event_loop_test_setup(void);
+void pcep_timers_event_loop_test_teardown(void);
+void test_walk_and_process_timers_no_timers(void);
+void test_walk_and_process_timers_timer_not_expired(void);
+void test_walk_and_process_timers_timer_expired(void);
+void test_event_loop_null_handle(void);
+void test_event_loop_not_active(void);
+
+#endif /* PCEPTIMERINTERNALS_H_ */
diff --git a/pceplib/test/pcep_timers_test.c b/pceplib/test/pcep_timers_test.c
new file mode 100644 (file)
index 0000000..9d9e0f6
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <stdbool.h>
+#include <CUnit/CUnit.h>
+
+#include "pcep_timers.h"
+#include "pcep_timers_test.h"
+
+/* Test case teardown called after each test.
+ * Declared in pcep_timers_tests.c */
+void pcep_timers_test_teardown()
+{
+       teardown_timers();
+}
+
+static void test_timer_expire_handler(void *data, int timerId)
+{
+       (void)data;
+       (void)timerId;
+}
+
+
+void test_double_initialization(void)
+{
+       CU_ASSERT_EQUAL(initialize_timers(test_timer_expire_handler), true);
+       CU_ASSERT_EQUAL(initialize_timers(test_timer_expire_handler), false);
+}
+
+
+void test_initialization_null_callback(void)
+{
+       CU_ASSERT_EQUAL(initialize_timers(NULL), false);
+}
+
+
+void test_not_initialized(void)
+{
+       /* All of these should fail if initialize_timers() hasnt been called */
+       CU_ASSERT_EQUAL(create_timer(5, NULL), -1);
+       CU_ASSERT_EQUAL(cancel_timer(7), false);
+       CU_ASSERT_EQUAL(reset_timer(7), false);
+       CU_ASSERT_EQUAL(teardown_timers(), false);
+}
+
+
+void test_create_timer(void)
+{
+       CU_ASSERT_EQUAL(initialize_timers(test_timer_expire_handler), true);
+
+       int timer_id = create_timer(0, NULL);
+       CU_ASSERT_TRUE(timer_id > -1);
+}
+
+
+void test_cancel_timer(void)
+{
+       CU_ASSERT_EQUAL(initialize_timers(test_timer_expire_handler), true);
+
+       int timer_id = create_timer(10, NULL);
+       CU_ASSERT_TRUE(timer_id > -1);
+
+       CU_ASSERT_EQUAL(cancel_timer(timer_id), true);
+}
+
+
+void test_cancel_timer_invalid(void)
+{
+       CU_ASSERT_EQUAL(initialize_timers(test_timer_expire_handler), true);
+       CU_ASSERT_EQUAL(cancel_timer(1), false);
+}
+
+
+void test_reset_timer(void)
+{
+       CU_ASSERT_EQUAL(initialize_timers(test_timer_expire_handler), true);
+
+       int timer_id = create_timer(10, NULL);
+       CU_ASSERT_TRUE(timer_id > -1);
+
+       CU_ASSERT_EQUAL(reset_timer(timer_id), true);
+}
+
+
+void test_reset_timer_invalid(void)
+{
+       CU_ASSERT_EQUAL(initialize_timers(test_timer_expire_handler), true);
+       CU_ASSERT_EQUAL(reset_timer(1), false);
+}
diff --git a/pceplib/test/pcep_timers_test.h b/pceplib/test/pcep_timers_test.h
new file mode 100644 (file)
index 0000000..6ac9a90
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Javier Garcia <javier.garcia@voltanet.io>
+ *
+ */
+
+/*
+ *  Timer definitions to be used internally by the pcep_timers library.
+ */
+
+#ifndef PCEP_TIMERS_TEST_H_
+#define PCEP_TIMERS_TEST_H_
+
+void pcep_timers_test_teardown(void);
+void test_double_initialization(void);
+void test_initialization_null_callback(void);
+void test_not_initialized(void);
+void test_create_timer(void);
+void test_cancel_timer(void);
+void test_cancel_timer_invalid(void);
+void test_reset_timer(void);
+void test_reset_timer_invalid(void);
+
+#endif /* PCEPTIMERINTERNALS_H_ */
diff --git a/pceplib/test/pcep_timers_tests.c b/pceplib/test/pcep_timers_tests.c
new file mode 100644 (file)
index 0000000..adfea17
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <CUnit/Basic.h>
+#include <CUnit/CUnit.h>
+#include <CUnit/TestDB.h>
+
+#include "pcep_timers_test.h"
+#include "pcep_timers_event_loop_test.h"
+
+
+int main(int argc, char **argv)
+{
+       /* Unused parameters cause compilation warnings */
+       (void)argc;
+       (void)argv;
+
+       CU_initialize_registry();
+
+       /*
+        * Tests defined in pcep_timers_test.c
+        */
+       CU_pSuite test_timers_suite = CU_add_suite_with_setup_and_teardown(
+               "PCEP Timers Test Suite", NULL,
+               NULL, // suite setup and cleanup function pointers
+               NULL, pcep_timers_test_teardown); // test case setup and
+                                                 // teardown function pointers
+       CU_add_test(test_timers_suite, "test_double_initialization",
+                   test_double_initialization);
+       CU_add_test(test_timers_suite, "test_initialization_null_callback",
+                   test_initialization_null_callback);
+       CU_add_test(test_timers_suite, "test_not_initialized",
+                   test_not_initialized);
+       CU_add_test(test_timers_suite, "test_create_timer", test_create_timer);
+       CU_add_test(test_timers_suite, "test_cancel_timer", test_cancel_timer);
+       CU_add_test(test_timers_suite, "test_cancel_timer_invalid",
+                   test_cancel_timer_invalid);
+       CU_add_test(test_timers_suite, "test_reset_timer", test_reset_timer);
+       CU_add_test(test_timers_suite, "test_reset_timer_invalid",
+                   test_reset_timer_invalid);
+
+       /*
+        * Tests defined in pcep_timers_event_loop_test.c
+        */
+       CU_pSuite test_timers_event_loop_suite =
+               CU_add_suite_with_setup_and_teardown(
+                       "PCEP Timers Event Loop Test Suite", NULL,
+                       NULL, // suite setup and cleanup function pointers
+                       pcep_timers_event_loop_test_setup, // test case setup
+                                                          // function pointer
+                       pcep_timers_event_loop_test_teardown); // test case
+                                                              // teardown
+                                                              // function
+                                                              // pointer
+       CU_add_test(test_timers_event_loop_suite,
+                   "test_walk_and_process_timers_no_timers",
+                   test_walk_and_process_timers_no_timers);
+       CU_add_test(test_timers_event_loop_suite,
+                   "test_walk_and_process_timers_timer_not_expired",
+                   test_walk_and_process_timers_timer_not_expired);
+       CU_add_test(test_timers_event_loop_suite,
+                   "test_walk_and_process_timers_timer_expired",
+                   test_walk_and_process_timers_timer_expired);
+       CU_add_test(test_timers_event_loop_suite, "test_event_loop_null_handle",
+                   test_event_loop_null_handle);
+       CU_add_test(test_timers_event_loop_suite, "test_event_loop_not_active",
+                   test_event_loop_not_active);
+
+       /*
+        * Run the tests and cleanup.
+        */
+       CU_basic_set_mode(CU_BRM_VERBOSE);
+       CU_basic_run_tests();
+       CU_FailureRecord *failure_record = CU_get_failure_list();
+       if (failure_record != NULL) {
+               printf("\nFailed tests:\n\t [Suite] [Test] [File:line-number]\n");
+               do {
+                       printf("\t [%s] [%s] [%s:%d]\n",
+                              failure_record->pSuite->pName,
+                              failure_record->pTest->pName,
+                              failure_record->strFileName,
+                              failure_record->uiLineNumber);
+                       failure_record = failure_record->pNext;
+
+               } while (failure_record != NULL);
+       }
+
+       CU_pRunSummary run_summary = CU_get_run_summary();
+       int result = run_summary->nTestsFailed;
+       CU_cleanup_registry();
+
+       return result;
+}
diff --git a/pceplib/test/pcep_timers_tests_valgrind.sh b/pceplib/test/pcep_timers_tests_valgrind.sh
new file mode 100755 (executable)
index 0000000..f9bff3b
--- /dev/null
@@ -0,0 +1,2 @@
+source pceplib/test/pcep_tests_valgrind.sh
+valgrind_test pceplib/test/pcep_timers_tests
diff --git a/pceplib/test/pcep_utils_counters_test.c b/pceplib/test/pcep_utils_counters_test.c
new file mode 100644 (file)
index 0000000..6f53e4d
--- /dev/null
@@ -0,0 +1,254 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <stdlib.h>
+
+#include <CUnit/CUnit.h>
+
+#include "pcep_utils_counters.h"
+#include "pcep_utils_counters_test.h"
+
+
+void test_create_counters_group()
+{
+       const char group_name[] = "group";
+       uint16_t num_subgroups = 10;
+
+       struct counters_group *group =
+               create_counters_group(NULL, num_subgroups);
+       CU_ASSERT_PTR_NULL(group);
+
+       group = create_counters_group(group_name, MAX_COUNTER_GROUPS + 1);
+       CU_ASSERT_PTR_NULL(group);
+
+       group = create_counters_group(group_name, num_subgroups);
+       CU_ASSERT_PTR_NOT_NULL(group);
+
+       CU_ASSERT_EQUAL(group->num_subgroups, 0);
+       CU_ASSERT_EQUAL(group->max_subgroups, num_subgroups);
+       CU_ASSERT_EQUAL(strcmp(group->counters_group_name, group_name), 0);
+
+       delete_counters_group(group);
+}
+
+void test_create_counters_subgroup()
+{
+       const char subgroup_name[] = "subgroup";
+       uint16_t subgroup_id = 10;
+       uint16_t num_counters = 20;
+
+       struct counters_subgroup *subgroup =
+               create_counters_subgroup(NULL, subgroup_id, num_counters);
+       CU_ASSERT_PTR_NULL(subgroup);
+
+       subgroup = create_counters_subgroup(
+               subgroup_name, MAX_COUNTER_GROUPS + 1, num_counters);
+       CU_ASSERT_PTR_NULL(subgroup);
+
+       subgroup = create_counters_subgroup(subgroup_name, subgroup_id,
+                                           MAX_COUNTERS + 1);
+       CU_ASSERT_PTR_NULL(subgroup);
+
+       subgroup = create_counters_subgroup(subgroup_name, subgroup_id,
+                                           num_counters);
+       CU_ASSERT_PTR_NOT_NULL(subgroup);
+
+       CU_ASSERT_EQUAL(subgroup->subgroup_id, subgroup_id);
+       CU_ASSERT_EQUAL(subgroup->num_counters, 0);
+       CU_ASSERT_EQUAL(subgroup->max_counters, num_counters);
+       CU_ASSERT_EQUAL(strcmp(subgroup->counters_subgroup_name, subgroup_name),
+                       0);
+
+       delete_counters_subgroup(subgroup);
+}
+
+void test_add_counters_subgroup()
+{
+       struct counters_group *group = create_counters_group("group", 1);
+       struct counters_subgroup *subgroup1 =
+               create_counters_subgroup("subgroup", 0, 5);
+       struct counters_subgroup *subgroup2 =
+               create_counters_subgroup("subgroup", 1, 5);
+
+       CU_ASSERT_FALSE(add_counters_subgroup(NULL, NULL));
+       CU_ASSERT_FALSE(add_counters_subgroup(NULL, subgroup1));
+       CU_ASSERT_FALSE(add_counters_subgroup(group, NULL));
+
+       CU_ASSERT_EQUAL(group->num_subgroups, 0);
+       CU_ASSERT_TRUE(add_counters_subgroup(group, subgroup1));
+       CU_ASSERT_EQUAL(group->num_subgroups, 1);
+       /* Cant add more than num_subgroups to the group */
+       CU_ASSERT_FALSE(add_counters_subgroup(group, subgroup2));
+
+       CU_ASSERT_PTR_NOT_NULL(find_subgroup(group, 0));
+       CU_ASSERT_PTR_NULL(find_subgroup(group, 1));
+
+       delete_counters_group(group);
+       delete_counters_subgroup(subgroup2);
+}
+
+void test_create_subgroup_counter()
+{
+       uint16_t counter_id = 1;
+       char counter_name[] = "my counter";
+       struct counters_subgroup *subgroup =
+               create_counters_subgroup("subgroup", 1, 2);
+
+       CU_ASSERT_FALSE(
+               create_subgroup_counter(NULL, counter_id, counter_name));
+       CU_ASSERT_FALSE(create_subgroup_counter(subgroup, counter_id + 1,
+                                               counter_name));
+       CU_ASSERT_FALSE(create_subgroup_counter(subgroup, counter_id, NULL));
+       CU_ASSERT_EQUAL(subgroup->num_counters, 0);
+       CU_ASSERT_TRUE(
+               create_subgroup_counter(subgroup, counter_id, counter_name));
+       CU_ASSERT_EQUAL(subgroup->num_counters, 1);
+
+       delete_counters_subgroup(subgroup);
+}
+
+void test_delete_counters_group()
+{
+       struct counters_group *group = create_counters_group("group", 1);
+
+       CU_ASSERT_FALSE(delete_counters_group(NULL));
+       CU_ASSERT_TRUE(delete_counters_group(group));
+}
+
+void test_delete_counters_subgroup()
+{
+       struct counters_subgroup *subgroup =
+               create_counters_subgroup("subgroup", 1, 1);
+
+       CU_ASSERT_FALSE(delete_counters_subgroup(NULL));
+       CU_ASSERT_TRUE(delete_counters_subgroup(subgroup));
+}
+
+void test_reset_group_counters()
+{
+       uint16_t subgroup_id = 1;
+       uint16_t counter_id = 1;
+       struct counters_group *group = create_counters_group("group", 10);
+       struct counters_subgroup *subgroup =
+               create_counters_subgroup("subgroup", subgroup_id, 10);
+       create_subgroup_counter(subgroup, counter_id, "counter");
+       add_counters_subgroup(group, subgroup);
+
+       struct counter *counter = subgroup->counters[counter_id];
+       counter->counter_value = 100;
+
+       CU_ASSERT_FALSE(reset_group_counters(NULL));
+       CU_ASSERT_TRUE(reset_group_counters(group));
+       CU_ASSERT_EQUAL(counter->counter_value, 0);
+
+       delete_counters_group(group);
+}
+
+void test_reset_subgroup_counters()
+{
+       uint16_t counter_id = 1;
+       struct counters_subgroup *subgroup =
+               create_counters_subgroup("subgroup", 1, 10);
+       create_subgroup_counter(subgroup, counter_id, "counter");
+
+       struct counter *counter = subgroup->counters[counter_id];
+       counter->counter_value = 100;
+
+       CU_ASSERT_FALSE(reset_subgroup_counters(NULL));
+       CU_ASSERT_TRUE(reset_subgroup_counters(subgroup));
+       CU_ASSERT_EQUAL(counter->counter_value, 0);
+
+       delete_counters_subgroup(subgroup);
+}
+
+void test_increment_counter()
+{
+       uint16_t subgroup_id = 1;
+       uint16_t counter_id = 1;
+       struct counters_group *group = create_counters_group("group", 10);
+       struct counters_subgroup *subgroup =
+               create_counters_subgroup("subgroup", subgroup_id, 10);
+       create_subgroup_counter(subgroup, counter_id, "counter");
+       add_counters_subgroup(group, subgroup);
+
+       struct counter *counter = subgroup->counters[counter_id];
+       counter->counter_value = 100;
+
+       CU_ASSERT_FALSE(increment_counter(NULL, subgroup_id, counter_id));
+       CU_ASSERT_FALSE(increment_counter(group, 100, counter_id));
+       CU_ASSERT_FALSE(increment_counter(group, subgroup_id, 123));
+       CU_ASSERT_TRUE(increment_counter(group, subgroup_id, counter_id));
+       CU_ASSERT_EQUAL(counter->counter_value, 101);
+       CU_ASSERT_EQUAL(subgroup_counters_total(subgroup), 101);
+
+       delete_counters_group(group);
+}
+
+void test_increment_subgroup_counter()
+{
+       int counter_id = 1;
+       uint32_t counter_value = 100;
+       struct counters_subgroup *subgroup =
+               create_counters_subgroup("subgroup", 1, 10);
+       create_subgroup_counter(subgroup, counter_id, "counter");
+
+       struct counter *counter = subgroup->counters[counter_id];
+       counter->counter_value = counter_value;
+
+       CU_ASSERT_FALSE(increment_subgroup_counter(NULL, counter_id));
+       CU_ASSERT_FALSE(increment_subgroup_counter(subgroup, counter_id + 1));
+       CU_ASSERT_TRUE(increment_subgroup_counter(subgroup, counter_id));
+       CU_ASSERT_EQUAL(counter->counter_value, counter_value + 1);
+
+       delete_counters_subgroup(subgroup);
+}
+
+void test_dump_counters_group_to_log()
+{
+       uint16_t subgroup_id = 1;
+       uint16_t counter_id = 1;
+       struct counters_group *group = create_counters_group("group", 10);
+       struct counters_subgroup *subgroup =
+               create_counters_subgroup("subgroup", subgroup_id, 10);
+       create_subgroup_counter(subgroup, counter_id, "counter");
+       add_counters_subgroup(group, subgroup);
+
+       CU_ASSERT_FALSE(dump_counters_group_to_log(NULL));
+       CU_ASSERT_TRUE(dump_counters_group_to_log(group));
+
+       delete_counters_group(group);
+}
+
+void test_dump_counters_subgroup_to_log()
+{
+       uint16_t subgroup_id = 1;
+       uint16_t counter_id = 1;
+       struct counters_subgroup *subgroup =
+               create_counters_subgroup("subgroup", subgroup_id, 10);
+       create_subgroup_counter(subgroup, counter_id, "counter");
+
+       CU_ASSERT_FALSE(dump_counters_subgroup_to_log(NULL));
+       CU_ASSERT_TRUE(dump_counters_subgroup_to_log(subgroup));
+
+       delete_counters_subgroup(subgroup);
+}
diff --git a/pceplib/test/pcep_utils_counters_test.h b/pceplib/test/pcep_utils_counters_test.h
new file mode 100644 (file)
index 0000000..07236dc
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Javier Garcia <javier.garcia@voltanet.io>
+ *
+ */
+
+/*
+ *  Timer definitions to be used internally by the pcep_timers library.
+ */
+
+#ifndef PCEP_UTILS_COUNTERS_TEST_H_
+#define PCEP_UTILS_COUNTERS_TEST_H_
+
+void test_create_counters_group(void);
+void test_create_counters_subgroup(void);
+void test_add_counters_subgroup(void);
+void test_create_subgroup_counter(void);
+void test_delete_counters_group(void);
+void test_delete_counters_subgroup(void);
+void test_reset_group_counters(void);
+void test_reset_subgroup_counters(void);
+void test_increment_counter(void);
+void test_increment_subgroup_counter(void);
+void test_dump_counters_group_to_log(void);
+void test_dump_counters_subgroup_to_log(void);
+
+#endif
diff --git a/pceplib/test/pcep_utils_double_linked_list_test.c b/pceplib/test/pcep_utils_double_linked_list_test.c
new file mode 100644 (file)
index 0000000..d2600e6
--- /dev/null
@@ -0,0 +1,297 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <CUnit/CUnit.h>
+
+#include "pcep_utils_double_linked_list.h"
+#include "pcep_utils_double_linked_list_test.h"
+
+typedef struct dll_node_data_ {
+       int int_data;
+
+} dll_node_data;
+
+void test_empty_dl_list()
+{
+       double_linked_list *handle = dll_initialize();
+
+       CU_ASSERT_PTR_NULL(dll_delete_first_node(handle));
+       CU_ASSERT_PTR_NULL(dll_delete_last_node(handle));
+       CU_ASSERT_PTR_NULL(dll_delete_node(handle, NULL));
+
+       dll_destroy(handle);
+}
+
+void test_null_dl_list_handle()
+{
+       dll_destroy(NULL);
+       CU_ASSERT_PTR_NULL(dll_prepend(NULL, NULL));
+       CU_ASSERT_PTR_NULL(dll_append(NULL, NULL));
+       CU_ASSERT_PTR_NULL(dll_delete_first_node(NULL));
+       CU_ASSERT_PTR_NULL(dll_delete_last_node(NULL));
+       CU_ASSERT_PTR_NULL(dll_delete_node(NULL, NULL));
+}
+
+void test_dll_prepend_data()
+{
+       dll_node_data data1, data2, data3;
+       data1.int_data = 1;
+       data2.int_data = 2;
+       data3.int_data = 3;
+
+       double_linked_list *handle = dll_initialize();
+
+       CU_ASSERT_PTR_NOT_NULL(dll_prepend(handle, &data3));
+       CU_ASSERT_PTR_NOT_NULL(dll_prepend(handle, &data2));
+       CU_ASSERT_PTR_NOT_NULL(dll_prepend(handle, &data1));
+
+       CU_ASSERT_EQUAL(handle->num_entries, 3);
+
+       double_linked_list_node *node = handle->head;
+       CU_ASSERT_PTR_EQUAL(node->data, &data1);
+       CU_ASSERT_PTR_NULL(node->prev_node);
+       CU_ASSERT_PTR_NOT_NULL(node->next_node);
+
+       node = node->next_node;
+       CU_ASSERT_PTR_EQUAL(node->data, &data2);
+       CU_ASSERT_PTR_NOT_NULL(node->prev_node);
+       CU_ASSERT_PTR_NOT_NULL(node->next_node);
+
+       node = node->next_node;
+       CU_ASSERT_PTR_EQUAL(node->data, &data3);
+       CU_ASSERT_PTR_NOT_NULL(node->prev_node);
+       CU_ASSERT_PTR_NULL(node->next_node);
+       CU_ASSERT_PTR_EQUAL(handle->tail, node);
+
+       dll_destroy(handle);
+}
+
+
+void test_dll_append_data()
+{
+       dll_node_data data1, data2, data3;
+       data1.int_data = 1;
+       data2.int_data = 2;
+       data3.int_data = 3;
+
+       double_linked_list *handle = dll_initialize();
+
+       CU_ASSERT_PTR_NOT_NULL(dll_append(handle, &data1));
+       CU_ASSERT_PTR_NOT_NULL(dll_append(handle, &data2));
+       CU_ASSERT_PTR_NOT_NULL(dll_append(handle, &data3));
+
+       CU_ASSERT_EQUAL(handle->num_entries, 3);
+
+       double_linked_list_node *node = handle->head;
+       CU_ASSERT_PTR_EQUAL(node->data, &data1);
+       CU_ASSERT_PTR_NULL(node->prev_node);
+       CU_ASSERT_PTR_NOT_NULL(node->next_node);
+
+       node = node->next_node;
+       CU_ASSERT_PTR_EQUAL(node->data, &data2);
+       CU_ASSERT_PTR_NOT_NULL(node->prev_node);
+       CU_ASSERT_PTR_NOT_NULL(node->next_node);
+
+       node = node->next_node;
+       CU_ASSERT_PTR_EQUAL(node->data, &data3);
+       CU_ASSERT_PTR_NOT_NULL(node->prev_node);
+       CU_ASSERT_PTR_NULL(node->next_node);
+       CU_ASSERT_PTR_EQUAL(handle->tail, node);
+
+       dll_destroy(handle);
+}
+
+
+void test_dll_delete_first_node()
+{
+       dll_node_data data1, data2;
+       data1.int_data = 1;
+       data2.int_data = 2;
+
+       double_linked_list *handle = dll_initialize();
+
+       /* Test deleting with just 1 node in the list */
+       CU_ASSERT_PTR_NOT_NULL(dll_append(handle, &data1));
+       CU_ASSERT_EQUAL(handle->num_entries, 1);
+
+       void *deleted_data = dll_delete_first_node(handle);
+       CU_ASSERT_PTR_NOT_NULL(deleted_data);
+       CU_ASSERT_PTR_EQUAL(&data1, deleted_data);
+
+       CU_ASSERT_EQUAL(handle->num_entries, 0);
+       CU_ASSERT_PTR_NULL(handle->head);
+       CU_ASSERT_PTR_NULL(handle->tail);
+
+       /* Test deleting with 2 nodes in the list */
+       CU_ASSERT_PTR_NOT_NULL(dll_append(handle, &data1));
+       CU_ASSERT_PTR_NOT_NULL(dll_append(handle, &data2));
+       CU_ASSERT_EQUAL(handle->num_entries, 2);
+
+       deleted_data = dll_delete_first_node(handle);
+       CU_ASSERT_PTR_NOT_NULL(deleted_data);
+       CU_ASSERT_PTR_EQUAL(&data1, deleted_data);
+
+       CU_ASSERT_EQUAL(handle->num_entries, 1);
+       CU_ASSERT_PTR_EQUAL(handle->head->data, &data2);
+       CU_ASSERT_PTR_EQUAL(handle->head, handle->tail);
+       CU_ASSERT_PTR_NULL(handle->head->prev_node);
+       CU_ASSERT_PTR_NULL(handle->head->next_node);
+
+       dll_destroy(handle);
+}
+
+
+void test_dll_delete_last_node()
+{
+       dll_node_data data1, data2;
+       data1.int_data = 1;
+       data2.int_data = 2;
+
+       double_linked_list *handle = dll_initialize();
+
+       /* Test deleting with just 1 node in the list */
+       CU_ASSERT_PTR_NOT_NULL(dll_append(handle, &data1));
+       CU_ASSERT_EQUAL(handle->num_entries, 1);
+
+       void *deleted_data = dll_delete_last_node(handle);
+       CU_ASSERT_PTR_NOT_NULL(deleted_data);
+       CU_ASSERT_PTR_EQUAL(&data1, deleted_data);
+
+       CU_ASSERT_EQUAL(handle->num_entries, 0);
+       CU_ASSERT_PTR_NULL(handle->head);
+       CU_ASSERT_PTR_NULL(handle->tail);
+
+       /* Test deleting with 2 nodes in the list */
+       CU_ASSERT_PTR_NOT_NULL(dll_append(handle, &data1));
+       CU_ASSERT_PTR_NOT_NULL(dll_append(handle, &data2));
+       CU_ASSERT_EQUAL(handle->num_entries, 2);
+
+       deleted_data = dll_delete_last_node(handle);
+       CU_ASSERT_PTR_NOT_NULL(deleted_data);
+       CU_ASSERT_PTR_EQUAL(&data2, deleted_data);
+
+       CU_ASSERT_EQUAL(handle->num_entries, 1);
+       CU_ASSERT_PTR_EQUAL(handle->head->data, &data1);
+       CU_ASSERT_PTR_EQUAL(handle->head, handle->tail);
+       CU_ASSERT_PTR_NULL(handle->head->prev_node);
+       CU_ASSERT_PTR_NULL(handle->head->next_node);
+
+       dll_destroy(handle);
+}
+
+
+void test_dll_delete_node()
+{
+       dll_node_data data1, data2, data3;
+       data1.int_data = 1;
+       data2.int_data = 2;
+       data3.int_data = 3;
+       double_linked_list_node *node1, *node2, *node3;
+       double_linked_list *handle;
+
+       /* Test deleting with just 1 node in the list */
+       handle = dll_initialize();
+       node1 = dll_append(handle, &data1);
+       CU_ASSERT_PTR_NOT_NULL(node1);
+       CU_ASSERT_EQUAL(handle->num_entries, 1);
+
+       void *deleted_data = dll_delete_node(handle, node1);
+       CU_ASSERT_PTR_NOT_NULL(deleted_data);
+       CU_ASSERT_PTR_EQUAL(&data1, deleted_data);
+
+       CU_ASSERT_EQUAL(handle->num_entries, 0);
+       CU_ASSERT_PTR_NULL(handle->head);
+       CU_ASSERT_PTR_NULL(handle->tail);
+
+       /*
+        * Test deleting the head with 2 nodes in the list
+        */
+       node1 = dll_append(handle, &data1);
+       node2 = dll_append(handle, &data2);
+       CU_ASSERT_PTR_NOT_NULL(node1);
+       CU_ASSERT_PTR_NOT_NULL(node2);
+       CU_ASSERT_EQUAL(handle->num_entries, 2);
+
+       /* Delete the head entry */
+       deleted_data = dll_delete_node(handle, node1);
+       CU_ASSERT_PTR_NOT_NULL(deleted_data);
+       CU_ASSERT_PTR_EQUAL(&data1, deleted_data);
+
+       CU_ASSERT_EQUAL(handle->num_entries, 1);
+       CU_ASSERT_PTR_EQUAL(handle->head->data, &data2);
+       CU_ASSERT_PTR_EQUAL(handle->head, handle->tail);
+       CU_ASSERT_PTR_NULL(handle->head->prev_node);
+       CU_ASSERT_PTR_NULL(handle->head->next_node);
+       dll_destroy(handle);
+
+       /*
+        * Test deleting the tail with 2 nodes in the list
+        */
+       handle = dll_initialize();
+       node1 = dll_append(handle, &data1);
+       node2 = dll_append(handle, &data2);
+       CU_ASSERT_PTR_NOT_NULL(node1);
+       CU_ASSERT_PTR_NOT_NULL(node2);
+       CU_ASSERT_EQUAL(handle->num_entries, 2);
+
+       /* Delete the tail entry */
+       deleted_data = dll_delete_node(handle, node2);
+       CU_ASSERT_PTR_NOT_NULL(deleted_data);
+       CU_ASSERT_PTR_EQUAL(&data2, deleted_data);
+
+       CU_ASSERT_EQUAL(handle->num_entries, 1);
+       CU_ASSERT_PTR_EQUAL(handle->head->data, &data1);
+       CU_ASSERT_PTR_EQUAL(handle->head, handle->tail);
+       CU_ASSERT_PTR_NULL(handle->head->prev_node);
+       CU_ASSERT_PTR_NULL(handle->head->next_node);
+       dll_destroy(handle);
+
+       /*
+        * Test deleting in the middle with 3 nodes in the list
+        */
+       handle = dll_initialize();
+       node1 = dll_append(handle, &data1);
+       node2 = dll_append(handle, &data2);
+       node3 = dll_append(handle, &data3);
+       CU_ASSERT_PTR_NOT_NULL(node1);
+       CU_ASSERT_PTR_NOT_NULL(node2);
+       CU_ASSERT_PTR_NOT_NULL(node3);
+       CU_ASSERT_EQUAL(handle->num_entries, 3);
+
+       /* Delete the middle entry */
+       deleted_data = dll_delete_node(handle, node2);
+       CU_ASSERT_PTR_NOT_NULL(deleted_data);
+       CU_ASSERT_PTR_EQUAL(&data2, deleted_data);
+
+       CU_ASSERT_EQUAL(handle->num_entries, 2);
+       CU_ASSERT_PTR_EQUAL(handle->head, node1);
+       CU_ASSERT_PTR_EQUAL(handle->tail, node3);
+       CU_ASSERT_PTR_EQUAL(node1->data, &data1);
+       CU_ASSERT_PTR_EQUAL(node3->data, &data3);
+       CU_ASSERT_PTR_EQUAL(node1->next_node, node3);
+       CU_ASSERT_PTR_EQUAL(node3->prev_node, node1);
+       CU_ASSERT_PTR_NULL(node1->prev_node);
+       CU_ASSERT_PTR_NULL(node3->next_node);
+
+       dll_destroy(handle);
+}
diff --git a/pceplib/test/pcep_utils_double_linked_list_test.h b/pceplib/test/pcep_utils_double_linked_list_test.h
new file mode 100644 (file)
index 0000000..ddb6467
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Javier Garcia <javier.garcia@voltanet.io>
+ *
+ */
+
+/*
+ *  Timer definitions to be used internally by the pcep_timers library.
+ */
+
+#ifndef PCEP_UTILS_DOUBLE_LINKED_LIST_TEST_H_
+#define PCEP_UTILS_DOUBLE_LINKED_LIST_TEST_H_
+
+void test_empty_dl_list(void);
+void test_null_dl_list_handle(void);
+void test_dll_prepend_data(void);
+void test_dll_append_data(void);
+void test_dll_delete_first_node(void);
+void test_dll_delete_last_node(void);
+void test_dll_delete_node(void);
+
+#endif /* PCEPTIMERINTERNALS_H_ */
diff --git a/pceplib/test/pcep_utils_memory_test.c b/pceplib/test/pcep_utils_memory_test.c
new file mode 100644 (file)
index 0000000..b0b528f
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <stdlib.h>
+#include <stdint.h>
+
+#include <CUnit/CUnit.h>
+
+#include "pcep_utils_memory.h"
+#include "pcep_utils_memory_test.h"
+
+void *test_pceplib_malloc(void *mem_type, size_t size);
+void *test_pceplib_calloc(void *mem_type, size_t size);
+void *test_pceplib_realloc(void *mem_type, void *ptr, size_t size);
+void *test_pceplib_strdup(void *mem_type, const char *str);
+void test_pceplib_free(void *mem_type, void *ptr);
+void verify_memory_type(struct pceplib_memory_type *mt, uint32_t num_alloc,
+                       uint32_t alloc_bytes, uint32_t num_free,
+                       uint32_t free_bytes);
+void verify_ext_memory_type(void *mt, int num_malloc_calls,
+                           int num_calloc_calls, int num_realloc_calls,
+                           int num_strdup_calls, int num_free_calls);
+
+struct test_memory_type {
+       int num_malloc_calls;
+       int num_calloc_calls;
+       int num_realloc_calls;
+       int num_strdup_calls;
+       int num_free_calls;
+};
+
+void *test_pceplib_malloc(void *mem_type, size_t size)
+{
+       ((struct test_memory_type *)mem_type)->num_malloc_calls++;
+       return malloc(size);
+}
+
+void *test_pceplib_calloc(void *mem_type, size_t size)
+{
+       ((struct test_memory_type *)mem_type)->num_calloc_calls++;
+       return calloc(1, size);
+}
+
+void *test_pceplib_realloc(void *mem_type, void *ptr, size_t size)
+{
+       ((struct test_memory_type *)mem_type)->num_realloc_calls++;
+       return realloc(ptr, size);
+}
+
+void *test_pceplib_strdup(void *mem_type, const char *str)
+{
+       ((struct test_memory_type *)mem_type)->num_strdup_calls++;
+       return strdup(str);
+}
+
+void test_pceplib_free(void *mem_type, void *ptr)
+{
+       ((struct test_memory_type *)mem_type)->num_free_calls++;
+       free(ptr);
+}
+
+void verify_memory_type(struct pceplib_memory_type *mt, uint32_t num_alloc,
+                       uint32_t alloc_bytes, uint32_t num_free,
+                       uint32_t free_bytes)
+{
+       CU_ASSERT_EQUAL(num_alloc, mt->num_allocates);
+       CU_ASSERT_EQUAL(alloc_bytes, mt->total_bytes_allocated);
+       CU_ASSERT_EQUAL(num_free, mt->num_frees);
+       CU_ASSERT_EQUAL(free_bytes, mt->total_bytes_freed);
+}
+
+void verify_ext_memory_type(void *mt, int num_malloc_calls,
+                           int num_calloc_calls, int num_realloc_calls,
+                           int num_strdup_calls, int num_free_calls)
+{
+       struct test_memory_type *mt_ptr = (struct test_memory_type *)mt;
+       CU_ASSERT_EQUAL(num_malloc_calls, mt_ptr->num_malloc_calls);
+       CU_ASSERT_EQUAL(num_calloc_calls, mt_ptr->num_calloc_calls);
+       CU_ASSERT_EQUAL(num_realloc_calls, mt_ptr->num_realloc_calls);
+       CU_ASSERT_EQUAL(num_strdup_calls, mt_ptr->num_strdup_calls);
+       CU_ASSERT_EQUAL(num_free_calls, mt_ptr->num_free_calls);
+}
+
+void test_memory_internal_impl()
+{
+       int alloc_size = 100;
+       struct pceplib_memory_type *pceplib_infra_ptr =
+               (struct pceplib_memory_type *)PCEPLIB_INFRA;
+       struct pceplib_memory_type *pceplib_messages_ptr =
+               (struct pceplib_memory_type *)PCEPLIB_MESSAGES;
+       int alloc_counter = 1;
+       int free_counter = 1;
+
+       /* reset the memory type counters for easier testing */
+       pceplib_infra_ptr->num_allocates =
+               pceplib_infra_ptr->total_bytes_allocated =
+                       pceplib_infra_ptr->num_frees =
+                               pceplib_infra_ptr->total_bytes_freed = 0;
+       pceplib_messages_ptr->num_allocates =
+               pceplib_messages_ptr->total_bytes_allocated =
+                       pceplib_messages_ptr->num_frees =
+                               pceplib_messages_ptr->total_bytes_freed = 0;
+
+       /* Make sure nothing crashes when all these are set NULL, since the
+        * internal default values should still be used. */
+       pceplib_memory_initialize(NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+
+       /* Test malloc() */
+       void *ptr = pceplib_malloc(PCEPLIB_INFRA, alloc_size);
+       CU_ASSERT_PTR_NOT_NULL(ptr);
+       pceplib_free(PCEPLIB_INFRA, ptr);
+       verify_memory_type(pceplib_infra_ptr, alloc_counter, alloc_size,
+                          free_counter++, 0);
+
+       /* Test calloc() */
+       ptr = pceplib_calloc(PCEPLIB_INFRA, alloc_size);
+       CU_ASSERT_PTR_NOT_NULL(ptr);
+       pceplib_free(PCEPLIB_INFRA, ptr);
+       alloc_counter++;
+       verify_memory_type(pceplib_infra_ptr, alloc_counter,
+                          alloc_size * alloc_counter, free_counter++, 0);
+
+       /* Test realloc() */
+       ptr = pceplib_malloc(PCEPLIB_INFRA, alloc_size);
+       CU_ASSERT_PTR_NOT_NULL(ptr);
+       ptr = pceplib_realloc(PCEPLIB_INFRA, ptr, alloc_size);
+       CU_ASSERT_PTR_NOT_NULL(ptr);
+       pceplib_free(PCEPLIB_INFRA, ptr);
+       alloc_counter += 2;
+       verify_memory_type(pceplib_infra_ptr, alloc_counter,
+                          alloc_size * alloc_counter, free_counter++, 0);
+
+       /* Test strdup() */
+       ptr = pceplib_malloc(PCEPLIB_INFRA, alloc_size);
+       /* Make strdup duplicate (alloc_size - 1) bytes */
+       memset(ptr, 'a', alloc_size);
+       ((char *)ptr)[alloc_size - 1] = '\0';
+       char *str = pceplib_strdup(PCEPLIB_INFRA, (char *)ptr);
+       CU_ASSERT_PTR_NOT_NULL(ptr);
+       pceplib_free(PCEPLIB_INFRA, ptr);
+       pceplib_free(PCEPLIB_INFRA, str);
+       alloc_counter += 2;
+       free_counter++;
+       verify_memory_type(pceplib_infra_ptr, alloc_counter,
+                          (alloc_size * alloc_counter) - 1, free_counter, 0);
+
+       /* Make sure only the pceplib_infra_ptr memory counters are incremented
+        */
+       verify_memory_type(pceplib_messages_ptr, 0, 0, 0, 0);
+}
+
+void test_memory_external_impl()
+{
+       int alloc_size = 100;
+       struct pceplib_memory_type *pceplib_infra_ptr =
+               (struct pceplib_memory_type *)PCEPLIB_INFRA;
+       struct pceplib_memory_type *pceplib_messages_ptr =
+               (struct pceplib_memory_type *)PCEPLIB_MESSAGES;
+
+       /* reset the internal memory type counters to later verify they are NOT
+        * incremented since an external impl was provided */
+       pceplib_infra_ptr->num_allocates =
+               pceplib_infra_ptr->total_bytes_allocated =
+                       pceplib_infra_ptr->num_frees =
+                               pceplib_infra_ptr->total_bytes_freed = 0;
+       pceplib_messages_ptr->num_allocates =
+               pceplib_messages_ptr->total_bytes_allocated =
+                       pceplib_messages_ptr->num_frees =
+                               pceplib_messages_ptr->total_bytes_freed = 0;
+
+       /* Setup the external memory type */
+       struct test_memory_type infra_mt, messages_mt;
+       void *infra_ptr = &infra_mt;
+       void *messages_ptr = &messages_mt;
+       memset(infra_ptr, 0, sizeof(struct test_memory_type));
+       memset(messages_ptr, 0, sizeof(struct test_memory_type));
+       int free_counter = 1;
+
+       /* Initialize the PCEPlib memory system with an external implementation
+        */
+       pceplib_memory_initialize(infra_ptr, messages_ptr, test_pceplib_malloc,
+                                 test_pceplib_calloc, test_pceplib_realloc,
+                                 test_pceplib_strdup, test_pceplib_free);
+
+       /* Test malloc() */
+       void *ptr = pceplib_malloc(PCEPLIB_MESSAGES, alloc_size);
+       CU_ASSERT_PTR_NOT_NULL(ptr);
+       pceplib_free(PCEPLIB_MESSAGES, ptr);
+       verify_ext_memory_type(messages_ptr, 1, 0, 0, 0, free_counter++);
+
+       /* Test calloc() */
+       ptr = pceplib_calloc(PCEPLIB_MESSAGES, alloc_size);
+       CU_ASSERT_PTR_NOT_NULL(ptr);
+       pceplib_free(PCEPLIB_MESSAGES, ptr);
+       verify_ext_memory_type(messages_ptr, 1, 1, 0, 0, free_counter++);
+
+       /* Test realloc() */
+       ptr = pceplib_malloc(PCEPLIB_MESSAGES, alloc_size);
+       CU_ASSERT_PTR_NOT_NULL(ptr);
+       ptr = pceplib_realloc(PCEPLIB_MESSAGES, ptr, alloc_size);
+       CU_ASSERT_PTR_NOT_NULL(ptr);
+       pceplib_free(PCEPLIB_MESSAGES, ptr);
+       verify_ext_memory_type(messages_ptr, 2, 1, 1, 0, free_counter++);
+
+       /* Test strdup() */
+       ptr = pceplib_malloc(PCEPLIB_MESSAGES, alloc_size);
+       /* Make strdup duplicate (alloc_size - 1) bytes */
+       memset(ptr, 'a', alloc_size);
+       ((char *)ptr)[alloc_size - 1] = '\0';
+       char *str = pceplib_strdup(PCEPLIB_MESSAGES, (char *)ptr);
+       CU_ASSERT_PTR_NOT_NULL(ptr);
+       pceplib_free(PCEPLIB_MESSAGES, ptr);
+       pceplib_free(PCEPLIB_MESSAGES, str);
+       verify_ext_memory_type(messages_ptr, 3, 1, 1, 1, free_counter + 1);
+
+       /* Make sure the internal memory counters are NOT incremented */
+       verify_memory_type(pceplib_infra_ptr, 0, 0, 0, 0);
+       verify_memory_type(pceplib_messages_ptr, 0, 0, 0, 0);
+
+       verify_ext_memory_type(infra_ptr, 0, 0, 0, 0, 0);
+}
diff --git a/pceplib/test/pcep_utils_memory_test.h b/pceplib/test/pcep_utils_memory_test.h
new file mode 100644 (file)
index 0000000..4e0c3fa
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Javier Garcia <javier.garcia@voltanet.io>
+ *
+ */
+
+/*
+ *  Timer definitions to be used internally by the pcep_timers library.
+ */
+
+#ifndef PCEP_MEMORY_TEST_H_
+#define PCEP_MEMORY_TEST_H_
+
+void test_memory_internal_impl(void);
+void test_memory_external_impl(void);
+
+#endif /* PCEPTIMERINTERNALS_H_ */
diff --git a/pceplib/test/pcep_utils_ordered_list_test.c b/pceplib/test/pcep_utils_ordered_list_test.c
new file mode 100644 (file)
index 0000000..fe9ee58
--- /dev/null
@@ -0,0 +1,248 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <CUnit/CUnit.h>
+
+#include "pcep_utils_ordered_list.h"
+#include "pcep_utils_ordered_list_test.h"
+
+typedef struct node_data_ {
+       int int_data;
+
+} node_data;
+
+
+int node_data_compare(void *list_entry, void *new_entry)
+{
+       /*
+        *   < 0  if new_entry  < list_entry
+        *   == 0 if new_entry == list_entry (new_entry will be inserted after
+        * list_entry) > 0  if new_entry  > list_entry
+        */
+
+       return ((node_data *)new_entry)->int_data
+              - ((node_data *)list_entry)->int_data;
+}
+
+
+void test_empty_list()
+{
+       ordered_list_handle *handle =
+               ordered_list_initialize(node_data_compare);
+
+       CU_ASSERT_PTR_NOT_NULL(handle);
+       CU_ASSERT_PTR_NULL(handle->head);
+       CU_ASSERT_PTR_NOT_NULL(handle->compare_function);
+       CU_ASSERT_EQUAL(handle->num_entries, 0);
+
+       ordered_list_destroy(handle);
+}
+
+
+void test_null_list_handle()
+{
+       node_data data;
+       ordered_list_node node_data;
+
+       void *ptr = ordered_list_add_node(NULL, &data);
+       CU_ASSERT_PTR_NULL(ptr);
+
+       ptr = ordered_list_find(NULL, &data);
+       CU_ASSERT_PTR_NULL(ptr);
+
+       ptr = ordered_list_remove_first_node(NULL);
+       CU_ASSERT_PTR_NULL(ptr);
+
+       ptr = ordered_list_remove_first_node_equals(NULL, &data);
+       CU_ASSERT_PTR_NULL(ptr);
+
+       ptr = ordered_list_remove_node(NULL, &node_data, &node_data);
+       CU_ASSERT_PTR_NULL(ptr);
+}
+
+
+void test_add_to_list()
+{
+       node_data data1, data2, data3;
+       data1.int_data = 1;
+       data2.int_data = 2;
+       data3.int_data = 3;
+
+       ordered_list_handle *handle =
+               ordered_list_initialize(node_data_compare);
+
+       ordered_list_add_node(handle, &data3);
+       ordered_list_add_node(handle, &data1);
+       ordered_list_add_node(handle, &data2);
+
+       CU_ASSERT_EQUAL(handle->num_entries, 3);
+
+       ordered_list_node *node = handle->head;
+       CU_ASSERT_PTR_EQUAL(node->data, &data1);
+
+       node = node->next_node;
+       CU_ASSERT_PTR_EQUAL(node->data, &data2);
+
+       node = node->next_node;
+       CU_ASSERT_PTR_EQUAL(node->data, &data3);
+
+       node = node->next_node;
+       CU_ASSERT_PTR_EQUAL(node, NULL);
+
+       ordered_list_destroy(handle);
+}
+
+
+void test_find()
+{
+       node_data data1, data2, data3, data_not_inList;
+       data1.int_data = 1;
+       data2.int_data = 2;
+       data3.int_data = 3;
+       data_not_inList.int_data = 5;
+
+       ordered_list_handle *handle =
+               ordered_list_initialize(node_data_compare);
+
+       ordered_list_add_node(handle, &data3);
+       ordered_list_add_node(handle, &data2);
+       ordered_list_add_node(handle, &data1);
+
+       ordered_list_node *node = ordered_list_find(handle, &data1);
+       CU_ASSERT_PTR_NOT_NULL(node);
+       CU_ASSERT_PTR_EQUAL(node->data, &data1);
+
+       node = ordered_list_find(handle, &data2);
+       CU_ASSERT_PTR_NOT_NULL(node);
+       CU_ASSERT_PTR_EQUAL(node->data, &data2);
+
+       node = ordered_list_find(handle, &data3);
+       CU_ASSERT_PTR_NOT_NULL(node);
+       CU_ASSERT_PTR_EQUAL(node->data, &data3);
+
+       node = ordered_list_find(handle, &data_not_inList);
+       CU_ASSERT_PTR_NULL(node);
+
+       ordered_list_destroy(handle);
+}
+
+
+void test_remove_first_node()
+{
+       node_data data1, data2, data3;
+       data1.int_data = 1;
+       data2.int_data = 2;
+       data3.int_data = 3;
+
+       ordered_list_handle *handle =
+               ordered_list_initialize(node_data_compare);
+
+       ordered_list_add_node(handle, &data1);
+       ordered_list_add_node(handle, &data2);
+       ordered_list_add_node(handle, &data3);
+
+       void *node_data = ordered_list_remove_first_node(handle);
+       CU_ASSERT_PTR_NOT_NULL(node_data);
+       CU_ASSERT_PTR_EQUAL(node_data, &data1);
+       CU_ASSERT_EQUAL(handle->num_entries, 2);
+
+       node_data = ordered_list_remove_first_node(handle);
+       CU_ASSERT_PTR_NOT_NULL(node_data);
+       CU_ASSERT_PTR_EQUAL(node_data, &data2);
+       CU_ASSERT_EQUAL(handle->num_entries, 1);
+
+       node_data = ordered_list_remove_first_node(handle);
+       CU_ASSERT_PTR_NOT_NULL(node_data);
+       CU_ASSERT_PTR_EQUAL(node_data, &data3);
+       CU_ASSERT_EQUAL(handle->num_entries, 0);
+       CU_ASSERT_PTR_NULL(handle->head);
+
+       node_data = ordered_list_remove_first_node(handle);
+       CU_ASSERT_PTR_NULL(node_data);
+
+       ordered_list_destroy(handle);
+}
+
+
+void test_remove_first_node_equals()
+{
+       node_data data1, data2, data3;
+       data1.int_data = 1;
+       data2.int_data = 2;
+       data3.int_data = 3;
+
+       ordered_list_handle *handle =
+               ordered_list_initialize(node_data_compare);
+
+       ordered_list_add_node(handle, &data1);
+       ordered_list_add_node(handle, &data2);
+       ordered_list_add_node(handle, &data3);
+
+       void *node_data = ordered_list_remove_first_node_equals(handle, &data2);
+       CU_ASSERT_PTR_NOT_NULL(node_data);
+       CU_ASSERT_PTR_EQUAL(node_data, &data2);
+       CU_ASSERT_EQUAL(handle->num_entries, 2);
+
+       node_data = ordered_list_remove_first_node_equals(handle, &data3);
+       CU_ASSERT_PTR_NOT_NULL(node_data);
+       CU_ASSERT_PTR_EQUAL(node_data, &data3);
+       CU_ASSERT_EQUAL(handle->num_entries, 1);
+
+       node_data = ordered_list_remove_first_node_equals(handle, &data1);
+       CU_ASSERT_PTR_NOT_NULL(node_data);
+       CU_ASSERT_PTR_EQUAL(node_data, &data1);
+       CU_ASSERT_EQUAL(handle->num_entries, 0);
+
+       node_data = ordered_list_remove_first_node_equals(handle, &data1);
+       CU_ASSERT_PTR_NULL(node_data);
+
+       ordered_list_destroy(handle);
+}
+
+
+void test_remove_node()
+{
+       node_data data1, data2, data3;
+       data1.int_data = 1;
+       data2.int_data = 2;
+       data3.int_data = 3;
+
+       ordered_list_handle *handle =
+               ordered_list_initialize(node_data_compare);
+
+       ordered_list_node *node1 = ordered_list_add_node(handle, &data1);
+       ordered_list_node *node2 = ordered_list_add_node(handle, &data2);
+       ordered_list_node *node3 = ordered_list_add_node(handle, &data3);
+
+       void *node_data = ordered_list_remove_node(handle, node2, node3);
+       CU_ASSERT_PTR_NOT_NULL(node_data);
+       CU_ASSERT_PTR_EQUAL(node_data, &data3);
+       CU_ASSERT_EQUAL(handle->num_entries, 2);
+
+       node_data = ordered_list_remove_node(handle, node1, node2);
+       CU_ASSERT_PTR_NOT_NULL(node_data);
+       CU_ASSERT_PTR_EQUAL(node_data, &data2);
+       CU_ASSERT_EQUAL(handle->num_entries, 1);
+
+       ordered_list_destroy(handle);
+}
diff --git a/pceplib/test/pcep_utils_ordered_list_test.h b/pceplib/test/pcep_utils_ordered_list_test.h
new file mode 100644 (file)
index 0000000..3686848
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Javier Garcia <javier.garcia@voltanet.io>
+ *
+ */
+
+/*
+ *  Timer definitions to be used internally by the pcep_timers library.
+ */
+
+#ifndef PCEP_UTILS_ORDERED_LIST_TEST_H_
+#define PCEP_UTILS_ORDERED_LIST_TEST_H_
+
+void test_empty_list(void);
+void test_null_list_handle(void);
+void test_add_to_list(void);
+void test_find(void);
+void test_remove_first_node(void);
+void test_remove_first_node_equals(void);
+void test_remove_node(void);
+int node_data_compare(void *list_entry, void *new_entry);
+
+#endif /* PCEPTIMERINTERNALS_H_ */
diff --git a/pceplib/test/pcep_utils_queue_test.c b/pceplib/test/pcep_utils_queue_test.c
new file mode 100644 (file)
index 0000000..1731457
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <CUnit/CUnit.h>
+
+#include "pcep_utils_queue.h"
+#include "pcep_utils_queue_test.h"
+
+typedef struct node_data_ {
+       int int_data;
+
+} node_data;
+
+
+void test_empty_queue()
+{
+       queue_handle *handle = queue_initialize();
+
+       CU_ASSERT_PTR_NOT_NULL(handle);
+       CU_ASSERT_PTR_NULL(handle->head);
+       CU_ASSERT_EQUAL(handle->num_entries, 0);
+
+       queue_destroy(handle);
+}
+
+
+void test_null_queue_handle()
+{
+       /* test each method handles a NULL handle without crashing */
+       node_data data;
+       queue_destroy(NULL);
+       void *ptr = queue_enqueue(NULL, &data);
+       CU_ASSERT_PTR_NULL(ptr);
+
+       ptr = queue_dequeue(NULL);
+       CU_ASSERT_PTR_NULL(ptr);
+}
+
+
+void test_enqueue()
+{
+       node_data data1, data2, data3;
+       data1.int_data = 1;
+       data2.int_data = 2;
+       data3.int_data = 3;
+
+       queue_handle *handle = queue_initialize();
+
+       queue_enqueue(handle, &data1);
+       queue_enqueue(handle, &data2);
+       queue_enqueue(handle, &data3);
+
+       CU_ASSERT_EQUAL(handle->num_entries, 3);
+
+       queue_node *node = handle->head;
+       CU_ASSERT_PTR_EQUAL(node->data, &data1);
+
+       node = node->next_node;
+       CU_ASSERT_PTR_EQUAL(node->data, &data2);
+
+       node = node->next_node;
+       CU_ASSERT_PTR_EQUAL(node->data, &data3);
+
+       node = node->next_node;
+       CU_ASSERT_PTR_NULL(node);
+
+       queue_destroy(handle);
+}
+
+
+void test_enqueue_with_limit()
+{
+       node_data data1, data2, data3;
+       data1.int_data = 1;
+       data2.int_data = 2;
+       data3.int_data = 3;
+
+       queue_handle *handle = queue_initialize_with_size(2);
+
+       queue_node *node = queue_enqueue(handle, &data1);
+       CU_ASSERT_PTR_NOT_NULL(node);
+
+       node = queue_enqueue(handle, &data2);
+       CU_ASSERT_PTR_NOT_NULL(node);
+
+       node = queue_enqueue(handle, &data3);
+       CU_ASSERT_PTR_NULL(node);
+
+       CU_ASSERT_EQUAL(handle->num_entries, 2);
+
+       node = handle->head;
+       CU_ASSERT_PTR_EQUAL(node->data, &data1);
+
+       node = node->next_node;
+       CU_ASSERT_PTR_EQUAL(node->data, &data2);
+
+       node = node->next_node;
+       CU_ASSERT_PTR_NULL(node);
+
+       queue_destroy(handle);
+}
+
+
+void test_dequeue()
+{
+       node_data data1, data2, data3;
+       data1.int_data = 1;
+       data2.int_data = 2;
+       data3.int_data = 3;
+
+       queue_handle *handle = queue_initialize();
+
+       /* first test dequeue handles an empty queue */
+       void *node_data = queue_dequeue(handle);
+       CU_ASSERT_PTR_NULL(node_data);
+
+       queue_enqueue(handle, &data1);
+       queue_enqueue(handle, &data2);
+       queue_enqueue(handle, &data3);
+
+       node_data = queue_dequeue(handle);
+       CU_ASSERT_PTR_EQUAL(node_data, &data1);
+       CU_ASSERT_EQUAL(handle->num_entries, 2);
+
+       node_data = queue_dequeue(handle);
+       CU_ASSERT_PTR_EQUAL(node_data, &data2);
+       CU_ASSERT_EQUAL(handle->num_entries, 1);
+
+       node_data = queue_dequeue(handle);
+       CU_ASSERT_PTR_EQUAL(node_data, &data3);
+       CU_ASSERT_EQUAL(handle->num_entries, 0);
+
+       node_data = queue_dequeue(handle);
+       CU_ASSERT_PTR_NULL(node_data);
+
+       queue_destroy(handle);
+}
diff --git a/pceplib/test/pcep_utils_queue_test.h b/pceplib/test/pcep_utils_queue_test.h
new file mode 100644 (file)
index 0000000..16236d0
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Javier Garcia <javier.garcia@voltanet.io>
+ *
+ */
+
+/*
+ *  Timer definitions to be used internally by the pcep_timers library.
+ */
+
+#ifndef PCEP_UTILS_QUEUE_TEST_H_
+#define PCEP_UTILS_QUEUE_TEST_H_
+
+void test_empty_queue(void);
+void test_null_queue_handle(void);
+void test_enqueue(void);
+void test_enqueue_with_limit(void);
+void test_dequeue(void);
+
+#endif /* PCEPTIMERINTERNALS_H_ */
diff --git a/pceplib/test/pcep_utils_tests.c b/pceplib/test/pcep_utils_tests.c
new file mode 100644 (file)
index 0000000..452b9fa
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * This file is part of the PCEPlib, a PCEP protocol library.
+ *
+ * Copyright (C) 2020 Volta Networks https://voltanet.io/
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ * Author : Brady Johnson <brady@voltanet.io>
+ *
+ */
+
+
+#include <CUnit/Basic.h>
+#include <CUnit/CUnit.h>
+#include <CUnit/TestDB.h>
+#include "pcep_utils_ordered_list_test.h"
+#include "pcep_utils_queue_test.h"
+#include "pcep_utils_double_linked_list_test.h"
+#include "pcep_utils_counters_test.h"
+#include "pcep_utils_memory_test.h"
+
+
+int main(int argc, char **argv)
+{
+       /* Unused parameters cause compilation warnings */
+       (void)argc;
+       (void)argv;
+
+       CU_initialize_registry();
+
+       CU_pSuite test_queue_suite =
+               CU_add_suite("PCEP Utils Queue Test Suite", NULL, NULL);
+       CU_add_test(test_queue_suite, "test_empty_queue", test_empty_queue);
+       CU_add_test(test_queue_suite, "test_null_queue_handle",
+                   test_null_queue_handle);
+       CU_add_test(test_queue_suite, "test_enqueue", test_enqueue);
+       CU_add_test(test_queue_suite, "test_enqueue_with_limit",
+                   test_enqueue_with_limit);
+       CU_add_test(test_queue_suite, "test_dequeue", test_dequeue);
+
+       CU_pSuite test_list_suite =
+               CU_add_suite("PCEP Utils Ordered List Test Suite", NULL, NULL);
+       CU_add_test(test_list_suite, "test_empty_list", test_empty_list);
+       CU_add_test(test_list_suite, "test_null_handle", test_null_list_handle);
+       CU_add_test(test_list_suite, "test_add_toList", test_add_to_list);
+       CU_add_test(test_list_suite, "test_find", test_find);
+       CU_add_test(test_list_suite, "test_remove_first_node",
+                   test_remove_first_node);
+       CU_add_test(test_list_suite, "test_remove_first_node_equals",
+                   test_remove_first_node_equals);
+       CU_add_test(test_list_suite, "test_remove_node", test_remove_node);
+
+       CU_pSuite test_dl_list_suite = CU_add_suite(
+               "PCEP Utils Double Linked List Test Suite", NULL, NULL);
+       CU_add_test(test_dl_list_suite, "test_empty_dl_list",
+                   test_empty_dl_list);
+       CU_add_test(test_dl_list_suite, "test_null_dl_handle",
+                   test_null_dl_list_handle);
+       CU_add_test(test_dl_list_suite, "test_dll_prepend_data",
+                   test_dll_prepend_data);
+       CU_add_test(test_dl_list_suite, "test_dll_append_data",
+                   test_dll_append_data);
+       CU_add_test(test_dl_list_suite, "test_dll_delete_first_node",
+                   test_dll_delete_first_node);
+       CU_add_test(test_dl_list_suite, "test_dll_delete_last_node",
+                   test_dll_delete_last_node);
+       CU_add_test(test_dl_list_suite, "test_dll_delete_node",
+                   test_dll_delete_node);
+
+       CU_pSuite test_counters_suite =
+               CU_add_suite("PCEP Utils Counters Test Suite", NULL, NULL);
+       CU_add_test(test_counters_suite, "test_create_counters_group",
+                   test_create_counters_group);
+       CU_add_test(test_counters_suite, "test_create_counters_subgroup",
+                   test_create_counters_subgroup);
+       CU_add_test(test_counters_suite, "test_add_counters_subgroup",
+                   test_add_counters_subgroup);
+       CU_add_test(test_counters_suite, "test_create_subgroup_counter",
+                   test_create_subgroup_counter);
+       CU_add_test(test_counters_suite, "test_delete_counters_group",
+                   test_delete_counters_group);
+       CU_add_test(test_counters_suite, "test_delete_counters_subgroup",
+                   test_delete_counters_subgroup);
+       CU_add_test(test_counters_suite, "test_reset_group_counters",
+                   test_reset_group_counters);
+       CU_add_test(test_counters_suite, "test_reset_subgroup_counters",
+                   test_reset_subgroup_counters);
+       CU_add_test(test_counters_suite, "test_increment_counter",
+                   test_increment_counter);
+       CU_add_test(test_counters_suite, "test_increment_subgroup_counter",
+                   test_increment_subgroup_counter);
+       CU_add_test(test_counters_suite, "test_dump_counters_group_to_log",
+                   test_dump_counters_group_to_log);
+       CU_add_test(test_counters_suite, "test_dump_counters_subgroup_to_log",
+                   test_dump_counters_subgroup_to_log);
+
+       CU_pSuite test_memory_suite =
+               CU_add_suite("PCEP Utils Memory Test Suite", NULL, NULL);
+       CU_add_test(test_memory_suite, "test_memory_internal_impl",
+                   test_memory_internal_impl);
+       CU_add_test(test_memory_suite, "test_memory_external_impl",
+                   test_memory_external_impl);
+
+       CU_basic_set_mode(CU_BRM_VERBOSE);
+       CU_basic_run_tests();
+       CU_FailureRecord *failure_record = CU_get_failure_list();
+       if (failure_record != NULL) {
+               printf("\nFailed tests:\n\t [Suite] [Test] [File:line-number]\n");
+               do {
+                       printf("\t [%s] [%s] [%s:%d]\n",
+                              failure_record->pSuite->pName,
+                              failure_record->pTest->pName,
+                              failure_record->strFileName,
+                              failure_record->uiLineNumber);
+                       failure_record = failure_record->pNext;
+
+               } while (failure_record != NULL);
+       }
+
+       CU_pRunSummary run_summary = CU_get_run_summary();
+       int result = run_summary->nTestsFailed;
+       CU_cleanup_registry();
+
+       return result;
+}
diff --git a/pceplib/test/pcep_utils_tests_valgrind.sh b/pceplib/test/pcep_utils_tests_valgrind.sh
new file mode 100755 (executable)
index 0000000..6348d82
--- /dev/null
@@ -0,0 +1,2 @@
+source pceplib/test/pcep_tests_valgrind.sh
+valgrind_test pceplib/test/pcep_utils_tests
diff --git a/pceplib/test/subdir.am b/pceplib/test/subdir.am
new file mode 100644 (file)
index 0000000..0ae61d1
--- /dev/null
@@ -0,0 +1,122 @@
+if PATHD_PCEP
+if PATHD_PCEP_TEST
+
+# The default Automake target is check, add a test target to call check.
+# Also make sure the binaries are current before running the tests.
+test: pceplib/test/pcep_msg_tests pceplib/test/pcep_pcc_api_tests pceplib/test/pcep_session_logic_tests pceplib/test/pcep_socket_comm_tests pceplib/test/pcep_timers_tests pceplib/test/pcep_utils_tests
+
+check_SCRIPTS = pceplib/test/pcep_msg_tests pceplib/test/pcep_pcc_api_tests pceplib/test/pcep_session_logic_tests pceplib/test/pcep_socket_comm_tests pceplib/test/pcep_timers_tests pceplib/test/pcep_utils_tests
+TESTS = $(check_SCRIPTS)
+
+
+# Definitions to build the Unit Test binaries with CUnit
+noinst_PROGRAMS += pceplib/test/pcep_msg_tests \
+               pceplib/test/pcep_pcc_api_tests \
+               pceplib/test/pcep_session_logic_tests \
+               pceplib/test/pcep_socket_comm_tests \
+               pceplib/test/pcep_timers_tests \
+               pceplib/test/pcep_utils_tests
+
+noinst_HEADERS += pceplib/test/pcep_msg_messages_test.h \
+               pceplib/test/pcep_msg_object_error_types_test.h \
+               pceplib/test/pcep_msg_objects_test.h \
+               pceplib/test/pcep_msg_tlvs_test.h \
+               pceplib/test/pcep_msg_tools_test.h \
+               pceplib/test/pcep_pcc_api_test.h \
+               pceplib/test/pcep_session_logic_loop_test.h \
+               pceplib/test/pcep_session_logic_states_test.h \
+               pceplib/test/pcep_session_logic_test.h \
+               pceplib/test/pcep_socket_comm_loop_test.h \
+               pceplib/test/pcep_socket_comm_test.h \
+               pceplib/test/pcep_timers_event_loop_test.h \
+               pceplib/test/pcep_timers_test.h \
+               pceplib/test/pcep_utils_counters_test.h \
+               pceplib/test/pcep_utils_double_linked_list_test.h \
+               pceplib/test/pcep_utils_memory_test.h \
+               pceplib/test/pcep_utils_ordered_list_test.h \
+               pceplib/test/pcep_utils_queue_test.h
+
+pceplib_test_pcep_msg_tests_CFLAGS =  -I$(top_srcdir)/pceplib
+pceplib_test_pcep_msg_tests_LDADD = $(top_builddir)/pceplib/libpcep_pcc.la  lib/libfrr.la -lcunit -lpthread
+pceplib_test_pcep_msg_tests_SOURCES = pceplib/test/pcep_msg_messages_test.c \
+               pceplib/test/pcep_msg_messages_tests.c \
+               pceplib/test/pcep_msg_object_error_types_test.c \
+               pceplib/test/pcep_msg_objects_test.c \
+               pceplib/test/pcep_msg_tlvs_test.c \
+               pceplib/test/pcep_msg_tools_test.c
+
+# The pcc_api_tests and pcep_session_logic_tests use the
+# socket_comm_mock, so the LDADD variable needs to be modified
+pceplib_test_pcep_pcc_api_tests_CFLAGS =  -I$(top_srcdir)/pceplib
+pceplib_test_pcep_pcc_api_tests_LDADD = $(top_builddir)/pceplib/libsocket_comm_mock.la $(top_builddir)/pceplib/libpcep_pcc.la  lib/libfrr.la -lcunit -lpthread
+pceplib_test_pcep_pcc_api_tests_SOURCES = pceplib/test/pcep_pcc_api_test.c pceplib/test/pcep_pcc_api_tests.c
+
+pceplib_test_pcep_session_logic_tests_CFLAGS =  -I$(top_srcdir)/pceplib
+pceplib_test_pcep_session_logic_tests_LDADD = $(top_builddir)/pceplib/libsocket_comm_mock.la $(top_builddir)/pceplib/libpcep_pcc.la  lib/libfrr.la -lcunit -lpthread
+pceplib_test_pcep_session_logic_tests_SOURCES = pceplib/test/pcep_session_logic_loop_test.c \
+               pceplib/test/pcep_session_logic_states_test.c \
+               pceplib/test/pcep_session_logic_test.c \
+               pceplib/test/pcep_session_logic_tests.c
+
+pceplib_test_pcep_socket_comm_tests_CFLAGS =  -I$(top_srcdir)/pceplib
+pceplib_test_pcep_socket_comm_tests_LDADD = $(top_builddir)/pceplib/libpcep_pcc.la lib/libfrr.la  -lcunit -lpthread
+pceplib_test_pcep_socket_comm_tests_SOURCES = pceplib/test/pcep_socket_comm_loop_test.c \
+               pceplib/test/pcep_socket_comm_test.c \
+               pceplib/test/pcep_socket_comm_tests.c
+
+pceplib_test_pcep_timers_tests_CFLAGS =  -I$(top_srcdir)/pceplib
+pceplib_test_pcep_timers_tests_LDADD = $(top_builddir)/pceplib/libpcep_pcc.la lib/libfrr.la  -lcunit -lpthread
+pceplib_test_pcep_timers_tests_SOURCES = pceplib/test/pcep_timers_event_loop_test.c \
+               pceplib/test/pcep_timers_test.c \
+               pceplib/test/pcep_timers_tests.c
+
+pceplib_test_pcep_utils_tests_CFLAGS =  -I$(top_srcdir)/pceplib
+pceplib_test_pcep_utils_tests_LDADD = $(top_builddir)/pceplib/libpcep_pcc.la lib/libfrr.la  -lcunit -lpthread
+pceplib_test_pcep_utils_tests_SOURCES = pceplib/test/pcep_utils_counters_test.c \
+               pceplib/test/pcep_utils_double_linked_list_test.c \
+               pceplib/test/pcep_utils_memory_test.c \
+               pceplib/test/pcep_utils_ordered_list_test.c \
+               pceplib/test/pcep_utils_queue_test.c \
+               pceplib/test/pcep_utils_tests.c
+
+# These test scripts will call the test binaries
+# defined above in noinst_PROGRAMS with Valgrind
+if HAVE_VALGRIND_PCEP
+
+dist_noinst_SCRIPTS = pceplib/test/pcep_pcc_api_tests_valgrind.sh \
+       pceplib/test/pcep_session_logic_tests_valgrind.sh \
+       pceplib/test/pcep_socket_comm_tests_valgrind.sh \
+       pceplib/test/pcep_timers_tests_valgrind.sh \
+       pceplib/test/pcep_utils_tests_valgrind.sh \
+       pceplib/test/pcep_msg_tests_valgrind.sh \
+       pceplib/test/pcep_tests_valgrind.sh
+
+check_SCRIPTS += pceplib/test/pcep_msg_tests_valgrind.sh \
+       pceplib/test/pcep_pcc_api_tests_valgrind.sh \
+       pceplib/test/pcep_session_logic_tests_valgrind.sh \
+       pceplib/test/pcep_socket_comm_tests_valgrind.sh \
+       pceplib/test/pcep_timers_tests_valgrind.sh \
+       pceplib/test/pcep_utils_tests_valgrind.sh
+
+TESTS += $(check_SCRIPTS)
+
+
+
+pceplib/test/pcep_msg_tests_valgrind.sh:
+       chmod +x pceplib/test/pcep_msg_tests_valgrind.sh
+pceplib/test/pcep_pcc_api_tests_valgrind.sh:
+       chmod +x pceplib/test/pcep_pcc_api_tests_valgrind.sh
+pceplib/test/pcep_session_logic_tests_valgrind.sh:
+       chmod +x pceplib/test/pcep_session_logic_tests_valgrind.sh
+pceplib/test/pcep_socket_comm_tests_valgrind.sh:
+       chmod +x pceplib/test/pcep_socket_comm_tests_valgrind.sh
+pceplib/test/pcep_timers_tests_valgrind.sh:
+       chmod +x pceplib/test/pcep_timers_tests_valgrind.sh
+pceplib/test/pcep_utils_tests_valgrind.sh:
+       chmod +x pceplib/test/pcep_utils_tests_valgrind.sh
+
+
+endif
+
+endif
+endif
index e873af57598ccaa517e320b2ccb3987f1243f17d..f43a31fde261d9a808acff75e15af672942a8b75 100644 (file)
@@ -42,10 +42,10 @@ static inline void pim_g2rp_timer_restart(struct bsm_rpinfo *bsrp,
                                          int hold_time);
 
 /* Memory Types */
-DEFINE_MTYPE_STATIC(PIMD, PIM_BSGRP_NODE, "PIM BSR advertised grp info")
-DEFINE_MTYPE_STATIC(PIMD, PIM_BSRP_NODE, "PIM BSR advertised RP info")
-DEFINE_MTYPE_STATIC(PIMD, PIM_BSM_INFO, "PIM BSM Info")
-DEFINE_MTYPE_STATIC(PIMD, PIM_BSM_PKT_VAR_MEM, "PIM BSM Packet")
+DEFINE_MTYPE_STATIC(PIMD, PIM_BSGRP_NODE, "PIM BSR advertised grp info");
+DEFINE_MTYPE_STATIC(PIMD, PIM_BSRP_NODE, "PIM BSR advertised RP info");
+DEFINE_MTYPE_STATIC(PIMD, PIM_BSM_INFO, "PIM BSM Info");
+DEFINE_MTYPE_STATIC(PIMD, PIM_BSM_PKT_VAR_MEM, "PIM BSM Packet");
 
 /* All bsm packets forwarded shall be fit within ip mtu less iphdr(max) */
 #define MAX_IP_HDR_LEN 24
index 5a09e7a8ee4d9761b736f5a5c49a0cd297843f81..70c233848a8b1ae601e90b3302e32a43de013122 100644 (file)
@@ -92,7 +92,8 @@ FRR_DAEMON_INFO(pimd, PIM, .vty_port = PIMD_VTY_PORT,
                .n_signals = 4 /* XXX array_size(pimd_signals) XXX*/,
 
                .privs = &pimd_privs, .yang_modules = pimd_yang_modules,
-               .n_yang_modules = array_size(pimd_yang_modules), )
+               .n_yang_modules = array_size(pimd_yang_modules),
+);
 
 
 int main(int argc, char **argv, char **envp)
index 6bc8062c4ba46f8d4234411183451208d751c74b..1d811d90016549d1af868302457a8bf84f57e5b7 100644 (file)
 
 #include "pim_memory.h"
 
-DEFINE_MGROUP(PIMD, "pimd")
-DEFINE_MTYPE(PIMD, PIM_CHANNEL_OIL, "PIM SSM (S,G) channel OIL")
-DEFINE_MTYPE(PIMD, PIM_INTERFACE, "PIM interface")
-DEFINE_MTYPE(PIMD, PIM_IGMP_JOIN, "PIM interface IGMP static join")
-DEFINE_MTYPE(PIMD, PIM_IGMP_SOCKET, "PIM interface IGMP socket")
-DEFINE_MTYPE(PIMD, PIM_IGMP_GROUP, "PIM interface IGMP group")
-DEFINE_MTYPE(PIMD, PIM_IGMP_GROUP_SOURCE, "PIM interface IGMP source")
-DEFINE_MTYPE(PIMD, PIM_NEIGHBOR, "PIM interface neighbor")
-DEFINE_MTYPE(PIMD, PIM_IFCHANNEL, "PIM interface (S,G) state")
-DEFINE_MTYPE(PIMD, PIM_UPSTREAM, "PIM upstream (S,G) state")
-DEFINE_MTYPE(PIMD, PIM_SSMPINGD, "PIM sspimgd socket")
-DEFINE_MTYPE(PIMD, PIM_STATIC_ROUTE, "PIM Static Route")
-DEFINE_MTYPE(PIMD, PIM_BR, "PIM Bridge Router info")
-DEFINE_MTYPE(PIMD, PIM_RP, "PIM RP info")
-DEFINE_MTYPE(PIMD, PIM_FILTER_NAME, "PIM RP filter info")
-DEFINE_MTYPE(PIMD, PIM_MSDP_PEER, "PIM MSDP peer")
-DEFINE_MTYPE(PIMD, PIM_MSDP_MG_NAME, "PIM MSDP mesh-group name")
-DEFINE_MTYPE(PIMD, PIM_MSDP_SA, "PIM MSDP source-active cache")
-DEFINE_MTYPE(PIMD, PIM_MSDP_MG, "PIM MSDP mesh group")
-DEFINE_MTYPE(PIMD, PIM_MSDP_MG_MBR, "PIM MSDP mesh group mbr")
-DEFINE_MTYPE(PIMD, PIM_SEC_ADDR, "PIM secondary address")
-DEFINE_MTYPE(PIMD, PIM_JP_AGG_GROUP, "PIM JP AGG Group")
-DEFINE_MTYPE(PIMD, PIM_JP_AGG_SOURCE, "PIM JP AGG Source")
-DEFINE_MTYPE(PIMD, PIM_PIM_INSTANCE, "PIM global state")
-DEFINE_MTYPE(PIMD, PIM_NEXTHOP_CACHE, "PIM nexthop cache state")
-DEFINE_MTYPE(PIMD, PIM_SSM_INFO, "PIM SSM configuration")
-DEFINE_MTYPE(PIMD, PIM_PLIST_NAME, "PIM Prefix List Names")
-DEFINE_MTYPE(PIMD, PIM_VXLAN_SG, "PIM VxLAN mroute cache")
+DEFINE_MGROUP(PIMD, "pimd");
+DEFINE_MTYPE(PIMD, PIM_CHANNEL_OIL, "PIM SSM (S,G) channel OIL");
+DEFINE_MTYPE(PIMD, PIM_INTERFACE, "PIM interface");
+DEFINE_MTYPE(PIMD, PIM_IGMP_JOIN, "PIM interface IGMP static join");
+DEFINE_MTYPE(PIMD, PIM_IGMP_SOCKET, "PIM interface IGMP socket");
+DEFINE_MTYPE(PIMD, PIM_IGMP_GROUP, "PIM interface IGMP group");
+DEFINE_MTYPE(PIMD, PIM_IGMP_GROUP_SOURCE, "PIM interface IGMP source");
+DEFINE_MTYPE(PIMD, PIM_NEIGHBOR, "PIM interface neighbor");
+DEFINE_MTYPE(PIMD, PIM_IFCHANNEL, "PIM interface (S,G) state");
+DEFINE_MTYPE(PIMD, PIM_UPSTREAM, "PIM upstream (S,G) state");
+DEFINE_MTYPE(PIMD, PIM_SSMPINGD, "PIM sspimgd socket");
+DEFINE_MTYPE(PIMD, PIM_STATIC_ROUTE, "PIM Static Route");
+DEFINE_MTYPE(PIMD, PIM_BR, "PIM Bridge Router info");
+DEFINE_MTYPE(PIMD, PIM_RP, "PIM RP info");
+DEFINE_MTYPE(PIMD, PIM_FILTER_NAME, "PIM RP filter info");
+DEFINE_MTYPE(PIMD, PIM_MSDP_PEER, "PIM MSDP peer");
+DEFINE_MTYPE(PIMD, PIM_MSDP_MG_NAME, "PIM MSDP mesh-group name");
+DEFINE_MTYPE(PIMD, PIM_MSDP_SA, "PIM MSDP source-active cache");
+DEFINE_MTYPE(PIMD, PIM_MSDP_MG, "PIM MSDP mesh group");
+DEFINE_MTYPE(PIMD, PIM_MSDP_MG_MBR, "PIM MSDP mesh group mbr");
+DEFINE_MTYPE(PIMD, PIM_SEC_ADDR, "PIM secondary address");
+DEFINE_MTYPE(PIMD, PIM_JP_AGG_GROUP, "PIM JP AGG Group");
+DEFINE_MTYPE(PIMD, PIM_JP_AGG_SOURCE, "PIM JP AGG Source");
+DEFINE_MTYPE(PIMD, PIM_PIM_INSTANCE, "PIM global state");
+DEFINE_MTYPE(PIMD, PIM_NEXTHOP_CACHE, "PIM nexthop cache state");
+DEFINE_MTYPE(PIMD, PIM_SSM_INFO, "PIM SSM configuration");
+DEFINE_MTYPE(PIMD, PIM_PLIST_NAME, "PIM Prefix List Names");
+DEFINE_MTYPE(PIMD, PIM_VXLAN_SG, "PIM VxLAN mroute cache");
index 6beeb60075089233687e9ad24173c9d2670596cb..4e5fcde7dda07109129e25a8f298d8ba45d45322 100644 (file)
 
 #include "memory.h"
 
-DECLARE_MGROUP(PIMD)
-DECLARE_MTYPE(PIM_CHANNEL_OIL)
-DECLARE_MTYPE(PIM_INTERFACE)
-DECLARE_MTYPE(PIM_IGMP_JOIN)
-DECLARE_MTYPE(PIM_IGMP_SOCKET)
-DECLARE_MTYPE(PIM_IGMP_GROUP)
-DECLARE_MTYPE(PIM_IGMP_GROUP_SOURCE)
-DECLARE_MTYPE(PIM_NEIGHBOR)
-DECLARE_MTYPE(PIM_IFCHANNEL)
-DECLARE_MTYPE(PIM_UPSTREAM)
-DECLARE_MTYPE(PIM_SSMPINGD)
-DECLARE_MTYPE(PIM_STATIC_ROUTE)
-DECLARE_MTYPE(PIM_BR)
-DECLARE_MTYPE(PIM_RP)
-DECLARE_MTYPE(PIM_FILTER_NAME)
-DECLARE_MTYPE(PIM_MSDP_PEER)
-DECLARE_MTYPE(PIM_MSDP_MG_NAME)
-DECLARE_MTYPE(PIM_MSDP_SA)
-DECLARE_MTYPE(PIM_MSDP_MG)
-DECLARE_MTYPE(PIM_MSDP_MG_MBR)
-DECLARE_MTYPE(PIM_SEC_ADDR)
-DECLARE_MTYPE(PIM_JP_AGG_GROUP)
-DECLARE_MTYPE(PIM_JP_AGG_SOURCE)
-DECLARE_MTYPE(PIM_PIM_INSTANCE)
-DECLARE_MTYPE(PIM_NEXTHOP_CACHE)
-DECLARE_MTYPE(PIM_SSM_INFO)
+DECLARE_MGROUP(PIMD);
+DECLARE_MTYPE(PIM_CHANNEL_OIL);
+DECLARE_MTYPE(PIM_INTERFACE);
+DECLARE_MTYPE(PIM_IGMP_JOIN);
+DECLARE_MTYPE(PIM_IGMP_SOCKET);
+DECLARE_MTYPE(PIM_IGMP_GROUP);
+DECLARE_MTYPE(PIM_IGMP_GROUP_SOURCE);
+DECLARE_MTYPE(PIM_NEIGHBOR);
+DECLARE_MTYPE(PIM_IFCHANNEL);
+DECLARE_MTYPE(PIM_UPSTREAM);
+DECLARE_MTYPE(PIM_SSMPINGD);
+DECLARE_MTYPE(PIM_STATIC_ROUTE);
+DECLARE_MTYPE(PIM_BR);
+DECLARE_MTYPE(PIM_RP);
+DECLARE_MTYPE(PIM_FILTER_NAME);
+DECLARE_MTYPE(PIM_MSDP_PEER);
+DECLARE_MTYPE(PIM_MSDP_MG_NAME);
+DECLARE_MTYPE(PIM_MSDP_SA);
+DECLARE_MTYPE(PIM_MSDP_MG);
+DECLARE_MTYPE(PIM_MSDP_MG_MBR);
+DECLARE_MTYPE(PIM_SEC_ADDR);
+DECLARE_MTYPE(PIM_JP_AGG_GROUP);
+DECLARE_MTYPE(PIM_JP_AGG_SOURCE);
+DECLARE_MTYPE(PIM_PIM_INSTANCE);
+DECLARE_MTYPE(PIM_NEXTHOP_CACHE);
+DECLARE_MTYPE(PIM_SSM_INFO);
 DECLARE_MTYPE(PIM_PLIST_NAME);
-DECLARE_MTYPE(PIM_VXLAN_SG)
+DECLARE_MTYPE(PIM_VXLAN_SG);
 
 #endif /* _QUAGGA_PIM_MEMORY_H */
index b613937f59bc7a51eb9756c522df40aaf95edb34..9c3cdb27115fef0db5f52ad26db70e0382c3c2d7 100644 (file)
@@ -35,6 +35,8 @@
 #include "pim_msdp.h"
 #include "pim_msdp_socket.h"
 
+#include "sockopt.h"
+
 /* increase socket send buffer size */
 static void pim_msdp_update_sock_send_buffer_size(int fd)
 {
@@ -194,6 +196,12 @@ int pim_msdp_sock_listen(struct pim_instance *pim)
                return rc;
        }
 
+       /* Set socket DSCP byte */
+       if (setsockopt_ipv4_tos(sock, IPTOS_PREC_INTERNETCONTROL)) {
+               zlog_warn("can't set sockopt IP_TOS to MSDP socket %d: %s",
+                               sock, safe_strerror(errno));
+       }
+
        /* add accept thread */
        listener->fd = sock;
        memcpy(&listener->su, &sin, socklen);
@@ -272,6 +280,12 @@ int pim_msdp_sock_connect(struct pim_msdp_peer *mp)
                return rc;
        }
 
+       /* Set socket DSCP byte */
+       if (setsockopt_ipv4_tos(mp->fd, IPTOS_PREC_INTERNETCONTROL)) {
+               zlog_warn("can't set sockopt IP_TOS to MSDP socket %d: %s",
+                               mp->fd, safe_strerror(errno));
+       }
+
        /* Connect to the remote mp. */
        return (sockunion_connect(mp->fd, &mp->su_peer,
                                  htons(PIM_MSDP_TCP_PORT), 0));
index 8a808afa73a23fe787310444972d09d7c578cd96..b0aa2b17c584daf28390622180f58a2fa0a779f7 100644 (file)
@@ -90,7 +90,7 @@ struct channel_counts {
   installed: indicate if this entry is installed in the kernel.
 
 */
-PREDECL_RBTREE_UNIQ(rb_pim_oil)
+PREDECL_RBTREE_UNIQ(rb_pim_oil);
 
 struct channel_oil {
        struct pim_instance *pim;
@@ -112,7 +112,7 @@ struct channel_oil {
 extern int pim_channel_oil_compare(const struct channel_oil *c1,
                                   const struct channel_oil *c2);
 DECLARE_RBTREE_UNIQ(rb_pim_oil, struct channel_oil, oil_rb,
-                    pim_channel_oil_compare)
+                    pim_channel_oil_compare);
 
 
 extern struct list *pim_channel_oil_list;
index 8030835fb247312ccc709728d821d8c5d10aba8d..adea3cd9efa25fd76b139b87f66a4f646b3e0ebe 100644 (file)
@@ -373,7 +373,7 @@ void join_timer_start(struct pim_upstream *up);
 int pim_upstream_compare(const struct pim_upstream *up1,
                         const struct pim_upstream *up2);
 DECLARE_RBTREE_UNIQ(rb_pim_upstream, struct pim_upstream, upstream_rb,
-                   pim_upstream_compare)
+                   pim_upstream_compare);
 
 void pim_upstream_register_reevaluate(struct pim_instance *pim);
 
index 02c272f47c794b066583af011571737c21d97c5b..b6d7ab2416adf399e7c0a4fd7e92f8708b42cc8e 100644 (file)
@@ -698,6 +698,7 @@ fi
 %endif
 %if %{with_pathd}
     %{_sbindir}/pathd
+    %{_libdir}/frr/modules/pathd_pcep.so
 %endif
 %{_libdir}/libfrr.so*
 %{_libdir}/libfrrcares*
index 89e7e5dc17ef09fa4d0c7f78b3098fa962c212a0..1ef64ff0def0112ddba918c7ecd3b699d7236db1 100644 (file)
 #include "ripd/rip_debug.h"
 #include "ripd/rip_interface.h"
 
-DEFINE_MTYPE_STATIC(RIPD, RIP_INTERFACE, "RIP interface")
-DEFINE_MTYPE(RIPD, RIP_INTERFACE_STRING, "RIP Interface String")
-DEFINE_HOOK(rip_ifaddr_add, (struct connected * ifc), (ifc))
-DEFINE_HOOK(rip_ifaddr_del, (struct connected * ifc), (ifc))
+DEFINE_MTYPE_STATIC(RIPD, RIP_INTERFACE, "RIP interface");
+DEFINE_MTYPE(RIPD, RIP_INTERFACE_STRING, "RIP Interface String");
+DEFINE_HOOK(rip_ifaddr_add, (struct connected * ifc), (ifc));
+DEFINE_HOOK(rip_ifaddr_del, (struct connected * ifc), (ifc));
 
 /* static prototypes */
 static void rip_enable_apply(struct interface *);
index 715daf2e503b63a60d5cc46cbfc21381ec4b2351..fe26a78bdc047848d3fa55d92ee1ede6cff8c5f4 100644 (file)
@@ -23,7 +23,7 @@
 #include "memory.h"
 #include "zclient.h"
 
-DECLARE_MTYPE(RIP_INTERFACE_STRING)
+DECLARE_MTYPE(RIP_INTERFACE_STRING);
 
 extern int rip_interface_down(int, struct zclient *, zebra_size_t, vrf_id_t);
 extern int rip_interface_up(int, struct zclient *, zebra_size_t, vrf_id_t);
index 7e381887fcbc41ba1ad432406f09e0ae5c36d487..2e5eec98448a1452d6d17f37b6a06930e9af3c10 100644 (file)
@@ -128,7 +128,8 @@ FRR_DAEMON_INFO(ripd, RIP, .vty_port = RIP_VTY_PORT,
                .signals = ripd_signals, .n_signals = array_size(ripd_signals),
 
                .privs = &ripd_privs, .yang_modules = ripd_yang_modules,
-               .n_yang_modules = array_size(ripd_yang_modules), )
+               .n_yang_modules = array_size(ripd_yang_modules),
+);
 
 #define DEPRECATED_OPTIONS ""
 
index 776f121d59dac59af71e64e0b6a7220243e97b2d..4034fe84241b5f579a362cca088786de4428bd71 100644 (file)
@@ -29,7 +29,7 @@
 
 #include "ripd/ripd.h"
 
-DEFINE_MTYPE_STATIC(RIPD, RIP_OFFSET_LIST, "RIP offset list")
+DEFINE_MTYPE_STATIC(RIPD, RIP_OFFSET_LIST, "RIP offset list");
 
 #define OFFSET_LIST_IN_NAME(O)  ((O)->direct[RIP_OFFSET_LIST_IN].alist_name)
 #define OFFSET_LIST_IN_METRIC(O)  ((O)->direct[RIP_OFFSET_LIST_IN].metric)
index 23599f08779019435a3eeeaa5a2e5a73968f4d75..63493e2539c315ed452ff6ee3f12dbad8a898290 100644 (file)
@@ -29,7 +29,7 @@
 
 #include "ripd/ripd.h"
 
-DEFINE_MTYPE_STATIC(RIPD, RIP_PEER, "RIP peer")
+DEFINE_MTYPE_STATIC(RIPD, RIP_PEER, "RIP peer");
 
 static struct rip_peer *rip_peer_new(void)
 {
index 4e6ed1400fce1448f809ea4d40f0041454fc4ec7..37bce7484cc1582a356880d195dd8eda2cd94e0f 100644 (file)
@@ -589,4 +589,5 @@ static int rip_snmp_module_init(void)
 
 FRR_MODULE_SETUP(.name = "ripd_snmp", .version = FRR_VERSION,
                 .description = "ripd AgentX SNMP module",
-                .init = rip_snmp_module_init, )
+                .init = rip_snmp_module_init,
+);
index 4a56efb6f810c2e62d81f2ab49c2732ee15f7a1e..1c23575bf3b8986e3fd05e13d34a30bcccf11e44 100644 (file)
 /* UDP receive buffer size */
 #define RIP_UDP_RCV_BUF 41600
 
-DEFINE_MGROUP(RIPD, "ripd")
-DEFINE_MTYPE_STATIC(RIPD, RIP, "RIP structure")
-DEFINE_MTYPE_STATIC(RIPD, RIP_VRF_NAME, "RIP VRF name")
-DEFINE_MTYPE_STATIC(RIPD, RIP_INFO, "RIP route info")
-DEFINE_MTYPE_STATIC(RIPD, RIP_DISTANCE, "RIP distance")
+DEFINE_MGROUP(RIPD, "ripd");
+DEFINE_MTYPE_STATIC(RIPD, RIP, "RIP structure");
+DEFINE_MTYPE_STATIC(RIPD, RIP_VRF_NAME, "RIP VRF name");
+DEFINE_MTYPE_STATIC(RIPD, RIP_INFO, "RIP route info");
+DEFINE_MTYPE_STATIC(RIPD, RIP_DISTANCE, "RIP distance");
 
 /* Prototypes. */
 static void rip_output_process(struct connected *, struct sockaddr_in *, int,
index 99718f7b9e464074bb176f5eecc61ade8c79e073..85aac985f57adc7e8f3982d9dd1775d587d6fa3d 100644 (file)
@@ -97,7 +97,7 @@
 #define RIP_INSTANCE   "/frr-ripd:ripd/instance"
 #define RIP_IFACE      "/frr-interface:lib/interface/frr-ripd:rip"
 
-DECLARE_MGROUP(RIPD)
+DECLARE_MGROUP(RIPD);
 
 /* RIP structure. */
 struct rip {
@@ -529,7 +529,7 @@ extern struct rip_instance_head rip_instances;
 /* Master thread strucutre. */
 extern struct thread_master *master;
 
-DECLARE_HOOK(rip_ifaddr_add, (struct connected * ifc), (ifc))
-DECLARE_HOOK(rip_ifaddr_del, (struct connected * ifc), (ifc))
+DECLARE_HOOK(rip_ifaddr_add, (struct connected * ifc), (ifc));
+DECLARE_HOOK(rip_ifaddr_del, (struct connected * ifc), (ifc));
 
 #endif /* _ZEBRA_RIP_H */
index 875239e871ac4f35110c1268bc38210baa304166..09d5590329e00aa82db7dea72055180dab66ce6e 100644 (file)
@@ -57,6 +57,6 @@ nodist_ripd_ripd_SOURCES = \
        # end
 
 ripd_ripd_snmp_la_SOURCES = ripd/rip_snmp.c
-ripd_ripd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu99
+ripd_ripd_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu11
 ripd_ripd_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
 ripd_ripd_snmp_la_LIBADD = lib/libfrrsnmp.la
index 115d7a6b993f94ff0d86dd416bb1e79afa158392..11a8fdff87e338959b2886d702cb751e20f3d451 100644 (file)
@@ -49,7 +49,7 @@
 #define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP
 #endif
 
-DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_IF, "ripng interface")
+DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_IF, "ripng interface");
 
 /* Static utility function. */
 static void ripng_enable_apply(struct interface *);
index 010bac851b66f545d6ae9a80c87152a0b7cd57b8..a5d837aa5566a51f9c328b8a558c8def54b622b2 100644 (file)
@@ -131,7 +131,8 @@ FRR_DAEMON_INFO(ripngd, RIPNG, .vty_port = RIPNG_VTY_PORT,
                .privs = &ripngd_privs,
 
                .yang_modules = ripngd_yang_modules,
-               .n_yang_modules = array_size(ripngd_yang_modules), )
+               .n_yang_modules = array_size(ripngd_yang_modules),
+);
 
 #define DEPRECATED_OPTIONS ""
 
index ba6e52fdda0e7f290443d1b73efe655a54524e93..3e9fa90938c917e82543dc322a3b4f25b3f318de 100644 (file)
@@ -39,7 +39,7 @@
 #include "ripngd/ripng_debug.h"
 #include "ripngd/ripng_nexthop.h"
 
-DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_RTE_DATA, "RIPng rte data")
+DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_RTE_DATA, "RIPng rte data");
 
 #define DEBUG 1
 
index 0094c993add429f58a869e6b6d9eb920f93e9a55..efce8a0926cddc1f0dc4bd5417dbf46b223b82d3 100644 (file)
@@ -33,7 +33,7 @@
 
 #include "ripngd/ripngd.h"
 
-DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_OFFSET_LIST, "RIPng offset lst")
+DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_OFFSET_LIST, "RIPng offset lst");
 
 #define OFFSET_LIST_IN_NAME(O)  ((O)->direct[RIPNG_OFFSET_LIST_IN].alist_name)
 #define OFFSET_LIST_IN_METRIC(O)  ((O)->direct[RIPNG_OFFSET_LIST_IN].metric)
index 0ac489c67ee2232ab88b00ceac02e5dfc83c7596..479fcaeb54d6a21312f3734b59a1afcc02539ceb 100644 (file)
@@ -34,7 +34,7 @@
 #include "ripngd/ripngd.h"
 #include "ripngd/ripng_nexthop.h"
 
-DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_PEER, "RIPng peer")
+DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_PEER, "RIPng peer");
 
 static struct ripng_peer *ripng_peer_new(void)
 {
index ed9d77a3783de0f4e02b0c0c92178853d12e6e37..1eb1d0f31d52c4f72814b5ef383230c53a8b27b0 100644 (file)
@@ -30,7 +30,7 @@
 #include "ripngd/ripngd.h"
 #include "ripngd/ripng_route.h"
 
-DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_AGGREGATE, "RIPng aggregate")
+DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_AGGREGATE, "RIPng aggregate");
 
 static struct ripng_aggregate *ripng_aggregate_new(void)
 {
index 37e23046e8386d0243465fe5ca82fde32fb49a3a..749feaca6cdadb370e7cc9d7b8f8a6039b7918f6 100644 (file)
 #include "ripngd/ripng_debug.h"
 #include "ripngd/ripng_nexthop.h"
 
-DEFINE_MGROUP(RIPNGD, "ripngd")
-DEFINE_MTYPE_STATIC(RIPNGD, RIPNG, "RIPng structure")
-DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_VRF_NAME, "RIPng VRF name")
-DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_ROUTE, "RIPng route info")
+DEFINE_MGROUP(RIPNGD, "ripngd");
+DEFINE_MTYPE_STATIC(RIPNGD, RIPNG, "RIPng structure");
+DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_VRF_NAME, "RIPng VRF name");
+DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_ROUTE, "RIPng route info");
 
 enum { ripng_all_route,
        ripng_changed_route,
index 14ac29b3fef851216e0fe3e7baf67871ed13f2e4..12e5a6d4ac2ebfb0c4c26d69752eb91e3df1b25b 100644 (file)
@@ -86,7 +86,7 @@
 #define RIPNG_INSTANCE "/frr-ripngd:ripngd/instance"
 #define RIPNG_IFACE    "/frr-interface:lib/interface/frr-ripngd:ripng"
 
-DECLARE_MGROUP(RIPNGD)
+DECLARE_MGROUP(RIPNGD);
 
 /* RIPng structure. */
 struct ripng {
index 52561fd451562798168bac6f16a7b949efc1bf02..ecb7053fd68a613ddce3b3a6ec424f8b0a06dac5 100644 (file)
@@ -22,7 +22,7 @@
 #ifndef __SHARP_GLOBAL_H__
 #define __SHARP_GLOBAL_H__
 
-DECLARE_MGROUP(SHARPD)
+DECLARE_MGROUP(SHARPD);
 
 struct sharp_routes {
        /* The original prefix for route installation */
index fe7f9851f9015d4e40df28083edd3bef46d271c9..a1216247c0f9a7734094323303dad9ac819b83ea 100644 (file)
@@ -49,7 +49,7 @@
 #include "sharp_globals.h"
 #include "sharp_nht.h"
 
-DEFINE_MGROUP(SHARPD, "sharpd")
+DEFINE_MGROUP(SHARPD, "sharpd");
 
 zebra_capabilities_t _caps_p[] = {
 };
@@ -129,7 +129,8 @@ FRR_DAEMON_INFO(sharpd, SHARP, .vty_port = SHARP_VTY_PORT,
                .n_signals = array_size(sharp_signals),
 
                .privs = &sharp_privs, .yang_modules = sharpd_yang_modules,
-               .n_yang_modules = array_size(sharpd_yang_modules), )
+               .n_yang_modules = array_size(sharpd_yang_modules),
+);
 
 struct sharp_global sg;
 
index bed0ebfa27cd1fe66b6fb29912b5d13736738365..a90387186e8295991494c53dece4ed01d26954b1 100644 (file)
@@ -32,8 +32,8 @@
 #include "sharp_globals.h"
 #include "sharp_zebra.h"
 
-DEFINE_MTYPE_STATIC(SHARPD, NH_TRACKER, "Nexthop Tracker")
-DEFINE_MTYPE_STATIC(SHARPD, NHG, "Nexthop Group")
+DEFINE_MTYPE_STATIC(SHARPD, NH_TRACKER, "Nexthop Tracker");
+DEFINE_MTYPE_STATIC(SHARPD, NHG, "Nexthop Group");
 
 struct sharp_nh_tracker *sharp_nh_tracker_get(struct prefix *p)
 {
index 0095aed547b517e939e12894ec608dea7cecdaa2..73bbaf0bc0367f7c30a5376dce329a96539eb641 100644 (file)
@@ -685,7 +685,8 @@ static int sharp_nexthop_update(ZAPI_CALLBACK_ARGS)
                return 0;
        }
 
-       zlog_debug("Received update for %pFX", &nhr.prefix);
+       zlog_debug("Received update for %pFX metric: %u", &nhr.prefix,
+                  nhr.metric);
 
        nht = sharp_nh_tracker_get(&nhr.prefix);
        nht->nhop_num = nhr.nexthop_num;
index 560814771d8e239a7ca560800ab6bc408d6b35be..1561b91efb7d839220439d6826c95db5f88524dc 100644 (file)
@@ -129,7 +129,7 @@ FRR_DAEMON_INFO(staticd, STATIC, .vty_port = STATIC_VTY_PORT,
 
                .privs = &static_privs, .yang_modules = staticd_yang_modules,
                .n_yang_modules = array_size(staticd_yang_modules),
-)
+);
 
 int main(int argc, char **argv, char **envp)
 {
diff --git a/staticd/static_memory.c b/staticd/static_memory.c
deleted file mode 100644 (file)
index 122cc9f..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * static memory code.
- * Copyright (C) 2018 Cumulus Networks, Inc.
- *               Donald Sharp
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; see the file COPYING; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-#include <zebra.h>
-
-#include <memory.h>
-
-#include "staticd/static_memory.h"
-
-DEFINE_MGROUP(STATIC, "staticd")
-
-DEFINE_MTYPE(STATIC, STATIC_NEXTHOP, "Static Nexthop");
diff --git a/staticd/static_memory.h b/staticd/static_memory.h
deleted file mode 100644 (file)
index 077cd0f..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * static memory code.
- * Copyright (C) 2018 Cumulus Networks, Inc.
- *               Donald Sharp
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; see the file COPYING; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-#ifndef __STATIC_MEMORY_H__
-
-#include "memory.h"
-
-DECLARE_MGROUP(STATIC)
-
-DECLARE_MTYPE(STATIC_ROUTE);
-DECLARE_MTYPE(STATIC_NEXTHOP);
-DECLARE_MTYPE(STATIC_PATH);
-
-#endif
index 9f7e19660d675216ad2ffb2b99eabd7578c0541e..739c08b09ebcac108046d6b3b8e375a3ddd3017c 100644 (file)
 
 #include "static_vrf.h"
 #include "static_routes.h"
-#include "static_memory.h"
 #include "static_zebra.h"
 #include "static_debug.h"
 
-DEFINE_MTYPE(STATIC, STATIC_ROUTE, "Static Route Info");
-DEFINE_MTYPE(STATIC, STATIC_PATH, "Static Path");
+DEFINE_MGROUP(STATIC, "staticd");
+
+DEFINE_MTYPE_STATIC(STATIC, STATIC_ROUTE,   "Static Route Info");
+DEFINE_MTYPE_STATIC(STATIC, STATIC_PATH,    "Static Path");
+DEFINE_MTYPE_STATIC(STATIC, STATIC_NEXTHOP, "Static Nexthop");
+
+void zebra_stable_node_cleanup(struct route_table *table,
+                              struct route_node *node)
+{
+       struct static_nexthop *nh;
+       struct static_path *pn;
+       struct static_route_info *si;
+       struct route_table *src_table;
+       struct route_node *src_node;
+       struct static_path *src_pn;
+       struct static_route_info *src_si;
+
+       si = node->info;
+
+       if (si) {
+               frr_each_safe(static_path_list, &si->path_list, pn) {
+                       frr_each_safe(static_nexthop_list, &pn->nexthop_list,
+                                      nh) {
+                               static_nexthop_list_del(&pn->nexthop_list, nh);
+                               XFREE(MTYPE_STATIC_NEXTHOP, nh);
+                       }
+                       static_path_list_del(&si->path_list, pn);
+                       XFREE(MTYPE_STATIC_PATH, pn);
+               }
+
+               /* clean up for dst table */
+               src_table = srcdest_srcnode_table(node);
+               if (src_table) {
+                       /* This means the route_node is part of the top
+                        * hierarchy and refers to a destination prefix.
+                        */
+                       for (src_node = route_top(src_table); src_node;
+                            src_node = route_next(src_node)) {
+                               src_si = src_node->info;
+
+                               frr_each_safe(static_path_list,
+                                             &src_si->path_list, src_pn) {
+                                       frr_each_safe(static_nexthop_list,
+                                                     &src_pn->nexthop_list,
+                                                     nh) {
+                                               static_nexthop_list_del(
+                                                       &src_pn->nexthop_list,
+                                                       nh);
+                                               XFREE(MTYPE_STATIC_NEXTHOP, nh);
+                                       }
+                                       static_path_list_del(&src_si->path_list,
+                                                            src_pn);
+                                       XFREE(MTYPE_STATIC_PATH, src_pn);
+                               }
+
+                               XFREE(MTYPE_STATIC_ROUTE, src_node->info);
+                       }
+               }
+
+               XFREE(MTYPE_STATIC_ROUTE, node->info);
+       }
+}
 
 /* Install static path into rib. */
 void static_install_path(struct route_node *rn, struct static_path *pn,
index 0fbf0674d72fe306c1da4ff04fb5c4b81bca86a6..f64a40329d466c8424fd0503a729e9976f49ca4d 100644 (file)
@@ -22,6 +22,9 @@
 
 #include "lib/mpls.h"
 #include "table.h"
+#include "memory.h"
+
+DECLARE_MGROUP(STATIC);
 
 /* Static route label information */
 struct static_nh_label {
@@ -198,6 +201,9 @@ extern bool static_add_nexthop_validate(const char *nh_vrf_name,
 extern struct stable_info *static_get_stable_info(struct route_node *rn);
 extern void static_route_info_init(struct static_route_info *si);
 
+extern void zebra_stable_node_cleanup(struct route_table *table,
+                                     struct route_node *node);
+
 /*
  * Max string return via API static_get_nh_str in size_t
  */
index 2133093bb302b3fa3f980085f35f96e312c9c9a4..ba1367b877f4175dc553e61ffc64f08b4693de23 100644 (file)
@@ -24,7 +24,6 @@
 #include "table.h"
 #include "srcdest_table.h"
 
-#include "static_memory.h"
 #include "static_vrf.h"
 #include "static_routes.h"
 #include "static_zebra.h"
 
 DEFINE_MTYPE_STATIC(STATIC, STATIC_RTABLE_INFO, "Static Route Table Info");
 
-static void zebra_stable_node_cleanup(struct route_table *table,
-                                     struct route_node *node)
-{
-       struct static_nexthop *nh;
-       struct static_path *pn;
-       struct static_route_info *si;
-       struct route_table *src_table;
-       struct route_node *src_node;
-       struct static_path *src_pn;
-       struct static_route_info *src_si;
-
-       si = node->info;
-
-       if (si) {
-               frr_each_safe(static_path_list, &si->path_list, pn) {
-                       frr_each_safe(static_nexthop_list, &pn->nexthop_list,
-                                      nh) {
-                               static_nexthop_list_del(&pn->nexthop_list, nh);
-                               XFREE(MTYPE_STATIC_NEXTHOP, nh);
-                       }
-                       static_path_list_del(&si->path_list, pn);
-                       XFREE(MTYPE_STATIC_PATH, pn);
-               }
-
-               /* clean up for dst table */
-               src_table = srcdest_srcnode_table(node);
-               if (src_table) {
-                       /* This means the route_node is part of the top
-                        * hierarchy and refers to a destination prefix.
-                        */
-                       for (src_node = route_top(src_table); src_node;
-                            src_node = route_next(src_node)) {
-                               src_si = src_node->info;
-
-                               frr_each_safe(static_path_list,
-                                             &src_si->path_list, src_pn) {
-                                       frr_each_safe(static_nexthop_list,
-                                                     &src_pn->nexthop_list,
-                                                     nh) {
-                                               static_nexthop_list_del(
-                                                       &src_pn->nexthop_list,
-                                                       nh);
-                                               XFREE(MTYPE_STATIC_NEXTHOP, nh);
-                                       }
-                                       static_path_list_del(&src_si->path_list,
-                                                            src_pn);
-                                       XFREE(MTYPE_STATIC_PATH, src_pn);
-                               }
-
-                               XFREE(MTYPE_STATIC_ROUTE, src_node->info);
-                       }
-               }
-
-               XFREE(MTYPE_STATIC_ROUTE, node->info);
-       }
-}
-
 static struct static_vrf *static_vrf_alloc(void)
 {
        struct route_table *table;
index dd03f8377885be8a8a257dc8257e798c27d5c0ef..33a2728cd0044c9b73d1b95e45bed1d73f7254dd 100644 (file)
@@ -33,7 +33,6 @@
 #include "northbound_cli.h"
 
 #include "static_vrf.h"
-#include "static_memory.h"
 #include "static_vty.h"
 #include "static_routes.h"
 #include "static_debug.h"
index 9c630e8f5ff6db4e0eb874759a88e29a192abd38..a0ae2569cbf65e30ba4dca30e239306d78a0615c 100644 (file)
@@ -13,7 +13,6 @@ endif
 
 staticd_libstatic_a_SOURCES = \
        staticd/static_debug.c \
-       staticd/static_memory.c \
        staticd/static_nht.c \
        staticd/static_routes.c \
        staticd/static_zebra.c \
@@ -25,7 +24,6 @@ staticd_libstatic_a_SOURCES = \
 
 noinst_HEADERS += \
        staticd/static_debug.h \
-       staticd/static_memory.h \
        staticd/static_nht.h \
        staticd/static_zebra.h \
        staticd/static_routes.h \
index 391ccd9268af72002311a4cfca762df296a3cdc9..fde0d6af520f63a8a1503a67e6e5c9388927be97 100644 (file)
 #include "lib/zassert.h"
 #include "lib/zclient.h"
 
-PREDECL_RBTREE_UNIQ(footree)
+PREDECL_RBTREE_UNIQ(footree);
 struct foo {
        int dummy;
        struct footree_item item;
@@ -116,7 +116,7 @@ static int foocmp(const struct foo *a, const struct foo *b)
 {
        return memcmp(&a->dummy, &b->dummy, sizeof(a->dummy));
 }
-DECLARE_RBTREE_UNIQ(footree, struct foo, item, foocmp)
+DECLARE_RBTREE_UNIQ(footree, struct foo, item, foocmp);
 
 int main(int argc, char **argv)
 {
index 40837b4722835e8c9abd123fa23ddac9871a6a45..83dd9f2c590457023b43b84c8adc398bbe4dc868 100644 (file)
 
 static struct seqlock sqlo;
 
-PREDECL_ATOMLIST(alist)
-PREDECL_ATOMSORT_UNIQ(asort)
+PREDECL_ATOMLIST(alist);
+PREDECL_ATOMSORT_UNIQ(asort);
 struct item {
        uint64_t val1;
        struct alist_item chain;
        struct asort_item sortc;
        uint64_t val2;
 };
-DECLARE_ATOMLIST(alist, struct item, chain)
+DECLARE_ATOMLIST(alist, struct item, chain);
 
 static int icmp(const struct item *a, const struct item *b);
-DECLARE_ATOMSORT_UNIQ(asort, struct item, sortc, icmp)
+DECLARE_ATOMSORT_UNIQ(asort, struct item, sortc, icmp);
 
 static int icmp(const struct item *a, const struct item *b)
 {
index cffd52ee021190fade2442c551938a46522aaf1d..00aa7b80dd0e65aa7431918f47a6ef98f9243165 100644 (file)
@@ -37,9 +37,9 @@
 
 #include "tests.h"
 
-DEFINE_MGROUP(TEST_HEAVYWQ, "heavy-wq test")
-DEFINE_MTYPE_STATIC(TEST_HEAVYWQ, WQ_NODE, "heavy_wq_node")
-DEFINE_MTYPE_STATIC(TEST_HEAVYWQ, WQ_NODE_STR, "heavy_wq_node->str")
+DEFINE_MGROUP(TEST_HEAVYWQ, "heavy-wq test");
+DEFINE_MTYPE_STATIC(TEST_HEAVYWQ, WQ_NODE, "heavy_wq_node");
+DEFINE_MTYPE_STATIC(TEST_HEAVYWQ, WQ_NODE_STR, "heavy_wq_node->str");
 
 extern struct thread_master *master;
 static struct work_queue *heavy_wq;
index 84be9cb769c6771c530ecb382db39daefe46ef0e..9f04304a2bd2e4a3b5a51acf715dedc5185db900 100644 (file)
@@ -19,8 +19,8 @@
 #include <zebra.h>
 #include <memory.h>
 
-DEFINE_MGROUP(TEST_MEMORY, "memory test")
-DEFINE_MTYPE_STATIC(TEST_MEMORY, TEST, "generic test mtype")
+DEFINE_MGROUP(TEST_MEMORY, "memory test");
+DEFINE_MTYPE_STATIC(TEST_MEMORY, TEST, "generic test mtype");
 
 /* Memory torture tests
  *
index f86cadd39858bbea772f055488bc961b04348eae..32331c14a03788006a7e6348114a8c998717e773 100644 (file)
@@ -47,7 +47,7 @@
 #define REALTYPE TYPE
 #endif
 
-PREDECL(REALTYPE, list)
+PREDECL(REALTYPE, list);
 struct item {
        uint64_t val;
        struct list_item itm;
@@ -59,7 +59,7 @@ static int list_cmp(const struct item *a, const struct item *b);
 
 #if IS_HASH(REALTYPE)
 static uint32_t list_hash(const struct item *a);
-DECLARE(REALTYPE, list, struct item, itm, list_cmp, list_hash)
+DECLARE(REALTYPE, list, struct item, itm, list_cmp, list_hash);
 
 static uint32_t list_hash(const struct item *a)
 {
@@ -72,7 +72,7 @@ static uint32_t list_hash(const struct item *a)
 }
 
 #else
-DECLARE(REALTYPE, list, struct item, itm, list_cmp)
+DECLARE(REALTYPE, list, struct item, itm, list_cmp);
 #endif
 
 static int list_cmp(const struct item *a, const struct item *b)
@@ -85,7 +85,7 @@ static int list_cmp(const struct item *a, const struct item *b)
 }
 
 #else /* !IS_SORTED */
-DECLARE(REALTYPE, list, struct item, itm)
+DECLARE(REALTYPE, list, struct item, itm);
 #endif
 
 #define NITEM 10000
index 700950de1fcd15823a98e9cd183ac05cddb9c06c..aa179141af0e7dbf105d4d5563959df9e6916f5b 100644 (file)
@@ -127,7 +127,7 @@ bool (*tests[])(void) = {
        test_logcall,
 };
 
-XREF_SETUP()
+XREF_SETUP();
 
 int main(int argc, char **argv)
 {
index fe330d98d4b6af6addee08b441e613b7737059e6..65195aa3e1be361eed5ed94d5e3ecc22b8904e88 100644 (file)
@@ -22,8 +22,8 @@
 #include "sigevent.h"
 #include "frr_zmq.h"
 
-DEFINE_MTYPE_STATIC(LIB, TESTBUF, "zmq test buffer")
-DEFINE_MTYPE_STATIC(LIB, ZMQMSG, "zmq message")
+DEFINE_MTYPE_STATIC(LIB, TESTBUF, "zmq test buffer");
+DEFINE_MTYPE_STATIC(LIB, ZMQMSG, "zmq message");
 
 static struct thread_master *master;
 
index a85f7e14eceb5a0c210815c3f018920132c83bdd..7808c3d47d3ab3798d81c9f29082e0d665f6539c 100644 (file)
@@ -23,9 +23,9 @@
 #include "common.h"
 
 DECLARE_RBTREE_UNIQ(p_spaces, struct p_space, p_spaces_item,
-                   p_spaces_compare_func)
+                   p_spaces_compare_func);
 DECLARE_RBTREE_UNIQ(q_spaces, struct q_space, q_spaces_item,
-                   q_spaces_compare_func)
+                   q_spaces_compare_func);
 
 static struct ospf *test_init(struct ospf_test_node *root)
 {
index b7042d84c6a02f030d71af920e084512b39235ec..c9110d2db9268a451c686b0a5c69f7dbac70b91c 100644 (file)
@@ -23,6 +23,7 @@ RUN export DEBIAN_FRONTEND=noninteractive \
         libreadline-dev \
         libc-ares-dev \
         libcap-dev \
+        libelf-dev \
         man \
         mininet \
         pkg-config \
index d1927ae49a1428ae40bdc70443c882f3d6b1fdb1..b436d5562e35c30f044d2f11e9774d42decce88d 100644 (file)
@@ -8,9 +8,10 @@
         "remote-diagnostic":"ok",
         "receive-interval":300,
         "transmit-interval":300,
-        "echo-interval":0,
+        "echo-receive-interval":50,
+        "echo-transmit-interval":0,
         "remote-receive-interval":300,
         "remote-transmit-interval":300,
-        "remote-echo-interval":50
+        "remote-echo-receive-interval":50
     }
 ]
index 25b47f18ecf4a2c7a0d97db337b575510999acc5..c7c7b96ee74d0fdc3ff973e79b446f284880a9b5 100644 (file)
@@ -6,9 +6,10 @@
         "status":"up",
         "receive-interval":300,
         "transmit-interval":300,
-        "echo-interval":0,
+        "echo-receive-interval":50,
+        "echo-transmit-interval":0,
         "remote-receive-interval":300,
         "remote-transmit-interval":300,
-        "remote-echo-interval":50
+        "remote-echo-receive-interval":50
     }
 ]
index 5193f2a6e25f824357033d5aa29541af6848fffa..fc9e1453401749b430db719fec6fcb1d3d467661 100644 (file)
@@ -8,9 +8,10 @@
         "remote-diagnostic":"ok",
         "receive-interval":300,
         "transmit-interval":300,
-        "echo-interval":0,
+        "echo-receive-interval":50,
+        "echo-transmit-interval":0,
         "remote-receive-interval":300,
         "remote-transmit-interval":300,
-        "remote-echo-interval":50
+        "remote-echo-receive-interval":50
     }
 ]
index 9e4bd2633f47362676aa745caa7bb8fce6108fa3..620c6ddcd47ff8d410cd37c4fafbaa487aa606c0 100644 (file)
@@ -6,9 +6,10 @@
         "status":"down",
         "receive-interval":300,
         "transmit-interval":300,
-        "echo-interval":0,
+        "echo-receive-interval":50,
+        "echo-transmit-interval":0,
         "remote-receive-interval":300,
         "remote-transmit-interval":300,
-        "remote-echo-interval":50
+        "remote-echo-receive-interval":50
     }
 ]
index bab24c4fa0c17205bbae044f4f3456b3298accbd..86a7e5139c4e27535c87f2e04dd1d1265fe308bc 100644 (file)
@@ -6,14 +6,14 @@
         "interface": "r1-eth1",
         "multihop": false,
         "peer": "172.16.100.2",
-        "receive-interval": 300,
+        "receive-interval": 800,
         "remote-detect-multiplier": 3,
         "remote-diagnostic": "ok",
         "remote-id": "*",
         "remote-receive-interval": 300,
         "remote-transmit-interval": 300,
         "status": "up",
-        "transmit-interval": 300,
+        "transmit-interval": 800,
         "uptime": "*",
         "vrf": "default"
     },
index 4d636ab0520b250b97aaf2bff0b1fd4b15a99cb8..688f2e839c4c785de55b6b200a1f00a8a4263573 100644 (file)
@@ -6,6 +6,7 @@ bfd
  profile slowtx
   receive-interval 800
   transmit-interval 800
+  echo receive-interval 400
  !
  peer 172.16.0.1 interface r1-eth0
   profile slowtx
index 4798d17c40e45706d3740704df883b0db24a3fc4..fcea5d48fcc697a05601ffd50047e0e8b657d717 100644 (file)
@@ -2,7 +2,7 @@ interface r1-eth1
  ip ospf area 0
  ip ospf hello-interval 2
  ip ospf dead-interval 10
- ip ospf bfd
+ ip ospf bfd profile slowtx
 !
 router ospf
  ospf router-id 10.254.254.1
index 3df9ec9c9de3d22c6d9ee1a0be80014794126bdb..503f776aec9bacdd85836fbff2d2bfe26a56d1b6 100644 (file)
@@ -12,6 +12,7 @@
         "remote-id": "*",
         "remote-receive-interval": 800,
         "remote-transmit-interval": 800,
+        "remote-echo-receive-interval": 400,
         "status": "up",
         "transmit-interval": 800,
         "uptime": "*",
@@ -27,7 +28,7 @@
         "receive-interval": 250,
         "remote-detect-multiplier": 3,
         "remote-diagnostic": "ok",
-        "remote-echo-interval": 50,
+        "remote-echo-receive-interval": 50,
         "remote-id": "*",
         "remote-receive-interval": 300,
         "remote-transmit-interval": 300,
index 23a39a6ee06623c024ed922afbbb1399b8812d17..700c46ba1e362144161f768fe24904c7dbab8b50 100644 (file)
@@ -10,6 +10,7 @@ bfd
  profile fasttx
   receive-interval 250
   transmit-interval 250
+  echo receive-interval disabled
  !
  peer 172.16.0.2 interface r2-eth0
   profile slowtx
index d2d0c601c3e47cb096e8ece1299b34b3c53dc508..d987a0ae7d087a3c6c8b8a2af2c84e0469a939ee 100644 (file)
@@ -12,6 +12,7 @@
         "remote-id": "*",
         "remote-receive-interval": 250,
         "remote-transmit-interval": 250,
+        "remote-echo-receive-interval": 0,
         "status": "up",
         "transmit-interval": 300,
         "uptime": "*",
index 2c2e136abf2783523f000c0c5c05a00451550fe7..c73296ac971b2f718800853c8eba6e34860a3f7d 100644 (file)
@@ -29,7 +29,7 @@
         "receive-interval": 300,
         "remote-detect-multiplier": 3,
         "remote-diagnostic": "ok",
-        "remote-echo-interval": 50,
+        "remote-echo-receive-interval": 50,
         "remote-id": "*",
         "remote-receive-interval": 300,
         "remote-transmit-interval": 300,
index 4e6fa869ba1b0703ae9ed95bb1c198b8e8f4ed30..ec973eb3659d1d50685951878a32ff7a0a04142d 100644 (file)
@@ -10,8 +10,8 @@
         "remote-detect-multiplier": 3,
         "remote-diagnostic": "ok",
         "remote-id": "*",
-        "remote-receive-interval": 300,
-        "remote-transmit-interval": 300,
+        "remote-receive-interval": 800,
+        "remote-transmit-interval": 800,
         "status": "up",
         "transmit-interval": 300,
         "uptime": "*",
index 5035d643c5142150f781fd1782e109e6fb30856c..267459c7a87e9ad9fc4d24851e9215db78b9ef68 100644 (file)
@@ -4,7 +4,7 @@
     "status": "up"
   },
   {
-    "remote-echo-interval": 100,
+    "remote-echo-receive-interval": 100,
     "peer": "192.168.1.1",
     "status": "up"
   },
index b14351cd81cf12132ac53344609a1fc77c418a24..9bce991d0d0068a0b145b426691a90f0885b6aee 100644 (file)
@@ -8,10 +8,11 @@
         "remote-diagnostic":"ok",
         "receive-interval":300,
         "transmit-interval":300,
-        "echo-interval":0,
+        "echo-receive-interval":50,
+        "echo-transmit-interval":0,
         "remote-receive-interval":300,
         "remote-transmit-interval":300,
-        "remote-echo-interval":50
+        "remote-echo-receive-interval":50
     },
     {
         "multihop":false,
         "remote-diagnostic":"ok",
         "receive-interval":300,
         "transmit-interval":300,
-        "echo-interval":0,
+        "echo-receive-interval":50,
+        "echo-transmit-interval":0,
         "remote-receive-interval":300,
         "remote-transmit-interval":300,
-        "remote-echo-interval":50
+        "remote-echo-receive-interval":50
     }
 ]
index 29075fcc807794203149c1cdb85eefff44c78cbd..ec2135ce374489f1be5eef374ad1ffeafc624568 100644 (file)
@@ -3,39 +3,42 @@
     "status": "up",
     "transmit-interval": 300,
     "remote-receive-interval": 300,
-    "echo-interval": 0,
+    "echo-receive-interval": 50,
+    "echo-transmit-interval": 0,
     "diagnostic": "ok",
     "multihop": false,
     "interface": "r2-eth0",
     "remote-transmit-interval": 300,
     "receive-interval": 300,
-    "remote-echo-interval": 50,
+    "remote-echo-receive-interval": 50,
     "remote-diagnostic": "ok"
   },
   {
     "status": "up",
     "transmit-interval": 300,
     "remote-receive-interval": 300,
-    "echo-interval": 0,
+    "echo-receive-interval": 50,
+    "echo-transmit-interval": 0,
     "diagnostic": "ok",
     "multihop": false,
     "interface": "r2-eth2",
     "remote-transmit-interval": 300,
     "receive-interval": 300,
-    "remote-echo-interval": 50,
+    "remote-echo-receive-interval": 50,
     "remote-diagnostic": "ok"
   },
   {
     "status": "up",
     "transmit-interval": 300,
     "remote-receive-interval": 300,
-    "echo-interval": 0,
+    "echo-receive-interval": 50,
+    "echo-transmit-interval": 0,
     "diagnostic": "ok",
     "multihop": false,
     "interface": "r2-eth1",
     "remote-transmit-interval": 300,
     "receive-interval": 300,
-    "remote-echo-interval": 50,
+    "remote-echo-receive-interval": 50,
     "remote-diagnostic": "ok",
     "peer": "10.0.3.1"
   }
index 6698bff201bce326c27192bfb0990abb7b1145a3..c19c98033880ff75b11d945468df6a55c24a1e3e 100644 (file)
@@ -3,13 +3,14 @@
     "status": "up",
     "transmit-interval": 300,
     "remote-receive-interval": 300,
-    "echo-interval": 0,
+    "echo-receive-interval": 50,
+    "echo-transmit-interval": 0,
     "diagnostic": "ok",
     "multihop": false,
     "interface": "r3-eth0",
     "remote-transmit-interval": 300,
     "receive-interval": 300,
-    "remote-echo-interval": 50,
+    "remote-echo-receive-interval": 50,
     "remote-diagnostic": "ok",
     "peer": "10.0.3.2"
   }
index 83101eb47f347d1b3527b4b8562ff631f2a08176..dd26b9b580ba9af1ccd5bce7e84168e2edd864dd 100644 (file)
@@ -8,10 +8,11 @@
         "remote-diagnostic":"ok",
         "receive-interval":300,
         "transmit-interval":300,
-        "echo-interval":0,
+        "echo-receive-interval": 50,
+        "echo-transmit-interval":0,
         "remote-receive-interval":300,
         "remote-transmit-interval":300,
-        "remote-echo-interval":50
+        "remote-echo-receive-interval":50
     },
     {
         "multihop":false,
         "remote-diagnostic":"ok",
         "receive-interval":300,
         "transmit-interval":300,
-        "echo-interval":0,
+        "echo-receive-interval": 50,
+        "echo-transmit-interval":0,
         "remote-receive-interval":300,
         "remote-transmit-interval":300,
-        "remote-echo-interval":50
+        "remote-echo-receive-interval":50
     }
 ]
index 56205d538b9c389806253844d13b60c1880f0f28..f8a354fc209e5b3ca11a8dc5995dff06dd5e6e87 100644 (file)
@@ -2,7 +2,8 @@
     {
         "detect-multiplier": 3,
         "diagnostic": "ok",
-        "echo-interval": 0,
+        "echo-receive-interval": 50,
+        "echo-transmit-interval": 0,
         "id": "*",
         "local": "2001:db8:1::1",
         "minimum-ttl": 253,
@@ -12,7 +13,7 @@
         "receive-interval": 2000,
         "remote-detect-multiplier": 3,
         "remote-diagnostic": "ok",
-        "remote-echo-interval": 50,
+        "remote-echo-receive-interval": 50,
         "remote-id": "*",
         "remote-receive-interval": 2000,
         "remote-transmit-interval": 2000,
@@ -24,7 +25,8 @@
     {
         "detect-multiplier": 3,
         "diagnostic": "ok",
-        "echo-interval": 0,
+        "echo-receive-interval": 50,
+        "echo-transmit-interval": 0,
         "id": "*",
         "interface": "r1-eth0",
         "local": "2001:db8:1::1",
@@ -34,7 +36,7 @@
         "receive-interval": 600,
         "remote-detect-multiplier": 3,
         "remote-diagnostic": "ok",
-        "remote-echo-interval": 50,
+        "remote-echo-receive-interval": 50,
         "remote-id": "*",
         "remote-receive-interval": 600,
         "remote-transmit-interval": 600,
@@ -46,7 +48,8 @@
     {
         "detect-multiplier": 3,
         "diagnostic": "ok",
-        "echo-interval": 0,
+        "echo-receive-interval": 50,
+        "echo-transmit-interval": 0,
         "id": "*",
         "local": "192.168.1.1",
         "minimum-ttl": 254,
@@ -56,7 +59,7 @@
         "receive-interval": 2000,
         "remote-detect-multiplier": 3,
         "remote-diagnostic": "ok",
-        "remote-echo-interval": 50,
+        "remote-echo-receive-interval": 50,
         "remote-id": "*",
         "remote-receive-interval": 2000,
         "remote-transmit-interval": 2000,
index cb8985b13e5f5b8b09558b7c9d214e5f47ba7f53..786d66dbe3a4e0a3236a45ccac5407e70c29f721 100644 (file)
@@ -2,7 +2,8 @@
     {
         "detect-multiplier": 3,
         "diagnostic": "ok",
-        "echo-interval": 0,
+        "echo-receive-interval": 50,
+        "echo-transmit-interval": 0,
         "id": "*",
         "interface": "r2-eth0",
         "local": "2001:db8:1::2",
@@ -12,7 +13,7 @@
         "receive-interval": 600,
         "remote-detect-multiplier": 3,
         "remote-diagnostic": "ok",
-        "remote-echo-interval": 50,
+        "remote-echo-receive-interval": 50,
         "remote-id": "*",
         "remote-receive-interval": 600,
         "remote-transmit-interval": 600,
@@ -24,7 +25,8 @@
     {
         "detect-multiplier": 3,
         "diagnostic": "ok",
-        "echo-interval": 0,
+        "echo-receive-interval": 50,
+        "echo-transmit-interval": 0,
         "id": "*",
         "interface": "r2-eth1",
         "local": "2001:db8:2::2",
@@ -34,7 +36,7 @@
         "receive-interval": 2000,
         "remote-detect-multiplier": 3,
         "remote-diagnostic": "ok",
-        "remote-echo-interval": 50,
+        "remote-echo-receive-interval": 50,
         "remote-id": "*",
         "remote-receive-interval": 2000,
         "remote-transmit-interval": 2000,
index 8be35fd08427b5a8c64add32485e70381dbc1650..1f58663a4ef784bdac4ec6e834f0bd35d020c27f 100644 (file)
@@ -2,7 +2,8 @@
     {
         "detect-multiplier": 3,
         "diagnostic": "ok",
-        "echo-interval": 0,
+        "echo-receive-interval": 50,
+        "echo-transmit-interval": 0,
         "id": "*",
         "interface": "r3-eth1",
         "local": "2001:db8:3::2",
@@ -12,7 +13,7 @@
         "receive-interval": 2000,
         "remote-detect-multiplier": 3,
         "remote-diagnostic": "ok",
-        "remote-echo-interval": 50,
+        "remote-echo-receive-interval": 50,
         "remote-id": "*",
         "remote-receive-interval": 2000,
         "remote-transmit-interval": 2000,
@@ -24,7 +25,8 @@
     {
         "detect-multiplier": 3,
         "diagnostic": "ok",
-        "echo-interval": 0,
+        "echo-receive-interval": 50,
+        "echo-transmit-interval": 0,
         "id": "*",
         "interface": "r3-eth0",
         "local": "2001:db8:2::1",
@@ -34,7 +36,7 @@
         "receive-interval": 2000,
         "remote-detect-multiplier": 3,
         "remote-diagnostic": "ok",
-        "remote-echo-interval": 50,
+        "remote-echo-receive-interval": 50,
         "remote-id": "*",
         "remote-receive-interval": 2000,
         "remote-transmit-interval": 2000,
@@ -46,7 +48,8 @@
     {
         "detect-multiplier": 3,
         "diagnostic": "ok",
-        "echo-interval": 0,
+        "echo-receive-interval": 50,
+        "echo-transmit-interval": 0,
         "id": "*",
         "local": "192.168.2.1",
         "minimum-ttl": 254,
@@ -56,7 +59,7 @@
         "receive-interval": 2000,
         "remote-detect-multiplier": 3,
         "remote-diagnostic": "ok",
-        "remote-echo-interval": 50,
+        "remote-echo-receive-interval": 50,
         "remote-id": "*",
         "remote-receive-interval": 2000,
         "remote-transmit-interval": 2000,
index e2e6722ef44a7827f526b65793242819a2fe89b9..5477f39120a6bfbd9611b108f887ee01ad64aeec 100644 (file)
@@ -2,7 +2,8 @@
     {
         "detect-multiplier": 3,
         "diagnostic": "ok",
-        "echo-interval": 0,
+        "echo-receive-interval": 50,
+        "echo-transmit-interval": 0,
         "id": "*",
         "local": "2001:db8:3::1",
         "minimum-ttl": 253,
@@ -12,7 +13,7 @@
         "receive-interval": 2000,
         "remote-detect-multiplier": 3,
         "remote-diagnostic": "ok",
-        "remote-echo-interval": 50,
+        "remote-echo-receive-interval": 50,
         "remote-id": "*",
         "remote-receive-interval": 2000,
         "remote-transmit-interval": 2000,
@@ -24,7 +25,8 @@
     {
         "detect-multiplier": 3,
         "diagnostic": "ok",
-        "echo-interval": 0,
+        "echo-receive-interval": 50,
+        "echo-transmit-interval": 0,
         "id": "*",
         "interface": "r4-eth0",
         "local": "2001:db8:3::1",
@@ -34,7 +36,7 @@
         "receive-interval": 2000,
         "remote-detect-multiplier": 3,
         "remote-diagnostic": "ok",
-        "remote-echo-interval": 50,
+        "remote-echo-receive-interval": 50,
         "remote-id": "*",
         "remote-receive-interval": 2000,
         "remote-transmit-interval": 2000,
index 5035d643c5142150f781fd1782e109e6fb30856c..267459c7a87e9ad9fc4d24851e9215db78b9ef68 100644 (file)
@@ -4,7 +4,7 @@
     "status": "up"
   },
   {
-    "remote-echo-interval": 100,
+    "remote-echo-receive-interval": 100,
     "peer": "192.168.1.1",
     "status": "up"
   },
diff --git a/tests/topotests/bgp-default-ipv4-ipv6-unicast/__init__.py b/tests/topotests/bgp-default-ipv4-ipv6-unicast/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/topotests/bgp-default-ipv4-ipv6-unicast/r1/bgpd.conf b/tests/topotests/bgp-default-ipv4-ipv6-unicast/r1/bgpd.conf
new file mode 100644 (file)
index 0000000..bf39152
--- /dev/null
@@ -0,0 +1,3 @@
+!
+router bgp 65001
+!
diff --git a/tests/topotests/bgp-default-ipv4-ipv6-unicast/r1/zebra.conf b/tests/topotests/bgp-default-ipv4-ipv6-unicast/r1/zebra.conf
new file mode 100644 (file)
index 0000000..6977651
--- /dev/null
@@ -0,0 +1,7 @@
+!
+interface r1-eth0
+ ip address 192.168.255.1/24
+!
+ip forwarding
+!
+
diff --git a/tests/topotests/bgp-default-ipv4-ipv6-unicast/r2/bgpd.conf b/tests/topotests/bgp-default-ipv4-ipv6-unicast/r2/bgpd.conf
new file mode 100644 (file)
index 0000000..abbd1b8
--- /dev/null
@@ -0,0 +1,5 @@
+!
+router bgp 65001
+ no bgp default ipv4-unicast
+ bgp default ipv6-unicast
+!
diff --git a/tests/topotests/bgp-default-ipv4-ipv6-unicast/r2/zebra.conf b/tests/topotests/bgp-default-ipv4-ipv6-unicast/r2/zebra.conf
new file mode 100644 (file)
index 0000000..606c17b
--- /dev/null
@@ -0,0 +1,6 @@
+!
+interface r2-eth0
+ ip address 192.168.255.2/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp-default-ipv4-ipv6-unicast/r3/bgpd.conf b/tests/topotests/bgp-default-ipv4-ipv6-unicast/r3/bgpd.conf
new file mode 100644 (file)
index 0000000..a405c04
--- /dev/null
@@ -0,0 +1,4 @@
+!
+router bgp 65001
+ bgp default ipv6-unicast
+!
diff --git a/tests/topotests/bgp-default-ipv4-ipv6-unicast/r3/zebra.conf b/tests/topotests/bgp-default-ipv4-ipv6-unicast/r3/zebra.conf
new file mode 100644 (file)
index 0000000..e9fdfb7
--- /dev/null
@@ -0,0 +1,6 @@
+!
+interface r3-eth0
+ ip address 192.168.255.3/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp-default-ipv4-ipv6-unicast/test_bgp-default-ipv4-ipv6-unicast.py b/tests/topotests/bgp-default-ipv4-ipv6-unicast/test_bgp-default-ipv4-ipv6-unicast.py
new file mode 100644 (file)
index 0000000..c1dbf0e
--- /dev/null
@@ -0,0 +1,140 @@
+#!/usr/bin/env python
+
+#
+# Copyright (c) 2021 by
+# Donatas Abraitis <donatas.abraitis@gmail.com>
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+Test if `bgp default ipv4-unicast` and `bgp default ipv6-unicast`
+commands work as expected.
+
+STEP 1: 'Check if neighbor 192.168.255.254 is enabled for ipv4 address-family only'
+STEP 2: 'Check if neighbor 192.168.255.254 is enabled for ipv6 address-family only'
+STEP 3: 'Check if neighbor 192.168.255.254 is enabled for ipv4 and ipv6 address-families'
+"""
+
+import os
+import sys
+import json
+import pytest
+import functools
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+from mininet.topo import Topo
+from lib.common_config import step
+
+
+class TemplateTopo(Topo):
+    def build(self, *_args, **_opts):
+        tgen = get_topogen(self)
+
+        for routern in range(1, 5):
+            tgen.add_router("r{}".format(routern))
+
+        switch = tgen.add_switch("s1")
+        switch.add_link(tgen.gears["r1"])
+        switch.add_link(tgen.gears["r2"])
+        switch.add_link(tgen.gears["r3"])
+        switch.add_link(tgen.gears["r4"])
+
+
+def setup_module(mod):
+    tgen = Topogen(TemplateTopo, mod.__name__)
+    tgen.start_topology()
+
+    router_list = tgen.routers()
+
+    for i, (rname, router) in enumerate(router_list.items(), 1):
+        router.load_config(
+            TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
+        )
+        router.load_config(
+            TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
+        )
+
+    tgen.start_router()
+
+
+def teardown_module(mod):
+    tgen = get_topogen()
+    tgen.stop_topology()
+
+
+def test_bgp_default_ipv4_ipv6_unicast():
+    tgen = get_topogen()
+
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    step("Check if neighbor 192.168.255.254 is enabled for ipv4 address-family only")
+
+    def _bgp_neighbor_ipv4_af_only():
+        tgen.gears["r1"].vtysh_cmd(
+            "conf t\nrouter bgp\nneighbor 192.168.255.254 remote-as external"
+        )
+
+        output = json.loads(tgen.gears["r1"].vtysh_cmd("show bgp summary json"))
+
+        if "ipv4Unicast" in output and "ipv6Unicast" not in output:
+            return True
+        return False
+
+    assert _bgp_neighbor_ipv4_af_only() == True
+
+    step("Check if neighbor 192.168.255.254 is enabled for ipv6 address-family only")
+
+    def _bgp_neighbor_ipv6_af_only():
+        tgen.gears["r2"].vtysh_cmd(
+            "conf t\nrouter bgp\nneighbor 192.168.255.254 remote-as external"
+        )
+
+        output = json.loads(tgen.gears["r2"].vtysh_cmd("show bgp summary json"))
+
+        if "ipv4Unicast" not in output and "ipv6Unicast" in output:
+            return True
+        return False
+
+    assert _bgp_neighbor_ipv6_af_only() == True
+
+    step(
+        "Check if neighbor 192.168.255.254 is enabled for ipv4 and ipv6 address-families"
+    )
+
+    def _bgp_neighbor_ipv4_and_ipv6_af():
+        tgen.gears["r3"].vtysh_cmd(
+            "conf t\nrouter bgp\nneighbor 192.168.255.254 remote-as external"
+        )
+
+        output = json.loads(tgen.gears["r3"].vtysh_cmd("show bgp summary json"))
+
+        if "ipv4Unicast" in output and "ipv6Unicast" in output:
+            return True
+        return False
+
+    assert _bgp_neighbor_ipv4_and_ipv6_af() == True
+
+
+if __name__ == "__main__":
+    args = ["-s"] + sys.argv[1:]
+    sys.exit(pytest.main(args))
index 89f5554d418048b99ac1840ac32defe67665b580..db4eab9d3d9f115d778001e4d42e48607bfe422b 100755 (executable)
@@ -505,10 +505,8 @@ def test_r1_mplsvpn_VrfTable():
     associated_int = r1_snmp.get(
         "mplsL3VpnVrfAssociatedInterfaces.{}".format(snmp_str_to_oid("VRF-a"))
     )
-    assertmsg = (
-        "mplsL3VpnVrfAssociatedInterfaces incorrect should be 3 value {}".format(
-            associated_int
-        )
+    assertmsg = "mplsL3VpnVrfAssociatedInterfaces incorrect should be 3 value {}".format(
+        associated_int
     )
 
     assert associated_int == "3", assertmsg
@@ -634,7 +632,6 @@ rte_table_test = {
         "C0 A8 C8 0A",
         '""',
     ],
-    "mplsL3VpnVrfRteInetCidrIfIndex": ["5", "6", "4", "5", "0", "6", "0"],
     "mplsL3VpnVrfRteInetCidrType": [
         "local(3)",
         "local(3)",
@@ -732,8 +729,24 @@ def test_r1_mplsvpn_rte_table():
             )
         if passed:
             break
+    # generate ifindex row grabbing ifindices from vtysh
+    if passed:
+        ifindex_row = [
+            router_interface_get_ifindex(r1r, "eth3"),
+            router_interface_get_ifindex(r1r, "eth4"),
+            router_interface_get_ifindex(r1r, "eth2"),
+            router_interface_get_ifindex(r1r, "eth3"),
+            "0",
+            router_interface_get_ifindex(r1r, "eth4"),
+            "0",
+        ]
+        if not r1_snmp.test_oid_walk(
+            "mplsL3VpnVrfRteInetCidrIfIndex", ifindex_row, oid_list
+        ):
+            passed = False
+
     print("passed {}".format(passed))
-    assert passed, assertmsg
+    assert passed, assertmsg
 
 
 def test_memory_leak():
index ac7ee44b25616ae459a005fe526dd70818880694..464d6eb475ccf3f81622711c12f9344ce8fe904a 100644 (file)
@@ -115,7 +115,7 @@ sys.path.append(os.path.join(CWD, "../lib/"))
 # Import topogen and topotest helpers
 from lib.topogen import Topogen, get_topogen
 from mininet.topo import Topo
-
+from lib.topotest import iproute2_is_vrf_capable
 from lib.common_config import (
     step,
     verify_rib,
@@ -215,6 +215,10 @@ def setup_module(mod):
     if result is not True:
         pytest.skip("Kernel requirements are not met")
 
+    # iproute2 needs to support VRFs for this suite to run.
+    if not iproute2_is_vrf_capable():
+        pytest.skip("Installed iproute2 version does not support VRFs")
+
     testsuite_run_time = time.asctime(time.localtime(time.time()))
     logger.info("Testsuite start time: {}".format(testsuite_run_time))
     logger.info("=" * 40)
index c6e1792e8406f5b877f36fc0ff2d2cb8f7a27224..10cf1c6ae8760c839444f6e33d64c6164a14935e 100644 (file)
@@ -71,7 +71,7 @@ sys.path.append(os.path.join(CWD, "../lib/"))
 # Import topogen and topotest helpers
 from lib.topogen import Topogen, get_topogen
 from mininet.topo import Topo
-
+from lib.topotest import iproute2_is_vrf_capable
 from lib.common_config import (
     step,
     verify_rib,
@@ -164,6 +164,10 @@ def setup_module(mod):
     if result is not True:
         pytest.skip("Kernel requirements are not met")
 
+    # iproute2 needs to support VRFs for this suite to run.
+    if not iproute2_is_vrf_capable():
+        pytest.skip("Installed iproute2 version does not support VRFs")
+
     testsuite_run_time = time.asctime(time.localtime(time.time()))
     logger.info("Testsuite start time: {}".format(testsuite_run_time))
     logger.info("=" * 40)
index d25856ea62eac5a84a8534066082a6d4d10d5da1..9ef59b3bbcd6e1db6b6a81cb0b80c6faf61bb5de 100755 (executable)
@@ -132,6 +132,7 @@ if [ -z "$TOPOTEST_FRR" ]; then
                echo "frr-topotests only works if you have your tree in git." >&2
                exit 1
        fi
+       git -C "$TOPOTEST_FRR" ls-files -z > "${TOPOTEST_LOGS}/git-ls-files"
 fi
 
 if [ -z "$TOPOTEST_BUILDCACHE" ]; then
index dee0ec81181fe8a4ec1d2154a47f34f1e44e033d..495beaf3cc401d9946772183f68fdf8e164955fd 100755 (executable)
@@ -34,19 +34,15 @@ CDIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
 
 if [ "${TOPOTEST_CLEAN}" != "0" ]; then
        log_info "Cleaning FRR builddir..."
-       rm -rf $FRR_SYNC_DIR $FRR_BUILD_DIR &> /dev/null
+       rm -rf $FRR_BUILD_DIR &> /dev/null
 fi
 
 log_info "Syncing FRR source with host..."
-mkdir -p $FRR_SYNC_DIR
+mkdir -p $FRR_BUILD_DIR
 rsync -a --info=progress2 \
-       --exclude '*.o' \
-       --exclude '*.lo'\
+       --from0 --files-from=/tmp/git-ls-files \
        --chown root:root \
-       $FRR_HOST_DIR/. $FRR_SYNC_DIR/
-(cd $FRR_SYNC_DIR && git clean -xdf > /dev/null)
-mkdir -p $FRR_BUILD_DIR
-rsync -a --info=progress2 --chown root:root $FRR_SYNC_DIR/. $FRR_BUILD_DIR/
+       $FRR_HOST_DIR/. $FRR_BUILD_DIR/
 
 cd "$FRR_BUILD_DIR" || \
        log_fatal "failed to find frr directory"
index acb8b55e970b63b58bdcd157bd004709ae35a135..d78d5006bc2d61b45cc8e67edc68f6ca5a9e1048 100755 (executable)
@@ -23,7 +23,6 @@
 # SOFTWARE.
 
 FRR_HOST_DIR=/root/host-frr
-FRR_SYNC_DIR=/root/persist/frr-sync
 FRR_BUILD_DIR=/root/persist/frr-build
 
 if [ ! -L "/root/frr" ]; then
index 6ab78c385e9947bd06f56ce45d7678ce286cc640..ae904ba69e831f087e93178bd90628df7216dd27 100644 (file)
@@ -40,6 +40,8 @@ sys.path.append(os.path.join(CWD, "../"))
 from lib import topotest
 from lib.topogen import Topogen, TopoRouter, get_topogen
 from lib.topolog import logger
+from lib.topotest import iproute2_is_vrf_capable
+from lib.common_config import required_linux_kernel_version
 
 from mininet.topo import Topo
 
@@ -193,18 +195,21 @@ def test_isis_route_installation():
 
 
 def test_isis_linux_route_installation():
-
-    dist = platform.dist()
-
-    if dist[1] == "16.04":
-        pytest.skip("Kernel not supported for vrf")
-
     "Check whether all expected routes are present and installed in the OS"
     tgen = get_topogen()
     # Don't run this test if we have any failure.
     if tgen.routers_have_failure():
         pytest.skip(tgen.errors)
 
+    # Required linux kernel version for this suite to run.
+    result = required_linux_kernel_version("4.15")
+    if result is not True:
+        pytest.skip("Kernel requirements are not met")
+
+    # iproute2 needs to support VRFs for this suite to run.
+    if not iproute2_is_vrf_capable():
+        pytest.skip("Installed iproute2 version does not support VRFs")
+
     logger.info("Checking routers for installed ISIS vrf routes in OS")
     # Check for routes in `ip route show vrf {}-cust1`
     for rname, router in tgen.routers().items():
@@ -236,18 +241,21 @@ def test_isis_route6_installation():
 
 
 def test_isis_linux_route6_installation():
-
-    dist = platform.dist()
-
-    if dist[1] == "16.04":
-        pytest.skip("Kernel not supported for vrf")
-
     "Check whether all expected routes are present and installed in the OS"
     tgen = get_topogen()
     # Don't run this test if we have any failure.
     if tgen.routers_have_failure():
         pytest.skip(tgen.errors)
 
+    # Required linux kernel version for this suite to run.
+    result = required_linux_kernel_version("4.15")
+    if result is not True:
+        pytest.skip("Kernel requirements are not met")
+
+    # iproute2 needs to support VRFs for this suite to run.
+    if not iproute2_is_vrf_capable():
+        pytest.skip("Installed iproute2 version does not support VRFs")
+
     logger.info("Checking routers for installed ISIS vrf IPv6 routes in OS")
     # Check for routes in `ip -6 route show vrf {}-cust1`
     for rname, router in tgen.routers().items():
index c8760f457a2cf16211164f7e33804889267a9359..4144f9b261033bf280a0ca0da89dc61159787a5d 100644 (file)
@@ -301,6 +301,41 @@ def test_r1_ldp_entity_table():
         'mplsLdpEntityRowStatus', ['createAndGo(4)'])
 
 
+def test_r1_ldp_entity_stats_table():
+    "Test mplsLdpEntityStatsTable"
+    tgen = get_topogen()
+
+    r1 = tgen.net.get("r1")
+    r1_snmp = SnmpTester(r1, "1.1.1.1", "public", "2c")
+
+    assert r1_snmp.test_oid_walk(
+        'mplsLdpEntityStatsSessionAttempts', ['0'])
+    assert r1_snmp.test_oid_walk(
+       'mplsLdpEntityStatsSessionRejectedNoHelloErrors', ['0'])
+    assert r1_snmp.test_oid_walk(
+        'mplsLdpEntityStatsSessionRejectedAdErrors', ['0'])
+    assert r1_snmp.test_oid_walk(
+        'mplsLdpEntityStatsSessionRejectedMaxPduErrors', ['0'])
+    assert r1_snmp.test_oid_walk(
+        'mplsLdpEntityStatsSessionRejectedLRErrors', ['0'])
+    assert r1_snmp.test_oid_walk(
+        'mplsLdpEntityStatsBadLdpIdentifierErrors', ['0'])
+    assert r1_snmp.test_oid_walk(
+        'mplsLdpEntityStatsBadPduLengthErrors', ['0'])
+    assert r1_snmp.test_oid_walk(
+        'mplsLdpEntityStatsBadMessageLengthErrors', ['0'])
+    assert r1_snmp.test_oid_walk(
+        'mplsLdpEntityStatsBadTlvLengthErrors', ['0'])
+    assert r1_snmp.test_oid_walk(
+        'mplsLdpEntityStatsMalformedTlvValueErrors', ['0'])
+    assert r1_snmp.test_oid_walk(
+        'mplsLdpEntityStatsKeepAliveTimerExpErrors', ['0'])
+    assert r1_snmp.test_oid_walk(
+        'mplsLdpEntityStatsShutdownReceivedNotifications', ['0'])
+    assert r1_snmp.test_oid_walk(
+        'mplsLdpEntityStatsShutdownSentNotifications', ['0'])
+
+
 def test_r1_ldp_peer_table():
     "Test mplsLdpPeerTable"
     tgen = get_topogen()
@@ -342,6 +377,19 @@ def test_r1_ldp_session_table():
         ['(0) 0:00:00.00', '(0) 0:00:00.00'])
 
 
+def test_r1_ldp_session_stats_table():
+    "Test mplsLdpSessionStatsTable"
+    tgen = get_topogen()
+
+    r1 = tgen.net.get("r1")
+    r1_snmp = SnmpTester(r1, "1.1.1.1", "public", "2c")
+
+    assert r1_snmp.test_oid_walk(
+        'mplsLdpSessionStatsUnknownMesTypeErrors', ['0', '0'])
+    assert r1_snmp.test_oid_walk(
+        'mplsLdpSessionStatsUnknownTlvErrors', ['0', '0'])
+
+
 def test_r1_ldp_hello_adjacency_table():
     "Test mplsLdpHelloAdjacencyTable"
     tgen = get_topogen()
index 55b11dab3c9a90bdc3ab1c1725f2e1e11dbc75a7..867831e11428ad90f10f26bd7ca9a9fb02f34b70 100644 (file)
@@ -43,6 +43,7 @@ from lib.common_config import (
     run_frr_cmd,
     FRRCFG_FILE,
     retry,
+    get_ipv6_linklocal_address
 )
 
 LOGDIR = "/tmp/topotests/"
@@ -446,7 +447,7 @@ def __create_bgp_unicast_neighbor(
                     cmd = "redistribute {}".format(redistribute["redist_type"])
                     redist_attr = redistribute.setdefault("attribute", None)
                     if redist_attr:
-                        if isinstance(redist_attr, dict):
+                        if type(redist_attr) is dict:
                             for key, value in redist_attr.items():
                                 cmd = "{} {} {}".format(cmd, key, value)
                         else:
@@ -528,7 +529,7 @@ def __create_l2vpn_evpn_address_family(
         if advertise_data:
             for address_type, unicast_type in advertise_data.items():
 
-                if isinstance(unicast_type, dict):
+                if type(unicast_type) is dict:
                     for key, value in unicast_type.items():
                         cmd = "advertise {} {}".format(address_type, key)
 
@@ -555,7 +556,7 @@ def __create_l2vpn_evpn_address_family(
                             "ipv4"
                         ].split("/")[0]
 
-                        if isinstance(action, dict):
+                        if type(action) is dict:
                             next_hop_self = action.setdefault("next_hop_self", None)
                             route_maps = action.setdefault("route_maps", {})
 
@@ -977,10 +978,6 @@ def modify_bgp_config_when_bgpd_down(tgen, topo, input_dict):
                 router_list[router].run(cmd)
 
     except Exception as e:
-        # handle any exception
-        logger.error("Error %s occured. Arguments %s.", e.message, e.args)
-
-        # Traceback
         errormsg = traceback.format_exc()
         logger.error(errormsg)
         return errormsg
@@ -1085,10 +1082,10 @@ def verify_bgp_convergence(tgen, topo, dut=None):
 
     logger.debug("Entering lib API: verify_bgp_convergence()")
     for router, rnode in tgen.routers().items():
-        if "bgp" not in topo["routers"][router]:
+        if dut is not None and dut != router:
             continue
 
-        if dut is not None and dut != router:
+        if "bgp" not in topo["routers"][router]:
             continue
 
         logger.info("Verifying BGP Convergence on router %s:", router)
@@ -1114,59 +1111,7 @@ def verify_bgp_convergence(tgen, topo, dut=None):
 
             # To find neighbor ip type
             bgp_addr_type = bgp_data["address_family"]
-            if "l2vpn" in bgp_addr_type:
-                total_evpn_peer = 0
-
-                if "neighbor" not in bgp_addr_type["l2vpn"]["evpn"]:
-                    continue
-
-                bgp_neighbors = bgp_addr_type["l2vpn"]["evpn"]["neighbor"]
-                total_evpn_peer += len(bgp_neighbors)
-
-                no_of_evpn_peer = 0
-                for bgp_neighbor, peer_data in bgp_neighbors.items():
-                    for _addr_type, dest_link_dict in peer_data.items():
-                        data = topo["routers"][bgp_neighbor]["links"]
-                        for dest_link in dest_link_dict.keys():
-                            if dest_link in data:
-                                peer_details = peer_data[_addr_type][dest_link]
-
-                                neighbor_ip = data[dest_link][_addr_type].split("/")[0]
-                                nh_state = None
-
-                                if (
-                                    "ipv4Unicast" in show_bgp_json[vrf]
-                                    or "ipv6Unicast" in show_bgp_json[vrf]
-                                ):
-                                    errormsg = (
-                                        "[DUT: %s] VRF: %s, "
-                                        "ipv4Unicast/ipv6Unicast"
-                                        " address-family present"
-                                        " under l2vpn" % (router, vrf)
-                                    )
-                                    return errormsg
-
-                                l2VpnEvpn_data = show_bgp_json[vrf]["l2VpnEvpn"][
-                                    "peers"
-                                ]
-                                nh_state = l2VpnEvpn_data[neighbor_ip]["state"]
-
-                                if nh_state == "Established":
-                                    no_of_evpn_peer += 1
-
-                if no_of_evpn_peer == total_evpn_peer:
-                    logger.info(
-                        "[DUT: %s] VRF: %s, BGP is Converged for " "epvn peers",
-                        router,
-                        vrf,
-                    )
-                else:
-                    errormsg = (
-                        "[DUT: %s] VRF: %s, BGP is not converged "
-                        "for evpn peers" % (router, vrf)
-                    )
-                    return errormsg
-            else:
+            if "ipv4" in bgp_addr_type or "ipv6" in bgp_addr_type:
                 for addr_type in bgp_addr_type.keys():
                     if not check_address_types(addr_type):
                         continue
@@ -1216,32 +1161,102 @@ def verify_bgp_convergence(tgen, topo, dut=None):
                                 nh_state = None
 
                                 if addr_type == "ipv4":
-                                    ipv4_data = show_bgp_json[vrf]["ipv4Unicast"][
-                                        "peers"
-                                    ]
-                                    nh_state = ipv4_data[neighbor_ip]["state"]
+                                    if "ipv4Unicast" in show_bgp_json[vrf]:
+                                        ipv4_data = show_bgp_json[vrf]["ipv4Unicast"][
+                                            "peers"
+                                        ]
+                                        nh_state = ipv4_data[neighbor_ip]["state"]
                                 else:
-                                    ipv6_data = show_bgp_json[vrf]["ipv6Unicast"][
-                                        "peers"
-                                    ]
-                                    nh_state = ipv6_data[neighbor_ip]["state"]
-
+                                    if "ipv6Unicast" in show_bgp_json[vrf]:
+                                        ipv6_data = show_bgp_json[vrf]["ipv6Unicast"][
+                                            "peers"
+                                        ]
+                                        nh_state = ipv6_data[neighbor_ip]["state"]
                                 if nh_state == "Established":
                                     no_of_peer += 1
 
-                    if no_of_peer == total_peer:
-                        logger.info(
-                            "[DUT: %s] VRF: %s, BGP is Converged for %s address-family",
-                            router,
-                            vrf,
-                            addr_type,
-                        )
+                    if "l2vpn" in bgp_addr_type:
+                        if "neighbor" not in bgp_addr_type["l2vpn"]["evpn"]:
+                            if no_of_peer == total_peer:
+                                logger.info(
+                                    "[DUT: %s] VRF: %s, BGP is Converged for %s address-family",
+                                    router,
+                                    vrf,
+                                    addr_type,
+                                )
+                            else:
+                                errormsg = (
+                                    "[DUT: %s] VRF: %s, BGP is not converged for %s address-family"
+                                    % (router, vrf, addr_type)
+                                )
+                                return errormsg
                     else:
-                        errormsg = (
-                            "[DUT: %s] VRF: %s, BGP is not converged for %s address-family"
-                            % (router, vrf, addr_type)
-                        )
-                        return errormsg
+                        if no_of_peer == total_peer:
+                            logger.info(
+                                "[DUT: %s] VRF: %s, BGP is Converged for %s address-family",
+                                router,
+                                vrf,
+                                addr_type,
+                            )
+                        else:
+                            errormsg = (
+                                "[DUT: %s] VRF: %s, BGP is not converged for %s address-family"
+                                % (router, vrf, addr_type)
+                            )
+                            return errormsg
+
+            if "l2vpn" in bgp_addr_type:
+                total_evpn_peer = 0
+
+                if "neighbor" not in bgp_addr_type["l2vpn"]["evpn"]:
+                    continue
+
+                bgp_neighbors = bgp_addr_type["l2vpn"]["evpn"]["neighbor"]
+                total_evpn_peer += len(bgp_neighbors)
+
+                no_of_evpn_peer = 0
+                for bgp_neighbor, peer_data in bgp_neighbors.items():
+                    for _addr_type, dest_link_dict in peer_data.items():
+                        data = topo["routers"][bgp_neighbor]["links"]
+                        for dest_link in dest_link_dict.keys():
+                            if dest_link in data:
+                                peer_details = peer_data[_addr_type][dest_link]
+
+                                neighbor_ip = data[dest_link][_addr_type].split("/")[0]
+                                nh_state = None
+
+                                if (
+                                    "ipv4Unicast" in show_bgp_json[vrf]
+                                    or "ipv6Unicast" in show_bgp_json[vrf]
+                                ):
+                                    errormsg = (
+                                        "[DUT: %s] VRF: %s, "
+                                        "ipv4Unicast/ipv6Unicast"
+                                        " address-family present"
+                                        " under l2vpn" % (router, vrf)
+                                    )
+                                    return errormsg
+
+                                l2VpnEvpn_data = show_bgp_json[vrf]["l2VpnEvpn"][
+                                    "peers"
+                                ]
+                                nh_state = l2VpnEvpn_data[neighbor_ip]["state"]
+
+                                if nh_state == "Established":
+                                    no_of_evpn_peer += 1
+
+                if no_of_evpn_peer == total_evpn_peer:
+                    logger.info(
+                        "[DUT: %s] VRF: %s, BGP is Converged for " "epvn peers",
+                        router,
+                        vrf,
+                    )
+                else:
+                    errormsg = (
+                        "[DUT: %s] VRF: %s, BGP is not converged "
+                        "for evpn peers" % (router, vrf)
+                    )
+                    return errormsg
 
     logger.debug("Exiting API: verify_bgp_convergence()")
     return True
@@ -1400,10 +1415,6 @@ def modify_as_number(tgen, topo, input_dict):
         create_router_bgp(tgen, new_topo)
 
     except Exception as e:
-        # handle any exception
-        logger.error("Error %s occured. Arguments %s.", e.message, e.args)
-
-        # Traceback
         errormsg = traceback.format_exc()
         logger.error(errormsg)
         return errormsg
@@ -2621,7 +2632,7 @@ def verify_bgp_rib(
                             found_routes.append(st_rt)
 
                             if next_hop and multi_nh and st_found:
-                                if not isinstance(next_hop, list):
+                                if type(next_hop) is not list:
                                     next_hop = [next_hop]
                                     list1 = next_hop
 
@@ -2661,7 +2672,7 @@ def verify_bgp_rib(
                                         nh_found = True
 
                             elif next_hop and multi_nh is None:
-                                if not isinstance(next_hop, list):
+                                if type(next_hop) is not list:
                                     next_hop = [next_hop]
                                     list1 = next_hop
                                 found_hops = [
@@ -4092,7 +4103,7 @@ def verify_attributes_for_evpn_routes(
                                 errormsg = (
                                     "[DUT: %s] RD: %s, Route : %s "
                                     "is not present in cli json "
-                                    "output " % (dut, route)
+                                    "output " % (dut, _rd, route)
                                 )
                                 return errormsg
 
@@ -4170,7 +4181,7 @@ def verify_evpn_routes(
                         return errormsg
 
                     for key, route_data_json in evpn_value_json.items():
-                        if isinstance(route_data_json, dict):
+                        if type(route_data_json) is dict:
                             rd_keys += 1
                             if prefix not in route_data_json:
                                 missing_routes[key] = prefix
@@ -4184,7 +4195,7 @@ def verify_evpn_routes(
                         return errormsg
 
                     for key, route_data_json in evpn_value_json.items():
-                        if isinstance(route_data_json, dict):
+                        if type(route_data_json) is dict:
                             if prefix not in route_data_json:
                                 continue
 
index 9174389bea5232ec06bc8be8514782d5ff4997d2..a4c98924b6e6d193c0882e2891f0a07134ef96b0 100644 (file)
@@ -1373,13 +1373,13 @@ def generate_ips(network, no_of_ips):
             if start_ip == "0.0.0.0" and mask == 0 and no_of_ips == 1:
                 ipaddress_list.append("{}/{}".format(start_ip, mask))
                 return ipaddress_list
-            start_ip = ipaddress.IPv4Address(unicode(start_ip))
+            start_ip = ipaddress.IPv4Address(frr_unicode(start_ip))
             step = 2 ** (32 - mask)
         elif addr_type == "ipv6":
             if start_ip == "0::0" and mask == 0 and no_of_ips == 1:
                 ipaddress_list.append("{}/{}".format(start_ip, mask))
                 return ipaddress_list
-            start_ip = ipaddress.IPv6Address(unicode(start_ip))
+            start_ip = ipaddress.IPv6Address(frr_unicode(start_ip))
             step = 2 ** (128 - mask)
         else:
             return []
@@ -1480,10 +1480,6 @@ def interface_status(tgen, topo, input_dict):
             load_config_to_router(tgen, router)
 
     except Exception as e:
-        # handle any exception
-        logger.error("Error %s occured. Arguments %s.", e.message, e.args)
-
-        # Traceback
         errormsg = traceback.format_exc()
         logger.error(errormsg)
         return errormsg
@@ -2442,51 +2438,6 @@ def shutdown_bringup_interface(tgen, dut, intf_name, ifaceaction=False):
     interface_set_status(router_list[dut], intf_name, ifaceaction)
 
 
-def stop_router(tgen, router):
-    """
-    Router's current config would be saved to /tmp/topotest/<suite>/<router>
-    for each daemon and router and its daemons would be stopped.
-
-    * `tgen`  : topogen object
-    * `router`: Device under test
-    """
-
-    router_list = tgen.routers()
-
-    # Saving router config to /etc/frr, which will be loaded to router
-    # when it starts
-    router_list[router].vtysh_cmd("write memory")
-
-    # Stop router
-    router_list[router].stop()
-
-
-def start_router(tgen, router):
-    """
-    Router will be started and config would be loaded from
-    /tmp/topotest/<suite>/<router> for each daemon
-
-    * `tgen`  : topogen object
-    * `router`: Device under test
-    """
-
-    logger.debug("Entering lib API: start_router")
-
-    try:
-        router_list = tgen.routers()
-
-        # Router and its daemons would be started and config would
-        #  be loaded to router for each daemon from /etc/frr
-        router_list[router].start()
-
-    except Exception as e:
-        errormsg = traceback.format_exc()
-        logger.error(errormsg)
-        return errormsg
-
-    logger.debug("Exiting lib API: start_router()")
-
-
 def addKernelRoute(
     tgen, router, intf, group_addr_range, next_hop=None, src=None, del_action=None
 ):
@@ -3754,6 +3705,43 @@ def verify_bgp_community(tgen, addr_type, router, network, input_dict=None):
     return True
 
 
+def get_ipv6_linklocal_address(topo, node, intf):
+    """
+    API to get the link local ipv6 address of a perticular interface
+
+    Parameters
+    ----------
+    * `node`: node on which link local ip to be fetched.
+    * `intf` : interface for which link local ip needs to be returned.
+    * `topo` : base topo
+
+    Usage
+    -----
+    result = get_ipv6_linklocal_address(topo, 'r1', 'r2')
+
+    Returns link local ip of interface between r1 and r2.
+
+    Returns
+    -------
+    1) link local ipv6 address from the interface
+    2) errormsg - when link local ip not found
+    """
+    tgen = get_topogen()
+    ext_nh = tgen.net[node].get_ipv6_linklocal()
+    req_nh = topo[node]['links'][intf]['interface']
+    llip = None
+    for llips in ext_nh:
+        if llips[0] == req_nh:
+            llip = llips[1]
+            logger.info("Link local ip found = %s", llip)
+            return llip
+
+    errormsg = "Failed: Link local ip not found on router {}, "\
+        "interface {}".format(node, intf)
+
+    return errormsg
+
+
 def verify_create_community_list(tgen, input_dict):
     """
     API is to verify if large community list is created for any given DUT in
index 79e4d97448569dd127f05583cecb8d549d1adf31..9f642411b542fa8567a6257ccf90e0f9609a02dc 100644 (file)
@@ -344,10 +344,9 @@ def config_ospf_interface(tgen, topo, input_dict=None, build=False, load_config=
         for lnk in input_dict[router]["links"].keys():
             if "ospf" not in input_dict[router]["links"][lnk]:
                 logger.debug(
-                    "Router %s: ospf configs is not present in"
-                    "input_dict, passed input_dict",
-                    router,
-                    input_dict,
+                    "Router %s: ospf config is not present in"
+                    "input_dict",
+                    router
                 )
                 continue
             ospf_data = input_dict[router]["links"][lnk]["ospf"]
@@ -724,7 +723,7 @@ def verify_ospf6_neighbor(tgen, topo):
                     nh_state = neighbor["state"]
                     break
             else:
-                return "[DUT: {}] OSPF6 peer {} missing".format(router, data_rid)
+                return "[DUT: {}] OSPF6 peer {} missing".format(router, ospf_nbr_rid)
 
             if nh_state == "Full":
                 no_of_peer += 1
index 5cc1a6981d26c0a3a865ee78de333d352f4310ab..70b2cfd648c2de67383d5f203599b30668db850b 100644 (file)
@@ -516,6 +516,44 @@ def normalize_text(text):
     return text
 
 
+def is_linux():
+    """
+    Parses unix name output to check if running on GNU/Linux.
+
+    Returns True if running on Linux, returns False otherwise.
+    """
+
+    if os.uname()[0] == "Linux":
+        return True
+    return False
+
+
+def iproute2_is_vrf_capable():
+    """
+    Checks if the iproute2 version installed on the system is capable of
+    handling VRFs by interpreting the output of the 'ip' utility found in PATH.
+
+    Returns True if capability can be detected, returns False otherwise.
+    """
+
+    if is_linux():
+        try:
+            subp = subprocess.Popen(
+                ["ip", "route", "show", "vrf"],
+                stdout=subprocess.PIPE,
+                stderr=subprocess.PIPE,
+                stdin=subprocess.PIPE,
+                encoding="utf-8"
+            )
+            iproute2_err = subp.communicate()[1].splitlines()[0].split()[0]
+
+            if iproute2_err != "Error:":
+                return True
+        except Exception:
+            pass
+    return False
+
+
 def module_present_linux(module, load):
     """
     Returns whether `module` is present.
index 087c35981d3efe508ec91de192f4310adb9fd0b9..0bc65479942fe169ae1269160aebcdd759e43222 100644 (file)
@@ -42,12 +42,13 @@ show zebra client summary
 show zebra router table summary
 show ip nht vrf all
 show ipv6 nht vrf all
+show ip route vrf all
+show ipv6 route vrf all
 show nexthop-group rib
 show route-map
 show memory
 show interface vrf all
 show vrf
-show zebra fpm stats
 show work-queues
 show debugging hashtable
 show running-config
index f4f489c3dd36377c790473ab2c78bee01af2c4a4..775611b3e3e225927281b5c22910cda36216dfe4 100644 (file)
@@ -40,8 +40,8 @@
 
 #define VRRP_LOGPFX "[CORE] "
 
-DEFINE_MTYPE_STATIC(VRRPD, VRRP_IP, "VRRP IP address")
-DEFINE_MTYPE_STATIC(VRRPD, VRRP_RTR, "VRRP Router")
+DEFINE_MTYPE_STATIC(VRRPD, VRRP_IP, "VRRP IP address");
+DEFINE_MTYPE_STATIC(VRRPD, VRRP_RTR, "VRRP Router");
 
 /* statics */
 struct hash *vrrp_vrouters_hash;
index 502d7b82b6137f8dead0a4f7606635a7e9d9dd44..c181c2159bf10aaa032d9095d230b6d1294981f7 100644 (file)
@@ -58,7 +58,7 @@
 /* User compatibility constant */
 #define CS2MS 10
 
-DECLARE_MGROUP(VRRPD)
+DECLARE_MGROUP(VRRPD);
 
 /* Northbound */
 extern const struct frr_yang_module_info frr_vrrpd_info;
index 94f10757a21e72d2c0cca3c681d0e85d6edaf0fc..a5ad37aa0c3ba2d3ab345e1af5cc154646a395e3 100644 (file)
@@ -40,7 +40,7 @@
 #include "vrrp_vty.h"
 #include "vrrp_zebra.h"
 
-DEFINE_MGROUP(VRRPD, "vrrpd")
+DEFINE_MGROUP(VRRPD, "vrrpd");
 
 char backup_config_file[256];
 
@@ -128,7 +128,7 @@ FRR_DAEMON_INFO(vrrpd, VRRP, .vty_port = VRRP_VTY_PORT,
                .privs = &vrrp_privs,
                .yang_modules = vrrp_yang_modules,
                .n_yang_modules = array_size(vrrp_yang_modules),
-)
+);
 
 int main(int argc, char **argv, char **envp)
 {
index 3cb13bd71b138a09c05d004cc3d5ca3978415aa2..991c030196e975e46469dfd691dbd7ae2fba7e3f 100644 (file)
@@ -30,7 +30,7 @@
 #include "vrrp_debug.h"
 #include "vrrp_packet.h"
 
-DEFINE_MTYPE_STATIC(VRRPD, VRRP_PKT, "VRRP packet")
+DEFINE_MTYPE_STATIC(VRRPD, VRRP_PKT, "VRRP packet");
 
 /* clang-format off */
 static const char *const vrrp_packet_names[16] = {
index 81c9770e55867b99bfc2452ed3ac60637454aa96..4855c23f4b15ab837b37614c9b2278bb1a981c5a 100755 (executable)
@@ -42,7 +42,7 @@ sub scan_file {
 
     $cppadd = $fabricd ? "-DFABRICD=1" : "";
 
-    open (FH, "@CPP@ -P -DHAVE_CONFIG_H -DVTYSH_EXTRACT_PL -Ivtysh/@top_builddir@ -Ivtysh/@top_srcdir@ -Ivtysh/@top_srcdir@/lib -Ivtysh/@top_builddir@/lib -Ivtysh/@top_srcdir@/bgpd -Ivtysh/@top_srcdir@/bgpd/rfapi @LUA_INCLUDE@ @CPPFLAGS@ $cppadd $file |");
+    open (FH, "@CPP@ -P -std=gnu11 -DHAVE_CONFIG_H -DVTYSH_EXTRACT_PL -Ivtysh/@top_builddir@ -Ivtysh/@top_srcdir@ -Ivtysh/@top_srcdir@/lib -Ivtysh/@top_builddir@/lib -Ivtysh/@top_srcdir@/bgpd -Ivtysh/@top_srcdir@/bgpd/rfapi @LUA_INCLUDE@ @CPPFLAGS@ $cppadd $file |");
     local $/; undef $/;
     $line = <FH>;
     if (!close (FH)) {
index 6e809a07137b614fb7f8ac0ba611cb8749df5598..06d224ec24a3784a7084ec42f0e70d4892291549 100644 (file)
@@ -48,7 +48,7 @@
 #include "json.h"
 #include "ferr.h"
 
-DEFINE_MTYPE_STATIC(MVTYSH, VTYSH_CMD, "Vtysh cmd copy")
+DEFINE_MTYPE_STATIC(MVTYSH, VTYSH_CMD, "Vtysh cmd copy");
 
 /* Struct VTY. */
 struct vty *vty;
index 20e1e1b0e92618eba021dd9fe2056c3246763a69..7c8d9315e1d1f25e80b5b6ddd2dc730fb33bf809 100644 (file)
@@ -22,7 +22,7 @@
 #define VTYSH_H
 
 #include "memory.h"
-DECLARE_MGROUP(MVTYSH)
+DECLARE_MGROUP(MVTYSH);
 
 #define VTYSH_ZEBRA     0x00001
 #define VTYSH_RIPD      0x00002
index 47f426b5e0723c31903f1e1b1321e90ad9bf75c0..498d3e5f67328be753cf874f6abb2e3952b9f438 100644 (file)
@@ -28,9 +28,9 @@
 #include "vtysh/vtysh.h"
 #include "vtysh/vtysh_user.h"
 
-DEFINE_MGROUP(MVTYSH, "vtysh")
-DEFINE_MTYPE_STATIC(MVTYSH, VTYSH_CONFIG, "Vtysh configuration")
-DEFINE_MTYPE_STATIC(MVTYSH, VTYSH_CONFIG_LINE, "Vtysh configuration line")
+DEFINE_MGROUP(MVTYSH, "vtysh");
+DEFINE_MTYPE_STATIC(MVTYSH, VTYSH_CONFIG, "Vtysh configuration");
+DEFINE_MTYPE_STATIC(MVTYSH, VTYSH_CONFIG_LINE, "Vtysh configuration line");
 
 vector configvec;
 
@@ -91,9 +91,9 @@ static uint32_t config_hash(const struct config *c)
        return string_hash_make(c->name);
 }
 
-DECLARE_LIST(config_master, struct config, rbt_item)
+DECLARE_LIST(config_master, struct config, rbt_item);
 DECLARE_HASH(config_master_hash, struct config, hash_item, config_cmp,
-            config_hash)
+            config_hash);
 
 /*
  * The config_master_head is a list for order of receipt
index 5f4d564507e94c34ebb4e7601e9a8a94f3fa9621..faf1777d7fd8922a5280da7c0b5783349853515b 100644 (file)
@@ -61,8 +61,8 @@
 
 #define PING_TOKEN     "PING"
 
-DEFINE_MGROUP(WATCHFRR, "watchfrr")
-DEFINE_MTYPE_STATIC(WATCHFRR, WATCHFRR_DAEMON, "watchfrr daemon entry")
+DEFINE_MGROUP(WATCHFRR, "watchfrr");
+DEFINE_MTYPE_STATIC(WATCHFRR, WATCHFRR_DAEMON, "watchfrr daemon entry");
 
 /* Needs to be global, referenced somewhere inside libfrr. */
 struct thread_master *master;
@@ -1336,7 +1336,8 @@ FRR_DAEMON_INFO(watchfrr, WATCHFRR,
                .signals = watchfrr_signals,
                .n_signals = array_size(watchfrr_signals),
 
-               .privs = &watchfrr_privs, )
+               .privs = &watchfrr_privs,
+);
 
 #define DEPRECATED_OPTIONS "aAezR:"
 
index ba6e94960f6d0a76320be55792336e9b6184f1f0..4df1bf74afb78857464704100b9f958c584e6980 100644 (file)
@@ -23,7 +23,7 @@
 
 #include "lib/memory.h"
 
-DECLARE_MGROUP(WATCHFRR)
+DECLARE_MGROUP(WATCHFRR);
 
 extern void watchfrr_vty_init(void);
 
index 0f090a1b7217b39cefa7bb65720c23815d727496..d21ff5068a718385cf46e9e564cb914faf0e8652 100644 (file)
@@ -210,7 +210,14 @@ module frr-bfdd {
       type uint32;
       units microseconds;
       default 50000;
-      description "Minimum desired control packet transmission interval";
+      description "Minimum desired echo packet transmission interval";
+    }
+
+    leaf required-echo-receive-interval {
+      type uint32;
+      units microseconds;
+      default 50000;
+      description "Minimum required echo packet receive interval";
     }
   }
 
index eb84dd746083d03f5eaf8cab71d3ae065e232f7f..9a864213ee9befada9ece98ff8aae82110e06593 100644 (file)
@@ -292,8 +292,6 @@ module frr-filter {
           mandatory true;
 
           case ipv4-prefix {
-            when "../type = 'ipv4'";
-
             leaf ipv4-prefix {
               description "Configure IPv4 prefix to match";
               type inet:ipv4-prefix;
@@ -318,8 +316,6 @@ module frr-filter {
             }
           }
           case ipv6-prefix {
-            when "../type = 'ipv6'";
-
             leaf ipv6-prefix {
               description "Configure IPv6 prefix to match";
               type inet:ipv6-prefix;
index dd8fab5e4e040b7bfdad9229946632900d0c4d34..6f405ca1bbbe533a1cca57e5bbaf11c51c9e5687 100644 (file)
@@ -29,7 +29,6 @@
 #include "table.h"
 #include "log.h"
 #include "memory.h"
-#include "zebra_memory.h"
 
 #include "vty.h"
 #include "zebra/debug.h"
index 79a5d148a6732ed2610e257dde63a8ec6a9d8440..9abed77fa61bfcc7a76a804942b3e34eee12f5ee 100644 (file)
@@ -1517,4 +1517,4 @@ FRR_MODULE_SETUP(
        .version = "0.0.1",
        .description = "Data plane plugin for FPM using netlink.",
        .init = fpm_nl_init,
-       )
+);
index 8bec2563553252db71cb11385471b5321e63fe2e..14d8ac442ebaf0ef7553017d911f29dfec148285 100644 (file)
@@ -29,7 +29,6 @@
 #include "ioctl.h"
 #include "connected.h"
 #include "memory.h"
-#include "zebra_memory.h"
 #include "log.h"
 #include "vrf.h"
 #include "vty.h"
index 98bde4b3c05640545672ef8a551db0c9a3e8abdf..af2c2516071d7e60874381f0fb6ff552d74200c8 100644 (file)
@@ -44,7 +44,6 @@
 #include "connected.h"
 #include "table.h"
 #include "memory.h"
-#include "zebra_memory.h"
 #include "rib.h"
 #include "thread.h"
 #include "privs.h"
index 695cef1995b35db6016e286e121b6732ba46b232..38729c8d38e4a9896d857bae105ee78b0ea8f1f8 100644 (file)
@@ -28,7 +28,6 @@
 #include "prefix.h"
 #include "connected.h"
 #include "memory.h"
-#include "zebra_memory.h"
 #include "ioctl.h"
 #include "log.h"
 #include "interface.h"
index 6373b4b200d8b4f83d04333656a968904e80bcd2..3eeed9ac90e27cbbcf62d0ceb4f8f6d0ecad8a7b 100644 (file)
@@ -28,7 +28,6 @@
 #include "prefix.h"
 #include "command.h"
 #include "memory.h"
-#include "zebra_memory.h"
 #include "ioctl.h"
 #include "connected.h"
 #include "log.h"
 #include "zebra/zebra_errors.h"
 #include "zebra/zebra_evpn_mh.h"
 
-DEFINE_MTYPE_STATIC(ZEBRA, ZINFO, "Zebra Interface Information")
+DEFINE_MTYPE_STATIC(ZEBRA, ZINFO, "Zebra Interface Information");
 
 #define ZEBRA_PTM_SUPPORT
 
 DEFINE_HOOK(zebra_if_extra_info, (struct vty * vty, struct interface *ifp),
-           (vty, ifp))
+           (vty, ifp));
 DEFINE_HOOK(zebra_if_config_wr, (struct vty * vty, struct interface *ifp),
-           (vty, ifp))
+           (vty, ifp));
 
 
 static void if_down_del_nbr_connected(struct interface *ifp);
index 64569742b4573abba065122a0e723d443e7acbc2..67eb1176b9a2deec121ba1a261a5beb12897d3e1 100644 (file)
@@ -417,9 +417,9 @@ struct zebra_if {
 };
 
 DECLARE_HOOK(zebra_if_extra_info, (struct vty * vty, struct interface *ifp),
-            (vty, ifp))
+            (vty, ifp));
 DECLARE_HOOK(zebra_if_config_wr, (struct vty * vty, struct interface *ifp),
-            (vty, ifp))
+            (vty, ifp));
 
 #define IS_ZEBRA_IF_VRF(ifp)                                                   \
        (((struct zebra_if *)(ifp->info))->zif_type == ZEBRA_IF_VRF)
index 5352c6214dde30de289842457923631c03875136..28db2ad87d6526619e67d79d4245fe5d8c04f9f4 100644 (file)
@@ -34,7 +34,6 @@
 #include "prefix.h"
 #include "command.h"
 #include "memory.h"
-#include "zebra_memory.h"
 #include "stream.h"
 #include "ioctl.h"
 #include "connected.h"
@@ -57,7 +56,7 @@
 
 extern int irdp_sock;
 
-DEFINE_MTYPE_STATIC(ZEBRA, IRDP_IF, "IRDP interface data")
+DEFINE_MTYPE_STATIC(ZEBRA, IRDP_IF, "IRDP interface data");
 
 #define IRDP_CONFIGED                                                                 \
        do {                                                                          \
index 936206641f9dcf7a9ce436c83a99ebe3cf84b5c1..600fc3f2fc8ee8299d287d7684d4e2d36f379f8f 100644 (file)
@@ -42,7 +42,6 @@
 #include "prefix.h"
 #include "command.h"
 #include "memory.h"
-#include "zebra_memory.h"
 #include "stream.h"
 #include "ioctl.h"
 #include "connected.h"
@@ -349,4 +348,5 @@ static int irdp_module_init(void)
 }
 
 FRR_MODULE_SETUP(.name = "zebra_irdp", .version = FRR_VERSION,
-                .description = "zebra IRDP module", .init = irdp_module_init, )
+                .description = "zebra IRDP module", .init = irdp_module_init,
+);
index 6134df9c41565a0dd0eeb1f0eb329f86b0e677e9..7d67c42a79e9b06f843b7ca9f4f7bf6af164ebf8 100644 (file)
@@ -54,7 +54,6 @@
 #include "zclient.h"
 #include "lib_errors.h"
 
-#include "zebra_memory.h"
 #include "zebra/interface.h"
 #include "zebra/rtadv.h"
 #include "zebra/rib.h"
index aa19b180890cccf0a3eb3c84b33ac8d79c4ffc14..e71e6624589d42acff66b861f3c0205f3ef287a5 100644 (file)
@@ -29,7 +29,6 @@
 #include "connected.h"
 #include "table.h"
 #include "memory.h"
-#include "zebra_memory.h"
 #include "rib.h"
 #include "thread.h"
 #include "privs.h"
@@ -159,7 +158,7 @@ extern uint32_t nl_rcvbufsize;
 
 extern struct zebra_privs_t zserv_privs;
 
-DEFINE_MTYPE_STATIC(ZEBRA, NL_BUF, "Zebra Netlink buffers")
+DEFINE_MTYPE_STATIC(ZEBRA, NL_BUF, "Zebra Netlink buffers");
 
 size_t nl_batch_tx_bufsize;
 char *nl_batch_tx_buf;
index adbdf54c1f763d640acdd7e2ea31bc9c5e424d78..03884a916820e2d200649029b93f453d772c86e3 100644 (file)
@@ -32,7 +32,6 @@
 #include "sockunion.h"
 #include "connected.h"
 #include "memory.h"
-#include "zebra_memory.h"
 #include "ioctl.h"
 #include "log.h"
 #include "table.h"
index 55fd3244cb022c89bb1bbbcc0509d09424f47016..09350f72c18fbaadaf6ef36b0436482f5ce4d3b2 100644 (file)
@@ -26,7 +26,6 @@
 #include "thread.h"
 #include "filter.h"
 #include "memory.h"
-#include "zebra_memory.h"
 #include "prefix.h"
 #include "log.h"
 #include "plist.h"
@@ -274,7 +273,8 @@ FRR_DAEMON_INFO(
        .privs = &zserv_privs,
 
        .yang_modules = zebra_yang_modules,
-       .n_yang_modules = array_size(zebra_yang_modules), )
+       .n_yang_modules = array_size(zebra_yang_modules),
+);
 
 /* Main startup routine. */
 int main(int argc, char **argv)
index ac60d09eccba6592e1490ec32fe2115f5b657d0b..9e675011ee76c8812936a38b369e80e04c68ff0d 100644 (file)
@@ -41,7 +41,6 @@
 #include "zebra/debug.h"
 #include "zebra/router-id.h"
 #include "zebra/zapi_msg.h"
-#include "zebra/zebra_memory.h"
 #include "zebra/zebra_vxlan.h"
 #include "zebra/zebra_errors.h"
 
index 86766b8175730a338e2cad42f26f55321485d5d2..e7676a132455bad1457ccc9bdb800cc37859a32f 100644 (file)
@@ -23,6 +23,7 @@
 #define _ZEBRA_RIB_H
 
 #include "zebra.h"
+#include "memory.h"
 #include "hook.h"
 #include "typesafe.h"
 #include "linklist.h"
 extern "C" {
 #endif
 
+DECLARE_MGROUP(ZEBRA);
+
+DECLARE_MTYPE(RE);
+
 enum rnh_type { RNH_NEXTHOP_TYPE, RNH_IMPORT_CHECK_TYPE };
 
-PREDECL_LIST(rnh_list)
+PREDECL_LIST(rnh_list);
 
 /* Nexthop structure. */
 struct rnh {
@@ -82,7 +87,7 @@ struct rnh {
 #define DISTANCE_INFINITY  255
 #define ZEBRA_KERNEL_TABLE_MAX 252 /* support for no more than this rt tables */
 
-PREDECL_LIST(re_list)
+PREDECL_LIST(re_list);
 
 struct opaque {
        uint16_t length;
@@ -541,7 +546,7 @@ static inline void rib_tables_iter_cleanup(rib_tables_iter_t *iter)
 }
 
 DECLARE_HOOK(rib_update, (struct route_node * rn, const char *reason),
-            (rn, reason))
+            (rn, reason));
 
 /*
  * Access installed/fib nexthops, which may be a subset of the
index ac21978ee826f96a5c398f68b8966a35ca23a133..3b556c92b5f18e7c0e669e62f13a337eb09e76c0 100644 (file)
@@ -29,7 +29,6 @@
 #include "stream.h"
 #include "command.h"
 #include "memory.h"
-#include "zebra_memory.h"
 #include "ioctl.h"
 #include "connected.h"
 #include "network.h"
index fdeef2c88c3cca535ee59dfb3039673506cf499e..55e0775a8c49dffe30f87564a4b55d4d9bf08b0f 100644 (file)
@@ -41,7 +41,6 @@
 #include "connected.h"
 #include "table.h"
 #include "memory.h"
-#include "zebra_memory.h"
 #include "rib.h"
 #include "thread.h"
 #include "privs.h"
index c3add16c5693a699373a73734f7aea49da630cf9..8ffb3870fa6fb019dfc2161565004428239ee76d 100644 (file)
@@ -23,7 +23,6 @@
 #include <zebra.h>
 
 #include "memory.h"
-#include "zebra_memory.h"
 #include "sockopt.h"
 #include "thread.h"
 #include "if.h"
@@ -54,7 +53,7 @@ extern struct zebra_privs_t zserv_privs;
 #include "zebra/rtadv_clippy.c"
 #endif
 
-DEFINE_MTYPE_STATIC(ZEBRA, RTADV_PREFIX, "Router Advertisement Prefix")
+DEFINE_MTYPE_STATIC(ZEBRA, RTADV_PREFIX, "Router Advertisement Prefix");
 
 #ifdef OPEN_BSD
 #include <netinet/icmp6.h>
@@ -71,8 +70,8 @@ DEFINE_MTYPE_STATIC(ZEBRA, RTADV_PREFIX, "Router Advertisement Prefix")
 #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")
+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. */
index 01a97db8b35912276b6af98f100a575e91910863..74c6825ba1225bb4d3dafcc6edc6d9b3e914c55b 100644 (file)
@@ -24,7 +24,6 @@
 #if !defined(GNU_LINUX)
 
 #include "memory.h"
-#include "zebra_memory.h"
 #include "log.h"
 #include "vrf.h"
 
index 464205f2f364aa77969f90e3eadad63415d6446d..e54186bc182be07e28795a5965aeb4a95b44d3cb 100644 (file)
@@ -130,4 +130,4 @@ FRR_MODULE_SETUP(
        .version = "0.0.1",
        .description = "Dataplane Sample Plugin",
        .init = module_init,
-       )
+);
index f842a8c0f33e674567bc9cf3ab1a64b50afc3935..b5c26d720fe77ed923db7a1a9243b23c3a04f1cb 100644 (file)
@@ -88,7 +88,6 @@ zebra_zebra_SOURCES = \
        zebra/zebra_evpn_neigh.c \
        zebra/zebra_mlag.c \
        zebra/zebra_mlag_vty.c \
-       zebra/zebra_memory.c \
        zebra/zebra_mpls.c \
        zebra/zebra_mpls_netlink.c \
        zebra/zebra_mpls_openbsd.c \
@@ -158,7 +157,6 @@ noinst_HEADERS += \
        zebra/zebra_evpn_vxlan.h \
        zebra/zebra_fpm_private.h \
        zebra/zebra_l2.h \
-       zebra/zebra_memory.h \
        zebra/zebra_mlag.h \
        zebra/zebra_mlag_vty.h \
        zebra/zebra_mpls.h \
@@ -193,7 +191,7 @@ zebra_zebra_irdp_la_SOURCES = \
 zebra_zebra_irdp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
 
 zebra_zebra_snmp_la_SOURCES = zebra/zebra_snmp.c
-zebra_zebra_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu99
+zebra_zebra_snmp_la_CFLAGS = $(WERROR) $(SNMP_CFLAGS) -std=gnu11
 zebra_zebra_snmp_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
 zebra_zebra_snmp_la_LIBADD = lib/libfrrsnmp.la
 
index 9f5adfa40993387e2daeeda9ee52aa87bbc9106c..63ba6cd8d906cff713b0c86305cc6e06600bbb92 100644 (file)
@@ -38,7 +38,6 @@
 
 #include "zebra/zebra_router.h"
 #include "zebra/rib.h"
-#include "zebra/zebra_memory.h"
 #include "zebra/zebra_ns.h"
 #include "zebra/zebra_vrf.h"
 #include "zebra/router-id.h"
@@ -62,6 +61,8 @@
 #include "zebra/zebra_opaque.h"
 #include "zebra/zebra_srte.h"
 
+DEFINE_MTYPE_STATIC(ZEBRA, OPAQUE, "Opaque Data");
+
 static int zapi_nhg_decode(struct stream *s, int cmd, struct zapi_nhg *api_nhg);
 
 /* Encoding helpers -------------------------------------------------------- */
@@ -2076,6 +2077,11 @@ static void zread_route_add(ZAPI_HANDLER_ARGS)
        }
 }
 
+void zapi_opaque_free(struct opaque *opaque)
+{
+       XFREE(MTYPE_OPAQUE, opaque);
+}
+
 static void zread_route_del(ZAPI_HANDLER_ARGS)
 {
        struct stream *s;
index 023b9f74a8fb6ba1426eb1909a69a854ebbc55e6..ca471f8d989bd1148c4a381805c15396739f38f1 100644 (file)
@@ -111,6 +111,8 @@ extern int zsend_client_close_notify(struct zserv *client,
 int zsend_nhg_notify(uint16_t type, uint16_t instance, uint32_t session_id,
                     uint32_t id, enum zapi_nhg_notify_owner note);
 
+extern void zapi_opaque_free(struct opaque *opaque);
+
 #ifdef __cplusplus
 }
 #endif
index 4e63d08aca25345868afd225ff2d2c6090366100..18fe0a7e853a597ae56964607f39df2cd019eedb 100644 (file)
@@ -28,7 +28,6 @@
 #include "lib/memory.h"
 #include "lib/queue.h"
 #include "lib/zebra.h"
-#include "zebra/zebra_memory.h"
 #include "zebra/zebra_router.h"
 #include "zebra/zebra_dplane.h"
 #include "zebra/zebra_vxlan_private.h"
 #include "printfrr.h"
 
 /* Memory type for context blocks */
-DEFINE_MTYPE_STATIC(ZEBRA, DP_CTX, "Zebra DPlane Ctx")
-DEFINE_MTYPE_STATIC(ZEBRA, DP_INTF, "Zebra DPlane Intf")
-DEFINE_MTYPE_STATIC(ZEBRA, DP_PROV, "Zebra DPlane Provider")
-DEFINE_MTYPE_STATIC(ZEBRA, DP_NETFILTER, "Zebra Netfilter Internal Object")
+DEFINE_MTYPE_STATIC(ZEBRA, DP_CTX, "Zebra DPlane Ctx");
+DEFINE_MTYPE_STATIC(ZEBRA, DP_INTF, "Zebra DPlane Intf");
+DEFINE_MTYPE_STATIC(ZEBRA, DP_PROV, "Zebra DPlane Provider");
+DEFINE_MTYPE_STATIC(ZEBRA, DP_NETFILTER, "Zebra Netfilter Internal Object");
 
 #ifndef AOK
 #  define AOK 0
index 27a5a07e486b0126aaa55a7a22f54d4ca83b86ef..80e06d913de097b0706e783f2f2740c733dd8956 100644 (file)
@@ -44,7 +44,6 @@
 #include "zebra/rt_netlink.h"
 #include "zebra/zebra_errors.h"
 #include "zebra/zebra_l2.h"
-#include "zebra/zebra_memory.h"
 #include "zebra/zebra_ns.h"
 #include "zebra/zebra_vrf.h"
 #include "zebra/zebra_vxlan.h"
index b36e8034b7b97974b6a5a586f6c830c9dd52d998..7bbe092d8c89ea60a5ebbcb29ebad32d3aa49871 100644 (file)
@@ -34,7 +34,6 @@
 #include "zebra/zserv.h"
 #include "zebra/debug.h"
 #include "zebra/zebra_router.h"
-#include "zebra/zebra_memory.h"
 #include "zebra/zebra_errors.h"
 #include "zebra/zebra_vrf.h"
 #include "zebra/zebra_evpn.h"
index 5a28ee10c621c651132bcb64dec03a49fbb36e02..1c258a04f76ed5e1f61d3663fa8fa8e22b8a60b4 100644 (file)
@@ -41,7 +41,6 @@
 #include "zebra/if_netlink.h"
 #include "zebra/zebra_errors.h"
 #include "zebra/zebra_l2.h"
-#include "zebra/zebra_memory.h"
 #include "zebra/zebra_ns.h"
 #include "zebra/zebra_vrf.h"
 #include "zebra/zebra_vxlan.h"
index 0e31617c4f0d4c84365265ed2af7763b39588cae..d1b93dbe8ab2437dd7b746d4b70f7f26ea4a0392 100644 (file)
@@ -34,7 +34,6 @@
 #include "zebra/debug.h"
 #include "zebra/zebra_router.h"
 #include "zebra/rt.h"
-#include "zebra/zebra_memory.h"
 #include "zebra/zebra_errors.h"
 #include "zebra/zebra_vrf.h"
 #include "zebra/zebra_evpn.h"
index 099ac1434bf4938953fb079eeb59a7321b9f01c0..5fe8934a8221f352c3a05e058c331d0c32ef78ff 100644 (file)
@@ -37,7 +37,6 @@
 #include "zebra/zebra_ns.h"
 #include "zebra/zebra_vrf.h"
 #include "zebra/zebra_errors.h"
-#include "zebra/zebra_memory.h"
 
 #include "fpm/fpm.h"
 #include "zebra_fpm_private.h"
@@ -2046,4 +2045,5 @@ static int zebra_fpm_module_init(void)
 
 FRR_MODULE_SETUP(.name = "zebra_fpm", .version = FRR_VERSION,
                 .description = "zebra FPM (Forwarding Plane Manager) module",
-                .init = zebra_fpm_module_init, )
+                .init = zebra_fpm_module_init,
+);
index 3583c5fbf41157dff50387e25972ccf04c258e40..c3fbff2723c60edf5398c554982313d1ebd8efaa 100644 (file)
@@ -38,7 +38,6 @@
 #include "zebra/zserv.h"
 #include "zebra/debug.h"
 #include "zebra/interface.h"
-#include "zebra/zebra_memory.h"
 #include "zebra/zebra_vrf.h"
 #include "zebra/rt_netlink.h"
 #include "zebra/interface.h"
diff --git a/zebra/zebra_memory.c b/zebra/zebra_memory.c
deleted file mode 100644 (file)
index 17b52a2..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/* zebra memory type definitions
- *
- * Copyright (C) 2015  David Lamparter
- *
- * This file is part of Quagga.
- *
- * Quagga 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.
- *
- * Quagga 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
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "zebra_memory.h"
-
-DEFINE_MGROUP(ZEBRA, "zebra")
-DEFINE_MTYPE(ZEBRA, RE, "Route Entry")
-DEFINE_MTYPE(ZEBRA, RIB_DEST, "RIB destination")
-DEFINE_MTYPE(ZEBRA, ZVLAN, "VLAN")
-DEFINE_MTYPE(ZEBRA, ZVLAN_BITMAP, "VLAN bitmap")
-DEFINE_MTYPE(ZEBRA, OPAQUE, "Opaque Data")
diff --git a/zebra/zebra_memory.h b/zebra/zebra_memory.h
deleted file mode 100644 (file)
index 71901b7..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/* zebra memory type declarations
- *
- * Copyright (C) 2015  David Lamparter
- *
- * This file is part of Quagga.
- *
- * Quagga 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.
- *
- * Quagga 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 _QUAGGA_ZEBRA_MEMORY_H
-#define _QUAGGA_ZEBRA_MEMORY_H
-
-#include "memory.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-DECLARE_MGROUP(ZEBRA)
-DECLARE_MTYPE(ZEBRA_NS)
-DECLARE_MTYPE(RE)
-DECLARE_MTYPE(RIB_DEST)
-DECLARE_MTYPE(OPAQUE)
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _QUAGGA_ZEBRA_MEMORY_H */
index d8ed9b2a3a4448a748dec5ec26c1fd2e6758097a..3b0c75151be2d71cb22a22714d8cc92d8c29f1cf 100644 (file)
@@ -29,7 +29,6 @@
 #include "zebra/zebra_mlag.h"
 #include "zebra/zebra_mlag_vty.h"
 #include "zebra/zebra_router.h"
-#include "zebra/zebra_memory.h"
 #include "zebra/zapi_msg.h"
 #include "zebra/debug.h"
 
 #endif
 
 DEFINE_HOOK(zebra_mlag_private_write_data,
-           (uint8_t *data, uint32_t len), (data, len))
-DEFINE_HOOK(zebra_mlag_private_monitor_state, (), ())
-DEFINE_HOOK(zebra_mlag_private_open_channel, (), ())
-DEFINE_HOOK(zebra_mlag_private_close_channel, (), ())
-DEFINE_HOOK(zebra_mlag_private_cleanup_data, (), ())
+           (uint8_t *data, uint32_t len), (data, len));
+DEFINE_HOOK(zebra_mlag_private_monitor_state, (), ());
+DEFINE_HOOK(zebra_mlag_private_open_channel, (), ());
+DEFINE_HOOK(zebra_mlag_private_close_channel, (), ());
+DEFINE_HOOK(zebra_mlag_private_cleanup_data, (), ());
 
 #define ZEBRA_MLAG_METADATA_LEN 4
 #define ZEBRA_MLAG_MSG_BCAST 0xFFFFFFFF
@@ -659,7 +658,7 @@ void zebra_mlag_terminate(void)
 
 #ifdef HAVE_PROTOBUF_VERSION_3
 
-DEFINE_MTYPE_STATIC(ZEBRA, MLAG_PBUF, "ZEBRA MLAG PROTOBUF")
+DEFINE_MTYPE_STATIC(ZEBRA, MLAG_PBUF, "ZEBRA MLAG PROTOBUF");
 
 int zebra_mlag_protobuf_encode_client_data(struct stream *s, uint32_t *msg_type)
 {
index b195c75ea3c1bcf183ed969671c89c55eb963ba2..eb96a57d3016499c123ecc01b7046c861c6efb9d 100644 (file)
@@ -34,11 +34,11 @@ extern "C" {
 #define ZEBRA_MLAG_LEN_SIZE 4
 
 DECLARE_HOOK(zebra_mlag_private_write_data,
-            (uint8_t *data, uint32_t len), (data, len))
-DECLARE_HOOK(zebra_mlag_private_monitor_state, (), ())
-DECLARE_HOOK(zebra_mlag_private_open_channel, (), ())
-DECLARE_HOOK(zebra_mlag_private_close_channel, (), ())
-DECLARE_HOOK(zebra_mlag_private_cleanup_data, (), ())
+            (uint8_t *data, uint32_t len), (data, len));
+DECLARE_HOOK(zebra_mlag_private_monitor_state, (), ());
+DECLARE_HOOK(zebra_mlag_private_open_channel, (), ());
+DECLARE_HOOK(zebra_mlag_private_close_channel, (), ());
+DECLARE_HOOK(zebra_mlag_private_cleanup_data, (), ());
 
 extern uint8_t mlag_wr_buffer[ZEBRA_MLAG_BUF_LIMIT];
 extern uint8_t mlag_rd_buffer[ZEBRA_MLAG_BUF_LIMIT];
index 8a66d6de726a99e90f810a56598c2b0f5d0ce358..aaf93b4dc17ffd7429ecd77d6a4f25117bec917e 100644 (file)
@@ -297,4 +297,4 @@ FRR_MODULE_SETUP(
        .version = FRR_VERSION,
        .description = "zebra Cumulus MLAG interface",
        .init = zebra_mlag_module_init,
-)
+);
index dc4969501991de638fa4fb7ee498435e95592e35..c0c064cbc7aea4df56556a71d37907b681a03538 100644 (file)
 #include "zebra/zebra_router.h"
 #include "zebra/redistribute.h"
 #include "zebra/debug.h"
-#include "zebra/zebra_memory.h"
 #include "zebra/zebra_vrf.h"
 #include "zebra/zebra_mpls.h"
 #include "zebra/zebra_srte.h"
 #include "zebra/zebra_errors.h"
 
-DEFINE_MTYPE_STATIC(ZEBRA, LSP, "MPLS LSP object")
-DEFINE_MTYPE_STATIC(ZEBRA, FEC, "MPLS FEC object")
-DEFINE_MTYPE_STATIC(ZEBRA, NHLFE, "MPLS nexthop object")
+DEFINE_MTYPE_STATIC(ZEBRA, LSP, "MPLS LSP object");
+DEFINE_MTYPE_STATIC(ZEBRA, FEC, "MPLS FEC object");
+DEFINE_MTYPE_STATIC(ZEBRA, NHLFE, "MPLS nexthop object");
 
 int mpls_enabled;
 
index 6a2d97d39533f4eed3bbdcd36dd801ea482dea04..79632dc83e3eadd0eb7cc12a575e4edcc7e85a55 100644 (file)
@@ -203,19 +203,6 @@ lib_vrf_zebra_ribs_rib_route_nexthop_group_frr_nexthops_nexthop_get_next(
        struct nb_cb_get_next_args *args);
 int lib_vrf_zebra_ribs_rib_route_nexthop_group_frr_nexthops_nexthop_get_keys(
        struct nb_cb_get_keys_args *args);
-int lib_vrf_zebra_ribs_rib_create(struct nb_cb_create_args *args);
-int lib_vrf_zebra_ribs_rib_destroy(struct nb_cb_destroy_args *args);
-const void *lib_vrf_zebra_ribs_rib_get_next(struct nb_cb_get_next_args *args);
-int lib_vrf_zebra_ribs_rib_get_keys(struct nb_cb_get_keys_args *args);
-const void *
-lib_vrf_zebra_ribs_rib_lookup_entry(struct nb_cb_lookup_entry_args *args);
-const void *
-lib_vrf_zebra_ribs_rib_route_get_next(struct nb_cb_get_next_args *args);
-int lib_vrf_zebra_ribs_rib_route_get_keys(struct nb_cb_get_keys_args *args);
-const void *
-lib_vrf_zebra_ribs_rib_route_lookup_entry(struct nb_cb_lookup_entry_args *args);
-struct yang_data *
-lib_vrf_zebra_ribs_rib_route_prefix_get_elem(struct nb_cb_get_elem_args *args);
 const void *lib_vrf_zebra_ribs_rib_route_route_entry_get_next(
        struct nb_cb_get_next_args *args);
 int lib_vrf_zebra_ribs_rib_route_route_entry_get_keys(
index ee2dc7a0edc11505e9486316cc298f74fdb8b676..3e89df68fdc9d44a5cfe8073670d7966dcdb2370 100644 (file)
@@ -37,7 +37,6 @@
 #include "lib_errors.h"
 
 #include "zebra_router.h"
-#include "zebra_memory.h"
 #endif /* defined(HAVE_NETLINK) */
 
 #include "zebra_netns_notify.h"
@@ -53,7 +52,7 @@
 #define ZEBRA_NS_POLLING_INTERVAL_MSEC     1000
 #define ZEBRA_NS_POLLING_MAX_RETRIES  200
 
-DEFINE_MTYPE_STATIC(ZEBRA, NETNS_MISC, "ZebraNetNSInfo")
+DEFINE_MTYPE_STATIC(ZEBRA, NETNS_MISC, "ZebraNetNSInfo");
 static struct thread *zebra_netns_notify_current;
 
 struct zebra_netns_info {
index 3f567d9a7079bda63da21d1c7ed8393ac4a1310c..12ed024a661ea3986dc027b700b907157bcbe8dc 100644 (file)
@@ -36,7 +36,6 @@
 #include "zebra/zebra_nhg_private.h"
 #include "zebra/zebra_rnh.h"
 #include "zebra/zebra_routemap.h"
-#include "zebra/zebra_memory.h"
 #include "zebra/zebra_srte.h"
 #include "zebra/zserv.h"
 #include "zebra/rt.h"
@@ -49,12 +48,23 @@ DEFINE_MTYPE_STATIC(ZEBRA, NHG, "Nexthop Group Entry");
 DEFINE_MTYPE_STATIC(ZEBRA, NHG_CONNECTED, "Nexthop Group Connected");
 DEFINE_MTYPE_STATIC(ZEBRA, NHG_CTX, "Nexthop Group Context");
 
+/* Map backup nexthop indices between two nhes */
+struct backup_nh_map_s {
+       int map_count;
+
+       struct {
+               uint8_t orig_idx;
+               uint8_t new_idx;
+       } map[MULTIPATH_NUM];
+};
+
 /* id counter to keep in sync with kernel */
 uint32_t id_counter;
 
-/*  */
+/* Controlled through ui */
 static bool g_nexthops_enabled = true;
 static bool proto_nexthops_only;
+static bool use_recursive_backups = true;
 
 static struct nhg_hash_entry *depends_find(const struct nexthop *nh, afi_t afi,
                                           int type, bool from_dplane);
@@ -371,8 +381,8 @@ void zebra_nhe_init(struct nhg_hash_entry *nhe, afi_t afi,
         */
        if (nh && (nh->next == NULL)) {
                switch (nh->type) {
-               case (NEXTHOP_TYPE_IFINDEX):
-               case (NEXTHOP_TYPE_BLACKHOLE):
+               case NEXTHOP_TYPE_IFINDEX:
+               case NEXTHOP_TYPE_BLACKHOLE:
                        /*
                         * This switch case handles setting the afi different
                         * for ipv4/v6 routes. Ifindex/blackhole nexthop
@@ -383,12 +393,12 @@ void zebra_nhe_init(struct nhg_hash_entry *nhe, afi_t afi,
                         */
                        nhe->afi = afi;
                        break;
-               case (NEXTHOP_TYPE_IPV4_IFINDEX):
-               case (NEXTHOP_TYPE_IPV4):
+               case NEXTHOP_TYPE_IPV4_IFINDEX:
+               case NEXTHOP_TYPE_IPV4:
                        nhe->afi = AFI_IP;
                        break;
-               case (NEXTHOP_TYPE_IPV6_IFINDEX):
-               case (NEXTHOP_TYPE_IPV6):
+               case NEXTHOP_TYPE_IPV6_IFINDEX:
+               case NEXTHOP_TYPE_IPV6:
                        nhe->afi = AFI_IP6;
                        break;
                }
@@ -1626,9 +1636,10 @@ void zebra_nhg_increment_ref(struct nhg_hash_entry *nhe)
                nhg_connected_tree_increment_ref(&nhe->nhg_depends);
 }
 
-static void nexthop_set_resolved(afi_t afi, const struct nexthop *newhop,
-                                struct nexthop *nexthop,
-                                struct zebra_sr_policy *policy)
+static struct nexthop *nexthop_set_resolved(afi_t afi,
+                                           const struct nexthop *newhop,
+                                           struct nexthop *nexthop,
+                                           struct zebra_sr_policy *policy)
 {
        struct nexthop *resolved_hop;
        uint8_t num_labels = 0;
@@ -1746,6 +1757,8 @@ static void nexthop_set_resolved(afi_t afi, const struct nexthop *newhop,
 
        resolved_hop->rparent = nexthop;
        _nexthop_add(&nexthop->resolved, resolved_hop);
+
+       return resolved_hop;
 }
 
 /* Checks if nexthop we are trying to resolve to is valid */
@@ -1784,13 +1797,109 @@ static bool nexthop_valid_resolve(const struct nexthop *nexthop,
 }
 
 /*
- * Given a nexthop we need to properly recursively resolve
- * the route.  As such, do a table lookup to find and match
- * if at all possible.  Set the nexthop->ifindex and resolved_id
- * as appropriate
+ * When resolving a recursive nexthop, capture backup nexthop(s) also
+ * so they can be conveyed through the dataplane to the FIB. We'll look
+ * at the backups in the resolving nh 'nexthop' and its nhe, and copy them
+ * into the route's resolved nh 'resolved' and its nhe 'nhe'.
+ */
+static int resolve_backup_nexthops(const struct nexthop *nexthop,
+                                  const struct nhg_hash_entry *nhe,
+                                  struct nexthop *resolved,
+                                  struct nhg_hash_entry *resolve_nhe,
+                                  struct backup_nh_map_s *map)
+{
+       int i, j, idx;
+       const struct nexthop *bnh;
+       struct nexthop *nh, *newnh;
+
+       assert(nexthop->backup_num <= NEXTHOP_MAX_BACKUPS);
+
+       if (resolve_nhe->backup_info->nhe == NULL)
+               resolve_nhe->backup_info->nhe = zebra_nhg_alloc();
+
+       /* Locate backups from the original nexthop's backup index and nhe */
+       for (i = 0; i < nexthop->backup_num; i++) {
+               idx = nexthop->backup_idx[i];
+
+               /* Do we already know about this particular backup? */
+               for (j = 0; j < map->map_count; j++) {
+                       if (map->map[j].orig_idx == idx)
+                               break;
+               }
+
+               if (j < map->map_count) {
+                       resolved->backup_idx[resolved->backup_num] =
+                               map->map[j].new_idx;
+                       resolved->backup_num++;
+
+                       if (IS_ZEBRA_DEBUG_RIB_DETAILED)
+                               zlog_debug("%s: found map idx orig %d, new %d",
+                                          __func__, map->map[j].orig_idx,
+                                          map->map[j].new_idx);
+
+                       continue;
+               }
+
+               /* We can't handle any new map entries at this point. */
+               if (map->map_count == MULTIPATH_NUM)
+                       break;
+
+               /* Need to create/copy a new backup */
+               bnh = nhe->backup_info->nhe->nhg.nexthop;
+               for (j = 0; j < idx; j++) {
+                       if (bnh == NULL)
+                               break;
+                       bnh = bnh->next;
+               }
+
+               /* Whoops - bad index in the nexthop? */
+               if (bnh == NULL)
+                       continue;
+
+               /* Update backup info in the resolving nexthop and its nhe */
+               newnh = nexthop_dup_no_recurse(bnh, NULL);
+
+               /* Need to compute the new backup index in the new
+                * backup list, and add to map struct.
+                */
+               j = 0;
+               nh = resolve_nhe->backup_info->nhe->nhg.nexthop;
+               if (nh) {
+                       while (nh->next) {
+                               nh = nh->next;
+                               j++;
+                       }
+
+                       nh->next = newnh;
+
+               } else  /* First one */
+                       resolve_nhe->backup_info->nhe->nhg.nexthop = newnh;
+
+               /* Capture index */
+               resolved->backup_idx[resolved->backup_num] = j;
+               resolved->backup_num++;
+
+               if (IS_ZEBRA_DEBUG_RIB_DETAILED)
+                       zlog_debug("%s: added idx orig %d, new %d",
+                                  __func__, idx, j);
+
+               /* Update map/cache */
+               map->map[map->map_count].orig_idx = idx;
+               map->map[map->map_count].new_idx = j;
+               map->map_count++;
+       }
+
+       return 0;
+}
+
+/*
+ * Given a nexthop we need to properly recursively resolve,
+ * do a table lookup to find and match if at all possible.
+ * Set the nexthop->ifindex and resolution info as appropriate.
  */
-static int nexthop_active(afi_t afi, struct route_entry *re,
-                         struct nexthop *nexthop, struct route_node *top)
+static int nexthop_active(struct nexthop *nexthop, struct nhg_hash_entry *nhe,
+                         const struct prefix *top, int type, uint32_t flags,
+                         uint32_t *pmtu)
 {
        struct prefix p;
        struct route_table *table;
@@ -1804,33 +1913,65 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
        struct zebra_vrf *zvrf;
        struct in_addr local_ipv4;
        struct in_addr *ipv4;
+       afi_t afi = AFI_IP;
 
+       /* Reset some nexthop attributes that we'll recompute if necessary */
        if ((nexthop->type == NEXTHOP_TYPE_IPV4)
-           || nexthop->type == NEXTHOP_TYPE_IPV6)
+           || (nexthop->type == NEXTHOP_TYPE_IPV6))
                nexthop->ifindex = 0;
 
-
        UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
        nexthops_free(nexthop->resolved);
        nexthop->resolved = NULL;
-       re->nexthop_mtu = 0;
-
-       if (IS_ZEBRA_DEBUG_NHG_DETAIL)
-               zlog_debug("%s: re %p, nexthop %pNHv",
-                          __func__, re, nexthop);
 
        /*
-        * If the kernel has sent us a NEW route, then
-        * by golly gee whiz it's a good route.
-        *
-        * If its an already INSTALLED route we have already handled, then the
-        * kernel route's nexthop might have became unreachable
-        * and we have to handle that.
+        * Set afi based on nexthop type.
+        * Some nexthop types get special handling, possibly skipping
+        * the normal processing.
         */
-       if (!CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)
-           && (re->type == ZEBRA_ROUTE_KERNEL
-               || re->type == ZEBRA_ROUTE_SYSTEM))
+       switch (nexthop->type) {
+       case NEXTHOP_TYPE_IFINDEX:
+
+               ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id);
+               /*
+                * If the interface exists and its operative or its a kernel
+                * route and interface is up, its active. We trust kernel routes
+                * to be good.
+                */
+               if (ifp
+                   && (if_is_operative(ifp)
+                       || (if_is_up(ifp)
+                           && (type == ZEBRA_ROUTE_KERNEL
+                               || type == ZEBRA_ROUTE_SYSTEM))))
+                       return 1;
+               else
+                       return 0;
+               break;
+
+       case NEXTHOP_TYPE_IPV6_IFINDEX:
+               afi = AFI_IP6;
+
+               if (IN6_IS_ADDR_LINKLOCAL(&nexthop->gate.ipv6)) {
+                       ifp = if_lookup_by_index(nexthop->ifindex,
+                                                nexthop->vrf_id);
+                       if (ifp && if_is_operative(ifp))
+                               return 1;
+                       else
+                               return 0;
+               }
+               break;
+
+       case NEXTHOP_TYPE_IPV4:
+       case NEXTHOP_TYPE_IPV4_IFINDEX:
+               afi = AFI_IP;
+               break;
+       case NEXTHOP_TYPE_IPV6:
+               afi = AFI_IP6;
+               break;
+
+       case NEXTHOP_TYPE_BLACKHOLE:
                return 1;
+       }
 
        /*
         * If the nexthop has been marked as 'onlink' we just need to make
@@ -1853,10 +1994,11 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
                return 1;
        }
 
-       if ((top->p.family == AF_INET && top->p.prefixlen == 32
-            && nexthop->gate.ipv4.s_addr == top->p.u.prefix4.s_addr)
-           || (top->p.family == AF_INET6 && top->p.prefixlen == 128
-               && memcmp(&nexthop->gate.ipv6, &top->p.u.prefix6, 16) == 0)) {
+       if (top &&
+           ((top->family == AF_INET && top->prefixlen == 32
+             && nexthop->gate.ipv4.s_addr == top->u.prefix4.s_addr)
+            || (top->family == AF_INET6 && top->prefixlen == 128
+                && memcmp(&nexthop->gate.ipv6, &top->u.prefix6, 16) == 0))) {
                if (IS_ZEBRA_DEBUG_RIB_DETAILED)
                        zlog_debug(
                                "        :%s: Attempting to install a max prefixlength route through itself",
@@ -1873,6 +2015,9 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
                ipv4 = &nexthop->gate.ipv4;
        }
 
+       /* Processing for nexthops with SR 'color' attribute, using
+        * the corresponding SR policy object.
+        */
        if (nexthop->srte_color) {
                struct ipaddr endpoint = {0};
                struct zebra_sr_policy *policy;
@@ -1950,7 +2095,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
                 * resolved by a route NH1. The exception is if the route is a
                 * host route.
                 */
-               if (rn == top)
+               if (prefix_same(&rn->p, top))
                        if (((afi == AFI_IP) && (rn->p.prefixlen != 32))
                            || ((afi == AFI_IP6) && (rn->p.prefixlen != 128))) {
                                if (IS_ZEBRA_DEBUG_RIB_DETAILED)
@@ -2020,8 +2165,10 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
                                           match->nhe->id, newhop);
 
                        return 1;
-               } else if (CHECK_FLAG(re->flags, ZEBRA_FLAG_ALLOW_RECURSION)) {
+               } else if (CHECK_FLAG(flags, ZEBRA_FLAG_ALLOW_RECURSION)) {
                        struct nexthop_group *nhg;
+                       struct nexthop *resolver;
+                       struct backup_nh_map_s map = {};
 
                        resolved = 0;
 
@@ -2051,17 +2198,29 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
 
                                SET_FLAG(nexthop->flags,
                                         NEXTHOP_FLAG_RECURSIVE);
-                               nexthop_set_resolved(afi, newhop, nexthop,
-                                                    NULL);
+                               resolver = nexthop_set_resolved(afi, newhop,
+                                                               nexthop, NULL);
                                resolved = 1;
+
+                               /* If there are backup nexthops, capture
+                                * that info with the resolving nexthop.
+                                */
+                               if (resolver && newhop->backup_num > 0) {
+                                       resolve_backup_nexthops(newhop,
+                                                               match->nhe,
+                                                               resolver, nhe,
+                                                               &map);
+                               }
                        }
 
                        /* Examine installed backup nexthops, if any. There
                         * are only installed backups *if* there is a
-                        * dedicated fib list.
+                        * dedicated fib list. The UI can also control use
+                        * of backups for resolution.
                         */
                        nhg = rib_get_fib_backup_nhg(match);
-                       if (nhg == NULL || nhg->nexthop == NULL)
+                       if (!use_recursive_backups ||
+                           nhg == NULL || nhg->nexthop == NULL)
                                goto done_with_match;
 
                        for (ALL_NEXTHOPS_PTR(nhg, newhop)) {
@@ -2079,10 +2238,14 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
                                                     NULL);
                                resolved = 1;
                        }
+
 done_with_match:
-                       if (resolved)
-                               re->nexthop_mtu = match->mtu;
-                       else if (IS_ZEBRA_DEBUG_RIB_DETAILED)
+                       /* Capture resolving mtu */
+                       if (resolved) {
+                               if (pmtu)
+                                       *pmtu = match->mtu;
+
+                       } else if (IS_ZEBRA_DEBUG_RIB_DETAILED)
                                zlog_debug(
                                        "        %s: Recursion failed to find",
                                        __func__);
@@ -2092,9 +2255,9 @@ done_with_match:
                        if (IS_ZEBRA_DEBUG_RIB_DETAILED) {
                                zlog_debug(
                                        "        %s: Route Type %s has not turned on recursion",
-                                       __func__, zebra_route_string(re->type));
-                               if (re->type == ZEBRA_ROUTE_BGP
-                                   && !CHECK_FLAG(re->flags, ZEBRA_FLAG_IBGP))
+                                       __func__, zebra_route_string(type));
+                               if (type == ZEBRA_ROUTE_BGP
+                                   && !CHECK_FLAG(flags, ZEBRA_FLAG_IBGP))
                                        zlog_debug(
                                                "        EBGP: see \"disable-ebgp-connected-route-check\" or \"disable-connected-check\"");
                        }
@@ -2110,23 +2273,23 @@ done_with_match:
 /* This function verifies reachability of one given nexthop, which can be
  * numbered or unnumbered, IPv4 or IPv6. The result is unconditionally stored
  * in nexthop->flags field. The nexthop->ifindex will be updated
- * appropriately as well.  An existing route map can turn an
- * otherwise active nexthop into inactive, but not vice versa.
+ * appropriately as well.
  *
- * If it finds a nexthop recursively, set the resolved_id
- * to match that nexthop's nhg_hash_entry ID;
+ * An existing route map can turn an otherwise active nexthop into inactive,
+ * but not vice versa.
  *
  * The return value is the final value of 'ACTIVE' flag.
  */
 static unsigned nexthop_active_check(struct route_node *rn,
                                     struct route_entry *re,
-                                    struct nexthop *nexthop)
+                                    struct nexthop *nexthop,
+                                    struct nhg_hash_entry *nhe)
 {
-       struct interface *ifp;
        route_map_result_t ret = RMAP_PERMITMATCH;
        afi_t family;
        const struct prefix *p, *src_p;
        struct zebra_vrf *zvrf;
+       uint32_t mtu = 0;
 
        srcdest_rnode_prefixes(rn, &p, &src_p);
 
@@ -2137,19 +2300,28 @@ static unsigned nexthop_active_check(struct route_node *rn,
        else
                family = 0;
 
+       if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+               zlog_debug("%s: re %p, nexthop %pNHv", __func__, re, nexthop);
+
+       /*
+        * If the kernel has sent us a NEW route, then
+        * by golly gee whiz it's a good route.
+        *
+        * If its an already INSTALLED route we have already handled, then the
+        * kernel route's nexthop might have became unreachable
+        * and we have to handle that.
+        */
+       if (!CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED) &&
+           (re->type == ZEBRA_ROUTE_KERNEL ||
+            re->type == ZEBRA_ROUTE_SYSTEM)) {
+               SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+               goto skip_check;
+       }
+
        switch (nexthop->type) {
        case NEXTHOP_TYPE_IFINDEX:
-               ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id);
-               /*
-                * If the interface exists and its operative or its a kernel
-                * route and interface is up, its active. We trust kernel routes
-                * to be good.
-                */
-               if (ifp
-                   && (if_is_operative(ifp)
-                       || (if_is_up(ifp)
-                           && (re->type == ZEBRA_ROUTE_KERNEL
-                               || re->type == ZEBRA_ROUTE_SYSTEM))))
+               if (nexthop_active(nexthop, nhe, &rn->p, re->type,
+                                  re->flags, &mtu))
                        SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
                else
                        UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
@@ -2157,14 +2329,16 @@ static unsigned nexthop_active_check(struct route_node *rn,
        case NEXTHOP_TYPE_IPV4:
        case NEXTHOP_TYPE_IPV4_IFINDEX:
                family = AFI_IP;
-               if (nexthop_active(AFI_IP, re, nexthop, rn))
+               if (nexthop_active(nexthop, nhe, &rn->p, re->type,
+                                  re->flags, &mtu))
                        SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
                else
                        UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
                break;
        case NEXTHOP_TYPE_IPV6:
                family = AFI_IP6;
-               if (nexthop_active(AFI_IP6, re, nexthop, rn))
+               if (nexthop_active(nexthop, nhe, &rn->p, re->type,
+                                  re->flags, &mtu))
                        SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
                else
                        UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
@@ -2173,19 +2347,12 @@ static unsigned nexthop_active_check(struct route_node *rn,
                /* RFC 5549, v4 prefix with v6 NH */
                if (rn->p.family != AF_INET)
                        family = AFI_IP6;
-               if (IN6_IS_ADDR_LINKLOCAL(&nexthop->gate.ipv6)) {
-                       ifp = if_lookup_by_index(nexthop->ifindex,
-                                                nexthop->vrf_id);
-                       if (ifp && if_is_operative(ifp))
-                               SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
-                       else
-                               UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
-               } else {
-                       if (nexthop_active(AFI_IP6, re, nexthop, rn))
-                               SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
-                       else
-                               UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
-               }
+
+               if (nexthop_active(nexthop, nhe, &rn->p, re->type,
+                                  re->flags, &mtu))
+                       SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+               else
+                       UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
                break;
        case NEXTHOP_TYPE_BLACKHOLE:
                SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
@@ -2194,6 +2361,8 @@ static unsigned nexthop_active_check(struct route_node *rn,
                break;
        }
 
+skip_check:
+
        if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) {
                if (IS_ZEBRA_DEBUG_RIB_DETAILED)
                        zlog_debug("        %s: Unable to find active nexthop",
@@ -2201,6 +2370,18 @@ static unsigned nexthop_active_check(struct route_node *rn,
                return 0;
        }
 
+       /* Capture recursive nexthop mtu.
+        * TODO -- the code used to just reset the re's value to zero
+        * for each nexthop, and then jam any resolving route's mtu value in,
+        * whether or not that was zero, or lt/gt any existing value? The
+        * way this is used appears to be as a floor value, so let's try
+        * using it that way here.
+        */
+       if (mtu > 0) {
+               if (re->nexthop_mtu == 0 || re->nexthop_mtu > mtu)
+                       re->nexthop_mtu = mtu;
+       }
+
        /* XXX: What exactly do those checks do? Do we support
         * e.g. IPv4 routes with IPv6 nexthops or vice versa?
         */
@@ -2214,7 +2395,7 @@ static unsigned nexthop_active_check(struct route_node *rn,
         * Possibly it may be better to use only the rib_table_info
         * in every case.
         */
-       if (!family) {
+       if (family == 0) {
                struct rib_table_info *info;
 
                info = srcdest_rnode_table_info(rn);
@@ -2277,21 +2458,26 @@ done:
 }
 
 /*
- * Process a list of nexthops, given an nhg, determining
+ * Process a list of nexthops, given an nhe, determining
  * whether each one is ACTIVE/installable at this time.
  */
 static uint32_t nexthop_list_active_update(struct route_node *rn,
                                           struct route_entry *re,
-                                          struct nexthop_group *nhg)
+                                          struct nhg_hash_entry *nhe,
+                                          bool is_backup)
 {
        union g_addr prev_src;
        unsigned int prev_active, new_active;
        ifindex_t prev_index;
        uint32_t counter = 0;
        struct nexthop *nexthop;
+       struct nexthop_group *nhg = &nhe->nhg;
 
        nexthop = nhg->nexthop;
 
+       /* Init recursive nh mtu */
+       re->nexthop_mtu = 0;
+
        /* Process nexthops one-by-one */
        for ( ; nexthop; nexthop = nexthop->next) {
 
@@ -2301,15 +2487,20 @@ static uint32_t nexthop_list_active_update(struct route_node *rn,
                prev_src = nexthop->rmap_src;
                prev_active = CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
                prev_index = nexthop->ifindex;
+
+               /* Include the containing nhe for primary nexthops: if there's
+                * recursive resolution, we capture the backup info also.
+                */
+               new_active =
+                       nexthop_active_check(rn, re, nexthop,
+                                            (is_backup ? NULL : nhe));
+
                /*
                 * We need to respect the multipath_num here
                 * as that what we should be able to install from
                 * a multipath perspective should not be a data plane
                 * decision point.
                 */
-               new_active =
-                       nexthop_active_check(rn, re, nexthop);
-
                if (new_active && counter >= zrouter.multipath_num) {
                        struct nexthop *nh;
 
@@ -2323,7 +2514,7 @@ static uint32_t nexthop_list_active_update(struct route_node *rn,
                if (new_active)
                        counter++;
 
-               /* Don't allow src setting on IPv6 addr for now */
+               /* Check for changes to the nexthop - set ROUTE_ENTRY_CHANGED */
                if (prev_active != new_active || prev_index != nexthop->ifindex
                    || ((nexthop->type >= NEXTHOP_TYPE_IFINDEX
                         && nexthop->type < NEXTHOP_TYPE_IPV6)
@@ -2392,7 +2583,7 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re)
        curr_nhe->id = 0;
 
        /* Process nexthops */
-       curr_active = nexthop_list_active_update(rn, re, &curr_nhe->nhg);
+       curr_active = nexthop_list_active_update(rn, re, curr_nhe, false);
 
        if (IS_ZEBRA_DEBUG_NHG_DETAIL)
                zlog_debug("%s: re %p curr_active %u", __func__, re,
@@ -2403,7 +2594,7 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re)
                goto backups_done;
 
        backup_active = nexthop_list_active_update(
-               rn, re, zebra_nhg_get_backup_nhg(curr_nhe));
+               rn, re, curr_nhe->backup_info->nhe, true /*is_backup*/);
 
        if (IS_ZEBRA_DEBUG_NHG_DETAIL)
                zlog_debug("%s: re %p backup_active %u", __func__, re,
@@ -2782,6 +2973,17 @@ bool zebra_nhg_kernel_nexthops_enabled(void)
        return g_nexthops_enabled;
 }
 
+/* Global control for use of activated backups for recursive resolution. */
+void zebra_nhg_set_recursive_use_backups(bool set)
+{
+       use_recursive_backups = set;
+}
+
+bool zebra_nhg_recursive_use_backups(void)
+{
+       return use_recursive_backups;
+}
+
 /*
  * Global control to only use kernel nexthops for protocol created NHGs.
  * There are some use cases where you may not want zebra to implicitly
index db20f2beaffc73e3dcac5a55e153fe91a4d252cb..38015bf557d3fede57ae50bf70c20de94d8ebabf 100644 (file)
@@ -180,8 +180,9 @@ struct nhg_ctx {
 
        vrf_id_t vrf_id;
        afi_t afi;
+
        /*
-        * This should only every be ZEBRA_ROUTE_NHG unless we get a a kernel
+        * This should only ever be ZEBRA_ROUTE_NHG unless we get a a kernel
         * created nexthop not made by us.
         */
        int type;
@@ -211,6 +212,10 @@ bool zebra_nhg_kernel_nexthops_enabled(void);
 void zebra_nhg_set_proto_nexthops_only(bool set);
 bool zebra_nhg_proto_nexthops_only(void);
 
+/* Global control for use of activated backups for recursive resolution. */
+void zebra_nhg_set_recursive_use_backups(bool set);
+bool zebra_nhg_recursive_use_backups(void);
+
 /**
  * NHE abstracted tree functions.
  * Use these where possible instead of direct access.
index e9ff3fcc087ef22b5f2fa7b6e5be53d4d0ffdd18..27b8a3ea477e9d527a45f35c6374faf253af8c62 100644 (file)
@@ -28,7 +28,6 @@
 
 #include "zebra_ns.h"
 #include "zebra_vrf.h"
-#include "zebra_memory.h"
 #include "rt.h"
 #include "zebra_vxlan.h"
 #include "debug.h"
@@ -41,7 +40,7 @@
 
 extern struct zebra_privs_t zserv_privs;
 
-DEFINE_MTYPE(ZEBRA, ZEBRA_NS, "Zebra Name Space")
+DEFINE_MTYPE_STATIC(ZEBRA, ZEBRA_NS, "Zebra Name Space");
 
 static struct zebra_ns *dzns;
 
index 1d59e0ab3486b4ff6c5e7e26e91db8fee4d4a75d..244f16302bf40cbe4c3d452207f32feaa440865a 100644 (file)
@@ -24,7 +24,6 @@
 #include "lib/stream.h"
 #include "zebra/debug.h"
 #include "zebra/zserv.h"
-#include "zebra/zebra_memory.h"
 #include "zebra/zebra_opaque.h"
 
 /* Mem type */
index 92a7a0ba3a5a405902e55849b99184151e22b2ce..c4004842e6c9c33099437dd165ac49f5723f0b83 100644 (file)
 #include "zebra/zebra_pbr.h"
 #include "zebra/rt.h"
 #include "zebra/zapi_msg.h"
-#include "zebra/zebra_memory.h"
 #include "zebra/zserv.h"
 #include "zebra/debug.h"
 
 /* definitions */
-DEFINE_MTYPE_STATIC(ZEBRA, PBR_IPTABLE_IFNAME, "PBR interface list")
+DEFINE_MTYPE_STATIC(ZEBRA, PBR_IPTABLE_IFNAME, "PBR interface list");
 
 /* definitions */
 static const struct message ipset_type_msg[] = {
@@ -128,12 +127,12 @@ static const struct message fragment_value_str[] = {
 DEFINE_HOOK(zebra_pbr_ipset_entry_get_stat,
            (struct zebra_pbr_ipset_entry *ipset, uint64_t *pkts,
             uint64_t *bytes),
-           (ipset, pkts, bytes))
+           (ipset, pkts, bytes));
 
 DEFINE_HOOK(zebra_pbr_iptable_get_stat,
            (struct zebra_pbr_iptable *iptable, uint64_t *pkts,
             uint64_t *bytes),
-           (iptable, pkts, bytes))
+           (iptable, pkts, bytes));
 
 DEFINE_HOOK(zebra_pbr_iptable_update,
            (int cmd, struct zebra_pbr_iptable *iptable), (cmd, iptable));
index ef930336614b81e22014a8baab1df1584a452f25..2e9658e7e5083fc32f801bf7abbc5eceda3b6407 100644 (file)
@@ -249,11 +249,11 @@ size_t zebra_pbr_tcpflags_snprintf(char *buffer, size_t len,
 DECLARE_HOOK(zebra_pbr_ipset_entry_get_stat,
             (struct zebra_pbr_ipset_entry *ipset, uint64_t *pkts,
              uint64_t *bytes),
-            (ipset, pkts, bytes))
+            (ipset, pkts, bytes));
 DECLARE_HOOK(zebra_pbr_iptable_get_stat,
             (struct zebra_pbr_iptable *iptable, uint64_t *pkts,
              uint64_t *bytes),
-            (iptable, pkts, bytes))
+            (iptable, pkts, bytes));
 DECLARE_HOOK(zebra_pbr_iptable_update,
             (int cmd, struct zebra_pbr_iptable *iptable), (cmd, iptable));
 
index 1e7b38086b1d03032cb53fe2ebd6c3e9efefd4d9..bea855d1af6f41f1923190a6ec9c6af65a0f9ceb 100644 (file)
@@ -1167,8 +1167,6 @@ void zebra_ptm_if_write(struct vty *vty, struct zebra_if *zebra_ifp)
 
 #else /* HAVE_BFDD */
 
-#include "zebra/zebra_memory.h"
-
 /*
  * Data structures.
  */
index eabc2e005e10c61d4f05ebb5250d4aa62e0c1728..537d69fbcaad1dad85e15b2406431f10610f71cf 100644 (file)
@@ -26,7 +26,6 @@
 #include "zebra/zapi_msg.h"
 #include "zebra/zebra_ptm.h"
 #include "zebra/zebra_ptm_redistribute.h"
-#include "zebra/zebra_memory.h"
 
 static int zsend_interface_bfd_update(int cmd, struct zserv *client,
                                      struct interface *ifp, struct prefix *dp,
index ecae021dba1e38909c72ed0e298ddff486c48141..5afb3e5926ec083b3bf72c7aa1b9e04af46fe979 100644 (file)
 #include "zebra/zebra_vrf.h"
 #include "zebra/zebra_pw.h"
 
-DEFINE_MTYPE_STATIC(LIB, PW, "Pseudowire")
+DEFINE_MTYPE_STATIC(LIB, PW, "Pseudowire");
 
-DEFINE_QOBJ_TYPE(zebra_pw)
+DEFINE_QOBJ_TYPE(zebra_pw);
 
-DEFINE_HOOK(pw_install, (struct zebra_pw * pw), (pw))
-DEFINE_HOOK(pw_uninstall, (struct zebra_pw * pw), (pw))
+DEFINE_HOOK(pw_install, (struct zebra_pw * pw), (pw));
+DEFINE_HOOK(pw_uninstall, (struct zebra_pw * pw), (pw));
 
 #define MPLS_NO_LABEL MPLS_INVALID_LABEL
 
index 7b13c7e16b13631182549c6b76ba46ac2644ad2c..0da8203802697582e6a6eea538d3be76e476ee20 100644 (file)
@@ -53,9 +53,9 @@ struct zebra_pw {
        struct zserv *client;
        struct rnh *rnh;
        struct thread *install_retry_timer;
-       QOBJ_FIELDS
+       QOBJ_FIELDS;
 };
-DECLARE_QOBJ_TYPE(zebra_pw)
+DECLARE_QOBJ_TYPE(zebra_pw);
 
 RB_HEAD(zebra_pw_head, zebra_pw);
 RB_PROTOTYPE(zebra_pw_head, zebra_pw, pw_entry, zebra_pw_compare);
@@ -63,8 +63,8 @@ RB_PROTOTYPE(zebra_pw_head, zebra_pw, pw_entry, zebra_pw_compare);
 RB_HEAD(zebra_static_pw_head, zebra_pw);
 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))
+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 *zvrf, const char *ifname,
                              uint8_t protocol, struct zserv *client);
index bc3c68638d12ca84b90a804b932104118dc790d8..ffe4be8557fd9d37bffeffeb8abb2ac730533d76 100644 (file)
@@ -49,7 +49,6 @@
 #include "zebra/rt.h"
 #include "zebra/zapi_msg.h"
 #include "zebra/zebra_errors.h"
-#include "zebra/zebra_memory.h"
 #include "zebra/zebra_ns.h"
 #include "zebra/zebra_rnh.h"
 #include "zebra/zebra_routemap.h"
 #include "zebra/zapi_msg.h"
 #include "zebra/zebra_dplane.h"
 
+DEFINE_MGROUP(ZEBRA, "zebra");
+
+DEFINE_MTYPE(ZEBRA, RE,       "Route Entry");
+DEFINE_MTYPE_STATIC(ZEBRA, RIB_DEST,       "RIB destination");
 DEFINE_MTYPE_STATIC(ZEBRA, RIB_UPDATE_CTX, "Rib update context object");
 
 /*
@@ -68,7 +71,7 @@ static struct thread *t_dplane;
 static struct dplane_ctx_q rib_dplane_q;
 
 DEFINE_HOOK(rib_update, (struct route_node * rn, const char *reason),
-           (rn, reason))
+           (rn, reason));
 
 /* Should we allow non Quagga processes to delete our routes */
 extern int allow_delete;
@@ -800,6 +803,23 @@ int rib_gc_dest(struct route_node *rn)
        return 1;
 }
 
+void zebra_rtable_node_cleanup(struct route_table *table,
+                              struct route_node *node)
+{
+       struct route_entry *re, *next;
+
+       RNODE_FOREACH_RE_SAFE (node, re, next) {
+               rib_unlink(node, re);
+       }
+
+       if (node->info) {
+               rib_dest_t *dest = node->info;
+
+               rnh_list_fini(&dest->nht);
+               XFREE(MTYPE_RIB_DEST, node->info);
+       }
+}
+
 static void rib_process_add_fib(struct zebra_vrf *zvrf, struct route_node *rn,
                                struct route_entry *new)
 {
@@ -2698,7 +2718,7 @@ void rib_unlink(struct route_node *rn, struct route_entry *re)
 
        nexthops_free(re->fib_ng.nexthop);
 
-       XFREE(MTYPE_OPAQUE, re->opaque);
+       zapi_opaque_free(re->opaque);
 
        XFREE(MTYPE_RE, re);
 }
index 48e2bafe4423e110122906107af77d3aa16fe1ef..3b0ef71987449e8cc4139ecd83d90d6011d1942d 100644 (file)
 #include "zebra/zebra_routemap.h"
 #include "zebra/zebra_srte.h"
 #include "zebra/interface.h"
-#include "zebra/zebra_memory.h"
 #include "zebra/zebra_errors.h"
 
-DEFINE_MTYPE_STATIC(ZEBRA, RNH, "Nexthop tracking object")
+DEFINE_MTYPE_STATIC(ZEBRA, RNH, "Nexthop tracking object");
 
 static void free_state(vrf_id_t vrf_id, struct route_entry *re,
                       struct route_node *rn);
index 17a9bf97f94c3936d5bb48968c0a15efe902296b..c9660c7309a067a3079529be35524191ab97fd3a 100644 (file)
@@ -21,7 +21,6 @@
 #include <zebra.h>
 
 #include "memory.h"
-#include "zebra_memory.h"
 #include "prefix.h"
 #include "rib.h"
 #include "vty.h"
index 249ec38a69bffa626eb8a6269b8613ba1f343449..5a00f3155d75071d2484fef4675773b08ed9b771 100644 (file)
 #include "lib/frratomic.h"
 
 #include "zebra_router.h"
-#include "zebra_memory.h"
 #include "zebra_pbr.h"
 #include "zebra_vxlan.h"
 #include "zebra_mlag.h"
 #include "zebra_nhg.h"
 #include "debug.h"
 
-DEFINE_MTYPE_STATIC(ZEBRA, RIB_TABLE_INFO, "RIB table info")
+DEFINE_MTYPE_STATIC(ZEBRA, RIB_TABLE_INFO, "RIB table info");
+DEFINE_MTYPE_STATIC(ZEBRA, ZEBRA_RT_TABLE, "Zebra VRF table");
 
 struct zebra_router zrouter = {
        .multipath_num = MULTIPATH_NUM,
@@ -121,7 +121,7 @@ struct route_table *zebra_router_get_table(struct zebra_vrf *zvrf,
        if (zrt)
                return zrt->table;
 
-       zrt = XCALLOC(MTYPE_ZEBRA_NS, sizeof(*zrt));
+       zrt = XCALLOC(MTYPE_ZEBRA_RT_TABLE, sizeof(*zrt));
        zrt->tableid = tableid;
        zrt->afi = afi;
        zrt->safi = safi;
@@ -185,7 +185,7 @@ static void zebra_router_free_table(struct zebra_router_table *zrt)
        RB_REMOVE(zebra_router_table_head, &zrouter.tables, zrt);
 
        XFREE(MTYPE_RIB_TABLE_INFO, table_info);
-       XFREE(MTYPE_ZEBRA_NS, zrt);
+       XFREE(MTYPE_ZEBRA_RT_TABLE, zrt);
 }
 
 void zebra_router_release_table(struct zebra_vrf *zvrf, uint32_t tableid,
index 89b8238c29386401e8f2b302c92f24f771c58729..3e08d83724454a66daba0190df6ccc5e1c90a09c 100644 (file)
@@ -566,4 +566,5 @@ static int zebra_snmp_module_init(void)
 
 FRR_MODULE_SETUP(.name = "zebra_snmp", .version = FRR_VERSION,
                 .description = "zebra AgentX SNMP module",
-                .init = zebra_snmp_module_init, )
+                .init = zebra_snmp_module_init,
+);
index d6043534e3e04842b777b75cc20b0b78d1424507..98158ecc12b2a22d1d9a694d1de255e93a7c51fd 100644 (file)
 #include "lib/lib_errors.h"
 
 #include "zebra/zebra_srte.h"
-#include "zebra/zebra_memory.h"
 #include "zebra/zebra_mpls.h"
 #include "zebra/zebra_rnh.h"
 #include "zebra/zapi_msg.h"
 
-DEFINE_MTYPE_STATIC(ZEBRA, ZEBRA_SR_POLICY, "SR Policy")
+DEFINE_MTYPE_STATIC(ZEBRA, ZEBRA_SR_POLICY, "SR Policy");
 
 static void zebra_sr_policy_deactivate(struct zebra_sr_policy *policy);
 
index be4fb29aae88d208dfe84c2fabe1c42628cbd801..b42923640f27e684b1d6ae569a35e494f06de31f 100644 (file)
@@ -36,7 +36,6 @@
 #include "zebra/zebra_vrf.h"
 #include "zebra/zebra_rnh.h"
 #include "zebra/router-id.h"
-#include "zebra/zebra_memory.h"
 #include "zebra/interface.h"
 #include "zebra/zebra_mpls.h"
 #include "zebra/zebra_vxlan.h"
@@ -48,8 +47,8 @@ static void zebra_vrf_table_create(struct zebra_vrf *zvrf, afi_t afi,
 static void zebra_rnhtable_node_cleanup(struct route_table *table,
                                        struct route_node *node);
 
-DEFINE_MTYPE_STATIC(ZEBRA, ZEBRA_VRF, "ZEBRA VRF")
-DEFINE_MTYPE_STATIC(ZEBRA, OTHER_TABLE, "Other Table")
+DEFINE_MTYPE_STATIC(ZEBRA, ZEBRA_VRF, "ZEBRA VRF");
+DEFINE_MTYPE_STATIC(ZEBRA, OTHER_TABLE, "Other Table");
 
 /* VRF information update. */
 static void zebra_vrf_add_update(struct zebra_vrf *zvrf)
@@ -413,23 +412,6 @@ done:
        return table;
 }
 
-void zebra_rtable_node_cleanup(struct route_table *table,
-                              struct route_node *node)
-{
-       struct route_entry *re, *next;
-
-       RNODE_FOREACH_RE_SAFE (node, re, next) {
-               rib_unlink(node, re);
-       }
-
-       if (node->info) {
-               rib_dest_t *dest = node->info;
-
-               rnh_list_fini(&dest->nht);
-               XFREE(MTYPE_RIB_DEST, node->info);
-       }
-}
-
 static void zebra_rnhtable_node_cleanup(struct route_table *table,
                                        struct route_node *node)
 {
index 910d1923175fad9105565ac79fc2499f101ce509..ed6376b01f14072211b41a028e83213e04ad999f 100644 (file)
@@ -238,7 +238,7 @@ zvrf_other_table_compare_func(const struct other_route_table *a,
 }
 
 DECLARE_RBTREE_UNIQ(otable, struct other_route_table, next,
-                   zvrf_other_table_compare_func)
+                   zvrf_other_table_compare_func);
 
 extern struct route_table *
 zebra_vrf_lookup_table_with_table_id(afi_t afi, safi_t safi, vrf_id_t vrf_id,
index f18d8fbb6d9151fc2af304eb14be4201d357b8d4..283a3e52d664896afcfc95d2484b2cbc5e887045 100644 (file)
@@ -21,7 +21,6 @@
 #include <zebra.h>
 
 #include "memory.h"
-#include "zebra_memory.h"
 #include "if.h"
 #include "prefix.h"
 #include "command.h"
@@ -1636,6 +1635,18 @@ DEFPY_HIDDEN(proto_nexthop_group_only, proto_nexthop_group_only_cmd,
        return CMD_SUCCESS;
 }
 
+DEFPY_HIDDEN(backup_nexthop_recursive_use_enable,
+            backup_nexthop_recursive_use_enable_cmd,
+            "[no] zebra nexthop resolve-via-backup",
+            NO_STR
+            ZEBRA_STR
+            "Nexthop configuration \n"
+            "Configure use of backup nexthops in recursive resolution\n")
+{
+       zebra_nhg_set_recursive_use_backups(!no);
+       return CMD_SUCCESS;
+}
+
 DEFUN (no_ip_nht_default_route,
        no_ip_nht_default_route_cmd,
        "no ip nht resolve-via-default",
@@ -2553,10 +2564,8 @@ DEFUN (default_vrf_vni_mapping,
        "VNI-ID\n"
        "Prefix routes only \n")
 {
-       int ret = 0;
-       char err[ERR_STR_SZ];
+       char xpath[XPATH_MAXLEN];
        struct zebra_vrf *zvrf = NULL;
-       vni_t vni = strtoul(argv[1]->arg, NULL, 10);
        int filter = 0;
 
        zvrf = vrf_info_lookup(VRF_DEFAULT);
@@ -2566,25 +2575,35 @@ DEFUN (default_vrf_vni_mapping,
        if (argc == 3)
                filter = 1;
 
-       ret = zebra_vxlan_process_vrf_vni_cmd(zvrf, vni, err, ERR_STR_SZ,
-                                             filter, 1);
-       if (ret != 0) {
-               vty_out(vty, "%s\n", err);
-               return CMD_WARNING;
+       snprintf(xpath, sizeof(xpath), FRR_VRF_KEY_XPATH "/frr-zebra:zebra",
+                VRF_DEFAULT_NAME);
+       nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+
+       snprintf(xpath, sizeof(xpath),
+                FRR_VRF_KEY_XPATH "/frr-zebra:zebra/l3vni-id",
+                VRF_DEFAULT_NAME);
+       nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, argv[1]->arg);
+
+       if (filter) {
+               snprintf(xpath, sizeof(xpath),
+                        FRR_VRF_KEY_XPATH "/frr-zebra:zebra/prefix-only",
+                        VRF_DEFAULT_NAME);
+               nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, "true");
        }
 
-       return CMD_SUCCESS;
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 DEFUN (no_default_vrf_vni_mapping,
        no_default_vrf_vni_mapping_cmd,
-       "no vni " CMD_VNI_RANGE,
+       "no vni " CMD_VNI_RANGE "[prefix-routes-only]",
        NO_STR
        "VNI corresponding to DEFAULT VRF\n"
-       "VNI-ID")
+       "VNI-ID\n"
+       "Prefix routes only \n")
 {
-       int ret = 0;
-       char err[ERR_STR_SZ];
+       char xpath[XPATH_MAXLEN];
+       int filter = 0;
        vni_t vni = strtoul(argv[2]->arg, NULL, 10);
        struct zebra_vrf *zvrf = NULL;
 
@@ -2592,13 +2611,32 @@ DEFUN (no_default_vrf_vni_mapping,
        if (!zvrf)
                return CMD_WARNING;
 
-       ret = zebra_vxlan_process_vrf_vni_cmd(zvrf, vni, err, ERR_STR_SZ, 0, 0);
-       if (ret != 0) {
-               vty_out(vty, "%s\n", err);
+       if (argc == 4)
+               filter = 1;
+
+       if (zvrf->l3vni != vni) {
+               vty_out(vty, "VNI %d doesn't exist in VRF: %s \n", vni,
+                       zvrf->vrf->name);
                return CMD_WARNING;
        }
 
-       return CMD_SUCCESS;
+       snprintf(xpath, sizeof(xpath),
+                FRR_VRF_KEY_XPATH "/frr-zebra:zebra/l3vni-id",
+                VRF_DEFAULT_NAME);
+       nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, argv[2]->arg);
+
+       if (filter) {
+               snprintf(xpath, sizeof(xpath),
+                        FRR_VRF_KEY_XPATH "/frr-zebra:zebra/prefix-only",
+                        VRF_DEFAULT_NAME);
+               nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, "true");
+       }
+
+       snprintf(xpath, sizeof(xpath), FRR_VRF_KEY_XPATH "/frr-zebra:zebra",
+                VRF_DEFAULT_NAME);
+       nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 DEFUN (vrf_vni_mapping,
@@ -2626,9 +2664,7 @@ DEFUN (vrf_vni_mapping,
                nb_cli_enqueue_change(vty, "./frr-zebra:zebra/prefix-only",
                                      NB_OP_MODIFY, "true");
 
-       nb_cli_apply_changes(vty, NULL);
-
-       return CMD_SUCCESS;
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 DEFUN (no_vrf_vni_mapping,
@@ -2665,9 +2701,7 @@ DEFUN (no_vrf_vni_mapping,
 
        nb_cli_enqueue_change(vty, "./frr-zebra:zebra", NB_OP_DESTROY, NULL);
 
-       nb_cli_apply_changes(vty, NULL);
-
-       return CMD_SUCCESS;
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 /* show vrf */
@@ -3619,6 +3653,9 @@ static int config_write_protocol(struct vty *vty)
        if (zebra_nhg_proto_nexthops_only())
                vty_out(vty, "zebra nexthop proto only\n");
 
+       if (!zebra_nhg_recursive_use_backups())
+               vty_out(vty, "no zebra nexthop resolve-via-backup\n");
+
 #ifdef HAVE_NETLINK
        /* Include netlink info */
        netlink_config_write_helper(vty);
@@ -4054,6 +4091,7 @@ void zebra_vty_init(void)
        install_element(CONFIG_NODE, &no_zebra_packet_process_cmd);
        install_element(CONFIG_NODE, &nexthop_group_use_enable_cmd);
        install_element(CONFIG_NODE, &proto_nexthop_group_only_cmd);
+       install_element(CONFIG_NODE, &backup_nexthop_recursive_use_enable_cmd);
 
        install_element(VIEW_NODE, &show_nexthop_group_cmd);
        install_element(VIEW_NODE, &show_interface_nexthop_group_cmd);
index e5efbe0d4a65f204f02f6aa7b38f11e976a55dc4..bc2eac7a0bf53f46383155c7265cdb56dc66ff90 100644 (file)
@@ -46,7 +46,6 @@
 #include "zebra/rt_netlink.h"
 #include "zebra/zebra_errors.h"
 #include "zebra/zebra_l2.h"
-#include "zebra/zebra_memory.h"
 #include "zebra/zebra_ns.h"
 #include "zebra/zebra_vrf.h"
 #include "zebra/zebra_vxlan.h"
@@ -65,7 +64,7 @@ DEFINE_MTYPE_STATIC(ZEBRA, L3NEIGH, "EVPN Neighbor");
 DEFINE_MTYPE_STATIC(ZEBRA, ZVXLAN_SG, "zebra VxLAN multicast group");
 
 DEFINE_HOOK(zebra_rmac_update, (zebra_mac_t *rmac, zebra_l3vni_t *zl3vni,
-           bool delete, const char *reason), (rmac, zl3vni, delete, reason))
+           bool delete, const char *reason), (rmac, zl3vni, delete, reason));
 
 /* static function declarations */
 static void zevpn_print_neigh_hash_all_evpn(struct hash_bucket *bucket,
index 4ec55542a7255ca0a2fd9c0b8e8edf2cc3fceb7a..0556c4adced13b03c1eb6f92425307772b9a974c 100644 (file)
@@ -226,7 +226,7 @@ extern struct interface *zl3vni_map_to_mac_vlan_if(zebra_l3vni_t *zl3vni);
 extern zebra_l3vni_t *zl3vni_lookup(vni_t vni);
 
 DECLARE_HOOK(zebra_rmac_update, (zebra_mac_t *rmac, zebra_l3vni_t *zl3vni,
-            bool delete, const char *reason), (rmac, zl3vni, delete, reason))
+            bool delete, const char *reason), (rmac, zl3vni, delete, reason));
 
 
 #ifdef __cplusplus