summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_bfd.c2
-rw-r--r--bgpd/bgp_clist.c36
-rw-r--r--bgpd/bgp_damp.c60
-rw-r--r--bgpd/bgp_damp.h3
-rw-r--r--bgpd/bgp_evpn.c2
-rw-r--r--bgpd/bgp_fsm.c11
-rw-r--r--bgpd/bgp_fsm.h6
-rw-r--r--bgpd/bgp_nexthop.c2
-rw-r--r--bgpd/bgp_nht.c2
-rw-r--r--bgpd/bgp_packet.c4
-rw-r--r--bgpd/bgp_route.c389
-rw-r--r--bgpd/bgp_route.h7
-rw-r--r--bgpd/bgp_rpki.c69
-rw-r--r--bgpd/bgp_vty.c168
-rw-r--r--bgpd/bgp_zebra.c7
-rw-r--r--bgpd/bgpd.c5
-rw-r--r--bgpd/bgpd.h4
-rwxr-xr-xconfigure.ac6
-rw-r--r--debian/control2
-rw-r--r--doc/developer/building-libyang.rst15
-rw-r--r--doc/developer/lists.rst61
-rw-r--r--doc/developer/process-architecture.rst4
-rw-r--r--doc/developer/topotests.rst2
-rw-r--r--doc/user/bgp.rst171
-rw-r--r--doc/user/overview.rst3
-rw-r--r--include/linux/net_namespace.h1
-rw-r--r--isisd/isis_circuit.c17
-rw-r--r--isisd/isis_circuit.h1
-rw-r--r--isisd/isis_cli.c184
-rw-r--r--isisd/isis_events.c13
-rw-r--r--isisd/isis_ldp_sync.c788
-rw-r--r--isisd/isis_ldp_sync.h54
-rw-r--r--isisd/isis_main.c2
-rw-r--r--isisd/isis_nb.c30
-rw-r--r--isisd/isis_nb.h16
-rw-r--r--isisd/isis_nb_config.c246
-rw-r--r--isisd/isis_route.c71
-rw-r--r--isisd/isis_zebra.c41
-rw-r--r--isisd/isisd.c44
-rw-r--r--isisd/isisd.h5
-rw-r--r--isisd/subdir.am3
-rw-r--r--ldpd/adjacency.c3
-rw-r--r--ldpd/control.c3
-rw-r--r--ldpd/hello.c1
-rw-r--r--ldpd/interface.c417
-rw-r--r--ldpd/ldp.h2
-rw-r--r--ldpd/ldp_debug.c12
-rw-r--r--ldpd/ldp_debug.h10
-rw-r--r--ldpd/ldp_vty.h2
-rw-r--r--ldpd/ldp_vty_cmds.c28
-rw-r--r--ldpd/ldp_vty_conf.c24
-rw-r--r--ldpd/ldp_vty_exec.c121
-rw-r--r--ldpd/ldp_zebra.c110
-rw-r--r--ldpd/ldpd.c17
-rw-r--r--ldpd/ldpd.h52
-rw-r--r--ldpd/ldpe.c24
-rw-r--r--ldpd/ldpe.h11
-rw-r--r--ldpd/neighbor.c2
-rw-r--r--ldpd/packet.c2
-rw-r--r--lib/command.h5
-rw-r--r--lib/ldp_sync.c93
-rw-r--r--lib/ldp_sync.h91
-rw-r--r--lib/libfrr.c3
-rw-r--r--lib/libfrr.h1
-rw-r--r--lib/netns_linux.c40
-rw-r--r--lib/northbound.c21
-rw-r--r--lib/northbound_cli.c4
-rw-r--r--lib/northbound_sysrepo.c68
-rw-r--r--lib/ns.h16
-rw-r--r--lib/pbr.h3
-rw-r--r--lib/subdir.am2
-rw-r--r--lib/thread.c8
-rw-r--r--lib/vrf.c28
-rw-r--r--lib/vrf.h2
-rw-r--r--lib/yang.c29
-rw-r--r--lib/yang.h7
-rw-r--r--lib/zclient.c11
-rw-r--r--lib/zclient.h11
-rw-r--r--lib/zlog_targets.c5
-rw-r--r--ospfd/ospf_abr.c9
-rw-r--r--ospfd/ospf_dump.c43
-rw-r--r--ospfd/ospf_dump.h4
-rw-r--r--ospfd/ospf_interface.c9
-rw-r--r--ospfd/ospf_interface.h3
-rw-r--r--ospfd/ospf_ldp_sync.c1142
-rw-r--r--ospfd/ospf_ldp_sync.h56
-rw-r--r--ospfd/ospf_lsa.c17
-rw-r--r--ospfd/ospf_main.c4
-rw-r--r--ospfd/ospf_vty.c11
-rw-r--r--ospfd/ospf_zebra.c72
-rw-r--r--ospfd/ospfd.c9
-rw-r--r--ospfd/ospfd.h4
-rw-r--r--ospfd/subdir.am4
-rw-r--r--pbrd/pbr_map.c7
-rw-r--r--pbrd/pbr_map.h2
-rw-r--r--pbrd/pbr_zebra.c8
-rw-r--r--pimd/pimd.c4
-rw-r--r--redhat/frr.spec.in2
-rw-r--r--snapcraft/snapcraft.yaml.in4
-rw-r--r--staticd/static_vty.c23
-rw-r--r--tests/topotests/all-protocol-startup/r1/bgpd.conf4
-rw-r--r--tests/topotests/bfd-bgp-cbit-topo3/r1/bgpd.conf1
-rw-r--r--tests/topotests/bfd-bgp-cbit-topo3/r3/bgpd.conf1
-rw-r--r--[-rwxr-xr-x]tests/topotests/bfd-bgp-cbit-topo3/test_bfd_bgp_cbit_topo3.py2
-rw-r--r--[-rwxr-xr-x]tests/topotests/bfd-isis-topo1/test_bfd_isis_topo1.py2
-rw-r--r--tests/topotests/bfd-profiles-topo1/r2/bgpd.conf2
-rw-r--r--tests/topotests/bfd-profiles-topo1/r3/bgpd.conf1
-rw-r--r--tests/topotests/bfd-profiles-topo1/r4/bgpd.conf1
-rw-r--r--[-rwxr-xr-x]tests/topotests/bfd-profiles-topo1/test_bfd_profiles_topo1.py2
-rw-r--r--tests/topotests/bfd-topo1/r1/bgpd.conf1
-rw-r--r--tests/topotests/bfd-topo1/r2/bgpd.conf3
-rw-r--r--tests/topotests/bfd-topo1/r3/bgpd.conf1
-rw-r--r--tests/topotests/bfd-topo1/r4/bgpd.conf1
-rw-r--r--tests/topotests/bfd-topo1/test_bfd_topo1.py2
-rw-r--r--tests/topotests/bfd-topo2/r1/bgpd.conf1
-rw-r--r--tests/topotests/bfd-topo2/r2/bgpd.conf1
-rw-r--r--tests/topotests/bfd-topo2/test_bfd_topo2.py2
-rw-r--r--tests/topotests/bfd-topo3/r1/bgpd.conf3
-rw-r--r--tests/topotests/bfd-topo3/r2/bgpd.conf2
-rw-r--r--tests/topotests/bfd-topo3/r3/bgpd.conf3
-rw-r--r--tests/topotests/bfd-topo3/r4/bgpd.conf2
-rw-r--r--tests/topotests/bfd-topo3/test_bfd_topo3.py2
-rw-r--r--tests/topotests/bfd-vrf-topo1/r1/bgpd.conf1
-rw-r--r--tests/topotests/bfd-vrf-topo1/r2/bgpd.conf3
-rw-r--r--tests/topotests/bfd-vrf-topo1/r3/bgpd.conf1
-rw-r--r--tests/topotests/bfd-vrf-topo1/r4/bgpd.conf1
-rw-r--r--[-rwxr-xr-x]tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.py8
-rw-r--r--[-rwxr-xr-x]tests/topotests/bgp-auth/test_bgp_auth.py8
-rwxr-xr-xtests/topotests/bgp-basic-functionality-topo1/test_bgp_basic_functionality.py6
-rw-r--r--tests/topotests/bgp-ecmp-topo1/r1/bgpd.conf20
-rw-r--r--[-rwxr-xr-x]tests/topotests/bgp-ecmp-topo1/test_bgp_ecmp_topo1.py4
-rw-r--r--[-rwxr-xr-x]tests/topotests/bgp-ecmp-topo2/test_ebgp_ecmp_topo2.py10
-rw-r--r--[-rwxr-xr-x]tests/topotests/bgp-ecmp-topo2/test_ibgp_ecmp_topo2.py10
-rw-r--r--[-rwxr-xr-x]tests/topotests/bgp-evpn-mh/test_evpn_mh.py10
-rw-r--r--[-rwxr-xr-x]tests/topotests/bgp-evpn-vxlan_topo1/test_bgp_evpn_vxlan.py2
-rw-r--r--[-rwxr-xr-x]tests/topotests/bgp-vrf-route-leak-basic/test_bgp-vrf-route-leak-basic.py2
-rw-r--r--tests/topotests/bgp_aggregate-address_origin/r1/bgpd.conf1
-rw-r--r--tests/topotests/bgp_aggregate-address_origin/r2/bgpd.conf1
-rw-r--r--tests/topotests/bgp_aggregate-address_origin/test_bgp_aggregate-address_origin.py2
-rw-r--r--tests/topotests/bgp_aggregate-address_route-map/r1/bgpd.conf1
-rw-r--r--tests/topotests/bgp_aggregate-address_route-map/r2/bgpd.conf1
-rw-r--r--tests/topotests/bgp_aggregate-address_route-map/test_bgp_aggregate-address_route-map.py2
-rwxr-xr-xtests/topotests/bgp_as_allow_in/test_bgp_as_allow_in.py6
-rw-r--r--tests/topotests/bgp_as_wide_bgp_identifier/r1/bgpd.conf1
-rw-r--r--tests/topotests/bgp_as_wide_bgp_identifier/r2/bgpd.conf2
-rw-r--r--tests/topotests/bgp_as_wide_bgp_identifier/r3/bgpd.conf1
-rw-r--r--tests/topotests/bgp_as_wide_bgp_identifier/test_bgp_as_wide_bgp_identifier.py2
-rw-r--r--tests/topotests/bgp_comm-list_delete/r1/bgpd.conf1
-rw-r--r--tests/topotests/bgp_comm-list_delete/r2/bgpd.conf1
-rw-r--r--tests/topotests/bgp_comm-list_delete/test_bgp_comm-list_delete.py2
-rw-r--r--tests/topotests/bgp_communities_topo1/test_bgp_communities.py6
-rw-r--r--tests/topotests/bgp_default-route_route-map/r1/bgpd.conf1
-rw-r--r--tests/topotests/bgp_default-route_route-map/r2/bgpd.conf1
-rw-r--r--tests/topotests/bgp_default-route_route-map/test_bgp_default-originate_route-map.py2
-rw-r--r--tests/topotests/bgp_distance_change/r1/bgpd.conf1
-rw-r--r--tests/topotests/bgp_distance_change/r2/bgpd.conf1
-rw-r--r--tests/topotests/bgp_distance_change/test_bgp_distance_change.py2
-rw-r--r--tests/topotests/bgp_ebgp_requires_policy/r1/bgpd.conf1
-rw-r--r--tests/topotests/bgp_ebgp_requires_policy/r2/bgpd.conf2
-rw-r--r--tests/topotests/bgp_ebgp_requires_policy/r3/bgpd.conf1
-rw-r--r--tests/topotests/bgp_ebgp_requires_policy/r4/bgpd.conf2
-rw-r--r--tests/topotests/bgp_ebgp_requires_policy/r5/bgpd.conf1
-rw-r--r--tests/topotests/bgp_ebgp_requires_policy/r6/bgpd.conf2
-rw-r--r--tests/topotests/bgp_ebgp_requires_policy/test_bgp_ebgp_requires_policy.py2
-rw-r--r--tests/topotests/bgp_evpn_rt5/__init__.py0
-rw-r--r--tests/topotests/bgp_evpn_rt5/r1/bgpd.conf26
-rw-r--r--tests/topotests/bgp_evpn_rt5/r1/zebra.conf22
-rw-r--r--tests/topotests/bgp_evpn_rt5/r2/bgpd.conf27
-rw-r--r--tests/topotests/bgp_evpn_rt5/r2/zebra.conf18
-rwxr-xr-xtests/topotests/bgp_evpn_rt5/test_bgp_evpn.py234
-rw-r--r--tests/topotests/bgp_features/r1/bgpd.conf2
-rw-r--r--tests/topotests/bgp_features/r2/bgpd.conf2
-rw-r--r--tests/topotests/bgp_features/r4/bgpd.conf1
-rw-r--r--tests/topotests/bgp_features/r5/bgpd.conf1
-rw-r--r--[-rwxr-xr-x]tests/topotests/bgp_features/test_bgp_features.py2
-rw-r--r--tests/topotests/bgp_flowspec/r1/bgpd.conf1
-rw-r--r--[-rwxr-xr-x]tests/topotests/bgp_flowspec/test_bgp_flowspec_topo.py2
-rwxr-xr-xtests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1.py6
-rwxr-xr-xtests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2.py6
-rw-r--r--tests/topotests/bgp_ipv6_rtadv/r1/bgpd.conf1
-rw-r--r--tests/topotests/bgp_ipv6_rtadv/r2/bgpd.conf1
-rw-r--r--tests/topotests/bgp_ipv6_rtadv/test_bgp_ipv6_rtadv.py2
-rwxr-xr-xtests/topotests/bgp_large_community/test_bgp_large_community_topo_1.py6
-rwxr-xr-xtests/topotests/bgp_large_community/test_bgp_large_community_topo_2.py6
-rw-r--r--tests/topotests/bgp_link_bw_ip/r1/bgpd.conf2
-rw-r--r--tests/topotests/bgp_link_bw_ip/r10/bgpd.conf1
-rw-r--r--tests/topotests/bgp_link_bw_ip/r2/bgpd.conf3
-rw-r--r--tests/topotests/bgp_link_bw_ip/r3/bgpd.conf2
-rw-r--r--tests/topotests/bgp_link_bw_ip/r4/bgpd.conf3
-rw-r--r--tests/topotests/bgp_link_bw_ip/r5/bgpd.conf2
-rw-r--r--tests/topotests/bgp_link_bw_ip/r6/bgpd.conf2
-rw-r--r--tests/topotests/bgp_link_bw_ip/r7/bgpd.conf1
-rw-r--r--tests/topotests/bgp_link_bw_ip/r8/bgpd.conf1
-rw-r--r--tests/topotests/bgp_link_bw_ip/r9/bgpd.conf1
-rw-r--r--[-rwxr-xr-x]tests/topotests/bgp_link_bw_ip/test_bgp_linkbw_ip.py2
-rw-r--r--tests/topotests/bgp_local_as_private_remove/r1/bgpd.conf1
-rw-r--r--tests/topotests/bgp_local_as_private_remove/r2/bgpd.conf2
-rw-r--r--tests/topotests/bgp_local_as_private_remove/r3/bgpd.conf1
-rw-r--r--tests/topotests/bgp_local_as_private_remove/r4/bgpd.conf2
-rw-r--r--tests/topotests/bgp_local_as_private_remove/test_bgp_local_as_private_remove.py2
-rw-r--r--tests/topotests/bgp_maximum_prefix_invalid_update/r1/bgpd.conf1
-rw-r--r--tests/topotests/bgp_maximum_prefix_invalid_update/r2/bgpd.conf1
-rw-r--r--tests/topotests/bgp_maximum_prefix_invalid_update/test_bgp_maximum_prefix_invalid_update.py2
-rw-r--r--tests/topotests/bgp_maximum_prefix_out/r1/bgpd.conf1
-rw-r--r--tests/topotests/bgp_maximum_prefix_out/r2/bgpd.conf1
-rw-r--r--tests/topotests/bgp_maximum_prefix_out/test_bgp_maximum_prefix_out.py2
-rwxr-xr-xtests/topotests/bgp_multi_vrf_topo1/test_bgp_multi_vrf_topo1.py5
-rwxr-xr-xtests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py5
-rw-r--r--tests/topotests/bgp_multiview_topo1/r1/bgpd.conf8
-rw-r--r--tests/topotests/bgp_prefix_sid/r1/bgpd.conf2
-rw-r--r--[-rwxr-xr-x]tests/topotests/bgp_prefix_sid/test_bgp_prefix_sid.py2
-rw-r--r--tests/topotests/bgp_reject_as_sets/r1/bgpd.conf1
-rw-r--r--tests/topotests/bgp_reject_as_sets/r2/bgpd.conf2
-rw-r--r--tests/topotests/bgp_reject_as_sets/r3/bgpd.conf1
-rw-r--r--tests/topotests/bgp_reject_as_sets/test_bgp_reject_as_sets.py2
-rw-r--r--tests/topotests/bgp_rfapi_basic_sanity/r1/bgpd.conf1
-rw-r--r--tests/topotests/bgp_rfapi_basic_sanity/r2/bgpd.conf3
-rw-r--r--tests/topotests/bgp_rfapi_basic_sanity/r3/bgpd.conf1
-rw-r--r--tests/topotests/bgp_rfapi_basic_sanity/r4/bgpd.conf1
-rw-r--r--tests/topotests/bgp_rfapi_basic_sanity_config2/r1/bgpd.conf1
-rw-r--r--tests/topotests/bgp_rfapi_basic_sanity_config2/r2/bgpd.conf3
-rw-r--r--tests/topotests/bgp_rfapi_basic_sanity_config2/r3/bgpd.conf1
-rw-r--r--tests/topotests/bgp_rfapi_basic_sanity_config2/r4/bgpd.conf1
-rw-r--r--tests/topotests/bgp_route_aggregation/bgp_aggregation.json249
-rwxr-xr-xtests/topotests/bgp_route_aggregation/test_bgp_aggregation.py1167
-rw-r--r--tests/topotests/bgp_rr_ibgp/spine1/bgpd.conf2
-rw-r--r--[-rwxr-xr-x]tests/topotests/bgp_rr_ibgp/test_bgp_rr_ibgp_topo1.py2
-rw-r--r--tests/topotests/bgp_rr_ibgp/tor1/bgpd.conf1
-rw-r--r--tests/topotests/bgp_rr_ibgp/tor2/bgpd.conf1
-rw-r--r--tests/topotests/bgp_sender-as-path-loop-detection/r1/bgpd.conf1
-rw-r--r--tests/topotests/bgp_sender-as-path-loop-detection/r2/bgpd.conf2
-rw-r--r--tests/topotests/bgp_sender-as-path-loop-detection/r3/bgpd.conf1
-rw-r--r--tests/topotests/bgp_sender-as-path-loop-detection/test_bgp_sender-as-path-loop-detection.py2
-rw-r--r--tests/topotests/bgp_set_local-preference_add_subtract/r1/bgpd.conf2
-rw-r--r--tests/topotests/bgp_set_local-preference_add_subtract/r2/bgpd.conf1
-rw-r--r--tests/topotests/bgp_set_local-preference_add_subtract/r3/bgpd.conf1
-rw-r--r--tests/topotests/bgp_set_local-preference_add_subtract/test_bgp_set_local-preference_add_subtract.py2
-rw-r--r--tests/topotests/bgp_update_delay/__init__.py0
-rw-r--r--tests/topotests/bgp_update_delay/r1/bgpd.conf10
-rw-r--r--tests/topotests/bgp_update_delay/r1/zebra.conf9
-rw-r--r--tests/topotests/bgp_update_delay/r2/bgpd.conf18
-rw-r--r--tests/topotests/bgp_update_delay/r2/zebra.conf20
-rw-r--r--tests/topotests/bgp_update_delay/r3/bgpd.conf10
-rw-r--r--tests/topotests/bgp_update_delay/r3/zebra.conf9
-rw-r--r--tests/topotests/bgp_update_delay/r4/bgpd.conf11
-rw-r--r--tests/topotests/bgp_update_delay/r4/zebra.conf9
-rw-r--r--tests/topotests/bgp_update_delay/r5/bgpd.conf11
-rw-r--r--tests/topotests/bgp_update_delay/r5/zebra.conf9
-rw-r--r--tests/topotests/bgp_update_delay/test_bgp_update_delay.py295
-rw-r--r--tests/topotests/bgp_vrf_lite_ipv6_rtadv/r1/bgpd.conf1
-rw-r--r--tests/topotests/bgp_vrf_lite_ipv6_rtadv/r2/bgpd.conf1
-rw-r--r--tests/topotests/bgp_vrf_lite_ipv6_rtadv/test_bgp_vrf_lite_ipv6_rtadv.py4
-rw-r--r--tests/topotests/bgp_vrf_netns/r1/bgpd.conf1
-rw-r--r--[-rwxr-xr-x]tests/topotests/bgp_vrf_netns/test_bgp_vrf_netns_topo.py2
-rw-r--r--[-rwxr-xr-x]tests/topotests/eigrp-topo1/test_eigrp_topo1.py2
-rw-r--r--tests/topotests/evpn-pim-1/leaf1/bgpd.conf1
-rw-r--r--tests/topotests/evpn-pim-1/leaf2/bgpd.conf1
-rw-r--r--tests/topotests/evpn-pim-1/spine/bgpd.conf2
-rw-r--r--[-rwxr-xr-x]tests/topotests/evpn-pim-1/test_evpn_pim_topo1.py2
-rw-r--r--[-rwxr-xr-x]tests/topotests/example-test/test_template.py2
-rw-r--r--[-rwxr-xr-x]tests/topotests/isis-sr-topo1/test_isis_sr_topo1.py2
-rw-r--r--[-rwxr-xr-x]tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py24
-rw-r--r--tests/topotests/isis-topo1/test_isis_topo1.py24
-rw-r--r--[-rwxr-xr-x]tests/topotests/ldp-oc-acl-topo1/test_ldp_oc_acl_topo1.py2
-rw-r--r--[-rwxr-xr-x]tests/topotests/ldp-oc-topo1/test_ldp_oc_topo1.py2
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/ce1/zebra.conf12
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/ce2/zebra.conf12
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/ce3/zebra.conf12
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r1/isisd.conf26
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r1/ldpd.conf33
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r1/show_ip_route.ref143
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r1/show_isis_interface_detail.ref16
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r1/show_isis_interface_detail_r1_eth1_shutdown.ref16
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r1/show_isis_interface_detail_r2_eth1_shutdown.ref16
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r1/show_isis_ldp_sync.ref13
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r1/show_isis_ldp_sync_r1_eth1_shutdown.ref13
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r1/show_isis_ldp_sync_r2_eth1_shutdown.ref13
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r1/show_l2vpn_binding.ref16
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r1/show_l2vpn_vc.ref8
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r1/show_ldp_binding.ref44
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r1/show_ldp_discovery.ref25
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r1/show_ldp_igp_sync.ref16
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r1/show_ldp_igp_sync_r1_eth1_shutdown.ref16
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r1/show_ldp_neighbor.ref16
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r1/show_yang_interface_isis_adjacencies.ref42
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r1/zebra.conf29
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r2/isisd.conf27
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r2/ldpd.conf33
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r2/ospfd.conf19
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r2/show_ip_route.ref143
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r2/show_isis_interface_detail.ref16
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r2/show_isis_interface_detail_r1_eth1_shutdown.ref16
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r2/show_isis_interface_detail_r2_eth1_shutdown.ref16
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r2/show_isis_ldp_sync.ref13
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r2/show_isis_ldp_sync_r1_eth1_shutdown.ref13
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r2/show_isis_ldp_sync_r2_eth1_shutdown.ref13
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r2/show_l2vpn_binding.ref16
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r2/show_l2vpn_vc.ref8
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r2/show_ldp_binding.ref44
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r2/show_ldp_discovery.ref25
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r2/show_ldp_igp_sync.ref16
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r2/show_ldp_igp_sync_r1_eth1_shutdown.ref16
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r2/show_ldp_igp_sync_r2_eth1_shutdown.ref16
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r2/show_ldp_neighbor.ref16
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r2/show_yang_interface_isis_adjacencies.ref42
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r2/zebra.conf28
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r3/isisd.conf28
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r3/ldpd.conf25
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r3/show_ip_route.ref143
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r3/show_isis_interface_detail.ref16
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r3/show_isis_interface_detail_r1_eth1_shutdown.ref16
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r3/show_isis_interface_detail_r2_eth1_shutdown.ref16
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r3/show_isis_ldp_sync.ref13
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r3/show_isis_ldp_sync_r1_eth1_shutdown.ref13
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r3/show_isis_ldp_sync_r2_eth1_shutdown.ref13
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r3/show_l2vpn_binding.ref2
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r3/show_l2vpn_vc.ref2
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r3/show_ldp_binding.ref44
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r3/show_ldp_discovery.ref18
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r3/show_ldp_igp_sync.ref16
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r3/show_ldp_igp_sync_r1_eth1_shutdown.ref16
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r3/show_ldp_neighbor.ref16
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r3/show_yang_interface_isis_adjacencies.ref42
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/r3/zebra.conf32
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/test_ldp_sync_isis_topo1.dot111
-rw-r--r--tests/topotests/ldp-sync-isis-topo1/test_ldp_sync_isis_topo1.py625
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/ce1/zebra.conf12
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/ce2/zebra.conf12
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/ce3/zebra.conf12
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/r1/ldpd.conf33
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/r1/ospf-nbrs.txt0
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/r1/ospfd.conf20
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/r1/show_ip_ospf_interface.ref11
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/r1/show_ip_ospf_interface_r1_eth1_shutdown.ref8
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/r1/show_ip_ospf_interface_r2_eth1_shutdown.ref11
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/r1/show_ip_ospf_neighbor.json26
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/r1/show_ip_route.ref157
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/r1/show_l2vpn_binding.ref16
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/r1/show_l2vpn_vc.ref8
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/r1/show_ldp_binding.ref44
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/r1/show_ldp_discovery.ref25
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/r1/show_ldp_igp_sync.ref16
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/r1/show_ldp_igp_sync_r1_eth1_shutdown.ref16
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/r1/show_ldp_neighbor.ref16
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/r1/show_ospf_ldp_sync.ref12
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/r1/show_ospf_ldp_sync_r1_eth1_shutdown.ref7
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/r1/show_ospf_ldp_sync_r2_eth1_shutdown.ref12
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/r1/zebra.conf29
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/r2/ldpd.conf33
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/r2/ospfd.conf19
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/r2/show_ip_ospf_interface.ref11
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/r2/show_ip_ospf_interface_r1_eth1_shutdown.ref11
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/r2/show_ip_ospf_interface_r2_eth1_shutdown.ref8
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/r2/show_ip_ospf_neighbor.json26
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/r2/show_ip_route.ref157
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/r2/show_l2vpn_binding.ref16
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/r2/show_l2vpn_vc.ref8
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/r2/show_ldp_binding.ref44
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/r2/show_ldp_discovery.ref25
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/r2/show_ldp_igp_sync.ref16
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/r2/show_ldp_igp_sync_r1_eth1_shutdown.ref16
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/r2/show_ldp_neighbor.ref16
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/r2/show_ospf_ldp_sync.ref12
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/r2/show_ospf_ldp_sync_r1_eth1_shutdown.ref12
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/r2/show_ospf_ldp_sync_r2_eth1_shutdown.ref7
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/r2/zebra.conf28
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/r3/ldpd.conf25
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/r3/ospfd.conf18
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/r3/show_ip_ospf_interface.ref11
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/r3/show_ip_ospf_interface_r1_eth1_shutdown.ref11
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/r3/show_ip_ospf_interface_r2_eth1_shutdown.ref11
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/r3/show_ip_ospf_neighbor.json26
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/r3/show_ip_route.ref157
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/r3/show_l2vpn_binding.ref2
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/r3/show_l2vpn_vc.ref2
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/r3/show_ldp_binding.ref44
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/r3/show_ldp_discovery.ref18
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/r3/show_ldp_igp_sync.ref16
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/r3/show_ldp_igp_sync_r1_eth1_shutdown.ref16
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/r3/show_ldp_neighbor.ref16
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/r3/show_ospf_ldp_sync.ref12
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/r3/show_ospf_ldp_sync_r1_eth1_shutdown.ref12
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/r3/show_ospf_ldp_sync_r2_eth1_shutdown.ref12
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/r3/zebra.conf32
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/test_ldp_sync_ospf_topo1.dot111
-rw-r--r--tests/topotests/ldp-sync-ospf-topo1/test_ldp_sync_ospf_topo1.py429
-rw-r--r--[-rwxr-xr-x]tests/topotests/ldp-vpls-topo1/test_ldp_vpls_topo1.py2
-rw-r--r--tests/topotests/lib/bgp.py81
-rw-r--r--tests/topotests/lib/common_config.py149
-rw-r--r--tests/topotests/lib/ltemplate.py2
-rw-r--r--tests/topotests/lib/ospf.py1182
-rw-r--r--tests/topotests/lib/topogen.py12
-rw-r--r--tests/topotests/lib/topojson.py89
-rw-r--r--[-rwxr-xr-x]tests/topotests/ospf-sr-topo1/test_ospf_sr_topo1.py2
-rw-r--r--[-rwxr-xr-x]tests/topotests/ospf-topo1-vrf/test_ospf_topo1_vrf.py12
-rw-r--r--[-rwxr-xr-x]tests/topotests/ospf-topo1/test_ospf_topo1.py6
-rw-r--r--[-rwxr-xr-x]tests/topotests/ospf-topo2/test_ospf_topo2.py4
-rw-r--r--[-rwxr-xr-x]tests/topotests/ospf6-topo1/test_ospf6_topo1.py6
-rw-r--r--tests/topotests/ospf_basic_functionality/ospf_authentication.json166
-rw-r--r--tests/topotests/ospf_basic_functionality/ospf_ecmp.json342
-rw-r--r--tests/topotests/ospf_basic_functionality/ospf_ecmp_lan.json234
-rw-r--r--tests/topotests/ospf_basic_functionality/ospf_lan.json138
-rw-r--r--tests/topotests/ospf_basic_functionality/ospf_nssa.json188
-rw-r--r--tests/topotests/ospf_basic_functionality/ospf_routemaps.json159
-rw-r--r--tests/topotests/ospf_basic_functionality/ospf_rte_calc.json168
-rw-r--r--tests/topotests/ospf_basic_functionality/ospf_single_area.json188
-rw-r--r--tests/topotests/ospf_basic_functionality/test_ospf_authentication.py891
-rw-r--r--tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py495
-rw-r--r--tests/topotests/ospf_basic_functionality/test_ospf_ecmp_lan.py369
-rw-r--r--tests/topotests/ospf_basic_functionality/test_ospf_lan.py724
-rw-r--r--tests/topotests/ospf_basic_functionality/test_ospf_nssa.py336
-rw-r--r--tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py540
-rw-r--r--tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py612
-rw-r--r--tests/topotests/ospf_basic_functionality/test_ospf_single_area.py781
-rw-r--r--[-rwxr-xr-x]tests/topotests/pbr-topo1/test_pbr_topo1.py2
-rw-r--r--tests/topotests/pim-basic/r1/bgpd.conf1
-rw-r--r--tests/topotests/pim-basic/rp/bgpd.conf1
-rw-r--r--tests/topotests/pim-basic/test_pim.py2
-rw-r--r--[-rwxr-xr-x]tests/topotests/route-scale/test_route_scale.py2
-rw-r--r--[-rwxr-xr-x]tests/topotests/zebra_netlink/test_zebra_netlink.py2
-rw-r--r--[-rwxr-xr-x]tests/topotests/zebra_rib/test_zebra_rib.py2
-rwxr-xr-xtools/frr-reload.py16
-rw-r--r--yang/frr-interface.yang6
-rw-r--r--yang/frr-isisd.yang40
-rw-r--r--yang/frr-ripd.yang6
-rw-r--r--yang/frr-ripngd.yang2
-rw-r--r--yang/frr-route-map.yang2
-rw-r--r--yang/frr-zebra.yang20
-rw-r--r--zebra/if_netlink.c17
-rw-r--r--zebra/interface.c20
-rw-r--r--zebra/main.c4
-rw-r--r--zebra/rule_netlink.c14
-rw-r--r--zebra/zapi_msg.c34
-rw-r--r--zebra/zebra_dplane.c15
-rw-r--r--zebra/zebra_dplane.h1
-rw-r--r--zebra/zebra_evpn.c224
-rw-r--r--zebra/zebra_evpn.h9
-rw-r--r--zebra/zebra_evpn_mac.c20
-rw-r--r--zebra/zebra_evpn_mac.h1
-rw-r--r--zebra/zebra_evpn_mh.c4
-rw-r--r--zebra/zebra_evpn_mh.h4
-rw-r--r--zebra/zebra_evpn_neigh.c7
-rw-r--r--zebra/zebra_l2.c32
-rw-r--r--zebra/zebra_l2.h7
-rw-r--r--zebra/zebra_netns_id.c43
-rw-r--r--zebra/zebra_netns_id.h2
-rw-r--r--zebra/zebra_netns_notify.c19
-rw-r--r--zebra/zebra_ns.c17
-rw-r--r--zebra/zebra_ns.h9
-rw-r--r--zebra/zebra_pbr.c15
-rw-r--r--zebra/zebra_vxlan.c196
451 files changed, 19906 insertions, 837 deletions
diff --git a/bgpd/bgp_bfd.c b/bgpd/bgp_bfd.c
index 67b8018c8e..1e1c97c2d9 100644
--- a/bgpd/bgp_bfd.c
+++ b/bgpd/bgp_bfd.c
@@ -361,7 +361,7 @@ static void bgp_bfd_peer_status_update(struct peer *peer, int status,
if ((status == BFD_STATUS_UP) && (old_status == BFD_STATUS_DOWN)
&& peer->status != Established) {
if (!BGP_PEER_START_SUPPRESSED(peer)) {
- bgp_fsm_event_update(peer, 1);
+ bgp_fsm_nht_update(peer, true);
BGP_EVENT_ADD(peer, BGP_Start);
}
}
diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c
index 5b3908442c..247d758f8c 100644
--- a/bgpd/bgp_clist.c
+++ b/bgpd/bgp_clist.c
@@ -337,18 +337,42 @@ static void community_list_entry_delete(struct community_list_master *cm,
community_list_delete(cm, list);
}
+/*
+ * Replace community-list entry in the list. Note that entry is the new one
+ * and replace is one one being replaced.
+ */
+static void community_list_entry_replace(struct community_list *list,
+ struct community_entry *replace,
+ struct community_entry *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;
+ }
+
+ community_entry_free(replace);
+}
+
/* Add community-list entry to the list. */
static void community_list_entry_add(struct community_list *list,
struct community_entry *entry,
struct community_list_handler *ch,
int master)
{
- struct community_list_master *cm = NULL;
struct community_entry *replace;
struct community_entry *point;
- cm = community_list_master_lookup(ch, master);
-
/* Automatic assignment of seq no. */
if (entry->seq == COMMUNITY_SEQ_NUMBER_AUTO)
entry->seq = bgp_clist_new_seq_get(list);
@@ -357,8 +381,10 @@ static void community_list_entry_add(struct community_list *list,
point = NULL;
else {
replace = bgp_clist_seq_check(list, entry->seq);
- if (replace)
- community_list_entry_delete(cm, list, entry);
+ if (replace) {
+ community_list_entry_replace(list, replace, entry);
+ return;
+ }
/* Check insert point. */
for (point = list->head; point; point = point->next)
diff --git a/bgpd/bgp_damp.c b/bgpd/bgp_damp.c
index 565d0b8e19..9992168182 100644
--- a/bgpd/bgp_damp.c
+++ b/bgpd/bgp_damp.c
@@ -36,6 +36,8 @@
#include "bgpd/bgp_attr.h"
#include "bgpd/bgp_advertise.h"
+const char *get_afi_safi_str(afi_t afi, safi_t safi, bool for_json);
+
/* Global variable to access damping configuration */
static struct bgp_damp_config damp[AFI_MAX][SAFI_MAX];
@@ -653,16 +655,9 @@ const char *bgp_damp_reuse_time_vty(struct vty *vty, struct bgp_path_info *path,
json);
}
-int bgp_show_dampening_parameters(struct vty *vty, afi_t afi, safi_t safi)
+static int bgp_print_dampening_parameters(struct bgp *bgp, struct vty *vty,
+ afi_t afi, safi_t safi)
{
- struct bgp *bgp;
- bgp = bgp_get_default();
-
- if (bgp == NULL) {
- vty_out(vty, "No BGP process is configured\n");
- return CMD_WARNING;
- }
-
if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)) {
vty_out(vty, "Half-life time: %lld min\n",
(long long)damp[afi][safi].half_life / 60);
@@ -677,7 +672,52 @@ int bgp_show_dampening_parameters(struct vty *vty, afi_t afi, safi_t safi)
vty_out(vty, "\n");
} else
vty_out(vty, "dampening not enabled for %s\n",
- afi == AFI_IP ? "IPv4" : "IPv6");
+ get_afi_safi_str(afi, safi, false));
+
+ return CMD_SUCCESS;
+}
+
+int bgp_show_dampening_parameters(struct vty *vty, afi_t afi, safi_t safi,
+ uint8_t show_flags)
+{
+ struct bgp *bgp;
+ bgp = bgp_get_default();
+
+ if (bgp == NULL) {
+ vty_out(vty, "No BGP process is configured\n");
+ return CMD_WARNING;
+ }
+
+ if (!CHECK_FLAG(show_flags, BGP_SHOW_OPT_AFI_ALL))
+ return bgp_print_dampening_parameters(bgp, vty, afi, safi);
+
+ if (CHECK_FLAG(show_flags, BGP_SHOW_OPT_AFI_IP)
+ || CHECK_FLAG(show_flags, BGP_SHOW_OPT_AFI_IP6)) {
+ afi = CHECK_FLAG(show_flags, BGP_SHOW_OPT_AFI_IP) ? AFI_IP
+ : AFI_IP6;
+ FOREACH_SAFI (safi) {
+ if (strmatch(get_afi_safi_str(afi, safi, true),
+ "Unknown"))
+ continue;
+ if (!CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON))
+ vty_out(vty, "\nFor address family: %s\n\n",
+ get_afi_safi_str(afi, safi, false));
+
+ bgp_print_dampening_parameters(bgp, vty, afi, safi);
+ }
+ } else {
+ FOREACH_AFI_SAFI (afi, safi) {
+ if (strmatch(get_afi_safi_str(afi, safi, true),
+ "Unknown"))
+ continue;
+
+ if (!CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON))
+ vty_out(vty, "\nFor address family: %s\n",
+ get_afi_safi_str(afi, safi, false));
+
+ bgp_print_dampening_parameters(bgp, vty, afi, safi);
+ }
+ }
return CMD_SUCCESS;
}
diff --git a/bgpd/bgp_damp.h b/bgpd/bgp_damp.h
index 4ab38326e2..604706300b 100644
--- a/bgpd/bgp_damp.h
+++ b/bgpd/bgp_damp.h
@@ -151,6 +151,7 @@ extern const char *bgp_damp_reuse_time_vty(struct vty *vty,
char *timebuf, size_t len, afi_t afi,
safi_t safi, bool use_json,
json_object *json);
-extern int bgp_show_dampening_parameters(struct vty *vty, afi_t, safi_t);
+extern int bgp_show_dampening_parameters(struct vty *vty, afi_t, safi_t,
+ uint8_t);
#endif /* _QUAGGA_BGP_DAMP_H */
diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c
index 8c3e54566e..0703853354 100644
--- a/bgpd/bgp_evpn.c
+++ b/bgpd/bgp_evpn.c
@@ -519,6 +519,8 @@ static void form_auto_rt(struct bgp *bgp, vni_t vni, struct list *rtl)
if (!ecom_found)
listnode_add_sort(rtl, ecomadd);
+ else
+ ecommunity_free(&ecomadd);
}
/*
diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c
index 14dcf2b593..d7df707a36 100644
--- a/bgpd/bgp_fsm.c
+++ b/bgpd/bgp_fsm.c
@@ -2037,24 +2037,24 @@ static int bgp_fsm_exeption(struct peer *peer)
return (bgp_stop(peer));
}
-void bgp_fsm_event_update(struct peer *peer, int valid)
+void bgp_fsm_nht_update(struct peer *peer, bool has_valid_nexthops)
{
if (!peer)
return;
switch (peer->status) {
case Idle:
- if (valid)
+ if (has_valid_nexthops)
BGP_EVENT_ADD(peer, BGP_Start);
break;
case Connect:
- if (!valid) {
+ if (!has_valid_nexthops) {
BGP_TIMER_OFF(peer->t_connect);
BGP_EVENT_ADD(peer, TCP_fatal_error);
}
break;
case Active:
- if (valid) {
+ if (has_valid_nexthops) {
BGP_TIMER_OFF(peer->t_connect);
BGP_EVENT_ADD(peer, ConnectRetry_timer_expired);
}
@@ -2062,7 +2062,8 @@ void bgp_fsm_event_update(struct peer *peer, int valid)
case OpenSent:
case OpenConfirm:
case Established:
- if (!valid && (peer->gtsm_hops == BGP_GTSM_HOPS_CONNECTED))
+ if (!has_valid_nexthops
+ && (peer->gtsm_hops == BGP_GTSM_HOPS_CONNECTED))
BGP_EVENT_ADD(peer, TCP_fatal_error);
case Clearing:
case Deleted:
diff --git a/bgpd/bgp_fsm.h b/bgpd/bgp_fsm.h
index 2fd5f6fc47..85c0eccc26 100644
--- a/bgpd/bgp_fsm.h
+++ b/bgpd/bgp_fsm.h
@@ -109,7 +109,11 @@
&& !CHECK_FLAG(peer->cap, PEER_CAP_RESTART_BIT_ADV))
/* Prototypes. */
-extern void bgp_fsm_event_update(struct peer *peer, int valid);
+
+/*
+ * Update FSM for peer based on whether we have valid nexthops or not.
+ */
+extern void bgp_fsm_nht_update(struct peer *peer, bool has_valid_nexthops);
extern int bgp_event(struct thread *);
extern int bgp_event_update(struct peer *, enum bgp_fsm_events event);
extern int bgp_stop(struct peer *peer);
diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c
index ed026a2fff..0d8214e4d6 100644
--- a/bgpd/bgp_nexthop.c
+++ b/bgpd/bgp_nexthop.c
@@ -563,7 +563,7 @@ bool bgp_nexthop_self(struct bgp *bgp, afi_t afi, uint8_t type,
if (addr)
return true;
- if (new_afi == AF_INET) {
+ if (new_afi == AF_INET && hashcount(bgp->tip_hash)) {
memset(&tmp_tip, 0, sizeof(struct tip_addr));
tmp_tip.addr = attr->nexthop;
diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c
index 9573d118e5..c89978e91b 100644
--- a/bgpd/bgp_nht.c
+++ b/bgpd/bgp_nht.c
@@ -846,7 +846,7 @@ static void evaluate_paths(struct bgp_nexthop_cache *bnc)
"%s: Updating peer (%s(%s)) status with NHT",
__func__, peer->host,
peer->bgp->name_pretty);
- bgp_fsm_event_update(peer, valid_nexthops);
+ bgp_fsm_nht_update(peer, !!valid_nexthops);
SET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED);
}
}
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index 15dba37667..ee3580edf1 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -1775,10 +1775,6 @@ static int bgp_update_receive(struct peer *peer, bgp_size_t size)
peer->update_time = bgp_clock();
- /* Rearm holdtime timer */
- BGP_TIMER_OFF(peer->t_holdtime);
- bgp_timer_set(peer);
-
return Receive_UPDATE_message;
}
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 8eaee36c2e..626f766987 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -9757,15 +9757,14 @@ static int bgp_show_regexp(struct vty *vty, struct bgp *bgp, const char *regstr,
bool use_json);
static int bgp_show_community(struct vty *vty, struct bgp *bgp,
const char *comstr, int exact, afi_t afi,
- safi_t safi, bool use_json);
+ safi_t safi, uint8_t show_flags);
static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
struct bgp_table *table, enum bgp_show_type type,
- void *output_arg, bool use_json, char *rd,
- int is_last, unsigned long *output_cum,
- unsigned long *total_cum,
- unsigned long *json_header_depth, bool wide)
+ void *output_arg, char *rd, int is_last,
+ unsigned long *output_cum, unsigned long *total_cum,
+ unsigned long *json_header_depth, uint8_t show_flags)
{
struct bgp_path_info *pi;
struct bgp_dest *dest;
@@ -9776,13 +9775,23 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
struct prefix *p;
json_object *json_paths = NULL;
int first = 1;
+ bool use_json = CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON);
+ bool wide = CHECK_FLAG(show_flags, BGP_SHOW_OPT_WIDE);
+ bool all = CHECK_FLAG(show_flags, BGP_SHOW_OPT_AFI_ALL);
if (output_cum && *output_cum != 0)
header = 0;
if (use_json && !*json_header_depth) {
+ if (all)
+ *json_header_depth = 1;
+ else {
+ vty_out(vty, "{\n");
+ *json_header_depth = 2;
+ }
+
vty_out(vty,
- "{\n \"vrfId\": %d,\n \"vrfName\": \"%s\",\n \"tableVersion\": %" PRId64",\n \"routerId\": \"%s\",\n \"defaultLocPrf\": %u,\n"
+ " \"vrfId\": %d,\n \"vrfName\": \"%s\",\n \"tableVersion\": %" PRId64",\n \"routerId\": \"%s\",\n \"defaultLocPrf\": %u,\n"
" \"localAS\": %u,\n \"routes\": { ",
bgp->vrf_id == VRF_UNKNOWN ? -1 : (int)bgp->vrf_id,
bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT
@@ -9790,7 +9799,6 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
: bgp->name,
table->version, inet_ntoa(bgp->router_id),
bgp->default_local_pref, bgp->as);
- *json_header_depth = 2;
if (rd) {
vty_out(vty, " \"routeDistinguishers\" : {");
++*json_header_depth;
@@ -10071,7 +10079,8 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
unsigned long i;
for (i = 0; i < *json_header_depth; ++i)
vty_out(vty, " } ");
- vty_out(vty, "\n");
+ if (!all)
+ vty_out(vty, "\n");
}
} else {
if (is_last) {
@@ -10101,9 +10110,13 @@ int bgp_show_table_rd(struct vty *vty, struct bgp *bgp, safi_t safi,
unsigned long json_header_depth = 0;
struct bgp_table *itable;
bool show_msg;
+ uint8_t show_flags = 0;
show_msg = (!use_json && type == bgp_show_type_normal);
+ if (use_json)
+ SET_FLAG(show_flags, BGP_SHOW_OPT_JSON);
+
for (dest = bgp_table_top(table); dest; dest = next) {
const struct prefix *dest_p = bgp_dest_get_prefix(dest);
@@ -10119,8 +10132,9 @@ int bgp_show_table_rd(struct vty *vty, struct bgp *bgp, safi_t safi,
memcpy(&prd, dest_p, sizeof(struct prefix_rd));
prefix_rd2str(&prd, rd, sizeof(rd));
bgp_show_table(vty, bgp, safi, itable, type, output_arg,
- use_json, rd, next == NULL, &output_cum,
- &total_cum, &json_header_depth, false);
+ rd, next == NULL, &output_cum,
+ &total_cum, &json_header_depth,
+ show_flags);
if (next == NULL)
show_msg = false;
}
@@ -10137,11 +10151,12 @@ int bgp_show_table_rd(struct vty *vty, struct bgp *bgp, safi_t safi,
return CMD_SUCCESS;
}
static int bgp_show(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
- enum bgp_show_type type, void *output_arg, bool use_json,
- bool wide)
+ enum bgp_show_type type, void *output_arg,
+ uint8_t show_flags)
{
struct bgp_table *table;
unsigned long json_header_depth = 0;
+ bool use_json = CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON);
if (bgp == NULL) {
bgp = bgp_get_default();
@@ -10171,18 +10186,18 @@ static int bgp_show(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
else if (safi == SAFI_LABELED_UNICAST)
safi = SAFI_UNICAST;
- return bgp_show_table(vty, bgp, safi, table, type, output_arg, use_json,
- NULL, 1, NULL, NULL, &json_header_depth, wide);
+ return bgp_show_table(vty, bgp, safi, table, type, output_arg, NULL, 1,
+ NULL, NULL, &json_header_depth, show_flags);
}
static void bgp_show_all_instances_routes_vty(struct vty *vty, afi_t afi,
- safi_t safi, bool use_json,
- bool wide)
+ safi_t safi, uint8_t show_flags)
{
struct listnode *node, *nnode;
struct bgp *bgp;
int is_first = 1;
bool route_output = false;
+ bool use_json = CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON);
if (use_json)
vty_out(vty, "{\n");
@@ -10206,7 +10221,7 @@ static void bgp_show_all_instances_routes_vty(struct vty *vty, afi_t afi,
: bgp->name);
}
bgp_show(vty, bgp, afi, safi, bgp_show_type_normal, NULL,
- use_json, wide);
+ show_flags);
}
if (use_json)
@@ -10667,6 +10682,10 @@ static int bgp_show_lcommunity(struct vty *vty, struct bgp *bgp, int argc,
int i;
char *str;
int first = 0;
+ uint8_t show_flags = 0;
+
+ if (uj)
+ SET_FLAG(show_flags, BGP_SHOW_OPT_JSON);
b = buffer_new(1024);
for (i = 0; i < argc; i++) {
@@ -10694,7 +10713,7 @@ static int bgp_show_lcommunity(struct vty *vty, struct bgp *bgp, int argc,
return bgp_show(vty, bgp, afi, safi,
(exact ? bgp_show_type_lcommunity_exact
: bgp_show_type_lcommunity),
- lcom, uj, false);
+ lcom, show_flags);
}
static int bgp_show_lcommunity_list(struct vty *vty, struct bgp *bgp,
@@ -10702,6 +10721,11 @@ static int bgp_show_lcommunity_list(struct vty *vty, struct bgp *bgp,
safi_t safi, bool uj)
{
struct community_list *list;
+ uint8_t show_flags = 0;
+
+ if (uj)
+ SET_FLAG(show_flags, BGP_SHOW_OPT_JSON);
+
list = community_list_lookup(bgp_clist, lcom, 0,
LARGE_COMMUNITY_LIST_MASTER);
@@ -10714,7 +10738,7 @@ static int bgp_show_lcommunity_list(struct vty *vty, struct bgp *bgp,
return bgp_show(vty, bgp, afi, safi,
(exact ? bgp_show_type_lcommunity_list_exact
: bgp_show_type_lcommunity_list),
- list, uj, false);
+ list, show_flags);
}
DEFUN (show_ip_bgp_large_community_list,
@@ -10777,14 +10801,17 @@ DEFUN (show_ip_bgp_large_community,
bool exact_match = 0;
struct bgp *bgp = NULL;
bool uj = use_json(argc, argv);
+ uint8_t show_flags = 0;
- if (uj)
- argc--;
+ if (uj) {
+ argc--;
+ SET_FLAG(show_flags, BGP_SHOW_OPT_JSON);
+ }
- bgp_vty_find_and_parse_afi_safi_bgp(vty, argv, argc, &idx, &afi, &safi,
- &bgp, uj);
- if (!idx)
- return CMD_WARNING;
+ bgp_vty_find_and_parse_afi_safi_bgp(vty, argv, argc, &idx, &afi, &safi,
+ &bgp, uj);
+ if (!idx)
+ return CMD_WARNING;
if (argv_find(argv, argc, "AA:BB:CC", &idx)) {
if (argv_find(argv, argc, "exact-match", &idx))
@@ -10793,7 +10820,7 @@ DEFUN (show_ip_bgp_large_community,
exact_match, afi, safi, uj);
} else
return bgp_show(vty, bgp, afi, safi,
- bgp_show_type_lcommunity_all, NULL, uj, false);
+ bgp_show_type_lcommunity_all, NULL, show_flags);
}
static int bgp_table_stats_single(struct vty *vty, struct bgp *bgp, afi_t afi,
@@ -10940,11 +10967,11 @@ DEFUN(show_ip_bgp_afi_safi_statistics, show_ip_bgp_afi_safi_statistics_cmd,
}
/* BGP route print out function without JSON */
-DEFUN(show_ip_bgp, show_ip_bgp_cmd,
+DEFPY(show_ip_bgp, show_ip_bgp_cmd,
"show [ip] bgp [<view|vrf> VIEWVRFNAME] [" BGP_AFI_CMD_STR
" [" BGP_SAFI_WITH_LABEL_CMD_STR
"]]\
- <dampening <parameters>\
+ <[all$all] dampening <parameters>\
|route-map WORD\
|prefix-list WORD\
|filter-list WORD\
@@ -10954,6 +10981,7 @@ DEFUN(show_ip_bgp, show_ip_bgp_cmd,
>",
SHOW_STR IP_STR BGP_STR BGP_INSTANCE_HELP_STR BGP_AFI_HELP_STR
BGP_SAFI_WITH_LABEL_HELP_STR
+ "Display the entries for all address families\n"
"Display detailed information about dampening\n"
"Display detail of configured dampening parameters\n"
"Display routes matching the route-map\n"
@@ -10976,6 +11004,17 @@ DEFUN(show_ip_bgp, show_ip_bgp_cmd,
int exact_match = 0;
struct bgp *bgp = NULL;
int idx = 0;
+ uint8_t show_flags = 0;
+
+ /* [<ipv4|ipv6> [all]] */
+ if (all) {
+ SET_FLAG(show_flags, BGP_SHOW_OPT_AFI_ALL);
+ if (argv_find(argv, argc, "ipv4", &idx))
+ SET_FLAG(show_flags, BGP_SHOW_OPT_AFI_IP);
+
+ if (argv_find(argv, argc, "ipv6", &idx))
+ SET_FLAG(show_flags, BGP_SHOW_OPT_AFI_IP6);
+ }
bgp_vty_find_and_parse_afi_safi_bgp(vty, argv, argc, &idx, &afi, &safi,
&bgp, false);
@@ -10984,7 +11023,8 @@ DEFUN(show_ip_bgp, show_ip_bgp_cmd,
if (argv_find(argv, argc, "dampening", &idx)) {
if (argv_find(argv, argc, "parameters", &idx))
- return bgp_show_dampening_parameters(vty, afi, safi);
+ return bgp_show_dampening_parameters(vty, afi, safi,
+ show_flags);
}
if (argv_find(argv, argc, "prefix-list", &idx))
@@ -11020,6 +11060,7 @@ DEFUN(show_ip_bgp, show_ip_bgp_cmd,
DEFPY (show_ip_bgp_json,
show_ip_bgp_json_cmd,
"show [ip] bgp [<view|vrf> VIEWVRFNAME] ["BGP_AFI_CMD_STR" ["BGP_SAFI_WITH_LABEL_CMD_STR"]]\
+ [all$all]\
[cidr-only\
|dampening <flap-statistics|dampened-paths>\
|community [AA:NN|local-AS|no-advertise|no-export\
@@ -11034,6 +11075,7 @@ DEFPY (show_ip_bgp_json,
BGP_INSTANCE_HELP_STR
BGP_AFI_HELP_STR
BGP_SAFI_WITH_LABEL_HELP_STR
+ "Display the entries for all address families\n"
"Display only routes with non-natural netmasks\n"
"Display detailed information about dampening\n"
"Display flap statistics of routes\n"
@@ -11064,9 +11106,29 @@ DEFPY (show_ip_bgp_json,
struct bgp *bgp = NULL;
int idx = 0;
int exact_match = 0;
+ char *community = NULL;
+ bool first = true;
+ uint8_t show_flags = 0;
- if (uj)
+
+ if (uj) {
argc--;
+ SET_FLAG(show_flags, BGP_SHOW_OPT_JSON);
+ }
+
+ /* [<ipv4|ipv6> [all]] */
+ if (all) {
+ SET_FLAG(show_flags, BGP_SHOW_OPT_AFI_ALL);
+
+ if (argv_find(argv, argc, "ipv4", &idx))
+ SET_FLAG(show_flags, BGP_SHOW_OPT_AFI_IP);
+
+ if (argv_find(argv, argc, "ipv6", &idx))
+ SET_FLAG(show_flags, BGP_SHOW_OPT_AFI_IP6);
+ }
+
+ if (wide)
+ SET_FLAG(show_flags, BGP_SHOW_OPT_WIDE);
bgp_vty_find_and_parse_afi_safi_bgp(vty, argv, argc, &idx, &afi, &safi,
&bgp, uj);
@@ -11074,23 +11136,17 @@ DEFPY (show_ip_bgp_json,
return CMD_WARNING;
if (argv_find(argv, argc, "cidr-only", &idx))
- return bgp_show(vty, bgp, afi, safi, bgp_show_type_cidr_only,
- NULL, uj, wide);
+ sh_type = bgp_show_type_cidr_only;
if (argv_find(argv, argc, "dampening", &idx)) {
if (argv_find(argv, argc, "dampened-paths", &idx))
- return bgp_show(vty, bgp, afi, safi,
- bgp_show_type_dampend_paths, NULL, uj,
- wide);
+ sh_type = bgp_show_type_dampend_paths;
else if (argv_find(argv, argc, "flap-statistics", &idx))
- return bgp_show(vty, bgp, afi, safi,
- bgp_show_type_flap_statistics, NULL, uj,
- wide);
+ sh_type = bgp_show_type_flap_statistics;
}
if (argv_find(argv, argc, "community", &idx)) {
char *maybecomm = NULL;
- char *community = NULL;
if (idx + 1 < argc) {
if (argv[idx + 1]->type == VARIABLE_TKN)
@@ -11106,16 +11162,103 @@ DEFPY (show_ip_bgp_json,
if (argv_find(argv, argc, "exact-match", &idx))
exact_match = 1;
+ if (!community)
+ sh_type = bgp_show_type_community_all;
+ }
+
+ if (!all) {
+ /* show bgp: AFI_IP6, show ip bgp: AFI_IP */
if (community)
return bgp_show_community(vty, bgp, community,
- exact_match, afi, safi, uj);
+ exact_match, afi, safi,
+ show_flags);
else
- return (bgp_show(vty, bgp, afi, safi,
- bgp_show_type_community_all, NULL, uj,
- wide));
- }
+ return bgp_show(vty, bgp, afi, safi, sh_type, NULL,
+ show_flags);
+ } else {
+ /* show <ip> bgp ipv4 all: AFI_IP, show <ip> bgp ipv6 all:
+ * AFI_IP6 */
+
+ if (uj)
+ vty_out(vty, "{\n");
+
+ if (CHECK_FLAG(show_flags, BGP_SHOW_OPT_AFI_IP)
+ || CHECK_FLAG(show_flags, BGP_SHOW_OPT_AFI_IP6)) {
+ afi = CHECK_FLAG(show_flags, BGP_SHOW_OPT_AFI_IP)
+ ? AFI_IP
+ : AFI_IP6;
+ FOREACH_SAFI (safi) {
+ if (strmatch(get_afi_safi_str(afi, safi, true),
+ "Unknown"))
+ continue;
+
+ if (!bgp_afi_safi_peer_exists(bgp, afi, safi))
+ continue;
+
+ if (uj) {
+ if (first)
+ first = false;
+ else
+ vty_out(vty, ",\n");
+ vty_out(vty, "\"%s\":{\n",
+ get_afi_safi_str(afi, safi,
+ true));
+ } else
+ vty_out(vty,
+ "\nFor address family: %s\n",
+ get_afi_safi_str(afi, safi,
+ false));
+
+ if (community)
+ bgp_show_community(vty, bgp, community,
+ exact_match, afi,
+ safi, show_flags);
+ else
+ bgp_show(vty, bgp, afi, safi, sh_type,
+ NULL, show_flags);
+ if (uj)
+ vty_out(vty, "}\n");
+ }
+ } else {
+ /* show <ip> bgp all: for each AFI and SAFI*/
+ FOREACH_AFI_SAFI (afi, safi) {
+ if (strmatch(get_afi_safi_str(afi, safi, true),
+ "Unknown"))
+ continue;
+
+ if (!bgp_afi_safi_peer_exists(bgp, afi, safi))
+ continue;
+
+ if (uj) {
+ if (first)
+ first = false;
+ else
+ vty_out(vty, ",\n");
- return bgp_show(vty, bgp, afi, safi, sh_type, NULL, uj, wide);
+ vty_out(vty, "\"%s\":{\n",
+ get_afi_safi_str(afi, safi,
+ true));
+ } else
+ vty_out(vty,
+ "\nFor address family: %s\n",
+ get_afi_safi_str(afi, safi,
+ false));
+
+ if (community)
+ bgp_show_community(vty, bgp, community,
+ exact_match, afi,
+ safi, show_flags);
+ else
+ bgp_show(vty, bgp, afi, safi, sh_type,
+ NULL, show_flags);
+ if (uj)
+ vty_out(vty, "}\n");
+ }
+ }
+ if (uj)
+ vty_out(vty, "}\n");
+ }
+ return CMD_SUCCESS;
}
DEFUN (show_ip_bgp_route,
@@ -11242,16 +11385,22 @@ DEFPY (show_ip_bgp_instance_all,
safi_t safi = SAFI_UNICAST;
struct bgp *bgp = NULL;
int idx = 0;
+ uint8_t show_flags = 0;
- if (uj)
+ if (uj) {
argc--;
+ SET_FLAG(show_flags, BGP_SHOW_OPT_JSON);
+ }
+
+ if (wide)
+ SET_FLAG(show_flags, BGP_SHOW_OPT_WIDE);
bgp_vty_find_and_parse_afi_safi_bgp(vty, argv, argc, &idx, &afi, &safi,
&bgp, uj);
if (!idx)
return CMD_WARNING;
- bgp_show_all_instances_routes_vty(vty, afi, safi, uj, wide);
+ bgp_show_all_instances_routes_vty(vty, afi, safi, show_flags);
return CMD_SUCCESS;
}
@@ -11261,6 +11410,10 @@ static int bgp_show_regexp(struct vty *vty, struct bgp *bgp, const char *regstr,
{
regex_t *regex;
int rc;
+ uint8_t show_flags = 0;
+
+ if (use_json)
+ SET_FLAG(show_flags, BGP_SHOW_OPT_JSON);
if (!config_bgp_aspath_validate(regstr)) {
vty_out(vty, "Invalid character in REGEX %s\n",
@@ -11274,7 +11427,7 @@ static int bgp_show_regexp(struct vty *vty, struct bgp *bgp, const char *regstr,
return CMD_WARNING;
}
- rc = bgp_show(vty, bgp, afi, safi, type, regex, use_json, false);
+ rc = bgp_show(vty, bgp, afi, safi, type, regex, show_flags);
bgp_regex_free(regex);
return rc;
}
@@ -11284,6 +11437,7 @@ static int bgp_show_prefix_list(struct vty *vty, struct bgp *bgp,
safi_t safi, enum bgp_show_type type)
{
struct prefix_list *plist;
+ uint8_t show_flags = 0;
plist = prefix_list_lookup(afi, prefix_list_str);
if (plist == NULL) {
@@ -11292,7 +11446,7 @@ static int bgp_show_prefix_list(struct vty *vty, struct bgp *bgp,
return CMD_WARNING;
}
- return bgp_show(vty, bgp, afi, safi, type, plist, 0, false);
+ return bgp_show(vty, bgp, afi, safi, type, plist, show_flags);
}
static int bgp_show_filter_list(struct vty *vty, struct bgp *bgp,
@@ -11300,6 +11454,7 @@ static int bgp_show_filter_list(struct vty *vty, struct bgp *bgp,
enum bgp_show_type type)
{
struct as_list *as_list;
+ uint8_t show_flags = 0;
as_list = as_list_lookup(filter);
if (as_list == NULL) {
@@ -11308,7 +11463,7 @@ static int bgp_show_filter_list(struct vty *vty, struct bgp *bgp,
return CMD_WARNING;
}
- return bgp_show(vty, bgp, afi, safi, type, as_list, 0, false);
+ return bgp_show(vty, bgp, afi, safi, type, as_list, show_flags);
}
static int bgp_show_route_map(struct vty *vty, struct bgp *bgp,
@@ -11316,6 +11471,7 @@ static int bgp_show_route_map(struct vty *vty, struct bgp *bgp,
enum bgp_show_type type)
{
struct route_map *rmap;
+ uint8_t show_flags = 0;
rmap = route_map_lookup_by_name(rmap_str);
if (!rmap) {
@@ -11323,12 +11479,12 @@ static int bgp_show_route_map(struct vty *vty, struct bgp *bgp,
return CMD_WARNING;
}
- return bgp_show(vty, bgp, afi, safi, type, rmap, 0, false);
+ return bgp_show(vty, bgp, afi, safi, type, rmap, show_flags);
}
static int bgp_show_community(struct vty *vty, struct bgp *bgp,
const char *comstr, int exact, afi_t afi,
- safi_t safi, bool use_json)
+ safi_t safi, uint8_t show_flags)
{
struct community *com;
int ret = 0;
@@ -11342,7 +11498,7 @@ static int bgp_show_community(struct vty *vty, struct bgp *bgp,
ret = bgp_show(vty, bgp, afi, safi,
(exact ? bgp_show_type_community_exact
: bgp_show_type_community),
- com, use_json, false);
+ com, show_flags);
community_free(&com);
return ret;
@@ -11353,6 +11509,7 @@ static int bgp_show_community_list(struct vty *vty, struct bgp *bgp,
safi_t safi)
{
struct community_list *list;
+ uint8_t show_flags = 0;
list = community_list_lookup(bgp_clist, com, 0, COMMUNITY_LIST_MASTER);
if (list == NULL) {
@@ -11363,7 +11520,7 @@ static int bgp_show_community_list(struct vty *vty, struct bgp *bgp,
return bgp_show(vty, bgp, afi, safi,
(exact ? bgp_show_type_community_list_exact
: bgp_show_type_community_list),
- list, 0, false);
+ list, show_flags);
}
static int bgp_show_prefix_longer(struct vty *vty, struct bgp *bgp,
@@ -11372,6 +11529,7 @@ static int bgp_show_prefix_longer(struct vty *vty, struct bgp *bgp,
{
int ret;
struct prefix *p;
+ uint8_t show_flags = 0;
p = prefix_new();
@@ -11381,7 +11539,7 @@ static int bgp_show_prefix_longer(struct vty *vty, struct bgp *bgp,
return CMD_WARNING;
}
- ret = bgp_show(vty, bgp, afi, safi, type, p, 0, false);
+ ret = bgp_show(vty, bgp, afi, safi, type, p, show_flags);
prefix_free(&p);
return ret;
}
@@ -12195,8 +12353,8 @@ static void show_adj_route_header(struct vty *vty, struct bgp *bgp,
static void show_adj_route(struct vty *vty, struct peer *peer, afi_t afi,
safi_t safi, enum bgp_show_adj_route_type type,
- const char *rmap_name, bool use_json,
- json_object *json, bool wide)
+ const char *rmap_name, json_object *json,
+ uint8_t show_flags)
{
struct bgp_table *table;
struct bgp_adj_in *ain;
@@ -12215,6 +12373,8 @@ static void show_adj_route(struct vty *vty, struct peer *peer, afi_t afi,
json_object *json_ar = NULL;
struct peer_af *paf;
bool route_filtered;
+ bool use_json = CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON);
+ bool wide = CHECK_FLAG(show_flags, BGP_SHOW_OPT_WIDE);
if (use_json) {
json_scode = json_object_new_object();
@@ -12423,9 +12583,10 @@ static void show_adj_route(struct vty *vty, struct peer *peer, afi_t afi,
static int peer_adj_routes(struct vty *vty, struct peer *peer, afi_t afi,
safi_t safi, enum bgp_show_adj_route_type type,
- const char *rmap_name, bool use_json, bool wide)
+ const char *rmap_name, uint8_t show_flags)
{
json_object *json = NULL;
+ bool use_json = CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON);
if (use_json)
json = json_object_new_object();
@@ -12460,8 +12621,7 @@ static int peer_adj_routes(struct vty *vty, struct peer *peer, afi_t afi,
return CMD_WARNING;
}
- show_adj_route(vty, peer, afi, safi, type, rmap_name, use_json, json,
- wide);
+ show_adj_route(vty, peer, afi, safi, type, rmap_name, json, show_flags);
return CMD_SUCCESS;
}
@@ -12491,6 +12651,13 @@ DEFPY (show_ip_bgp_instance_neighbor_bestpath_route,
struct peer *peer;
enum bgp_show_adj_route_type type = bgp_show_adj_route_bestpath;
int idx = 0;
+ uint8_t show_flags = 0;
+
+ if (uj)
+ SET_FLAG(show_flags, BGP_SHOW_OPT_JSON);
+
+ if (wide)
+ SET_FLAG(show_flags, BGP_SHOW_OPT_WIDE);
bgp_vty_find_and_parse_afi_safi_bgp(vty, argv, argc, &idx, &afi, &safi,
&bgp, uj);
@@ -12505,18 +12672,20 @@ DEFPY (show_ip_bgp_instance_neighbor_bestpath_route,
if (!peer)
return CMD_WARNING;
- return peer_adj_routes(vty, peer, afi, safi, type, rmap_name, uj, wide);
+ return peer_adj_routes(vty, peer, afi, safi, type, rmap_name,
+ show_flags);
}
DEFPY (show_ip_bgp_instance_neighbor_advertised_route,
show_ip_bgp_instance_neighbor_advertised_route_cmd,
- "show [ip] bgp [<view|vrf> VIEWVRFNAME] ["BGP_AFI_CMD_STR" ["BGP_SAFI_WITH_LABEL_CMD_STR"]] neighbors <A.B.C.D|X:X::X:X|WORD> <advertised-routes|received-routes|filtered-routes> [route-map WORD] [json$uj | wide$wide]",
+ "show [ip] bgp [<view|vrf> VIEWVRFNAME] ["BGP_AFI_CMD_STR" ["BGP_SAFI_WITH_LABEL_CMD_STR"]] [all$all] neighbors <A.B.C.D|X:X::X:X|WORD> <advertised-routes|received-routes|filtered-routes> [route-map WORD] [json$uj | wide$wide]",
SHOW_STR
IP_STR
BGP_STR
BGP_INSTANCE_HELP_STR
BGP_AFI_HELP_STR
BGP_SAFI_WITH_LABEL_HELP_STR
+ "Display the entries for all address families\n"
"Detailed information on TCP and BGP neighbor connections\n"
"Neighbor to display information about\n"
"Neighbor to display information about\n"
@@ -12537,9 +12706,25 @@ DEFPY (show_ip_bgp_instance_neighbor_advertised_route,
struct peer *peer;
enum bgp_show_adj_route_type type = bgp_show_adj_route_advertised;
int idx = 0;
+ bool first = true;
+ uint8_t show_flags = 0;
- if (uj)
+ if (uj) {
argc--;
+ SET_FLAG(show_flags, BGP_SHOW_OPT_JSON);
+ }
+
+ if (all) {
+ SET_FLAG(show_flags, BGP_SHOW_OPT_AFI_ALL);
+ if (argv_find(argv, argc, "ipv4", &idx))
+ SET_FLAG(show_flags, BGP_SHOW_OPT_AFI_IP);
+
+ if (argv_find(argv, argc, "ipv6", &idx))
+ SET_FLAG(show_flags, BGP_SHOW_OPT_AFI_IP6);
+ }
+
+ if (wide)
+ SET_FLAG(show_flags, BGP_SHOW_OPT_WIDE);
bgp_vty_find_and_parse_afi_safi_bgp(vty, argv, argc, &idx, &afi, &safi,
&bgp, uj);
@@ -12564,7 +12749,66 @@ DEFPY (show_ip_bgp_instance_neighbor_advertised_route,
if (argv_find(argv, argc, "route-map", &idx))
rmap_name = argv[++idx]->arg;
- return peer_adj_routes(vty, peer, afi, safi, type, rmap_name, uj, wide);
+ if (!all)
+ return peer_adj_routes(vty, peer, afi, safi, type, rmap_name,
+ show_flags);
+ if (uj)
+ vty_out(vty, "{\n");
+
+ if (CHECK_FLAG(show_flags, BGP_SHOW_OPT_AFI_IP)
+ || CHECK_FLAG(show_flags, BGP_SHOW_OPT_AFI_IP6)) {
+ afi = CHECK_FLAG(show_flags, BGP_SHOW_OPT_AFI_IP) ? AFI_IP
+ : AFI_IP6;
+ FOREACH_SAFI (safi) {
+ if (strmatch(get_afi_safi_str(afi, safi, true),
+ "Unknown"))
+ continue;
+
+ if (!bgp_afi_safi_peer_exists(bgp, afi, safi))
+ continue;
+
+ if (uj) {
+ if (first)
+ first = false;
+ else
+ vty_out(vty, ",\n");
+ vty_out(vty, "\"%s\":",
+ get_afi_safi_str(afi, safi, true));
+ } else
+ vty_out(vty, "\nFor address family: %s\n",
+ get_afi_safi_str(afi, safi, false));
+
+ peer_adj_routes(vty, peer, afi, safi, type, rmap_name,
+ show_flags);
+ }
+ } else {
+ FOREACH_AFI_SAFI (afi, safi) {
+ if (strmatch(get_afi_safi_str(afi, safi, true),
+ "Unknown"))
+ continue;
+
+ if (!bgp_afi_safi_peer_exists(bgp, afi, safi))
+ continue;
+
+ if (uj) {
+ if (first)
+ first = false;
+ else
+ vty_out(vty, ",\n");
+ vty_out(vty, "\"%s\":",
+ get_afi_safi_str(afi, safi, true));
+ } else
+ vty_out(vty, "\nFor address family: %s\n",
+ get_afi_safi_str(afi, safi, false));
+
+ peer_adj_routes(vty, peer, afi, safi, type, rmap_name,
+ show_flags);
+ }
+ }
+ if (uj)
+ vty_out(vty, "}\n");
+
+ return CMD_SUCCESS;
}
DEFUN (show_ip_bgp_neighbor_received_prefix_filter,
@@ -12653,6 +12897,11 @@ static int bgp_show_neighbor_route(struct vty *vty, struct peer *peer,
afi_t afi, safi_t safi,
enum bgp_show_type type, bool use_json)
{
+ uint8_t show_flags = 0;
+
+ if (use_json)
+ SET_FLAG(show_flags, BGP_SHOW_OPT_JSON);
+
/* labeled-unicast routes live in the unicast table */
if (safi == SAFI_LABELED_UNICAST)
safi = SAFI_UNICAST;
@@ -12672,8 +12921,7 @@ static int bgp_show_neighbor_route(struct vty *vty, struct peer *peer,
return CMD_WARNING;
}
- return bgp_show(vty, peer->bgp, afi, safi, type, &peer->su, use_json,
- false);
+ return bgp_show(vty, peer->bgp, afi, safi, type, &peer->su, show_flags);
}
DEFUN (show_ip_bgp_flowspec_routes_detailed,
@@ -12693,17 +12941,20 @@ DEFUN (show_ip_bgp_flowspec_routes_detailed,
struct bgp *bgp = NULL;
int idx = 0;
bool uj = use_json(argc, argv);
+ uint8_t show_flags = 0;
- if (uj)
+ if (uj) {
argc--;
+ SET_FLAG(show_flags, BGP_SHOW_OPT_JSON);
+ }
bgp_vty_find_and_parse_afi_safi_bgp(vty, argv, argc, &idx, &afi, &safi,
&bgp, uj);
if (!idx)
return CMD_WARNING;
- return bgp_show(vty, bgp, afi, safi, bgp_show_type_detail, NULL, uj,
- false);
+ return bgp_show(vty, bgp, afi, safi, bgp_show_type_detail, NULL,
+ show_flags);
}
DEFUN (show_ip_bgp_neighbor_routes,
diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
index 3f734d2672..3407884897 100644
--- a/bgpd/bgp_route.h
+++ b/bgpd/bgp_route.h
@@ -498,6 +498,13 @@ DECLARE_HOOK(bgp_process,
struct peer *peer, bool withdraw),
(bgp, afi, safi, bn, peer, withdraw))
+/* BGP show options */
+#define BGP_SHOW_OPT_JSON (1 << 0)
+#define BGP_SHOW_OPT_WIDE (1 << 1)
+#define BGP_SHOW_OPT_AFI_ALL (1 << 2)
+#define BGP_SHOW_OPT_AFI_IP (1 << 3)
+#define BGP_SHOW_OPT_AFI_IP6 (1 << 4)
+
/* Prototypes. */
extern void bgp_rib_remove(struct bgp_dest *dest, struct bgp_path_info *pi,
struct peer *peer, afi_t afi, safi_t safi);
diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c
index 63cfacf678..ca47fb316a 100644
--- a/bgpd/bgp_rpki.c
+++ b/bgpd/bgp_rpki.c
@@ -1060,67 +1060,6 @@ DEFUN (no_rpki_retry_interval,
return CMD_SUCCESS;
}
-#if (CONFDATE > 20200901)
-CPP_NOTICE("bgpd: time to remove rpki timeout")
-CPP_NOTICE("bgpd: this includes rpki_timeout and rpki_synchronisation_timeout")
-#endif
-
-DEFPY_HIDDEN (rpki_timeout,
- rpki_timeout_cmd,
- "rpki timeout (1-4294967295)$to_arg",
- RPKI_OUTPUT_STRING
- "Set timeout\n"
- "Timeout value\n")
-{
- vty_out(vty,
- "This config option is deprecated, and is scheduled for removal.\n");
- vty_out(vty,
- "This functionality has also already been removed because it caused bugs and was pointless\n");
- return CMD_SUCCESS;
-}
-
-DEFUN_HIDDEN (no_rpki_timeout,
- no_rpki_timeout_cmd,
- "no rpki timeout",
- NO_STR
- RPKI_OUTPUT_STRING
- "Set timeout back to default\n")
-{
- vty_out(vty,
- "This config option is deprecated, and is scheduled for removal.\n");
- vty_out(vty,
- "This functionality has also already been removed because it caused bugs and was pointless\n");
- return CMD_SUCCESS;
-}
-
-DEFPY_HIDDEN (rpki_synchronisation_timeout,
- rpki_synchronisation_timeout_cmd,
- "rpki initial-synchronisation-timeout (1-4294967295)$ito_arg",
- RPKI_OUTPUT_STRING
- "Set a timeout for the initial synchronisation of prefix validation data\n"
- "Timeout value\n")
-{
- vty_out(vty,
- "This config option is deprecated, and is scheduled for removal.\n");
- vty_out(vty,
- "This functionality has also already been removed because it caused bugs and was pointless\n");
- return CMD_SUCCESS;
-}
-
-DEFUN_HIDDEN (no_rpki_synchronisation_timeout,
- no_rpki_synchronisation_timeout_cmd,
- "no rpki initial-synchronisation-timeout",
- NO_STR
- RPKI_OUTPUT_STRING
- "Set the initial synchronisation timeout back to default (30 sec.)\n")
-{
- vty_out(vty,
- "This config option is deprecated, and is scheduled for removal.\n");
- vty_out(vty,
- "This functionality has also already been removed because it caused bugs and was pointless\n");
- return CMD_SUCCESS;
-}
-
DEFPY (rpki_cache,
rpki_cache_cmd,
"rpki cache <A.B.C.D|WORD><TCPPORT|(1-65535)$sshport SSH_UNAME SSH_PRIVKEY SSH_PUBKEY [SERVER_PUBKEY]> preference (1-255)",
@@ -1516,14 +1455,6 @@ static void install_cli_commands(void)
install_element(RPKI_NODE, &rpki_retry_interval_cmd);
install_element(RPKI_NODE, &no_rpki_retry_interval_cmd);
- /* Install rpki timeout commands */
- install_element(RPKI_NODE, &rpki_timeout_cmd);
- install_element(RPKI_NODE, &no_rpki_timeout_cmd);
-
- /* Install rpki synchronisation timeout commands */
- install_element(RPKI_NODE, &rpki_synchronisation_timeout_cmd);
- install_element(RPKI_NODE, &no_rpki_synchronisation_timeout_cmd);
-
/* Install rpki cache commands */
install_element(RPKI_NODE, &rpki_cache_cmd);
install_element(RPKI_NODE, &no_rpki_cache_cmd);
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index d80667699a..505f743e29 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -1642,16 +1642,91 @@ DEFUN (no_bgp_maxmed_onstartup,
return CMD_SUCCESS;
}
-static int bgp_update_delay_config_vty(struct vty *vty, const char *delay,
- const char *wait)
+static int bgp_global_update_delay_config_vty(struct vty *vty,
+ uint16_t update_delay,
+ uint16_t establish_wait)
+{
+ struct listnode *node, *nnode;
+ struct bgp *bgp;
+ bool vrf_cfg = false;
+
+ /*
+ * See if update-delay is set per-vrf and warn user to delete it
+ * Note that we only need to check this if this is the first time
+ * setting the global config.
+ */
+ if (bm->v_update_delay == BGP_UPDATE_DELAY_DEF) {
+ for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
+ if (bgp->v_update_delay != BGP_UPDATE_DELAY_DEF) {
+ vty_out(vty,
+ "%% update-delay configuration found in vrf %s\n",
+ bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT
+ ? VRF_DEFAULT_NAME
+ : bgp->name);
+ vrf_cfg = true;
+ }
+ }
+ }
+
+ if (vrf_cfg) {
+ vty_out(vty,
+ "%%Failed: global update-delay config not permitted\n");
+ return CMD_WARNING;
+ }
+
+ if (!establish_wait) { /* update-delay <delay> */
+ bm->v_update_delay = update_delay;
+ bm->v_establish_wait = bm->v_update_delay;
+ } else {
+ /* update-delay <delay> <establish-wait> */
+ if (update_delay < establish_wait) {
+ vty_out(vty,
+ "%%Failed: update-delay less than the establish-wait!\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ bm->v_update_delay = update_delay;
+ bm->v_establish_wait = establish_wait;
+ }
+
+ for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
+ bgp->v_update_delay = bm->v_update_delay;
+ bgp->v_establish_wait = bm->v_establish_wait;
+ }
+
+ return CMD_SUCCESS;
+}
+
+static int bgp_global_update_delay_deconfig_vty(struct vty *vty)
+{
+ struct listnode *node, *nnode;
+ struct bgp *bgp;
+
+ bm->v_update_delay = BGP_UPDATE_DELAY_DEF;
+ bm->v_establish_wait = bm->v_update_delay;
+
+ for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
+ bgp->v_update_delay = bm->v_update_delay;
+ bgp->v_establish_wait = bm->v_establish_wait;
+ }
+
+ return CMD_SUCCESS;
+}
+
+static int bgp_update_delay_config_vty(struct vty *vty, uint16_t update_delay,
+ uint16_t establish_wait)
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
- uint16_t update_delay;
- uint16_t establish_wait;
- update_delay = strtoul(delay, NULL, 10);
+ /* if configured globally, per-instance config is not allowed */
+ if (bm->v_update_delay) {
+ vty_out(vty,
+ "%%Failed: per-vrf update-delay config not permitted with global update-delay\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
- if (!wait) /* update-delay <delay> */
+ if (!establish_wait) /* update-delay <delay> */
{
bgp->v_update_delay = update_delay;
bgp->v_establish_wait = bgp->v_update_delay;
@@ -1659,7 +1734,6 @@ static int bgp_update_delay_config_vty(struct vty *vty, const char *delay,
}
/* update-delay <delay> <establish-wait> */
- establish_wait = atoi(wait);
if (update_delay < establish_wait) {
vty_out(vty,
"%%Failed: update-delay less than the establish-wait!\n");
@@ -1676,6 +1750,12 @@ static int bgp_update_delay_deconfig_vty(struct vty *vty)
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
+ /* If configured globally, cannot remove from one bgp instance */
+ if (bm->v_update_delay) {
+ vty_out(vty,
+ "%%Failed: bgp update-delay configured globally. Delete per-vrf not permitted\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
bgp->v_update_delay = BGP_UPDATE_DELAY_DEF;
bgp->v_establish_wait = bgp->v_update_delay;
@@ -1684,7 +1764,8 @@ static int bgp_update_delay_deconfig_vty(struct vty *vty)
void bgp_config_write_update_delay(struct vty *vty, struct bgp *bgp)
{
- if (bgp->v_update_delay != BGP_UPDATE_DELAY_DEF) {
+ /* If configured globally, no need to display per-instance value */
+ if (bgp->v_update_delay != bm->v_update_delay) {
vty_out(vty, " update-delay %d", bgp->v_update_delay);
if (bgp->v_update_delay != bgp->v_establish_wait)
vty_out(vty, " %d", bgp->v_establish_wait);
@@ -1692,39 +1773,51 @@ void bgp_config_write_update_delay(struct vty *vty, struct bgp *bgp)
}
}
+/* Global update-delay configuration */
+DEFPY (bgp_global_update_delay,
+ bgp_global_update_delay_cmd,
+ "bgp update-delay (0-3600)$delay [(1-3600)$wait]",
+ BGP_STR
+ "Force initial delay for best-path and updates for all bgp instances\n"
+ "Max delay in seconds\n"
+ "Establish wait in seconds\n")
+{
+ return bgp_global_update_delay_config_vty(vty, delay, wait);
+}
-/* Update-delay configuration */
-DEFUN (bgp_update_delay,
- bgp_update_delay_cmd,
- "update-delay (0-3600)",
+/* Global update-delay deconfiguration */
+DEFPY (no_bgp_global_update_delay,
+ no_bgp_global_update_delay_cmd,
+ "no bgp update-delay [(0-3600) [(1-3600)]]",
+ NO_STR
+ BGP_STR
"Force initial delay for best-path and updates\n"
- "Seconds\n")
+ "Max delay in seconds\n"
+ "Establish wait in seconds\n")
{
- int idx_number = 1;
- return bgp_update_delay_config_vty(vty, argv[idx_number]->arg, NULL);
+ return bgp_global_update_delay_deconfig_vty(vty);
}
-DEFUN (bgp_update_delay_establish_wait,
- bgp_update_delay_establish_wait_cmd,
- "update-delay (0-3600) (1-3600)",
+/* Update-delay configuration */
+
+DEFPY (bgp_update_delay,
+ bgp_update_delay_cmd,
+ "update-delay (0-3600)$delay [(1-3600)$wait]",
"Force initial delay for best-path and updates\n"
- "Seconds\n"
- "Seconds\n")
+ "Max delay in seconds\n"
+ "Establish wait in seconds\n")
{
- int idx_number = 1;
- int idx_number_2 = 2;
- return bgp_update_delay_config_vty(vty, argv[idx_number]->arg,
- argv[idx_number_2]->arg);
+ return bgp_update_delay_config_vty(vty, delay, wait);
}
/* Update-delay deconfiguration */
-DEFUN (no_bgp_update_delay,
+DEFPY (no_bgp_update_delay,
no_bgp_update_delay_cmd,
"no update-delay [(0-3600) [(1-3600)]]",
NO_STR
"Force initial delay for best-path and updates\n"
- "Seconds\n"
- "Seconds\n")
+ "Max delay in seconds\n"
+ "Establish wait in seconds\n")
{
return bgp_update_delay_deconfig_vty(vty);
}
@@ -9774,15 +9867,16 @@ int bgp_show_summary_vty(struct vty *vty, const char *name, afi_t afi,
}
/* `show [ip] bgp summary' commands. */
-DEFUN (show_ip_bgp_summary,
+DEFPY (show_ip_bgp_summary,
show_ip_bgp_summary_cmd,
- "show [ip] bgp [<view|vrf> VIEWVRFNAME] ["BGP_AFI_CMD_STR" ["BGP_SAFI_WITH_LABEL_CMD_STR"]] summary [established|failed] [json]",
+ "show [ip] bgp [<view|vrf> VIEWVRFNAME] ["BGP_AFI_CMD_STR" ["BGP_SAFI_WITH_LABEL_CMD_STR"]] [all$all] summary [established|failed] [json$uj]",
SHOW_STR
IP_STR
BGP_STR
BGP_INSTANCE_HELP_STR
BGP_AFI_HELP_STR
BGP_SAFI_WITH_LABEL_HELP_STR
+ "Display the entries for all address families\n"
"Summary of BGP neighbor status\n"
"Show only sessions in Established state\n"
"Show only sessions not in Established state\n"
@@ -9797,7 +9891,7 @@ DEFUN (show_ip_bgp_summary,
int idx = 0;
/* show [ip] bgp */
- if (argv_find(argv, argc, "ip", &idx))
+ if (!all && argv_find(argv, argc, "ip", &idx))
afi = AFI_IP;
/* [<vrf> VIEWVRFNAME] */
if (argv_find(argv, argc, "vrf", &idx)) {
@@ -9817,8 +9911,6 @@ DEFUN (show_ip_bgp_summary,
if (argv_find(argv, argc, "established", &idx))
show_established = true;
- bool uj = use_json(argc, argv);
-
return bgp_show_summary_vty(vty, vrf, afi, safi, show_failed,
show_established, uj);
}
@@ -15429,6 +15521,13 @@ int bgp_config_write(struct vty *vty)
vty_out(vty, "bgp route-map delay-timer %u\n",
bm->rmap_update_timer);
+ if (bm->v_update_delay != BGP_UPDATE_DELAY_DEF) {
+ vty_out(vty, "bgp update-delay %d", bm->v_update_delay);
+ if (bm->v_update_delay != bm->v_establish_wait)
+ vty_out(vty, " %d", bm->v_establish_wait);
+ vty_out(vty, "\n");
+ }
+
/* BGP configuration. */
for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) {
@@ -15943,6 +16042,10 @@ void bgp_vty_init(void)
install_element(CONFIG_NODE, &bgp_set_route_map_delay_timer_cmd);
install_element(CONFIG_NODE, &no_bgp_set_route_map_delay_timer_cmd);
+ /* global bgp update-delay command */
+ install_element(CONFIG_NODE, &bgp_global_update_delay_cmd);
+ install_element(CONFIG_NODE, &no_bgp_global_update_delay_cmd);
+
/* Dummy commands (Currently not supported) */
install_element(BGP_NODE, &no_synchronization_cmd);
install_element(BGP_NODE, &no_auto_summary_cmd);
@@ -15983,7 +16086,6 @@ void bgp_vty_init(void)
/* bgp update-delay command */
install_element(BGP_NODE, &bgp_update_delay_cmd);
install_element(BGP_NODE, &no_bgp_update_delay_cmd);
- install_element(BGP_NODE, &bgp_update_delay_establish_wait_cmd);
install_element(BGP_NODE, &bgp_wpkt_quanta_cmd);
install_element(BGP_NODE, &bgp_rpkt_quanta_cmd);
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index 15bd6d33b8..11e872f6b4 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -1144,7 +1144,8 @@ static bool update_ipv6nh_for_route_install(int nh_othervrf, struct bgp *nh_bgp,
api_nh->ifindex = 0;
}
}
- api_nh->gate.ipv6 = *nexthop;
+ if (nexthop)
+ api_nh->gate.ipv6 = *nexthop;
return true;
}
@@ -2153,10 +2154,10 @@ static int rule_notify_owner(ZAPI_CALLBACK_ARGS)
enum zapi_rule_notify_owner note;
struct bgp_pbr_action *bgp_pbra;
struct bgp_pbr_rule *bgp_pbr = NULL;
- ifindex_t ifi;
+ char ifname[INTERFACE_NAMSIZ + 1];
if (!zapi_rule_notify_decode(zclient->ibuf, &seqno, &priority, &unique,
- &ifi, &note))
+ ifname, &note))
return -1;
bgp_pbra = bgp_pbr_action_rule_lookup(vrf_id, unique);
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index d638c6686e..b654e85206 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -2969,7 +2969,8 @@ static struct bgp *bgp_create(as_t *as, const char *name,
bgp->gr_info[afi][safi].route_list = list_new();
}
- bgp->v_update_delay = BGP_UPDATE_DELAY_DEF;
+ bgp->v_update_delay = bm->v_update_delay;
+ bgp->v_establish_wait = bm->v_establish_wait;
bgp->default_local_pref = BGP_DEFAULT_LOCAL_PREF;
bgp->default_subgroup_pkt_queue_max =
BGP_DEFAULT_SUBGROUP_PKT_QUEUE_MAX;
@@ -7005,6 +7006,8 @@ void bgp_master_init(struct thread_master *master, const int buffer_size)
bm->start_time = bgp_clock();
bm->t_rmap_update = NULL;
bm->rmap_update_timer = RMAP_DEFAULT_UPDATE_TIMER;
+ bm->v_update_delay = BGP_UPDATE_DELAY_DEF;
+ bm->v_establish_wait = BGP_UPDATE_DELAY_DEF;
bm->terminating = false;
bm->socket_buffer = buffer_size;
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index 8707ebacb6..2aa0690025 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -169,6 +169,10 @@ struct bgp_master {
/* EVPN multihoming */
struct bgp_evpn_mh_info *mh_info;
+ /* global update-delay timer values */
+ uint16_t v_update_delay;
+ uint16_t v_establish_wait;
+
bool terminating; /* global flag that sigint terminate seen */
QOBJ_FIELDS
};
diff --git a/configure.ac b/configure.ac
index ae116ef754..a952cf7063 100755
--- a/configure.ac
+++ b/configure.ac
@@ -7,7 +7,7 @@
##
AC_PREREQ([2.60])
-AC_INIT([frr], [7.5-dev], [https://github.com/frrouting/frr/issues])
+AC_INIT([frr], [7.6-dev], [https://github.com/frrouting/frr/issues])
PACKAGE_URL="https://frrouting.org/"
AC_SUBST([PACKAGE_URL])
PACKAGE_FULLNAME="FRRouting"
@@ -1728,8 +1728,8 @@ AC_SUBST([SNMP_CFLAGS])
dnl ---------------
dnl libyang
dnl ---------------
-PKG_CHECK_MODULES([LIBYANG], [libyang >= 0.16.105], , [
- AC_MSG_ERROR([libyang (>= 0.16.105) was not found on your system.])
+PKG_CHECK_MODULES([LIBYANG], [libyang >= 1.0.184], , [
+ AC_MSG_ERROR([libyang (>= 1.0.184) was not found on your system.])
])
ac_cflags_save="$CFLAGS"
CFLAGS="$CFLAGS $LIBYANG_CFLAGS"
diff --git a/debian/control b/debian/control
index f4275471d5..fca6956760 100644
--- a/debian/control
+++ b/debian/control
@@ -24,7 +24,7 @@ Build-Depends:
libsnmp-dev,
libssh-dev <!pkg.frr.nortrlib>,
libsystemd-dev <!pkg.frr.nosystemd>,
- libyang-dev (>= 0.16.74),
+ libyang-dev (>= 1.0.184),
pkg-config,
python3,
python3-dev,
diff --git a/doc/developer/building-libyang.rst b/doc/developer/building-libyang.rst
index f50b8cf72d..5f82447d74 100644
--- a/doc/developer/building-libyang.rst
+++ b/doc/developer/building-libyang.rst
@@ -5,12 +5,16 @@ library.
**Option 1: Binary Install**
-The FRR project builds binary ``libyang`` packages, which we offer for download
-`here <https://ci1.netdef.org/browse/LIBYANG-YANGRELEASE/latestSuccessful/artifact>`_.
+The FRR project builds some binary ``libyang`` packages.
+
+RPM packages are at our `RPM repository <https://rpm.frrouting.org>`_.
+
+DEB packages are available as CI artifacts `here
+<https://ci1.netdef.org/browse/LIBYANG-LY1REL-DEB10AMD64-4/artifact>`_.
.. warning::
- ``libyang`` version 0.16.105 or newer is required to build FRR.
+ ``libyang`` version 1.0.184 or newer is required to build FRR.
.. note::
@@ -50,8 +54,3 @@ The FRR project builds binary ``libyang`` packages, which we offer for download
-D CMAKE_BUILD_TYPE:String="Release" ..
make
sudo make install
-
-When building ``libyang`` version ``0.16.x`` it's also necessary to pass the
-``-DENABLE_CACHE=OFF`` parameter to ``cmake`` to work around a
-`known bug <https://github.com/CESNET/libyang/issues/752>`_ in libyang.
-
diff --git a/doc/developer/lists.rst b/doc/developer/lists.rst
index 9355141aa4..28b21533c0 100644
--- a/doc/developer/lists.rst
+++ b/doc/developer/lists.rst
@@ -497,6 +497,7 @@ API for hash tables
Items that compare as equal cannot be inserted. Refer to the notes
about sorted structures in the previous section.
+
.. c:function:: void Z_init_size(struct Z_head *, size_t size)
Same as :c:func:`Z_init()` but preset the minimum hash table to
@@ -506,6 +507,66 @@ Hash tables also support :c:func:`Z_add()` and :c:func:`Z_find()` with
the same semantics as noted above. :c:func:`Z_find_gteq()` and
:c:func:`Z_find_lt()` are **not** provided for hash tables.
+Hash table invariants
+^^^^^^^^^^^^^^^^^^^^^
+
+There are several ways to injure yourself using the hash table API.
+
+First, note that there are two functions related to computing uniqueness of
+objects inserted into the hash table. There is a hash function and a comparison
+function. The hash function computes the hash of the object. Our hash table
+implementation uses `chaining
+<https://en.wikipedia.org/wiki/Hash_table#Separate_chaining_with_linked_lists>`_.
+This means that your hash function does not have to be perfect; multiple
+objects having the same computed hash will be placed into a linked list
+corresponding to that key. The closer to perfect the hash function, the better
+performance, as items will be more evenly distributed and the chain length will
+not be long on any given lookup, minimizing the number of list operations
+required to find the correct item. However, the comparison function *must* be
+perfect, in the sense that any two unique items inserted into the hash table
+must compare not equal. At insertion time, if you try to insert an item that
+compares equal to an existing item the insertion will not happen and
+``hash_get()`` will return the existing item. However, this invariant *must* be
+maintained while the object is in the hash table. Suppose you insert items
+``A`` and ``B`` into the hash table which both hash to the same value ``1234``
+but do not compare equal. They will be placed in a chain like so::
+
+ 1234 : A -> B
+
+Now suppose you do something like this elsewhere in the code::
+
+ *A = *B
+
+I.e. you copy all fields of ``B`` into ``A``, such that the comparison function
+now says that they are equal based on their contents. At this point when you
+look up ``B`` in the hash table, ``hash_get()`` will search the chain for the
+first item that compares equal to ``B``, which will be ``A``. This leads to
+insidious bugs.
+
+.. warning::
+
+ Never modify the values looked at by the comparison or hash functions after
+ inserting an item into a hash table.
+
+A similar situation can occur with the hash allocation function. ``hash_get()``
+accepts a function pointer that it will call to get the item that should be
+inserted into the list if the provided item is not already present. There is a
+builtin function, ``hash_alloc_intern``, that will simply return the item you
+provided; if you always want to store the value you pass to ``hash_get`` you
+should use this one. If you choose to provide a different one, that function
+*must* return a new item that hashes and compares equal to the one you provided
+to ``hash_get()``. If it does not the behavior of the hash table is undefined.
+
+.. warning::
+
+ Always make sure your hash allocation function returns a value that hashes
+ and compares equal to the item you provided to ``hash_get()``.
+
+Finally, if you maintain pointers to items you have inserted into a hash table,
+then before deallocating them you must release them from the hash table. This
+is basic memory management but worth repeating as bugs have arisen from failure
+to do this.
+
API for heaps
-------------
diff --git a/doc/developer/process-architecture.rst b/doc/developer/process-architecture.rst
index 6e0eb68188..6a028d0000 100644
--- a/doc/developer/process-architecture.rst
+++ b/doc/developer/process-architecture.rst
@@ -94,7 +94,9 @@ irrelevant for the time being) for the specific type. For example, to add a
thread_add_read(struct thread_master *master, int (*handler)(struct thread *), void *arg, int fd, struct thread **ref);
The ``struct thread`` is then created and added to the appropriate internal
-datastructure within the ``threadmaster``.
+datastructure within the ``threadmaster``. Note that the ``READ`` and
+``WRITE`` tasks are independent - a ``READ`` task only tests for
+readability, for example.
The Event Loop
^^^^^^^^^^^^^^
diff --git a/doc/developer/topotests.rst b/doc/developer/topotests.rst
index b32f2bbf49..5486fd826d 100644
--- a/doc/developer/topotests.rst
+++ b/doc/developer/topotests.rst
@@ -722,7 +722,7 @@ Example:
.. code:: py
# For all registered routers, load the zebra configuration file
- for rname, router in router_list.iteritems():
+ for rname, router in router_list.items():
router.load_config(
TopoRouter.RD_ZEBRA,
os.path.join(CWD, '{}/zebra.conf'.format(rname))
diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst
index 25eaa577c1..9983911581 100644
--- a/doc/user/bgp.rst
+++ b/doc/user/bgp.rst
@@ -1103,6 +1103,41 @@ Redistribution
Redistribute VNC direct (not via zebra) routes to BGP process.
+.. index:: bgp update-delay MAX-DELAY
+.. clicmd:: bgp update-delay MAX-DELAY
+
+.. index:: bgp update-delay MAX-DELAY ESTABLISH-WAIT
+.. clicmd:: bgp update-delay MAX-DELAY ESTABLISH-WAIT
+
+ This feature is used to enable read-only mode on BGP process restart or when
+ a BGP process is cleared using 'clear ip bgp \*'. Note that this command is
+ configured at the global level and applies to all bgp instances/vrfs. It
+ cannot be used at the same time as the "update-delay" command described below,
+ which is entered in each bgp instance/vrf desired to delay update installation
+ and advertisements. The global and per-vrf approaches to defining update-delay
+ are mutually exclusive.
+
+ When applicable, read-only mode would begin as soon as the first peer reaches
+ Established status and a timer for max-delay seconds is started. During this
+ mode BGP doesn't run any best-path or generate any updates to its peers. This
+ mode continues until:
+
+ 1. All the configured peers, except the shutdown peers, have sent explicit EOR
+ (End-Of-RIB) or an implicit-EOR. The first keep-alive after BGP has reached
+ Established is considered an implicit-EOR.
+ If the establish-wait optional value is given, then BGP will wait for
+ peers to reach established from the beginning of the update-delay till the
+ establish-wait period is over, i.e. the minimum set of established peers for
+ which EOR is expected would be peers established during the establish-wait
+ window, not necessarily all the configured neighbors.
+ 2. max-delay period is over.
+
+ On hitting any of the above two conditions, BGP resumes the decision process
+ and generates updates to its peers.
+
+ Default max-delay is 0, i.e. the feature is off by default.
+
+
.. index:: update-delay MAX-DELAY
.. clicmd:: update-delay MAX-DELAY
@@ -1110,12 +1145,17 @@ Redistribution
.. clicmd:: update-delay MAX-DELAY ESTABLISH-WAIT
This feature is used to enable read-only mode on BGP process restart or when
- BGP process is cleared using 'clear ip bgp \*'. When applicable, read-only
- mode would begin as soon as the first peer reaches Established status and a
- timer for max-delay seconds is started.
-
- During this mode BGP doesn't run any best-path or generate any updates to its
- peers. This mode continues until:
+ a BGP process is cleared using 'clear ip bgp \*'. Note that this command is
+ configured under the specific bgp instance/vrf that the feaure is enabled for.
+ It cannot be used at the same time as the global "bgp update-delay" described
+ above, which is entered at the global level and applies to all bgp instances.
+ The global and per-vrf approaches to defining update-delay are mutually
+ exclusive.
+
+ When applicable, read-only mode would begin as soon as the first peer reaches
+ Established status and a timer for max-delay seconds is started. During this
+ mode BGP doesn't run any best-path or generate any updates to its peers. This
+ mode continues until:
1. All the configured peers, except the shutdown peers, have sent explicit EOR
(End-Of-RIB) or an implicit-EOR. The first keep-alive after BGP has reached
@@ -2500,6 +2540,26 @@ the same behavior of using same next-hop and RMAC values.
Enables or disables advertise-pip feature, specifiy system-IP and/or system-MAC
parameters.
++Support with VRF network namespace backend
++^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+It is possible to separate overlay networks contained in VXLAN interfaces from
+underlay networks by using VRFs. VRF-lite and VRF-netns backends can be used for
+that. In the latter case, it is necessary to set both bridge and vxlan interface
+in the same network namespace, as below example illustrates:
+
+.. code-block:: shell
+
+ # linux shell
+ ip netns add vrf1
+ ip link add name vxlan101 type vxlan id 101 dstport 4789 dev eth0 local 10.1.1.1
+ ip link set dev vxlan101 netns vrf1
+ ip netns exec vrf1 ip link set dev lo up
+ ip netns exec vrf1 brctl addbr bridge101
+ ip netns exec vrf1 brctl addif bridge101 vxlan101
+
+This makes it possible to separate not only layer 3 networks like VRF-lite networks.
+Also, VRF netns based make possible to separate layer 2 networks on separate VRF
+instances.
.. _bgp-debugging:
@@ -2681,17 +2741,17 @@ daemon project, while :clicmd:`show bgp` command is the new format. The choice
has been done to keep old format with IPv4 routing table, while new format
displays IPv6 routing table.
-.. index:: show ip bgp [wide]
-.. clicmd:: show ip bgp [wide]
+.. index:: show ip bgp [all] [wide|json]
+.. clicmd:: show ip bgp [all] [wide|json]
-.. index:: show ip bgp A.B.C.D [wide]
-.. clicmd:: show ip bgp A.B.C.D [wide]
+.. index:: show ip bgp A.B.C.D [json]
+.. clicmd:: show ip bgp A.B.C.D [json]
-.. index:: show bgp [wide]
-.. clicmd:: show bgp [wide]
+.. index:: show bgp [all] [wide|json]
+.. clicmd:: show bgp [all] [wide|json]
-.. index:: show bgp X:X::X:X [wide]
-.. clicmd:: show bgp X:X::X:X [wide]
+.. index:: show bgp X:X::X:X [json]
+.. clicmd:: show bgp X:X::X:X [json]
These commands display BGP routes. When no route is specified, the default
is to display all BGP routes.
@@ -2713,6 +2773,11 @@ displays IPv6 routing table.
This is especially handy dealing with IPv6 prefixes and
if :clicmd:`[no] bgp default show-nexthop-hostname` is enabled.
+ If _all_ option is specified, _ip_ keyword is ignored, show bgp all and
+ show ip bgp all commands display routes for all AFIs and SAFIs.
+
+ If _json_ option is specified, output is displayed in JSON format.
+
Some other commands provide additional options for filtering the output.
.. index:: show [ip] bgp regexp LINE
@@ -2721,8 +2786,8 @@ Some other commands provide additional options for filtering the output.
This command displays BGP routes using AS path regular expression
(:ref:`bgp-regular-expressions`).
-.. index:: show [ip] bgp summary
-.. clicmd:: show [ip] bgp summary
+.. index:: show [ip] bgp [all] summary [json]
+.. clicmd:: show [ip] bgp [all] summary [json]
Show a bgp peer summary for the specified address family.
@@ -2731,8 +2796,8 @@ and should no longer be used. In order to reach the other BGP routing tables
other than the IPv6 routing table given by :clicmd:`show bgp`, the new command
structure is extended with :clicmd:`show bgp [afi] [safi]`.
-.. index:: show bgp [afi] [safi]
-.. clicmd:: show bgp [afi] [safi]
+.. index:: show bgp [afi] [safi] [all] [wide|json]
+.. clicmd:: show bgp [afi] [safi] [all] [wide|json]
.. index:: show bgp <ipv4|ipv6> <unicast|multicast|vpn|labeled-unicast>
.. clicmd:: show bgp <ipv4|ipv6> <unicast|multicast|vpn|labeled-unicast>
@@ -2748,20 +2813,20 @@ structure is extended with :clicmd:`show bgp [afi] [safi]`.
Additionally, you can also filter this output by route type.
-.. index:: show bgp [afi] [safi] summary
-.. clicmd:: show bgp [afi] [safi] summary
+.. index:: show bgp [afi] [safi] [all] summary [json]
+.. clicmd:: show bgp [afi] [safi] [all] summary [json]
Show a bgp peer summary for the specified address family, and subsequent
address-family.
-.. index:: show bgp [afi] [safi] summary failed [json]
-.. clicmd:: show bgp [afi] [safi] summary failed [json]
+.. index:: show bgp [afi] [safi] [all] summary failed [json]
+.. clicmd:: show bgp [afi] [safi] [all] summary failed [json]
Show a bgp peer summary for peers that are not succesfully exchanging routes
for the specified address family, and subsequent address-family.
-.. index:: show bgp [afi] [safi] summary established [json]
-.. clicmd:: show bgp [afi] [safi] summary established [json]
+.. index:: show bgp [afi] [safi] [all] summary established [json]
+.. clicmd:: show bgp [afi] [safi] [all] summary established [json]
Show a bgp peer summary for peers that are succesfully exchanging routes
for the specified address family, and subsequent address-family.
@@ -2772,14 +2837,14 @@ structure is extended with :clicmd:`show bgp [afi] [safi]`.
This command shows information on a specific BGP peer of the relevant
afi and safi selected.
-.. index:: show bgp [afi] [safi] dampening dampened-paths
-.. clicmd:: show bgp [afi] [safi] dampening dampened-paths
+.. index:: show bgp [afi] [safi] [all] dampening dampened-paths [wide|json]
+.. clicmd:: show bgp [afi] [safi] [all] dampening dampened-paths [wide|json]
Display paths suppressed due to dampening of the selected afi and safi
selected.
-.. index:: show bgp [afi] [safi] dampening flap-statistics
-.. clicmd:: show bgp [afi] [safi] dampening flap-statistics
+.. index:: show bgp [afi] [safi] [all] dampening flap-statistics [wide|json]
+.. clicmd:: show bgp [afi] [safi] [all] dampening flap-statistics [wide|json]
Display flap statistics of routes of the selected afi and safi selected.
@@ -2793,6 +2858,31 @@ structure is extended with :clicmd:`show bgp [afi] [safi]`.
Display statistics of routes of all the afi and safi.
+.. index:: show [ip] bgp [afi] [safi] [all] cidr-only [wide|json]
+.. clicmd:: show [ip] bgp [afi] [safi] [all] cidr-only [wide|json]
+
+ Display routes with non-natural netmasks.
+
+.. index:: show [ip] bgp [afi] [safi] [all] neighbors A.B.C.D [advertised-routes|received-routes|filtered-routes] [json|wide]
+.. clicmd:: show [ip] bgp [afi] [safi] [all] neighbors A.B.C.D [advertised-routes|received-routes|filtered-routes] [json|wide]
+
+ Display the routes advertised to a BGP neighbor or received routes
+ from neighbor or filtered routes received from neighbor based on the
+ option specified.
+
+ If _wide_ option is specified, then the prefix table's width is increased
+ to fully display the prefix and the nexthop.
+
+ This is especially handy dealing with IPv6 prefixes and
+ if :clicmd:`[no] bgp default show-nexthop-hostname` is enabled.
+
+ If _all_ option is specified, _ip_ keyword is ignored and,
+ routes displayed for all AFIs and SAFIs.
+ if afi is specified, with _all_ option, routes will be displayed for
+ each SAFI in the selcted AFI
+
+ If _json_ option is specified, output is displayed in JSON format.
+
.. _bgp-display-routes-by-community:
Displaying Routes by Community Attribute
@@ -2801,14 +2891,14 @@ Displaying Routes by Community Attribute
The following commands allow displaying routes based on their community
attribute.
-.. index:: show [ip] bgp <ipv4|ipv6> community
-.. clicmd:: show [ip] bgp <ipv4|ipv6> community
+.. index:: show [ip] bgp <ipv4|ipv6> [all] community [wide|json]
+.. clicmd:: show [ip] bgp <ipv4|ipv6> [all] community [wide|json]
-.. index:: show [ip] bgp <ipv4|ipv6> community COMMUNITY
-.. clicmd:: show [ip] bgp <ipv4|ipv6> community COMMUNITY
+.. index:: show [ip] bgp <ipv4|ipv6> [all] community COMMUNITY [wide|json]
+.. clicmd:: show [ip] bgp <ipv4|ipv6> [all] community COMMUNITY [wide|json]
-.. index:: show [ip] bgp <ipv4|ipv6> community COMMUNITY exact-match
-.. clicmd:: show [ip] bgp <ipv4|ipv6> community COMMUNITY exact-match
+.. index:: show [ip] bgp <ipv4|ipv6> [all] community COMMUNITY exact-match [wide|json]
+.. clicmd:: show [ip] bgp <ipv4|ipv6> [all] community COMMUNITY exact-match [wide|json]
These commands display BGP routes which have the community attribute.
attribute. When ``COMMUNITY`` is specified, BGP routes that match that
@@ -2825,6 +2915,19 @@ attribute.
match the specified community list. When `exact-match` is specified, it
displays only routes that have an exact match.
+ If _wide_ option is specified, then the prefix table's width is increased
+ to fully display the prefix and the nexthop.
+
+ This is especially handy dealing with IPv6 prefixes and
+ if :clicmd:`[no] bgp default show-nexthop-hostname` is enabled.
+
+ If _all_ option is specified, _ip_ keyword is ignored and,
+ routes displayed for all AFIs and SAFIs.
+ if afi is specified, with _all_ option, routes will be displayed for
+ each SAFI in the selcted AFI
+
+ If _json_ option is specified, output is displayed in JSON format.
+
.. _bgp-display-routes-by-lcommunity:
Displaying Routes by Large Community Attribute
diff --git a/doc/user/overview.rst b/doc/user/overview.rst
index ac6a1e5a8c..724d1d0b9c 100644
--- a/doc/user/overview.rst
+++ b/doc/user/overview.rst
@@ -31,7 +31,8 @@ information, as well as links to additional resources.
Several distributions provide packages for FRR. Check your distribution's
repositories to find out if a suitable version is available.
-Up-to-date Debian packages are available at https://deb.frrouting.org/.
+Up-to-date Debian & Redhat packages are available at https://deb.frrouting.org/
+& https://rpm.frrouting.org/ respectively.
For instructions on installing from source, refer to the
`developer documentation <http://docs.frrouting.org/projects/dev-guide/en/latest/>`_.
diff --git a/include/linux/net_namespace.h b/include/linux/net_namespace.h
index 0187c74d88..0ed9dd61d3 100644
--- a/include/linux/net_namespace.h
+++ b/include/linux/net_namespace.h
@@ -16,6 +16,7 @@ enum {
NETNSA_NSID,
NETNSA_PID,
NETNSA_FD,
+ NETNSA_TARGET_NSID,
__NETNSA_MAX,
};
diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c
index 1214c01a12..d6988095e5 100644
--- a/isisd/isis_circuit.c
+++ b/isisd/isis_circuit.c
@@ -59,6 +59,7 @@
#include "isisd/isis_errors.h"
#include "isisd/isis_tx_queue.h"
#include "isisd/isis_nb.h"
+#include "isisd/isis_ldp_sync.h"
DEFINE_QOBJ_TYPE(isis_circuit)
@@ -1280,6 +1281,7 @@ struct isis_circuit *isis_circuit_create(struct isis_area *area,
isis_circuit_if_bind(circuit, ifp);
if (circuit->area->mta && circuit->area->mta->status)
isis_link_params_update(circuit, ifp);
+
return circuit;
}
@@ -1350,11 +1352,16 @@ ferr_r isis_circuit_metric_set(struct isis_circuit *circuit, int level,
return ferr_cfg_invalid("metric %d too large for narrow metric",
metric);
- circuit->te_metric[level - 1] = metric;
- circuit->metric[level - 1] = metric;
-
- if (circuit->area)
- lsp_regenerate_schedule(circuit->area, level, 0);
+ /* inform ldp-sync of metric change
+ * if ldp-sync is running need to save metric
+ * and restore new values after ldp-sync completion.
+ */
+ if (isis_ldp_sync_if_metric_config(circuit, level, metric)) {
+ circuit->te_metric[level - 1] = metric;
+ circuit->metric[level - 1] = metric;
+ if (circuit->area)
+ lsp_regenerate_schedule(circuit->area, level, 0);
+ }
return ferr_ok();
}
diff --git a/isisd/isis_circuit.h b/isisd/isis_circuit.h
index da358f411b..5766d1962f 100644
--- a/isisd/isis_circuit.h
+++ b/isisd/isis_circuit.h
@@ -139,6 +139,7 @@ struct isis_circuit {
uint8_t flags;
bool disable_threeway_adj;
struct bfd_info *bfd_info;
+ struct ldp_sync_info *ldp_sync_info;
/*
* Counters as in 10589--11.2.5.9
*/
diff --git a/isisd/isis_cli.c b/isisd/isis_cli.c
index 31fe41db82..406717e04f 100644
--- a/isisd/isis_cli.c
+++ b/isisd/isis_cli.c
@@ -235,7 +235,7 @@ DEFPY_YANG(ip_router_isis, ip_router_isis_cmd,
}
/* check if the interface is a loopback and if so set it as passive */
- if (ifp && if_is_loopback(ifp))
+ if (if_is_loopback(ifp))
nb_cli_enqueue_change(vty, "./frr-isisd:isis/passive",
NB_OP_MODIFY, "true");
@@ -326,7 +326,7 @@ DEFPY_YANG(ip6_router_isis, ip6_router_isis_cmd,
}
/* check if the interface is a loopback and if so set it as passive */
- if (ifp && if_is_loopback(ifp))
+ if (if_is_loopback(ifp))
nb_cli_enqueue_change(vty, "./frr-isisd:isis/passive",
NB_OP_MODIFY, "true");
@@ -2386,6 +2386,178 @@ void cli_show_isis_log_adjacency(struct vty *vty, struct lyd_node *dnode,
vty_out(vty, " log-adjacency-changes\n");
}
+/*
+ * XPath: /frr-isisd:isis/instance/mpls/ldp-sync
+ */
+DEFPY(isis_mpls_ldp_sync, isis_mpls_ldp_sync_cmd, "mpls ldp-sync",
+ MPLS_STR MPLS_LDP_SYNC_STR)
+{
+ nb_cli_enqueue_change(vty, "./mpls/ldp-sync", NB_OP_CREATE, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(no_isis_mpls_ldp_sync, no_isis_mpls_ldp_sync_cmd, "no mpls ldp-sync",
+ NO_STR MPLS_STR NO_MPLS_LDP_SYNC_STR)
+{
+ nb_cli_enqueue_change(vty, "./mpls/ldp-sync", NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+void cli_show_isis_mpls_ldp_sync(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults)
+{
+ vty_out(vty, " mpls ldp-sync\n");
+}
+
+DEFPY(isis_mpls_ldp_sync_holddown, isis_mpls_ldp_sync_holddown_cmd,
+ "mpls ldp-sync holddown (0-10000)",
+ MPLS_STR MPLS_LDP_SYNC_STR
+ "Time to wait for LDP-SYNC to occur before restoring interface metric\n"
+ "Time in seconds\n")
+{
+ nb_cli_enqueue_change(vty, "./mpls/ldp-sync/holddown", NB_OP_MODIFY,
+ holddown_str);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(no_isis_mpls_ldp_sync_holddown, no_isis_mpls_ldp_sync_holddown_cmd,
+ "no mpls ldp-sync holddown [<(1-10000)>]",
+ NO_STR MPLS_STR MPLS_LDP_SYNC_STR NO_MPLS_LDP_SYNC_HOLDDOWN_STR)
+{
+ nb_cli_enqueue_change(vty, "./mpls/ldp-sync/holddown", NB_OP_DESTROY,
+ NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+void cli_show_isis_mpls_ldp_sync_holddown(struct vty *vty,
+ struct lyd_node *dnode,
+ bool show_defaults)
+{
+ vty_out(vty, " mpls ldp-sync holddown %s\n",
+ yang_dnode_get_string(dnode, NULL));
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-isisd:isis/mpls/ldp-sync
+ */
+DEFPY(isis_mpls_if_ldp_sync, isis_mpls_if_ldp_sync_cmd,
+ "[no] isis mpls ldp-sync",
+ NO_STR "IS-IS routing protocol\n" MPLS_STR MPLS_LDP_SYNC_STR)
+{
+ const struct lyd_node *dnode;
+ struct interface *ifp;
+
+ dnode = yang_dnode_get(vty->candidate_config->dnode,
+ "%s/frr-isisd:isis", VTY_CURR_XPATH);
+ if (dnode == NULL) {
+ vty_out(vty, "ISIS is not enabled on this circuit\n");
+ return CMD_SUCCESS;
+ }
+
+ ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
+ if (if_is_loopback(ifp)) {
+ vty_out(vty, "ldp-sync does not run on loopback interface\n");
+ return CMD_SUCCESS;
+ }
+
+ if (ifp->vrf_id != VRF_DEFAULT) {
+ vty_out(vty, "ldp-sync only runs on DEFAULT VRF\n");
+ return CMD_SUCCESS;
+ }
+
+ nb_cli_enqueue_change(vty, "./frr-isisd:isis/mpls/ldp-sync",
+ NB_OP_MODIFY, no ? "false" : "true");
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+
+void cli_show_isis_mpls_if_ldp_sync(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults)
+{
+ if (!yang_dnode_get_bool(dnode, NULL))
+ vty_out(vty, " no");
+
+ vty_out(vty, " isis mpls ldp-sync\n");
+}
+
+DEFPY(isis_mpls_if_ldp_sync_holddown, isis_mpls_if_ldp_sync_holddown_cmd,
+ "isis mpls ldp-sync holddown (0-10000)",
+ "IS-IS routing protocol\n" MPLS_STR MPLS_LDP_SYNC_STR
+ "Time to wait for LDP-SYNC to occur before restoring interface metric\n"
+ "Time in seconds\n")
+{
+ const struct lyd_node *dnode;
+ struct interface *ifp;
+
+ dnode = yang_dnode_get(vty->candidate_config->dnode,
+ "%s/frr-isisd:isis", VTY_CURR_XPATH);
+ if (dnode == NULL) {
+ vty_out(vty, "ISIS is not enabled on this circuit\n");
+ return CMD_SUCCESS;
+ }
+
+ ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
+ if (if_is_loopback(ifp)) {
+ vty_out(vty, "ldp-sync does not run on loopback interface\n");
+ return CMD_SUCCESS;
+ }
+
+ if (ifp->vrf_id != VRF_DEFAULT) {
+ vty_out(vty, "ldp-sync only runs on DEFAULT VRF\n");
+ return CMD_SUCCESS;
+ }
+
+ nb_cli_enqueue_change(vty, "./frr-isisd:isis/mpls/holddown",
+ NB_OP_MODIFY, holddown_str);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY(no_isis_mpls_if_ldp_sync_holddown, no_isis_mpls_if_ldp_sync_holddown_cmd,
+ "no isis mpls ldp-sync holddown [<(1-10000)>]",
+ NO_STR "IS-IS routing protocol\n" MPLS_STR NO_MPLS_LDP_SYNC_STR
+ NO_MPLS_LDP_SYNC_HOLDDOWN_STR)
+{
+ const struct lyd_node *dnode;
+ struct interface *ifp;
+
+ dnode = yang_dnode_get(vty->candidate_config->dnode,
+ "%s/frr-isisd:isis", VTY_CURR_XPATH);
+ if (dnode == NULL) {
+ vty_out(vty, "ISIS is not enabled on this circuit\n");
+ return CMD_SUCCESS;
+ }
+
+ ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false);
+ if (if_is_loopback(ifp)) {
+ vty_out(vty, "ldp-sync does not run on loopback interface\n");
+ return CMD_SUCCESS;
+ }
+
+ if (ifp->vrf_id != VRF_DEFAULT) {
+ vty_out(vty, "ldp-sync only runs on DEFAULT VRF\n");
+ return CMD_SUCCESS;
+ }
+
+ nb_cli_enqueue_change(vty, "./frr-isisd:isis/mpls/holddown",
+ NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+void cli_show_isis_mpls_if_ldp_sync_holddown(struct vty *vty,
+ struct lyd_node *dnode,
+ bool show_defaults)
+{
+ vty_out(vty, " isis mpls ldp-sync holddown %s\n",
+ yang_dnode_get_string(dnode, NULL));
+}
+
void isis_cli_init(void)
{
install_element(CONFIG_NODE, &router_isis_cmd);
@@ -2489,6 +2661,14 @@ void isis_cli_init(void)
install_element(INTERFACE_NODE, &no_isis_priority_cmd);
install_element(ISIS_NODE, &log_adj_changes_cmd);
+
+ install_element(ISIS_NODE, &isis_mpls_ldp_sync_cmd);
+ install_element(ISIS_NODE, &no_isis_mpls_ldp_sync_cmd);
+ install_element(ISIS_NODE, &isis_mpls_ldp_sync_holddown_cmd);
+ install_element(ISIS_NODE, &no_isis_mpls_ldp_sync_holddown_cmd);
+ install_element(INTERFACE_NODE, &isis_mpls_if_ldp_sync_cmd);
+ install_element(INTERFACE_NODE, &isis_mpls_if_ldp_sync_holddown_cmd);
+ install_element(INTERFACE_NODE, &no_isis_mpls_if_ldp_sync_holddown_cmd);
}
#endif /* ifndef FABRICD */
diff --git a/isisd/isis_events.c b/isisd/isis_events.c
index f330407bf5..717a5fd046 100644
--- a/isisd/isis_events.c
+++ b/isisd/isis_events.c
@@ -76,6 +76,12 @@ void isis_event_circuit_state_change(struct isis_circuit *circuit,
static void circuit_commence_level(struct isis_circuit *circuit, int level)
{
+ if (IS_DEBUG_EVENTS)
+ zlog_debug(
+ "ISIS-Evt (%s) circuit %u on iface %s commencing on L%d",
+ circuit->area->area_tag, circuit->circuit_id,
+ circuit->interface->name, level);
+
if (!circuit->is_passive) {
if (level == 1) {
thread_add_timer(master, send_l1_psnp, circuit,
@@ -105,6 +111,12 @@ static void circuit_resign_level(struct isis_circuit *circuit, int level)
{
int idx = level - 1;
+ if (IS_DEBUG_EVENTS)
+ zlog_debug(
+ "ISIS-Evt (%s) circuit %u on iface %s resigning on L%d",
+ circuit->area->area_tag, circuit->circuit_id,
+ circuit->interface->name, level);
+
THREAD_TIMER_OFF(circuit->t_send_csnp[idx]);
THREAD_TIMER_OFF(circuit->t_send_psnp[idx]);
@@ -114,6 +126,7 @@ static void circuit_resign_level(struct isis_circuit *circuit, int level)
THREAD_TIMER_OFF(circuit->u.bc.t_refresh_pseudo_lsp[idx]);
circuit->lsp_regenerate_pending[idx] = 0;
circuit->u.bc.run_dr_elect[idx] = 0;
+ circuit->u.bc.is_dr[idx] = 0;
if (circuit->u.bc.lan_neighs[idx] != NULL)
list_delete(&circuit->u.bc.lan_neighs[idx]);
}
diff --git a/isisd/isis_ldp_sync.c b/isisd/isis_ldp_sync.c
new file mode 100644
index 0000000000..42928e069a
--- /dev/null
+++ b/isisd/isis_ldp_sync.c
@@ -0,0 +1,788 @@
+/**
+ * isis_ldp_sync.c: ISIS LDP-IGP Sync handling routines
+ * Copyright (C) 2020 Volta Networks, 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 <string.h>
+
+#include "monotime.h"
+#include "memory.h"
+#include "thread.h"
+#include "prefix.h"
+#include "table.h"
+#include "vty.h"
+#include "command.h"
+#include "plist.h"
+#include "log.h"
+#include "zclient.h"
+#include <lib/json.h>
+#include "defaults.h"
+#include "ldp_sync.h"
+
+#include "isisd/isis_constants.h"
+#include "isisd/isis_common.h"
+#include "isisd/isis_flags.h"
+#include "isisd/isis_circuit.h"
+#include "isisd/isis_lsp.h"
+#include "isisd/isis_pdu.h"
+#include "isisd/isis_network.h"
+#include "isisd/isis_misc.h"
+#include "isisd/isis_constants.h"
+#include "isisd/isis_adjacency.h"
+#include "isisd/isis_dr.h"
+#include "isisd/isisd.h"
+#include "isisd/isis_csm.h"
+#include "isisd/isis_events.h"
+#include "isisd/isis_te.h"
+#include "isisd/isis_mt.h"
+#include "isisd/isis_errors.h"
+#include "isisd/isis_tx_queue.h"
+#include "isisd/isis_nb.h"
+#include "isisd/isis_ldp_sync.h"
+
+extern struct zclient *zclient;
+
+/*
+ * LDP-SYNC msg between IGP and LDP
+ */
+int isis_ldp_sync_state_update(struct ldp_igp_sync_if_state state)
+{
+ struct interface *ifp;
+ struct isis_circuit *circuit = NULL;
+ struct isis_area *area;
+ struct listnode *node;
+ struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+
+ /* if isis is not enabled or LDP-SYNC is not configured ignore */
+ if (!isis ||
+ !CHECK_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE))
+ return 0;
+
+ /* lookup circuit */
+ ifp = if_lookup_by_index(state.ifindex, VRF_DEFAULT);
+ if (ifp == NULL)
+ return 0;
+
+ for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
+ circuit = circuit_lookup_by_ifp(ifp, area->circuit_list);
+ if (circuit != NULL)
+ break;
+ }
+
+ /* if isis is not enabled or LDP-SYNC is not configured ignore */
+ if (circuit == NULL ||
+ !CHECK_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE))
+ return 0;
+
+ /* received ldp-sync interface state from LDP */
+ ils_debug("ldp_sync: rcvd %s from LDP if %s",
+ state.sync_start ? "sync-start" : "sync-complete", ifp->name);
+ if (state.sync_start)
+ isis_ldp_sync_if_start(circuit, false);
+ else
+ isis_ldp_sync_if_complete(circuit);
+
+ return 0;
+}
+
+int isis_ldp_sync_announce_update(struct ldp_igp_sync_announce announce)
+{
+ struct isis_area *area;
+ struct listnode *node;
+ struct vrf *vrf;
+ struct interface *ifp;
+ struct isis_circuit *circuit;
+ struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+
+ /* if isis is not enabled or LDP-SYNC is not configured ignore */
+ if (!isis ||
+ !CHECK_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE))
+ return 0;
+
+ if (announce.proto != ZEBRA_ROUTE_LDP)
+ return 0;
+
+ ils_debug("ldp_sync: rcvd announce from LDP");
+
+ /* LDP just started up:
+ * set cost to LSInfinity
+ * send request to LDP for LDP-SYNC state for each interface
+ * start hello timer
+ */
+ vrf = vrf_lookup_by_id(VRF_DEFAULT);
+ FOR_ALL_INTERFACES (vrf, ifp) {
+ for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
+ circuit = circuit_lookup_by_ifp(ifp,
+ area->circuit_list);
+ if (circuit == NULL)
+ continue;
+ isis_ldp_sync_if_start(circuit, true);
+ }
+ }
+
+ THREAD_TIMER_OFF(isis->ldp_sync_cmd.t_hello);
+ isis->ldp_sync_cmd.t_hello = NULL;
+ isis->ldp_sync_cmd.sequence = 0;
+ isis_ldp_sync_hello_timer_add();
+
+ return 0;
+}
+
+int isis_ldp_sync_hello_update(struct ldp_igp_sync_hello hello)
+{
+ struct isis_area *area;
+ struct listnode *node;
+ struct vrf *vrf;
+ struct interface *ifp;
+ struct isis_circuit *circuit;
+ struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+
+ /* if isis is not enabled or LDP-SYNC is not configured ignore */
+ if (!isis ||
+ !CHECK_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE))
+ return 0;
+
+ if (hello.proto != ZEBRA_ROUTE_LDP)
+ return 0;
+
+ /* Received Hello from LDP:
+ * if current sequence number is greater than received hello
+ * sequence number then assume LDP restarted
+ * set cost to LSInfinity
+ * send request to LDP for LDP-SYNC state for each interface
+ * else all is fine just restart hello timer
+ */
+ if (hello.sequence == 0)
+ /* rolled over */
+ isis->ldp_sync_cmd.sequence = 0;
+
+ if (isis->ldp_sync_cmd.sequence > hello.sequence) {
+ zlog_err("ldp_sync: LDP restarted");
+
+ vrf = vrf_lookup_by_id(VRF_DEFAULT);
+ FOR_ALL_INTERFACES (vrf, ifp) {
+ for (ALL_LIST_ELEMENTS_RO(isis->area_list, node,
+ area)) {
+ circuit = circuit_lookup_by_ifp(ifp,
+ area->circuit_list);
+ if (circuit == NULL)
+ continue;
+ isis_ldp_sync_if_start(circuit, true);
+ }
+ }
+ } else {
+ THREAD_TIMER_OFF(isis->ldp_sync_cmd.t_hello);
+ isis_ldp_sync_hello_timer_add();
+ }
+ isis->ldp_sync_cmd.sequence = hello.sequence;
+
+ return 0;
+}
+
+void isis_ldp_sync_state_req_msg(struct isis_circuit *circuit)
+{
+ struct ldp_igp_sync_if_state_req request;
+ struct interface *ifp = circuit->interface;
+
+ ils_debug("ldp_sync: send state request to LDP for %s",
+ ifp->name);
+
+ strlcpy(request.name, ifp->name, sizeof(ifp->name));
+ request.proto = LDP_IGP_SYNC_IF_STATE_REQUEST;
+ request.ifindex = ifp->ifindex;
+
+ zclient_send_opaque(zclient, LDP_IGP_SYNC_IF_STATE_REQUEST,
+ (uint8_t *)&request, sizeof(request));
+}
+
+/*
+ * LDP-SYNC general interface routines
+ */
+void isis_ldp_sync_if_init(struct isis_circuit *circuit, struct isis *isis)
+{
+ struct ldp_sync_info *ldp_sync_info;
+ struct interface *ifp = circuit->interface;
+
+ /* called when ISIS is configured on an interface
+ * if LDP-IGP Sync is configured globally set state
+ * and if ptop interface LDP LDP-SYNC is enabled
+ */
+ ils_debug("ldp_sync: init if %s ", ifp->name);
+ if (circuit->ldp_sync_info == NULL)
+ circuit->ldp_sync_info = ldp_sync_info_create();
+ ldp_sync_info = circuit->ldp_sync_info;
+
+ /* specifed on interface overrides global config. */
+ if (!CHECK_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_HOLDDOWN))
+ ldp_sync_info->holddown = isis->ldp_sync_cmd.holddown;
+
+ if (!CHECK_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_IF_CONFIG))
+ ldp_sync_info->enabled = LDP_IGP_SYNC_ENABLED;
+
+ if ((circuit->circ_type == CIRCUIT_T_P2P || if_is_pointopoint(ifp)) &&
+ ldp_sync_info->enabled == LDP_IGP_SYNC_ENABLED)
+ ldp_sync_info->state = LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP;
+}
+
+void isis_ldp_sync_if_start(struct isis_circuit *circuit,
+ bool send_state_req)
+{
+ struct ldp_sync_info *ldp_sync_info;
+
+ ldp_sync_info = circuit->ldp_sync_info;
+
+ /* Start LDP-SYNC on this interface:
+ * set cost of interface to LSInfinity so traffic will use different
+ * interface until LDP has learned all labels from peer
+ * start holddown timer if configured
+ * send msg to LDP to get LDP-SYNC state
+ */
+ if (ldp_sync_info &&
+ ldp_sync_info->enabled == LDP_IGP_SYNC_ENABLED &&
+ ldp_sync_info->state != LDP_IGP_SYNC_STATE_NOT_REQUIRED) {
+ ils_debug("ldp_sync: start on if %s state: %s",
+ circuit->interface->name, "Holding down until Sync");
+ ldp_sync_info->state = LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP;
+ isis_ldp_sync_set_if_metric(circuit, true);
+ isis_ldp_sync_holddown_timer_add(circuit);
+
+ if (send_state_req)
+ isis_ldp_sync_state_req_msg(circuit);
+ }
+}
+
+void isis_ldp_sync_if_complete(struct isis_circuit *circuit)
+{
+ struct ldp_sync_info *ldp_sync_info;
+
+ ldp_sync_info = circuit->ldp_sync_info;
+
+ /* received sync-complete from LDP:
+ * set state to up
+ * stop timer
+ * restore interface cost to original value
+ */
+ if (ldp_sync_info && ldp_sync_info->enabled == LDP_IGP_SYNC_ENABLED) {
+ if (ldp_sync_info->state == LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP)
+ ldp_sync_info->state = LDP_IGP_SYNC_STATE_REQUIRED_UP;
+ THREAD_TIMER_OFF(ldp_sync_info->t_holddown);
+ ldp_sync_info->t_holddown = NULL;
+ isis_ldp_sync_set_if_metric(circuit, true);
+ }
+}
+
+void isis_ldp_sync_ldp_fail(struct isis_circuit *circuit)
+{
+ struct ldp_sync_info *ldp_sync_info;
+
+ ldp_sync_info = circuit->ldp_sync_info;
+
+ /* LDP failed to send hello:
+ * stop holddown timer
+ * set cost of interface to LSInfinity so traffic will use different
+ * interface until LDP restarts and has learned all labels from peer
+ */
+ if (ldp_sync_info &&
+ ldp_sync_info->enabled == LDP_IGP_SYNC_ENABLED &&
+ ldp_sync_info->state != LDP_IGP_SYNC_STATE_NOT_REQUIRED) {
+ if (ldp_sync_info->t_holddown != NULL) {
+ THREAD_TIMER_OFF(ldp_sync_info->t_holddown);
+ ldp_sync_info->t_holddown = NULL;
+ }
+ ldp_sync_info->state = LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP;
+ isis_ldp_sync_set_if_metric(circuit, true);
+ }
+}
+
+void isis_ldp_sync_if_remove(struct isis_circuit *circuit, bool remove)
+{
+ struct ldp_sync_info *ldp_sync_info;
+
+ if (circuit->ldp_sync_info == NULL)
+ return;
+
+ ldp_sync_info = circuit->ldp_sync_info;
+
+ /* Stop LDP-SYNC on this interface:
+ * if holddown timer is running stop it
+ * delete ldp instance on interface
+ * restore metric
+ */
+ ils_debug("ldp_sync: remove if %s", circuit->interface
+ ? circuit->interface->name : "");
+
+ if (ldp_sync_info->t_holddown)
+ THREAD_TIMER_OFF(ldp_sync_info->t_holddown);
+ ldp_sync_info->state = LDP_IGP_SYNC_STATE_NOT_REQUIRED;
+ isis_ldp_sync_set_if_metric(circuit, true);
+ if (remove) {
+ /* ISIS instance being removed free ldp-sync info */
+ ldp_sync_info_free((struct ldp_sync_info **)&(ldp_sync_info));
+ circuit->ldp_sync_info = NULL;
+ }
+}
+
+static int isis_ldp_sync_adj_state_change(struct isis_adjacency *adj)
+{
+ struct isis_circuit *circuit = adj->circuit;
+ struct ldp_sync_info *ldp_sync_info;
+ struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+
+ if (!isis ||
+ !CHECK_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE) ||
+ circuit->interface->vrf_id != VRF_DEFAULT ||
+ if_is_loopback(circuit->interface))
+ return 0;
+
+ if (circuit->ldp_sync_info == NULL)
+ isis_ldp_sync_if_init(circuit, isis);
+ ldp_sync_info = circuit->ldp_sync_info;
+
+ if (ldp_sync_info->enabled != LDP_IGP_SYNC_ENABLED)
+ return 0;
+
+ if (adj->adj_state == ISIS_ADJ_UP) {
+ if (circuit->circ_type == CIRCUIT_T_P2P ||
+ if_is_pointopoint(circuit->interface)) {
+ /* If LDP-SYNC is configure on interface then start */
+ ldp_sync_info->state =
+ LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP;
+ isis_ldp_sync_if_start(circuit, true);
+ } else {
+ /* non ptop link so don't run ldp-sync */
+ ldp_sync_info->state = LDP_IGP_SYNC_STATE_NOT_REQUIRED;
+ isis_ldp_sync_set_if_metric(circuit, true);
+ }
+ } else {
+ /* If LDP-SYNC is configure on this interface then stop it */
+ if (circuit->circ_type == CIRCUIT_T_P2P ||
+ if_is_pointopoint(circuit->interface))
+ ldp_sync_info->state =
+ LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP;
+ else
+ ldp_sync_info->state = LDP_IGP_SYNC_STATE_NOT_REQUIRED;
+
+ ils_debug("ldp_sync: down on if %s", circuit->interface->name);
+ ldp_sync_if_down(circuit->ldp_sync_info);
+ }
+
+ return 0;
+}
+
+bool isis_ldp_sync_if_metric_config(struct isis_circuit *circuit, int level,
+ int metric)
+{
+ struct ldp_sync_info *ldp_sync_info = circuit->ldp_sync_info;
+ struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+
+ /* configured interface metric has been changed:
+ * if LDP-IGP Sync is running and metric has been set to LSInfinity
+ * change saved value so when ldp-sync completes proper metric is
+ * restored
+ */
+ if (isis &&
+ CHECK_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE) &&
+ ldp_sync_info != NULL) {
+
+ if (CHECK_FLAG(ldp_sync_info->flags,
+ LDP_SYNC_FLAG_SET_METRIC)) {
+ ldp_sync_info->metric[level-1] = metric;
+ ldp_sync_info->metric[level-1] = metric;
+ return false;
+ }
+ }
+ return true;
+}
+
+void isis_ldp_sync_set_if_metric(struct isis_circuit *circuit, bool run_regen)
+{
+ struct ldp_sync_info *ldp_sync_info;
+
+ /* set interface metric:
+ * if LDP-IGP Sync is starting set metric so interface
+ * is used only as last resort
+ * else restore metric to original value
+ */
+ if (circuit->ldp_sync_info == NULL || circuit->area == NULL)
+ return;
+
+ ldp_sync_info = circuit->ldp_sync_info;
+ if (ldp_sync_if_is_enabled(ldp_sync_info)) {
+ /* if metric already set to LSInfinity just return */
+ if (CHECK_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_SET_METRIC))
+ return;
+
+ SET_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_SET_METRIC);
+ if (circuit->is_type & IS_LEVEL_1) {
+ if (circuit->area->newmetric) {
+ ldp_sync_info->metric[0] =
+ circuit->te_metric[0];
+ circuit->te_metric[0] = LDP_ISIS_LSINFINITY;
+ } else {
+ ldp_sync_info->metric[0] = circuit->metric[0];
+ circuit->metric[0] = LDP_ISIS_LSINFINITY_NL;
+ }
+ }
+ if (circuit->is_type & IS_LEVEL_2) {
+ if (circuit->area->newmetric) {
+ ldp_sync_info->metric[1] =
+ circuit->te_metric[1];
+ circuit->te_metric[1] = LDP_ISIS_LSINFINITY;
+ } else {
+ ldp_sync_info->metric[1] = circuit->metric[1];
+ circuit->metric[1] = LDP_ISIS_LSINFINITY_NL;
+ }
+ }
+ } else {
+ /* if metric already restored just return */
+ if (!CHECK_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_SET_METRIC))
+ return;
+
+ UNSET_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_SET_METRIC);
+ if (circuit->is_type & IS_LEVEL_1) {
+ circuit->te_metric[0] = ldp_sync_info->metric[0];
+ circuit->metric[0] = ldp_sync_info->metric[0];
+ }
+ if (circuit->is_type & IS_LEVEL_2) {
+ circuit->te_metric[1] = ldp_sync_info->metric[1];
+ circuit->metric[1] = ldp_sync_info->metric[1];
+ }
+ }
+
+ if (run_regen)
+ lsp_regenerate_schedule(circuit->area, circuit->is_type, 0);
+}
+
+
+/*
+ * LDP-SYNC holddown timer routines
+ */
+static int isis_ldp_sync_holddown_timer(struct thread *thread)
+{
+ struct isis_circuit *circuit;
+ struct ldp_sync_info *ldp_sync_info;
+
+ /* holddown timer expired:
+ * didn't receive msg from LDP indicating sync-complete
+ * restore interface cost to original value
+ */
+ circuit = THREAD_ARG(thread);
+ if (circuit->ldp_sync_info == NULL)
+ return 0;
+
+ ldp_sync_info = circuit->ldp_sync_info;
+
+ ldp_sync_info->state = LDP_IGP_SYNC_STATE_REQUIRED_UP;
+ ldp_sync_info->t_holddown = NULL;
+
+ ils_debug("ldp_sync: holddown timer expired for %s state:sync achieved",
+ circuit->interface->name);
+
+ isis_ldp_sync_set_if_metric(circuit, true);
+ return 0;
+}
+
+void isis_ldp_sync_holddown_timer_add(struct isis_circuit *circuit)
+{
+ struct ldp_sync_info *ldp_sync_info;
+
+ ldp_sync_info = circuit->ldp_sync_info;
+
+ /* Start holddown timer:
+ * this timer is used to keep interface cost at LSInfinity
+ * once expires returns cost to original value
+ * if timer is already running or holddown time is off just return
+ */
+ if (ldp_sync_info->t_holddown ||
+ ldp_sync_info->holddown == LDP_IGP_SYNC_HOLDDOWN_DEFAULT)
+ return;
+
+ ils_debug("ldp_sync: start holddown timer for %s time %d",
+ circuit->interface->name, ldp_sync_info->holddown);
+
+ thread_add_timer(master, isis_ldp_sync_holddown_timer,
+ circuit, ldp_sync_info->holddown,
+ &ldp_sync_info->t_holddown);
+}
+
+/*
+ * LDP-SYNC hello timer routines
+ */
+static int isis_ldp_sync_hello_timer(struct thread *thread)
+{
+ struct isis_area *area;
+ struct listnode *node;
+ struct isis_circuit *circuit;
+ struct interface *ifp;
+ struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
+ struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+
+ if (!isis)
+ return 0;
+
+ /* hello timer expired:
+ * didn't receive hello msg from LDP
+ * set cost of all interfaces to LSInfinity
+ */
+ FOR_ALL_INTERFACES (vrf, ifp) {
+ for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
+ circuit = circuit_lookup_by_ifp(ifp,
+ area->circuit_list);
+ if (circuit == NULL)
+ continue;
+
+ isis_ldp_sync_ldp_fail(circuit);
+ }
+ }
+
+ zlog_debug("ldp_sync: hello timer expired, LDP down");
+
+ return 0;
+}
+
+void isis_ldp_sync_hello_timer_add(void)
+{
+ struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+
+ /* Start hello timer:
+ * this timer is used to make sure LDP is up
+ * if expires set interface cost to LSInfinity
+ */
+ if (!isis ||
+ !CHECK_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE))
+ return;
+
+ thread_add_timer(master, isis_ldp_sync_hello_timer,
+ NULL, LDP_IGP_SYNC_HELLO_TIMEOUT,
+ &isis->ldp_sync_cmd.t_hello);
+}
+
+/*
+ * LDP-SYNC routes used by set commands.
+ */
+
+void isis_if_set_ldp_sync_enable(struct isis_circuit *circuit)
+{
+ struct ldp_sync_info *ldp_sync_info;
+ struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+
+ /* called when setting LDP-SYNC at the global level:
+ * specifed on interface overrides global config
+ * if ptop link send msg to LDP indicating ldp-sync enabled
+ */
+ if (!isis || if_is_loopback(circuit->interface))
+ return;
+
+ if (CHECK_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE)) {
+ if (circuit->ldp_sync_info == NULL)
+ isis_ldp_sync_if_init(circuit, isis);
+ ldp_sync_info = circuit->ldp_sync_info;
+
+ /* config on interface, overrides global config. */
+ if (CHECK_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_IF_CONFIG))
+ if (ldp_sync_info->enabled != LDP_IGP_SYNC_ENABLED)
+ return;
+
+ ldp_sync_info->enabled = LDP_IGP_SYNC_ENABLED;
+ ils_debug("ldp_sync: enable if %s", circuit->interface->name);
+
+ /* send message to LDP if ptop link */
+ if (circuit->circ_type == CIRCUIT_T_P2P ||
+ if_is_pointopoint(circuit->interface)) {
+ ldp_sync_info->state =
+ LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP;
+ isis_ldp_sync_state_req_msg(circuit);
+ } else {
+ ldp_sync_info->state = LDP_IGP_SYNC_STATE_NOT_REQUIRED;
+ zlog_debug("ldp_sync: Sync only runs on P2P links %s",
+ circuit->interface->name);
+ }
+ } else
+ /* delete LDP sync even if configured on an interface */
+ isis_ldp_sync_if_remove(circuit, false);
+}
+
+void isis_if_set_ldp_sync_holddown(struct isis_circuit *circuit)
+{
+ struct ldp_sync_info *ldp_sync_info;
+ struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+
+ /* called when setting LDP-SYNC at the global level:
+ * specifed on interface overrides global config.
+ */
+ if (!isis || if_is_loopback(circuit->interface))
+ return;
+
+ if (circuit->ldp_sync_info == NULL)
+ isis_ldp_sync_if_init(circuit, isis);
+ ldp_sync_info = circuit->ldp_sync_info;
+
+ /* config on interface, overrides global config. */
+ if (CHECK_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_HOLDDOWN))
+ return;
+ if (CHECK_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_HOLDDOWN))
+ ldp_sync_info->holddown = isis->ldp_sync_cmd.holddown;
+ else
+ ldp_sync_info->holddown = LDP_IGP_SYNC_HOLDDOWN_DEFAULT;
+}
+
+void isis_ldp_sync_gbl_exit(bool remove)
+{
+ struct isis_area *area;
+ struct listnode *node;
+ struct isis_circuit *circuit;
+ struct interface *ifp;
+ struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
+ struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+
+ /* if you delete LDP-SYNC at a gobal level is clears all LDP-SYNC
+ * configuration, even interface configuration
+ */
+ if (isis &&
+ CHECK_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE)) {
+ /* register with opaque client to recv LDP-IGP Sync msgs */
+ zclient_unregister_opaque(zclient,
+ LDP_IGP_SYNC_IF_STATE_UPDATE);
+ zclient_unregister_opaque(zclient,
+ LDP_IGP_SYNC_ANNOUNCE_UPDATE);
+ zclient_unregister_opaque(zclient, LDP_IGP_SYNC_HELLO_UPDATE);
+
+ /* disable LDP-SYNC globally */
+ UNSET_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE);
+ UNSET_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_HOLDDOWN);
+ isis->ldp_sync_cmd.holddown = LDP_IGP_SYNC_HOLDDOWN_DEFAULT;
+ THREAD_TIMER_OFF(isis->ldp_sync_cmd.t_hello);
+ isis->ldp_sync_cmd.t_hello = NULL;
+
+ /* remove LDP-SYNC on all ISIS interfaces */
+ FOR_ALL_INTERFACES (vrf, ifp) {
+ for (ALL_LIST_ELEMENTS_RO(isis->area_list, node,
+ area)) {
+ circuit = circuit_lookup_by_ifp(ifp,
+ area->circuit_list);
+ if (circuit == NULL)
+ continue;
+ isis_ldp_sync_if_remove(circuit, remove);
+ }
+ }
+ }
+}
+
+/*
+ * LDP-SYNC routines used by show commands.
+ */
+
+static void isis_circuit_ldp_sync_print_vty(struct isis_circuit *circuit,
+ struct vty *vty)
+{
+ struct ldp_sync_info *ldp_sync_info;
+ const char *ldp_state;
+
+ if (circuit->ldp_sync_info == NULL ||
+ if_is_loopback(circuit->interface))
+ return;
+
+ ldp_sync_info = circuit->ldp_sync_info;
+ vty_out(vty, "%-10s\n", circuit->interface->name);
+ vty_out(vty, " LDP-IGP Synchronization enabled: %s\n",
+ ldp_sync_info->enabled == LDP_IGP_SYNC_ENABLED
+ ? "yes"
+ : "no");
+ vty_out(vty, " holddown timer in seconds: %u\n",
+ ldp_sync_info->holddown);
+
+ switch (ldp_sync_info->state) {
+ case LDP_IGP_SYNC_STATE_REQUIRED_UP:
+ vty_out(vty, " State: Sync achieved\n");
+ break;
+ case LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP:
+ if (ldp_sync_info->t_holddown != NULL) {
+ struct timeval remain = thread_timer_remain(
+ ldp_sync_info->t_holddown);
+ vty_out(vty,
+ " Holddown timer is running %lld.%03lld remaining\n",
+ (long long)remain.tv_sec,
+ (long long)remain.tv_usec/1000);
+
+ vty_out(vty, " State: Holding down until Sync\n");
+ } else
+ vty_out(vty, " State: Sync not achieved\n");
+ break;
+ case LDP_IGP_SYNC_STATE_NOT_REQUIRED:
+ default:
+ if ((circuit->circ_type != CIRCUIT_T_P2P &&
+ !if_is_pointopoint(circuit->interface)) &&
+ circuit->circ_type != CIRCUIT_T_UNKNOWN)
+ ldp_state = "Sync not required: non-p2p link";
+ else
+ ldp_state = "Sync not required";
+ vty_out(vty, " State: %s\n", ldp_state);
+ break;
+ }
+}
+
+DEFUN (show_isis_mpls_ldp_interface,
+ show_isis_mpls_ldp_interface_cmd,
+ "show " PROTO_NAME " mpls ldp-sync [interface <INTERFACE|all>]",
+ SHOW_STR
+ PROTO_HELP
+ MPLS_STR
+ "LDP-IGP Sync information\n"
+ "Interface name\n")
+{
+ char *ifname = NULL;
+ int idx_intf = 0;
+ struct listnode *anode, *cnode;
+ struct isis_area *area;
+ struct isis_circuit *circuit;
+ struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+
+ if (!isis) {
+ vty_out(vty, "IS-IS Routing Process not enabled\n");
+ return CMD_SUCCESS;
+ }
+
+ if (!CHECK_FLAG(isis->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE)) {
+ vty_out(vty, "LDP-sync is disabled\n");
+ return CMD_SUCCESS;
+ }
+
+ if (argv_find(argv, argc, "INTERFACE", &idx_intf))
+ ifname = argv[idx_intf]->arg;
+
+ for (ALL_LIST_ELEMENTS_RO(isis->area_list, anode, area)) {
+ for (ALL_LIST_ELEMENTS_RO(area->circuit_list, cnode, circuit))
+ if (!ifname)
+ isis_circuit_ldp_sync_print_vty(circuit, vty);
+ else if (strcmp(circuit->interface->name, ifname) == 0)
+ isis_circuit_ldp_sync_print_vty(circuit, vty);
+ }
+
+ return CMD_SUCCESS;
+}
+
+void isis_ldp_sync_init(void)
+{
+
+ /* "show ip isis mpls ldp interface" commands. */
+ install_element(VIEW_NODE, &show_isis_mpls_ldp_interface_cmd);
+
+ /* register for adjacency state changes */
+ hook_register(isis_adj_state_change_hook,
+ isis_ldp_sync_adj_state_change);
+}
diff --git a/isisd/isis_ldp_sync.h b/isisd/isis_ldp_sync.h
new file mode 100644
index 0000000000..6017cdf001
--- /dev/null
+++ b/isisd/isis_ldp_sync.h
@@ -0,0 +1,54 @@
+/*
+ * isis_ldp_sync.h: ISIS LDP-IGP Sync handling routines
+ * Copyright (C) 2020 Volta Networks, 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 _ZEBRA_ISIS_LDP_SYNC_H
+#define _ZEBRA_ISIS_LDP_SYNC_H
+
+#define LDP_ISIS_LSINFINITY 0xFFFFFE /* wide link metric */
+#define LDP_ISIS_LSINFINITY_NL 62 /* narrow link metric */
+
+/* Macro to log debug message */
+#define ils_debug(...) \
+ do { \
+ if (IS_DEBUG_LDP_SYNC) \
+ zlog_debug(__VA_ARGS__); \
+ } while (0)
+
+extern void isis_if_set_ldp_sync_enable(struct isis_circuit *circuit);
+extern void isis_if_set_ldp_sync_holddown(struct isis_circuit *circuit);
+extern void isis_ldp_sync_if_init(struct isis_circuit *circuit,
+ struct isis *isis);
+extern void isis_ldp_sync_if_start(struct isis_circuit *circuit,
+ bool send_state_req);
+extern void isis_ldp_sync_if_remove(struct isis_circuit *circuit, bool remove);
+extern void isis_ldp_sync_if_complete(struct isis_circuit *circuit);
+extern void isis_ldp_sync_holddown_timer_add(struct isis_circuit *circuit);
+extern void isis_ldp_sync_hello_timer_add(void);
+extern void isis_ldp_sync_ldp_fail(struct isis_circuit *circuit);
+extern int isis_ldp_sync_state_update(struct ldp_igp_sync_if_state state);
+extern int isis_ldp_sync_announce_update(struct ldp_igp_sync_announce announce);
+extern int isis_ldp_sync_hello_update(struct ldp_igp_sync_hello hello);
+extern void isis_ldp_sync_state_req_msg(struct isis_circuit *circuit);
+extern void isis_ldp_sync_set_if_metric(struct isis_circuit *circuit,
+ bool run_regen);
+extern bool isis_ldp_sync_if_metric_config(struct isis_circuit *circuit,
+ int level, int metric);
+extern void isis_ldp_sync_init(void);
+extern void isis_ldp_sync_gbl_exit(bool remove);
+#endif /* _ZEBRA_ISIS_LDP_SYNC_H */
diff --git a/isisd/isis_main.c b/isisd/isis_main.c
index 26f5227aae..22df3ff37e 100644
--- a/isisd/isis_main.c
+++ b/isisd/isis_main.c
@@ -58,6 +58,7 @@
#include "isisd/isis_mt.h"
#include "isisd/fabricd.h"
#include "isisd/isis_nb.h"
+#include "isisd/isis_ldp_sync.h"
/* Default configuration file name */
#define ISISD_DEFAULT_CONFIG "isisd.conf"
@@ -264,6 +265,7 @@ int main(int argc, char **argv, char **envp)
isis_zebra_init(master, instance);
isis_bfd_init();
+ isis_ldp_sync_init();
fabricd_init();
frr_config_fork();
diff --git a/isisd/isis_nb.c b/isisd/isis_nb.c
index 33b0b4d02c..14ea1170c4 100644
--- a/isisd/isis_nb.c
+++ b/isisd/isis_nb.c
@@ -538,6 +538,21 @@ const struct frr_yang_module_info frr_isisd_info = {
},
},
{
+ .xpath = "/frr-isisd:isis/instance/mpls/ldp-sync",
+ .cbs = {
+ .cli_show = cli_show_isis_mpls_ldp_sync,
+ .create = isis_instance_mpls_ldp_sync_create,
+ .destroy = isis_instance_mpls_ldp_sync_destroy,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/mpls/ldp-sync/holddown",
+ .cbs = {
+ .cli_show = cli_show_isis_mpls_ldp_sync_holddown,
+ .modify = isis_instance_mpls_ldp_sync_holddown_modify,
+ },
+ },
+ {
.xpath = "/frr-interface:lib/interface/frr-isisd:isis",
.cbs = {
.create = lib_interface_isis_create,
@@ -906,6 +921,21 @@ const struct frr_yang_module_info frr_isisd_info = {
}
},
{
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/mpls/ldp-sync",
+ .cbs = {
+ .cli_show = cli_show_isis_mpls_if_ldp_sync,
+ .modify = lib_interface_isis_mpls_ldp_sync_modify,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/frr-isisd:isis/mpls/holddown",
+ .cbs = {
+ .cli_show = cli_show_isis_mpls_if_ldp_sync_holddown,
+ .modify = lib_interface_isis_mpls_holddown_modify,
+ .destroy = lib_interface_isis_mpls_holddown_destroy,
+ }
+ },
+ {
.xpath = NULL,
},
}
diff --git a/isisd/isis_nb.h b/isisd/isis_nb.h
index a79cb8ff57..8a6d24b845 100644
--- a/isisd/isis_nb.h
+++ b/isisd/isis_nb.h
@@ -206,6 +206,9 @@ int isis_instance_segment_routing_prefix_sid_map_prefix_sid_sid_value_modify(
struct nb_cb_modify_args *args);
int isis_instance_segment_routing_prefix_sid_map_prefix_sid_last_hop_behavior_modify(
struct nb_cb_modify_args *args);
+int isis_instance_mpls_ldp_sync_destroy(struct nb_cb_destroy_args *args);
+int isis_instance_mpls_ldp_sync_create(struct nb_cb_create_args *args);
+int isis_instance_mpls_ldp_sync_holddown_modify(struct nb_cb_modify_args *args);
int lib_interface_isis_csnp_interval_level_1_modify(
struct nb_cb_modify_args *args);
int lib_interface_isis_csnp_interval_level_2_modify(
@@ -250,6 +253,9 @@ int lib_interface_isis_multi_topology_ipv6_management_modify(
struct nb_cb_modify_args *args);
int lib_interface_isis_multi_topology_ipv6_dstsrc_modify(
struct nb_cb_modify_args *args);
+int lib_interface_isis_mpls_ldp_sync_modify(struct nb_cb_modify_args *args);
+int lib_interface_isis_mpls_holddown_modify(struct nb_cb_modify_args *args);
+int lib_interface_isis_mpls_holddown_destroy(struct nb_cb_destroy_args *args);
struct yang_data *
lib_interface_state_isis_get_elem(struct nb_cb_get_elem_args *args);
const void *lib_interface_state_isis_adjacencies_adjacency_get_next(
@@ -434,6 +440,16 @@ void cli_show_ip_isis_priority(struct vty *vty, struct lyd_node *dnode,
bool show_defaults);
void cli_show_isis_log_adjacency(struct vty *vty, struct lyd_node *dnode,
bool show_defaults);
+void cli_show_isis_mpls_ldp_sync(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_isis_mpls_ldp_sync_holddown(struct vty *vty,
+ struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_isis_mpls_if_ldp_sync(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_isis_mpls_if_ldp_sync_holddown(struct vty *vty,
+ struct lyd_node *dnode,
+ bool show_defaults);
/* Notifications. */
void isis_notif_db_overload(const struct isis_area *area, bool overload);
diff --git a/isisd/isis_nb_config.c b/isisd/isis_nb_config.c
index 170fe92c28..0988fe8578 100644
--- a/isisd/isis_nb_config.c
+++ b/isisd/isis_nb_config.c
@@ -29,6 +29,8 @@
#include "spf_backoff.h"
#include "lib_errors.h"
#include "vrf.h"
+#include "zclient.h"
+#include "ldp_sync.h"
#include "isisd/isisd.h"
#include "isisd/isis_nb.h"
@@ -45,6 +47,9 @@
#include "isisd/isis_memory.h"
#include "isisd/isis_mt.h"
#include "isisd/isis_redist.h"
+#include "isisd/isis_ldp_sync.h"
+
+extern struct zclient *zclient;
/*
* XPath: /frr-isisd:isis/instance
@@ -81,6 +86,10 @@ int isis_instance_destroy(struct nb_cb_destroy_args *args)
area = nb_running_unset_entry(args->dnode);
isis_area_destroy(area);
+ /* remove ldp-sync config */
+ if (area->isis->vrf_id == VRF_DEFAULT)
+ isis_ldp_sync_gbl_exit(true);
+
return NB_OK;
}
@@ -1826,6 +1835,113 @@ int isis_instance_segment_routing_prefix_sid_map_prefix_sid_last_hop_behavior_mo
}
/*
+ * XPath: /frr-isisd:isis/instance/mpls/ldp-sync
+ */
+int isis_instance_mpls_ldp_sync_create(struct nb_cb_create_args *args)
+{
+ struct isis_area *area;
+ struct listnode *node;
+ struct isis_circuit *circuit;
+ struct interface *ifp;
+ struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
+ struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+
+ switch (args->event) {
+ case NB_EV_VALIDATE:
+ if (isis == NULL)
+ return NB_ERR_VALIDATION;
+ break;
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ break;
+ case NB_EV_APPLY:
+ /* register with opaque client to recv LDP-IGP Sync msgs */
+ zclient_register_opaque(zclient, LDP_IGP_SYNC_IF_STATE_UPDATE);
+ zclient_register_opaque(zclient, LDP_IGP_SYNC_ANNOUNCE_UPDATE);
+ zclient_register_opaque(zclient, LDP_IGP_SYNC_HELLO_UPDATE);
+
+ if (!CHECK_FLAG(isis->ldp_sync_cmd.flags,
+ LDP_SYNC_FLAG_ENABLE)) {
+ SET_FLAG(isis->ldp_sync_cmd.flags,
+ LDP_SYNC_FLAG_ENABLE);
+
+ /* turn on LDP-IGP Sync on all ptop ISIS interfaces */
+ FOR_ALL_INTERFACES (vrf, ifp) {
+ for (ALL_LIST_ELEMENTS_RO(isis->area_list, node,
+ area)) {
+ circuit = circuit_lookup_by_ifp(
+ ifp, area->circuit_list);
+ if (circuit == NULL)
+ continue;
+ isis_if_set_ldp_sync_enable(circuit);
+ }
+ }
+ }
+ break;
+ }
+ return NB_OK;
+}
+
+int isis_instance_mpls_ldp_sync_destroy(struct nb_cb_destroy_args *args)
+{
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ /* remove ldp-sync config */
+ isis_ldp_sync_gbl_exit(false);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/mpls/ldp-sync/holddown
+ */
+int isis_instance_mpls_ldp_sync_holddown_modify(struct nb_cb_modify_args *args)
+{
+ struct isis_area *area;
+ struct listnode *node;
+ struct isis_circuit *circuit;
+ struct interface *ifp;
+ struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
+ uint16_t holddown = LDP_IGP_SYNC_HOLDDOWN_DEFAULT;
+ struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+
+ switch (args->event) {
+ case NB_EV_VALIDATE:
+ if (isis == NULL)
+ return NB_ERR_VALIDATION;
+ break;
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ break;
+ case NB_EV_APPLY:
+ holddown = yang_dnode_get_uint16(args->dnode, NULL);
+
+ if (holddown == LDP_IGP_SYNC_HOLDDOWN_DEFAULT)
+ UNSET_FLAG(isis->ldp_sync_cmd.flags,
+ LDP_SYNC_FLAG_HOLDDOWN);
+ else
+ SET_FLAG(isis->ldp_sync_cmd.flags,
+ LDP_SYNC_FLAG_HOLDDOWN);
+ isis->ldp_sync_cmd.holddown = holddown;
+
+ /* set holddown time on all ISIS interfaces */
+ FOR_ALL_INTERFACES (vrf, ifp) {
+ for (ALL_LIST_ELEMENTS_RO(isis->area_list, node,
+ area)) {
+ circuit = circuit_lookup_by_ifp(ifp,
+ area->circuit_list);
+ if (circuit == NULL)
+ continue;
+ isis_if_set_ldp_sync_holddown(circuit);
+ }
+ }
+ break;
+ }
+ return NB_OK;
+}
+
+/*
* XPath: /frr-interface:lib/interface/frr-isisd:isis
*/
int lib_interface_isis_create(struct nb_cb_create_args *args)
@@ -1915,6 +2031,9 @@ int lib_interface_isis_destroy(struct nb_cb_destroy_args *args)
if (!circuit)
return NB_ERR_INCONSISTENCY;
+ /* remove ldp-sync config */
+ isis_ldp_sync_if_remove(circuit, true);
+
/* disable both AFs for this circuit. this will also update the
* CSM state by sending an ISIS_DISABLED signal. If there is no
* area associated to the circuit there is nothing to do
@@ -2646,3 +2765,130 @@ int lib_interface_isis_multi_topology_ipv6_dstsrc_modify(
args->event, args->dnode, args->errmsg, args->errmsg_len,
ISIS_MT_IPV6_DSTSRC);
}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-isisd:isis/mpls/ldp-sync
+ */
+int lib_interface_isis_mpls_ldp_sync_modify(struct nb_cb_modify_args *args)
+{
+ struct isis_circuit *circuit;
+ struct ldp_sync_info *ldp_sync_info;
+ bool ldp_sync_enable;
+ struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+
+ switch (args->event) {
+ case NB_EV_VALIDATE:
+ if (isis == NULL)
+ return NB_ERR_VALIDATION;
+ break;
+
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ break;
+ case NB_EV_APPLY:
+ circuit = nb_running_get_entry(args->dnode, NULL, true);
+ ldp_sync_enable = yang_dnode_get_bool(args->dnode, NULL);
+
+ if (circuit->ldp_sync_info == NULL)
+ isis_ldp_sync_if_init(circuit, isis);
+ ldp_sync_info = circuit->ldp_sync_info;
+
+ if (ldp_sync_enable) {
+ /* enable LDP-SYNC on an interface
+ * if ptop interface send message to LDP to get state
+ */
+ SET_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_IF_CONFIG);
+ ldp_sync_info->enabled = LDP_IGP_SYNC_ENABLED;
+ if (circuit->circ_type == CIRCUIT_T_P2P) {
+ ldp_sync_info->state =
+ LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP;
+ isis_ldp_sync_state_req_msg(circuit);
+ } else {
+ zlog_debug("ldp_sync: only runs on P2P links %s",
+ circuit->interface->name);
+ ldp_sync_info->state =
+ LDP_IGP_SYNC_STATE_NOT_REQUIRED;
+ }
+ } else {
+ /* disable LDP-SYNC on an interface
+ * stop holddown timer if running
+ * restore isis metric
+ */
+ SET_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_IF_CONFIG);
+ ldp_sync_info->enabled = LDP_IGP_SYNC_DEFAULT;
+ ldp_sync_info->state = LDP_IGP_SYNC_STATE_NOT_REQUIRED;
+ THREAD_TIMER_OFF(ldp_sync_info->t_holddown);
+ ldp_sync_info->t_holddown = NULL;
+ isis_ldp_sync_set_if_metric(circuit, true);
+ }
+ break;
+ }
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-interface:lib/interface/frr-isisd:isis/mpls/holddown
+ */
+int lib_interface_isis_mpls_holddown_modify(struct nb_cb_modify_args *args)
+{
+ struct isis_circuit *circuit;
+ struct ldp_sync_info *ldp_sync_info;
+ uint16_t holddown;
+ struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+
+ switch (args->event) {
+ case NB_EV_VALIDATE:
+ if (isis == NULL)
+ return NB_ERR_VALIDATION;
+ break;
+
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ break;
+ case NB_EV_APPLY:
+ circuit = nb_running_get_entry(args->dnode, NULL, true);
+ holddown = yang_dnode_get_uint16(args->dnode, NULL);
+
+ if (circuit->ldp_sync_info == NULL)
+ isis_ldp_sync_if_init(circuit, isis);
+ ldp_sync_info = circuit->ldp_sync_info;
+
+ SET_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_HOLDDOWN);
+ ldp_sync_info->holddown = holddown;
+ break;
+ }
+ return NB_OK;
+}
+
+int lib_interface_isis_mpls_holddown_destroy(struct nb_cb_destroy_args *args)
+{
+ struct isis_circuit *circuit;
+ struct ldp_sync_info *ldp_sync_info;
+ struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+
+ switch (args->event) {
+ case NB_EV_VALIDATE:
+ if (isis == NULL)
+ return NB_ERR_VALIDATION;
+ circuit = nb_running_get_entry(args->dnode, NULL, true);
+ if (circuit->ldp_sync_info == NULL)
+ return NB_ERR_VALIDATION;
+
+ break;
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ break;
+ case NB_EV_APPLY:
+ circuit = nb_running_get_entry(args->dnode, NULL, true);
+ ldp_sync_info = circuit->ldp_sync_info;
+ UNSET_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_HOLDDOWN);
+
+ if (CHECK_FLAG(isis->ldp_sync_cmd.flags,
+ LDP_SYNC_FLAG_HOLDDOWN))
+ ldp_sync_info->holddown = isis->ldp_sync_cmd.holddown;
+ else
+ ldp_sync_info->holddown = LDP_IGP_SYNC_HOLDDOWN_DEFAULT;
+ break;
+ }
+ return NB_OK;
+}
diff --git a/isisd/isis_route.c b/isisd/isis_route.c
index c83a7c04bb..fa06572555 100644
--- a/isisd/isis_route.c
+++ b/isisd/isis_route.c
@@ -239,41 +239,51 @@ static void isis_route_info_delete(struct isis_route_info *route_info)
XFREE(MTYPE_ISIS_ROUTE_INFO, route_info);
}
-static int isis_route_info_same_attrib(struct isis_route_info *new,
- struct isis_route_info *old)
-{
- if (new->cost != old->cost)
- return 0;
- if (new->depth != old->depth)
- return 0;
-
- return 1;
-}
-
static int isis_route_info_same(struct isis_route_info *new,
- struct isis_route_info *old, uint8_t family)
+ struct isis_route_info *old, char *buf,
+ size_t buf_size)
{
struct listnode *node;
struct isis_nexthop *nexthop;
- if (!CHECK_FLAG(old->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED))
+ if (new->cost != old->cost) {
+ if (buf)
+ snprintf(buf, buf_size, "cost (old: %u, new: %u)",
+ old->cost, new->cost);
return 0;
+ }
- if (CHECK_FLAG(new->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC))
+ if (new->depth != old->depth) {
+ if (buf)
+ snprintf(buf, buf_size, "depth (old: %u, new: %u)",
+ old->depth, new->depth);
return 0;
+ }
- if (!isis_route_info_same_attrib(new, old))
+ if (new->nexthops->count != old->nexthops->count) {
+ if (buf)
+ snprintf(buf, buf_size, "nhops num (old: %u, new: %u)",
+ old->nexthops->count, new->nexthops->count);
return 0;
+ }
- for (ALL_LIST_ELEMENTS_RO(new->nexthops, node, nexthop))
+ for (ALL_LIST_ELEMENTS_RO(new->nexthops, node, nexthop)) {
if (!nexthoplookup(old->nexthops, nexthop->family, &nexthop->ip,
- nexthop->ifindex))
+ nexthop->ifindex)) {
+ if (buf)
+ snprintf(buf, buf_size,
+ "new nhop"); /* TODO: print nhop */
return 0;
+ }
+ }
- for (ALL_LIST_ELEMENTS_RO(old->nexthops, node, nexthop))
- if (!nexthoplookup(new->nexthops, nexthop->family, &nexthop->ip,
- nexthop->ifindex))
- return 0;
+ /* only the resync flag needs to be checked */
+ if (CHECK_FLAG(new->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC)
+ != CHECK_FLAG(old->flag, ISIS_ROUTE_FLAG_ZEBRA_RESYNC)) {
+ if (buf)
+ snprintf(buf, buf_size, "resync flag");
+ return 0;
+ }
return 1;
}
@@ -289,9 +299,8 @@ struct isis_route_info *isis_route_create(struct prefix *prefix,
struct route_node *route_node;
struct isis_route_info *rinfo_new, *rinfo_old, *route_info = NULL;
char buff[PREFIX2STR_BUFFER];
- uint8_t family;
+ char change_buf[64];
- family = prefix->family;
/* for debugs */
prefix2str(prefix, buff, sizeof(buff));
@@ -311,19 +320,25 @@ struct isis_route_info *isis_route_create(struct prefix *prefix,
UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
} else {
route_unlock_node(route_node);
+#ifdef EXTREME_DEBUG
if (IS_DEBUG_RTE_EVENTS)
zlog_debug("ISIS-Rte (%s) route already exists: %s",
area->area_tag, buff);
- if (isis_route_info_same(rinfo_new, rinfo_old, family)) {
+#endif /* EXTREME_DEBUG */
+ if (isis_route_info_same(rinfo_new, rinfo_old, change_buf,
+ sizeof(change_buf))) {
+#ifdef EXTREME_DEBUG
if (IS_DEBUG_RTE_EVENTS)
zlog_debug("ISIS-Rte (%s) route unchanged: %s",
area->area_tag, buff);
+#endif /* EXTREME_DEBUG */
isis_route_info_delete(rinfo_new);
route_info = rinfo_old;
} else {
if (IS_DEBUG_RTE_EVENTS)
- zlog_debug("ISIS-Rte (%s) route changed: %s",
- area->area_tag, buff);
+ zlog_debug(
+ "ISIS-Rte (%s): route changed: %s, change: %s",
+ area->area_tag, buff, change_buf);
isis_route_info_delete(rinfo_old);
route_info = rinfo_new;
UNSET_FLAG(route_info->flag,
@@ -401,7 +416,9 @@ static void _isis_route_verify_table(struct isis_area *area,
{
struct route_node *rnode, *drnode;
struct isis_route_info *rinfo;
+#ifdef EXTREME_DEBUG
char buff[SRCDEST2STR_BUFFER];
+#endif /* EXTREME_DEBUG */
for (rnode = route_top(table); rnode;
rnode = srcdest_route_next(rnode)) {
@@ -416,6 +433,7 @@ static void _isis_route_verify_table(struct isis_area *area,
(const struct prefix **)&dst_p,
(const struct prefix **)&src_p);
+#ifdef EXTREME_DEBUG
if (IS_DEBUG_RTE_EVENTS) {
srcdest2str(dst_p, src_p, buff, sizeof(buff));
zlog_debug(
@@ -434,6 +452,7 @@ static void _isis_route_verify_table(struct isis_area *area,
: "inactive"),
buff);
}
+#endif /* EXTREME_DEBUG */
isis_route_update(area, dst_p, src_p, rinfo);
diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c
index a50eb607d9..15b51589ae 100644
--- a/isisd/isis_zebra.c
+++ b/isisd/isis_zebra.c
@@ -52,6 +52,7 @@
#include "isisd/isis_adjacency.h"
#include "isisd/isis_te.h"
#include "isisd/isis_sr.h"
+#include "isisd/isis_ldp_sync.h"
struct zclient *zclient;
static struct zclient *zclient_sync;
@@ -596,6 +597,44 @@ static void isis_zebra_connected(struct zclient *zclient)
zclient_send_reg_requests(zclient, VRF_DEFAULT);
}
+/*
+ * opaque messages between processes
+ */
+static int isis_opaque_msg_handler(ZAPI_CALLBACK_ARGS)
+{
+ struct stream *s;
+ struct zapi_opaque_msg info;
+ struct ldp_igp_sync_if_state state;
+ struct ldp_igp_sync_announce announce;
+ struct ldp_igp_sync_hello hello;
+ int ret = 0;
+
+ s = zclient->ibuf;
+ if (zclient_opaque_decode(s, &info) != 0)
+ return -1;
+
+ switch (info.type) {
+ case LDP_IGP_SYNC_IF_STATE_UPDATE:
+ STREAM_GET(&state, s, sizeof(state));
+ ret = isis_ldp_sync_state_update(state);
+ break;
+ case LDP_IGP_SYNC_ANNOUNCE_UPDATE:
+ STREAM_GET(&announce, s, sizeof(announce));
+ ret = isis_ldp_sync_announce_update(announce);
+ break;
+ case LDP_IGP_SYNC_HELLO_UPDATE:
+ STREAM_GET(&hello, s, sizeof(hello));
+ ret = isis_ldp_sync_hello_update(hello);
+ break;
+ default:
+ break;
+ }
+
+stream_failure:
+
+ return ret;
+}
+
void isis_zebra_init(struct thread_master *master, int instance)
{
/* Initialize asynchronous zclient. */
@@ -622,6 +661,8 @@ void isis_zebra_init(struct thread_master *master, int instance)
*/
zclient_sync->session_id = 1;
zclient_sync->privs = &isisd_privs;
+
+ zclient->opaque_msg_handler = isis_opaque_msg_handler;
}
void isis_zebra_stop(void)
diff --git a/isisd/isisd.c b/isisd/isisd.c
index 2a2c71b1fd..7bba783b39 100644
--- a/isisd/isisd.c
+++ b/isisd/isisd.c
@@ -76,6 +76,7 @@ unsigned long debug_flooding;
unsigned long debug_bfd;
unsigned long debug_tx_queue;
unsigned long debug_sr;
+unsigned long debug_ldp_sync;
DEFINE_QOBJ_TYPE(isis_area)
@@ -1207,6 +1208,8 @@ void print_debug(struct vty *vty, int flags, int onoff)
vty_out(vty, "IS-IS Flooding debugging is %s\n", onoffs);
if (flags & DEBUG_BFD)
vty_out(vty, "IS-IS BFD debugging is %s\n", onoffs);
+ if (flags & DEBUG_LDP_SYNC)
+ vty_out(vty, "IS-IS ldp-sync debugging is %s\n", onoffs);
}
DEFUN_NOSH (show_debugging,
@@ -1244,6 +1247,8 @@ DEFUN_NOSH (show_debugging,
print_debug(vty, DEBUG_FLOODING, 1);
if (IS_DEBUG_BFD)
print_debug(vty, DEBUG_BFD, 1);
+ if (IS_DEBUG_LDP_SYNC)
+ print_debug(vty, DEBUG_LDP_SYNC, 1);
return CMD_SUCCESS;
}
@@ -1312,6 +1317,10 @@ static int config_write_debug(struct vty *vty)
vty_out(vty, "debug " PROTO_NAME " bfd\n");
write++;
}
+ if (IS_DEBUG_LDP_SYNC) {
+ vty_out(vty, "debug " PROTO_NAME " ldp-sync\n");
+ write++;
+ }
write += spf_backoff_write_config(vty);
return write;
@@ -1668,11 +1677,32 @@ DEFUN (no_debug_isis_bfd,
return CMD_SUCCESS;
}
-DEFUN(show_hostname, show_hostname_cmd,
- "show " PROTO_NAME " [vrf <NAME|all>] hostname",
- SHOW_STR PROTO_HELP VRF_CMD_HELP_STR
- "All VRFs\n"
- "IS-IS Dynamic hostname mapping\n")
+DEFUN(debug_isis_ldp_sync, debug_isis_ldp_sync_cmd,
+ "debug " PROTO_NAME " ldp-sync",
+ DEBUG_STR PROTO_HELP PROTO_NAME " interaction with LDP-Sync\n")
+{
+ debug_ldp_sync |= DEBUG_LDP_SYNC;
+ print_debug(vty, DEBUG_LDP_SYNC, 1);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(no_debug_isis_ldp_sync, no_debug_isis_ldp_sync_cmd,
+ "no debug " PROTO_NAME " ldp-sync",
+ NO_STR UNDEBUG_STR PROTO_HELP PROTO_NAME " interaction with LDP-Sync\n")
+{
+ debug_ldp_sync &= ~DEBUG_LDP_SYNC;
+ print_debug(vty, DEBUG_LDP_SYNC, 0);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_hostname,
+ show_hostname_cmd,
+ "show " PROTO_NAME " hostname",
+ SHOW_STR
+ PROTO_HELP
+ "IS-IS Dynamic hostname mapping\n")
{
struct listnode *node;
const char *vrf_name = VRF_DEFAULT_NAME;
@@ -2830,6 +2860,8 @@ void isis_init(void)
install_element(ENABLE_NODE, &no_debug_isis_lsp_sched_cmd);
install_element(ENABLE_NODE, &debug_isis_bfd_cmd);
install_element(ENABLE_NODE, &no_debug_isis_bfd_cmd);
+ install_element(ENABLE_NODE, &debug_isis_ldp_sync_cmd);
+ install_element(ENABLE_NODE, &no_debug_isis_ldp_sync_cmd);
install_element(CONFIG_NODE, &debug_isis_adj_cmd);
install_element(CONFIG_NODE, &no_debug_isis_adj_cmd);
@@ -2857,6 +2889,8 @@ void isis_init(void)
install_element(CONFIG_NODE, &no_debug_isis_lsp_sched_cmd);
install_element(CONFIG_NODE, &debug_isis_bfd_cmd);
install_element(CONFIG_NODE, &no_debug_isis_bfd_cmd);
+ install_element(CONFIG_NODE, &debug_isis_ldp_sync_cmd);
+ install_element(CONFIG_NODE, &no_debug_isis_ldp_sync_cmd);
install_default(ROUTER_NODE);
diff --git a/isisd/isisd.h b/isisd/isisd.h
index c26a62dfac..d8df6eead9 100644
--- a/isisd/isisd.h
+++ b/isisd/isisd.h
@@ -35,6 +35,7 @@
#include "isis_lsp.h"
#include "isis_memory.h"
#include "qobj.h"
+#include "ldp_sync.h"
#ifdef FABRICD
static const bool fabricd = true;
@@ -93,6 +94,7 @@ struct isis {
uint32_t circuit_ids_used[8]; /* 256 bits to track circuit ids 1 through 255 */
struct route_table *ext_info[REDIST_PROTOCOL_COUNT];
+ struct ldp_sync_info_cmd ldp_sync_cmd; /* MPLS LDP-IGP Sync */
};
extern struct isis_master *im;
@@ -275,6 +277,7 @@ extern unsigned long debug_flooding;
extern unsigned long debug_bfd;
extern unsigned long debug_tx_queue;
extern unsigned long debug_sr;
+extern unsigned long debug_ldp_sync;
#define DEBUG_ADJ_PACKETS (1<<0)
#define DEBUG_SNP_PACKETS (1<<1)
@@ -289,6 +292,7 @@ extern unsigned long debug_sr;
#define DEBUG_BFD (1<<10)
#define DEBUG_TX_QUEUE (1<<11)
#define DEBUG_SR (1<<12)
+#define DEBUG_LDP_SYNC (1 << 13)
/* Debug related macro. */
#define IS_DEBUG_ADJ_PACKETS (debug_adj_pkt & DEBUG_ADJ_PACKETS)
@@ -304,6 +308,7 @@ extern unsigned long debug_sr;
#define IS_DEBUG_BFD (debug_bfd & DEBUG_BFD)
#define IS_DEBUG_TX_QUEUE (debug_tx_queue & DEBUG_TX_QUEUE)
#define IS_DEBUG_SR (debug_sr & DEBUG_SR)
+#define IS_DEBUG_LDP_SYNC (debug_ldp_sync & DEBUG_LDP_SYNC)
#define lsp_debug(...) \
do { \
diff --git a/isisd/subdir.am b/isisd/subdir.am
index 9e855ad8cf..50d4746534 100644
--- a/isisd/subdir.am
+++ b/isisd/subdir.am
@@ -8,6 +8,7 @@ sbin_PROGRAMS += isisd/isisd
dist_examples_DATA += isisd/isisd.conf.sample
vtysh_scan += \
isisd/isis_cli.c \
+ isisd/isis_ldp_sync.c \
isisd/isis_redist.c \
isisd/isis_spf.c \
isisd/isis_te.c \
@@ -36,6 +37,7 @@ noinst_HEADERS += \
isisd/isis_errors.h \
isisd/isis_events.h \
isisd/isis_flags.h \
+ isisd/isis_ldp_sync.h \
isisd/isis_lsp.h \
isisd/isis_memory.h \
isisd/isis_misc.h \
@@ -69,6 +71,7 @@ LIBISIS_SOURCES = \
isisd/isis_errors.c \
isisd/isis_events.c \
isisd/isis_flags.c \
+ isisd/isis_ldp_sync.c \
isisd/isis_lsp.c \
isisd/isis_memory.c \
isisd/isis_misc.c \
diff --git a/ldpd/adjacency.c b/ldpd/adjacency.c
index 0bdd2423c7..4e09a6c4c9 100644
--- a/ldpd/adjacency.c
+++ b/ldpd/adjacency.c
@@ -125,6 +125,9 @@ adj_del(struct adj *adj, uint32_t notif_status)
switch (adj->source.type) {
case HELLO_LINK:
RB_REMOVE(ia_adj_head, &adj->source.link.ia->adj_tree, adj);
+
+ if (nbr)
+ ldp_sync_fsm_adj_event(adj, LDP_SYNC_EVT_ADJ_DEL);
break;
case HELLO_TARGETED:
adj->source.target->adj = NULL;
diff --git a/ldpd/control.c b/ldpd/control.c
index cde99dc8a9..6554f0a6f1 100644
--- a/ldpd/control.c
+++ b/ldpd/control.c
@@ -263,6 +263,9 @@ control_dispatch_imsg(struct thread *thread)
nbr_clear_ctl(imsg.data);
break;
+ case IMSG_CTL_SHOW_LDP_SYNC:
+ ldpe_ldp_sync_ctl(c);
+ break;
case IMSG_CTL_LOG_VERBOSE:
/* ignore */
break;
diff --git a/ldpd/hello.c b/ldpd/hello.c
index ac24704bca..caf63c13d7 100644
--- a/ldpd/hello.c
+++ b/ldpd/hello.c
@@ -378,6 +378,7 @@ recv_hello(struct in_addr lsr_id, struct ldp_msg *msg, int af,
adj->nbr = nbr;
RB_INSERT(nbr_adj_head, &nbr->adj_tree, adj);
}
+ ldp_sync_fsm_adj_event(adj, LDP_SYNC_EVT_ADJ_NEW);
}
adj->ds_tlv = ds_tlv;
diff --git a/ldpd/interface.c b/ldpd/interface.c
index 371c7d0bb1..bc8f26bc58 100644
--- a/ldpd/interface.c
+++ b/ldpd/interface.c
@@ -23,6 +23,7 @@
#include "ldpd.h"
#include "ldpe.h"
#include "log.h"
+#include "ldp_debug.h"
#include "sockopt.h"
@@ -40,6 +41,17 @@ static int if_leave_ipv4_group(struct iface *, struct in_addr *);
static int if_join_ipv6_group(struct iface *, struct in6_addr *);
static int if_leave_ipv6_group(struct iface *, struct in6_addr *);
+static int ldp_sync_fsm_init(struct iface *iface, int state);
+static int ldp_sync_act_iface_start_sync(struct iface *iface);
+static int iface_wait_for_ldp_sync_timer(struct thread *thread);
+static void start_wait_for_ldp_sync_timer(struct iface *iface);
+static void stop_wait_for_ldp_sync_timer(struct iface *iface);
+static int ldp_sync_act_ldp_start_sync(struct iface *iface);
+static int ldp_sync_act_ldp_complete_sync(struct iface *iface);
+static int iface_to_oper_nbr_count(struct iface *iface, unsigned int type);
+static void ldp_sync_get_peer_ldp_id(struct iface *iface,
+ struct in_addr *peer_ldp_id);
+
RB_GENERATE(iface_head, iface, entry, iface_compare)
static __inline int
@@ -87,6 +99,9 @@ ldpe_if_init(struct iface *iface)
iface->ipv6.iface = iface;
iface->ipv6.state = IF_STA_DOWN;
RB_INIT(ia_adj_head, &iface->ipv6.adj_tree);
+
+ /* LGP IGP Sync */
+ ldp_sync_fsm_init(iface, LDP_SYNC_STA_NOT_ACH);
}
void
@@ -96,6 +111,8 @@ ldpe_if_exit(struct iface *iface)
log_debug("%s: interface %s", __func__, iface->name);
+ ldp_sync_fsm(iface, LDP_SYNC_EVT_CONFIG_LDP_OFF);
+
if (iface->ipv4.state == IF_STA_ACTIVE)
if_reset(iface, AF_INET);
if (iface->ipv6.state == IF_STA_ACTIVE)
@@ -138,6 +155,10 @@ if_update_info(struct iface *iface, struct kif *kif)
kif->flags & IFF_MULTICAST)
iface->type = IF_TYPE_BROADCAST;
+ if (ldpd_process == PROC_LDP_ENGINE && iface->operative &&
+ !kif->operative)
+ ldp_sync_fsm(iface, LDP_SYNC_EVT_IFACE_SHUTDOWN);
+
/* get index and flags */
iface->ifindex = kif->ifindex;
iface->operative = kif->operative;
@@ -426,6 +447,12 @@ if_get_hello_interval(struct iface_af *ia)
return (leconf->lhello_interval);
}
+uint16_t
+if_get_wait_for_sync_interval(void)
+{
+ return (leconf->wait_for_sync_interval);
+}
+
/* timers */
/* ARGSUSED */
static int
@@ -484,6 +511,55 @@ if_to_ctl(struct iface_af *ia)
return (&ictl);
}
+static void
+ldp_sync_get_peer_ldp_id(struct iface *iface, struct in_addr *peer_ldp_id)
+{
+ struct iface_af *ia;
+ struct adj *adj;
+
+ if (iface->ipv4.state == IF_STA_ACTIVE) {
+ ia = iface_af_get(iface, AF_INET);
+ RB_FOREACH(adj, ia_adj_head, &ia->adj_tree)
+ if (adj->nbr && adj->nbr->state == NBR_STA_OPER) {
+ *peer_ldp_id = adj->nbr->id;
+ return;
+ }
+ }
+
+ if (iface->ipv6.state == IF_STA_ACTIVE) {
+ ia = iface_af_get(iface, AF_INET6);
+ RB_FOREACH(adj, ia_adj_head, &ia->adj_tree)
+ if (adj->nbr && adj->nbr->state == NBR_STA_OPER) {
+ *peer_ldp_id = adj->nbr->id;
+ return;
+ }
+ }
+}
+
+struct ctl_ldp_sync *
+ldp_sync_to_ctl(struct iface *iface)
+{
+ static struct ctl_ldp_sync ictl;
+
+ memcpy(ictl.name, iface->name, sizeof(ictl.name));
+ ictl.ifindex = iface->ifindex;
+ ictl.in_sync = (iface->ldp_sync.state == LDP_SYNC_STA_ACH);
+ ictl.wait_time = if_get_wait_for_sync_interval();
+ ictl.timer_running = iface->ldp_sync.wait_for_sync_timer ? true : false;
+
+ if (iface->ldp_sync.wait_for_sync_timer)
+ ictl.wait_time_remaining =
+ thread_timer_remain_second(iface->ldp_sync.wait_for_sync_timer);
+ else
+ ictl.wait_time_remaining = 0;
+
+ memset(&ictl.peer_ldp_id, 0, sizeof(ictl.peer_ldp_id));
+
+ ldp_sync_get_peer_ldp_id(iface, &ictl.peer_ldp_id);
+
+ return (&ictl);
+}
+
/* multicast membership sockopts */
in_addr_t
if_get_ipv4_addr(struct iface *iface)
@@ -576,3 +652,344 @@ if_leave_ipv6_group(struct iface *iface, struct in6_addr *addr)
return (0);
}
+
+const struct {
+ int state;
+ enum ldp_sync_event event;
+ enum ldp_sync_action action;
+ int new_state;
+} ldp_sync_fsm_tbl[] = {
+ /* current state event that happened action to take resulting state */
+/* LDP IGP Sync not achieved */
+ {LDP_SYNC_STA_NOT_ACH, LDP_SYNC_EVT_LDP_SYNC_START, LDP_SYNC_ACT_LDP_START_SYNC, 0},
+ {LDP_SYNC_STA_NOT_ACH, LDP_SYNC_EVT_LDP_SYNC_COMPLETE, LDP_SYNC_ACT_LDP_COMPLETE_SYNC, LDP_SYNC_STA_ACH},
+ {LDP_SYNC_STA_NOT_ACH, LDP_SYNC_EVT_CONFIG_LDP_OFF, LDP_SYNC_ACT_CONFIG_LDP_OFF, 0},
+ {LDP_SYNC_STA_NOT_ACH, LDP_SYNC_EVT_IFACE_SHUTDOWN, LDP_SYNC_ACT_IFACE_SHUTDOWN, 0},
+ {LDP_SYNC_STA_NOT_ACH, LDP_SYNC_EVT_SESSION_CLOSE, LDP_SYNC_ACT_NOTHING, 0},
+ {LDP_SYNC_STA_NOT_ACH, LDP_SYNC_EVT_ADJ_DEL, LDP_SYNC_ACT_NOTHING, 0},
+ {LDP_SYNC_STA_NOT_ACH, LDP_SYNC_EVT_ADJ_NEW, LDP_SYNC_ACT_NOTHING, 0},
+/* LDP IGP Sync achieved */
+ {LDP_SYNC_STA_ACH, LDP_SYNC_EVT_CONFIG_LDP_OFF, LDP_SYNC_ACT_CONFIG_LDP_OFF, LDP_SYNC_STA_NOT_ACH},
+ {LDP_SYNC_STA_ACH, LDP_SYNC_EVT_LDP_SYNC_COMPLETE, LDP_SYNC_ACT_NOTHING, 0},
+ {LDP_SYNC_STA_ACH, LDP_SYNC_EVT_LDP_SYNC_START, LDP_SYNC_ACT_NOTHING, 0},
+ {LDP_SYNC_STA_ACH, LDP_SYNC_EVT_IFACE_SHUTDOWN, LDP_SYNC_ACT_IFACE_SHUTDOWN, LDP_SYNC_STA_NOT_ACH},
+ {LDP_SYNC_STA_ACH, LDP_SYNC_EVT_SESSION_CLOSE, LDP_SYNC_ACT_IFACE_START_SYNC, LDP_SYNC_STA_NOT_ACH},
+ {LDP_SYNC_STA_ACH, LDP_SYNC_EVT_ADJ_DEL, LDP_SYNC_ACT_IFACE_START_SYNC, LDP_SYNC_STA_NOT_ACH},
+ {LDP_SYNC_STA_ACH, LDP_SYNC_EVT_ADJ_NEW, LDP_SYNC_ACT_NOTHING, 0},
+ {-1, LDP_SYNC_EVT_NOTHING, LDP_SYNC_ACT_NOTHING, 0},
+};
+
+const char * const ldp_sync_event_names[] = {
+ "NOTHING",
+ "LDP SYNC START",
+ "LDP SYNC COMPLETE",
+ "CONFIG LDP OFF",
+ "IFACE SYNC START (ADJ DEL)",
+ "IFACE SYNC START (ADJ NEW)",
+ "IFACE SYNC START (SESSION CLOSE)",
+ "IFACE SYNC START (CONFIG LDP ON)",
+ "IFACE SHUTDOWN",
+ "N/A"
+};
+
+const char * const ldp_sync_action_names[] = {
+ "NOTHING",
+ "IFACE SYNC START",
+ "LDP START SYNC",
+ "LDP COMPLETE SYNC",
+ "CONFIG LDP OFF",
+ "IFACE SHUTDOWN",
+ "N/A"
+};
+
+const char *
+ldp_sync_state_name(int state)
+{
+ switch (state) {
+ case LDP_SYNC_STA_NOT_ACH:
+ return ("NOT ACHIEVED");
+ case LDP_SYNC_STA_ACH:
+ return ("ACHIEVED");
+ default:
+ return ("UNKNOWN");
+ }
+}
+
+static int
+send_ldp_sync_state_update(char *name, int ifindex, int sync_start)
+{
+ debug_evt_ldp_sync("%s: interface %s (%d), sync_start=%d",
+ __func__, name, ifindex, sync_start);
+
+ struct ldp_igp_sync_if_state state;
+
+ state.ifindex = ifindex;
+ state.sync_start = sync_start;
+
+ return ldpe_imsg_compose_parent(IMSG_LDP_SYNC_IF_STATE_UPDATE,
+ getpid(), &state, sizeof(state));
+}
+
+static int
+ldp_sync_act_iface_start_sync(struct iface *iface)
+{
+ send_ldp_sync_state_update(iface->name, iface->ifindex, true);
+
+ return (0);
+}
+
+static int
+iface_wait_for_ldp_sync_timer(struct thread *thread)
+{
+ struct iface *iface = THREAD_ARG(thread);
+
+ ldp_sync_fsm(iface, LDP_SYNC_EVT_LDP_SYNC_COMPLETE);
+
+ return (0);
+}
+
+static void start_wait_for_ldp_sync_timer(struct iface *iface)
+{
+ if (iface->ldp_sync.wait_for_sync_timer)
+ return;
+
+ THREAD_TIMER_OFF(iface->ldp_sync.wait_for_sync_timer);
+ iface->ldp_sync.wait_for_sync_timer = NULL;
+ thread_add_timer(master, iface_wait_for_ldp_sync_timer, iface,
+ if_get_wait_for_sync_interval(),
+ &iface->ldp_sync.wait_for_sync_timer);
+}
+
+static void stop_wait_for_ldp_sync_timer(struct iface *iface)
+{
+ THREAD_TIMER_OFF(iface->ldp_sync.wait_for_sync_timer);
+ iface->ldp_sync.wait_for_sync_timer = NULL;
+}
+
+static int
+ldp_sync_act_ldp_start_sync(struct iface *iface)
+{
+ start_wait_for_ldp_sync_timer(iface);
+
+ return 0;
+}
+
+static int
+ldp_sync_act_ldp_complete_sync(struct iface *iface)
+{
+ send_ldp_sync_state_update(iface->name, iface->ifindex, false);
+
+ return 0;
+}
+
+static int
+iface_to_oper_nbr_count(struct iface *iface, unsigned int type)
+{
+ int oper_nbr_count = 0;
+ struct adj *adj;
+
+ RB_FOREACH(adj, ia_adj_head, &iface->ipv4.adj_tree) {
+ if (type == adj->source.type && adj->nbr &&
+ adj->nbr->state == NBR_STA_OPER)
+ oper_nbr_count++;
+ }
+
+ RB_FOREACH(adj, ia_adj_head, &iface->ipv6.adj_tree) {
+ if (type == adj->source.type && adj->nbr &&
+ adj->nbr->state == NBR_STA_OPER)
+ oper_nbr_count++;
+ }
+
+ return oper_nbr_count;
+}
+
+int
+ldp_sync_fsm_adj_event(struct adj *adj, enum ldp_sync_event event)
+{
+ if (adj->source.type != HELLO_LINK)
+ return -1;
+
+ struct iface *iface = adj->source.link.ia->iface;
+
+ if (!iface->operative)
+ return 0;
+
+ if (event == LDP_SYNC_EVT_ADJ_NEW) {
+ struct nbr *nbr = adj->nbr;
+ if (nbr && nbr->state == NBR_STA_OPER) {
+ event = LDP_SYNC_EVT_LDP_SYNC_START;
+ }
+ } else if (event == LDP_SYNC_EVT_ADJ_DEL) {
+ /* Ignore if an operational neighbor exists.
+ */
+ int oper_nbr_count = iface_to_oper_nbr_count(iface, HELLO_LINK);
+ if (oper_nbr_count > 0)
+ return 0;
+ }
+
+ debug_evt_ldp_sync("%s: event %s, "
+ "adj iface %s (%d) lsr-id %s "
+ "source address %s transport address %s",
+ __func__, ldp_sync_event_names[event],
+ adj->source.link.ia->iface->name,
+ adj->source.link.ia->iface->ifindex,
+ inet_ntoa(adj->lsr_id),
+ log_addr(adj_get_af(adj), &adj->source.link.src_addr),
+ log_addr(adj_get_af(adj), &adj->trans_addr));
+
+ return ldp_sync_fsm(iface, event);
+}
+
+int
+ldp_sync_fsm_nbr_event(struct nbr *nbr, enum ldp_sync_event event)
+{
+ struct adj *adj;
+ struct iface *iface = NULL;
+ RB_FOREACH(adj, nbr_adj_head, &nbr->adj_tree) {
+ if (HELLO_LINK != adj->source.type)
+ continue;
+
+ iface = adj->source.link.ia->iface;
+
+ if (!iface || !iface->operative)
+ continue;
+
+ int oper_nbr_count = iface_to_oper_nbr_count(iface, HELLO_LINK);
+
+ if (event == LDP_SYNC_EVT_SESSION_CLOSE && oper_nbr_count > 0)
+ /* Ignore if an operational neighbor exists.
+ */
+ continue;
+
+ debug_evt_ldp_sync("%s: event %s, iface %s, lsr-id %s",
+ __func__, ldp_sync_event_names[event],
+ iface->name, inet_ntoa(nbr->id));
+
+ ldp_sync_fsm(iface, event);
+ }
+
+ return 0;
+}
+
+int
+ldp_sync_fsm_state_req(struct ldp_igp_sync_if_state_req *state_req)
+{
+ debug_evt_ldp_sync("%s: interface %s (%d) proto %s",
+ __func__, state_req->name, state_req->ifindex,
+ zebra_route_string(state_req->proto));
+
+ struct iface *iface = if_lookup_name(leconf, state_req->name);
+
+ if (!iface) {
+ debug_evt_ldp_sync("%s: Warning: Ignoring LDP IGP SYNC "
+ "interface state request for interface %s (%d). "
+ "Interface does not exist in LDP.",
+ __func__, state_req->name, state_req->ifindex);
+
+ return 0;
+ }
+
+ return send_ldp_sync_state_update(state_req->name,
+ state_req->ifindex,
+ (iface->ldp_sync.state != LDP_SYNC_STA_ACH));
+}
+
+static int
+ldp_sync_fsm_init(struct iface *iface, int state)
+{
+ int old_state = iface->ldp_sync.state;
+
+ iface->ldp_sync.state = state;
+ stop_wait_for_ldp_sync_timer(iface);
+
+ send_ldp_sync_state_update(iface->name, iface->ifindex,
+ (iface->ldp_sync.state != LDP_SYNC_STA_ACH));
+
+ if (old_state != iface->ldp_sync.state) {
+ debug_evt_ldp_sync("%s: resulted in "
+ "changing state for interface %s (%d) from %s to %s",
+ __func__,
+ iface->name, iface->ifindex,
+ ldp_sync_state_name(old_state),
+ ldp_sync_state_name(iface->ldp_sync.state));
+ }
+
+ return 0;
+}
+
+int
+ldp_sync_fsm(struct iface *iface, enum ldp_sync_event event)
+{
+ int old_state = iface->ldp_sync.state;
+ int new_state = 0;
+ int i;
+
+ for (i = 0; ldp_sync_fsm_tbl[i].state != -1; i++)
+ if ((ldp_sync_fsm_tbl[i].state & old_state) &&
+ (ldp_sync_fsm_tbl[i].event == event)) {
+ new_state = ldp_sync_fsm_tbl[i].new_state;
+ break;
+ }
+
+ if (ldp_sync_fsm_tbl[i].state == -1) {
+ /* event outside of the defined fsm, ignore it. */
+ log_warnx("%s: interface %s, event %s not expected in "
+ "state %s ", __func__, iface->name,
+ ldp_sync_event_names[event],
+ ldp_sync_state_name(old_state));
+ return (0);
+ }
+
+ if (new_state != 0)
+ iface->ldp_sync.state = new_state;
+
+ switch (ldp_sync_fsm_tbl[i].action) {
+ case LDP_SYNC_ACT_IFACE_START_SYNC:
+ ldp_sync_act_iface_start_sync(iface);
+ break;
+ case LDP_SYNC_ACT_LDP_START_SYNC:
+ ldp_sync_act_ldp_start_sync(iface);
+ break;
+ case LDP_SYNC_ACT_LDP_COMPLETE_SYNC:
+ ldp_sync_act_ldp_complete_sync(iface);
+ break;
+ case LDP_SYNC_ACT_CONFIG_LDP_OFF:
+ ldp_sync_fsm_init(iface, LDP_SYNC_STA_NOT_ACH);
+ break;
+ case LDP_SYNC_ACT_IFACE_SHUTDOWN:
+ ldp_sync_fsm_init(iface, iface->ldp_sync.state);
+ break;
+ case LDP_SYNC_ACT_NOTHING:
+ /* do nothing */
+ break;
+ }
+
+ if (old_state != iface->ldp_sync.state) {
+
+ debug_evt_ldp_sync("%s: event %s resulted in action %s "
+ "for interface %s, changing state from %s to %s",
+ __func__, ldp_sync_event_names[event],
+ ldp_sync_action_names[ldp_sync_fsm_tbl[i].action],
+ iface->name, ldp_sync_state_name(old_state),
+ ldp_sync_state_name(iface->ldp_sync.state));
+
+ } else {
+ debug_evt_ldp_sync("%s: event %s resulted in action %s "
+ "for interface %s, remaining in state %s",
+ __func__, ldp_sync_event_names[event],
+ ldp_sync_action_names[ldp_sync_fsm_tbl[i].action],
+ iface->name,
+ ldp_sync_state_name(iface->ldp_sync.state));
+ }
+
+ return (0);
+}
+
+void
+ldp_sync_fsm_reset_all(void)
+{
+ struct iface *iface;
+
+ RB_FOREACH(iface, iface_head, &leconf->iface_tree)
+ ldp_sync_fsm(iface, LDP_SYNC_EVT_CONFIG_LDP_OFF);
+}
diff --git a/ldpd/ldp.h b/ldpd/ldp.h
index 5d1bf81ec7..4bad3afc3c 100644
--- a/ldpd/ldp.h
+++ b/ldpd/ldp.h
@@ -51,6 +51,8 @@
#define INIT_DELAY_TMR 15
#define MAX_DELAY_TMR 120
+#define DFLT_WAIT_FOR_SYNC 10
+
#define MIN_PWID_ID 1
#define MAX_PWID_ID 0xffffffff
diff --git a/ldpd/ldp_debug.c b/ldpd/ldp_debug.c
index b9ef60ff94..a8d9833dde 100644
--- a/ldpd/ldp_debug.c
+++ b/ldpd/ldp_debug.c
@@ -99,6 +99,11 @@ ldp_vty_debug(struct vty *vty, const char *negate, const char *type_str,
DEBUG_ON(msg, LDP_DEBUG_MSG_SEND_ALL);
}
}
+ } else if (strcmp(type_str, "sync") == 0) {
+ if (negate)
+ DEBUG_OFF(sync, LDP_DEBUG_SYNC);
+ else
+ DEBUG_ON(sync, LDP_DEBUG_SYNC);
} else if (strcmp(type_str, "zebra") == 0) {
if (negate)
DEBUG_OFF(zebra, LDP_DEBUG_ZEBRA);
@@ -137,6 +142,8 @@ ldp_vty_show_debugging(struct vty *vty)
" LDP detailed messages debugging is on (outbound)\n");
else if (LDP_DEBUG(msg, LDP_DEBUG_MSG_SEND))
vty_out (vty," LDP messages debugging is on (outbound)\n");
+ if (LDP_DEBUG(sync, LDP_DEBUG_SYNC))
+ vty_out (vty, " LDP sync debugging is on\n");
if (LDP_DEBUG(zebra, LDP_DEBUG_ZEBRA))
vty_out (vty, " LDP zebra debugging is on\n");
vty_out (vty, "\n");
@@ -195,5 +202,10 @@ ldp_debug_config_write(struct vty *vty)
write = 1;
}
+ if (CONF_LDP_DEBUG(sync, LDP_DEBUG_SYNC)) {
+ vty_out (vty, "debug mpls ldp sync\n");
+ write = 1;
+ }
+
return (write);
}
diff --git a/ldpd/ldp_debug.h b/ldpd/ldp_debug.h
index 8ae144d93a..977734bddf 100644
--- a/ldpd/ldp_debug.h
+++ b/ldpd/ldp_debug.h
@@ -42,6 +42,10 @@ struct ldp_debug {
int zebra;
#define LDP_DEBUG_ZEBRA 0x01
+
+ int sync;
+#define LDP_DEBUG_SYNC 0x01
+
};
extern struct ldp_debug conf_ldp_debug;
extern struct ldp_debug ldp_debug;
@@ -143,4 +147,10 @@ do { \
log_debug("zebra[out]: " emsg, __VA_ARGS__); \
} while (0)
+#define debug_evt_ldp_sync(emsg, ...) \
+do { \
+ if (LDP_DEBUG(sync, LDP_DEBUG_SYNC)) \
+ log_debug("sync: " emsg, __VA_ARGS__); \
+} while (0)
+
#endif /* _LDP_DEBUG_H_ */
diff --git a/ldpd/ldp_vty.h b/ldpd/ldp_vty.h
index f6ba8f8c97..882874f1be 100644
--- a/ldpd/ldp_vty.h
+++ b/ldpd/ldp_vty.h
@@ -50,6 +50,7 @@ int ldp_vty_label_accept(struct vty *, const char *, const char *, const char *
int ldp_vty_ttl_security(struct vty *, const char *);
int ldp_vty_router_id(struct vty *, const char *, struct in_addr);
int ldp_vty_ordered_control(struct vty *, const char *);
+int ldp_vty_wait_for_sync_interval(struct vty *, const char *, long);
int ldp_vty_ds_cisco_interop(struct vty *, const char *);
int ldp_vty_trans_pref_ipv4(struct vty *, const char *);
int ldp_vty_neighbor_password(struct vty *, const char *, struct in_addr, const char *);
@@ -73,6 +74,7 @@ int ldp_vty_show_discovery(struct vty *, const char *, const char *, const char
int ldp_vty_show_interface(struct vty *, const char *, const char *);
int ldp_vty_show_capabilities(struct vty *, const char *);
int ldp_vty_show_neighbor(struct vty *, const char *, int, const char *, const char *);
+int ldp_vty_show_ldp_sync(struct vty *, const char *);
int ldp_vty_show_atom_binding(struct vty *, const char *, unsigned long,
unsigned long, const char *);
int ldp_vty_show_atom_vc(struct vty *, const char *, const char *,
diff --git a/ldpd/ldp_vty_cmds.c b/ldpd/ldp_vty_cmds.c
index 53a384fe55..1f102f86fa 100644
--- a/ldpd/ldp_vty_cmds.c
+++ b/ldpd/ldp_vty_cmds.c
@@ -230,6 +230,17 @@ DEFPY (ldp_ordered_control,
return (ldp_vty_ordered_control(vty, no));
}
+DEFPY (ldp_wait_for_sync,
+ ldp_wait_for_sync_cmd,
+ "[no] wait-for-sync (1-10000)$waitforsync",
+ NO_STR
+ "Time to wait for LDP-IGP Sync to complete label exchange\n"
+ "Time (seconds)\n")
+{
+ return (ldp_vty_wait_for_sync_interval(vty, no, waitforsync));
+
+}
+
DEFPY (ldp_discovery_targeted_hello_accept,
ldp_discovery_targeted_hello_accept_cmd,
"[no] discovery targeted-hello accept [from <(1-199)|(1300-2699)|WORD>$from_acl]",
@@ -547,7 +558,7 @@ DEFPY (ldp_debug_mpls_ldp_discovery_hello,
DEFPY (ldp_debug_mpls_ldp_type,
ldp_debug_mpls_ldp_type_cmd,
- "[no] debug mpls ldp <errors|event|labels|zebra>$type",
+ "[no] debug mpls ldp <errors|event|labels|sync|zebra>$type",
NO_STR
"Debugging functions\n"
"MPLS information\n"
@@ -555,6 +566,7 @@ DEFPY (ldp_debug_mpls_ldp_type,
"Errors\n"
"LDP event information\n"
"LDP label allocation information\n"
+ "LDP sync information\n"
"LDP zebra information\n")
{
return (ldp_vty_debug(vty, no, type, NULL, NULL));
@@ -695,6 +707,18 @@ DEFPY (ldp_show_mpls_ldp_neighbor_capabilities,
return (ldp_vty_show_neighbor(vty, lsr_id_str, 1, NULL, json));
}
+DEFPY (ldp_show_mpls_ldp_igp_sync,
+ ldp_show_mpls_ldp_igp_sync_cmd,
+ "show mpls ldp igp-sync [json]$json",
+ "Show mpls ldp ldp-sync information\n"
+ "MPLS information\n"
+ "Label Distribution Protocol\n"
+ "LDP-IGP Sync information\n"
+ JSON_STR)
+{
+ return (ldp_vty_show_ldp_sync(vty, json));
+}
+
DEFPY (ldp_show_l2vpn_atom_binding,
ldp_show_l2vpn_atom_binding_cmd,
"show l2vpn atom binding\
@@ -819,6 +843,7 @@ ldp_vty_init (void)
install_element(LDP_NODE, &ldp_neighbor_ttl_security_cmd);
install_element(LDP_NODE, &ldp_router_id_cmd);
install_element(LDP_NODE, &ldp_ordered_control_cmd);
+ install_element(LDP_NODE, &ldp_wait_for_sync_cmd);
install_element(LDP_IPV4_NODE, &ldp_discovery_link_holdtime_cmd);
install_element(LDP_IPV4_NODE, &ldp_discovery_targeted_holdtime_cmd);
@@ -888,4 +913,5 @@ ldp_vty_init (void)
install_element(VIEW_NODE, &ldp_show_l2vpn_atom_binding_cmd);
install_element(VIEW_NODE, &ldp_show_l2vpn_atom_vc_cmd);
install_element(VIEW_NODE, &ldp_show_debugging_mpls_ldp_cmd);
+ install_element(VIEW_NODE, &ldp_show_mpls_ldp_igp_sync_cmd);
}
diff --git a/ldpd/ldp_vty_conf.c b/ldpd/ldp_vty_conf.c
index 03dee23b47..c217cfc78a 100644
--- a/ldpd/ldp_vty_conf.c
+++ b/ldpd/ldp_vty_conf.c
@@ -285,6 +285,11 @@ ldp_config_write(struct vty *vty)
if (ldpd_conf->flags & F_LDPD_ORDERED_CONTROL)
vty_out (vty, " ordered-control\n");
+ if (ldpd_conf->wait_for_sync_interval != DFLT_WAIT_FOR_SYNC &&
+ ldpd_conf->wait_for_sync_interval != 0)
+ vty_out (vty, " wait-for-sync %u\n",
+ ldpd_conf->wait_for_sync_interval);
+
RB_FOREACH(nbrp, nbrp_head, &ldpd_conf->nbrp_tree) {
if (nbrp->flags & F_NBRP_KEEPALIVE)
vty_out (vty, " neighbor %s session holdtime %u\n",
@@ -477,7 +482,6 @@ int ldp_vty_disc_holdtime(struct vty *vty, const char *negate,
struct iface *iface;
struct iface_af *ia;
int af;
-
switch (vty->node) {
case LDP_NODE:
if (negate) {
@@ -1014,6 +1018,24 @@ ldp_vty_ordered_control(struct vty *vty, const char *negate)
return (CMD_SUCCESS);
}
+int ldp_vty_wait_for_sync_interval(struct vty *vty, const char *negate,
+ long secs)
+{
+ switch (vty->node) {
+ case LDP_NODE:
+ if (negate)
+ vty_conf->wait_for_sync_interval = DFLT_WAIT_FOR_SYNC;
+ else
+ vty_conf->wait_for_sync_interval = secs;
+
+ ldp_config_apply(vty, vty_conf);
+ break;
+ default:
+ fatalx("ldp_vty_wait_for_sync_interval: unexpected node");
+ }
+ return (CMD_SUCCESS);
+}
+
int
ldp_vty_ds_cisco_interop(struct vty *vty, const char * negate)
{
diff --git a/ldpd/ldp_vty_exec.c b/ldpd/ldp_vty_exec.c
index d8ed5ccccc..609598a768 100644
--- a/ldpd/ldp_vty_exec.c
+++ b/ldpd/ldp_vty_exec.c
@@ -37,7 +37,8 @@ enum show_command {
SHOW_NBR,
SHOW_LIB,
SHOW_L2VPN_PW,
- SHOW_L2VPN_BINDING
+ SHOW_L2VPN_BINDING,
+ SHOW_LDP_SYNC
};
struct show_params {
@@ -86,6 +87,10 @@ static void show_discovery_detail_adj_json(json_object *,
struct ctl_adj *);
static int show_discovery_detail_msg_json(struct imsg *,
struct show_params *, json_object *);
+static int show_ldp_sync_msg(struct vty *, struct imsg *,
+ struct show_params *);
+static int show_ldp_sync_msg_json(struct imsg *,
+ struct show_params *, json_object *);
static int show_nbr_msg(struct vty *, struct imsg *,
struct show_params *);
@@ -122,7 +127,6 @@ static int show_l2vpn_pw_msg(struct vty *, struct imsg *,
struct show_params *);
static int show_l2vpn_pw_msg_json(struct imsg *,
struct show_params *, json_object *);
-static int ldp_vty_connect(struct imsgbuf *);
static int ldp_vty_dispatch_msg(struct vty *, struct imsg *,
enum show_command, struct show_params *,
json_object *);
@@ -207,6 +211,87 @@ show_interface_msg_json(struct imsg *imsg, struct show_params *params,
}
static int
+show_ldp_sync_msg(struct vty *vty, struct imsg *imsg,
+ struct show_params *params)
+{
+ struct ctl_ldp_sync *iface;
+
+ switch (imsg->hdr.type) {
+ case IMSG_CTL_SHOW_LDP_SYNC:
+ iface = imsg->data;
+
+ vty_out (vty, "%s:\n", iface->name);
+ if (iface->in_sync)
+ vty_out (vty, " Status: initial label exchange complete\n");
+ else
+ vty_out (vty, " Status: label exchange not complete\n");
+
+ if (iface->timer_running) {
+ vty_out (vty, " Wait time: %d seconds (%d seconds left)\n",
+ iface->wait_time, iface->wait_time_remaining);
+ vty_out (vty, " Timer is running\n");
+ } else {
+ vty_out (vty, " Wait time: %d seconds\n",
+ iface->wait_time);
+ vty_out (vty, " Timer is not running\n");
+ }
+
+ if (iface->peer_ldp_id.s_addr)
+ vty_out (vty, " Peer LDP Identifier: %s:0\n",
+ inet_ntoa(iface->peer_ldp_id));
+
+ break;
+ case IMSG_CTL_END:
+ return (1);
+ default:
+ break;
+ }
+
+ return (0);
+}
+
+static int
+show_ldp_sync_msg_json(struct imsg *imsg, struct show_params *params,
+ json_object *json)
+{
+ struct ctl_ldp_sync *iface;
+ json_object *json_iface;
+
+ switch (imsg->hdr.type) {
+ case IMSG_CTL_SHOW_LDP_SYNC:
+ iface = imsg->data;
+
+ json_iface = json_object_new_object();
+ json_object_string_add(json_iface, "state",
+ iface->in_sync
+ ? "labelExchangeComplete"
+ : "labelExchangeNotComplete");
+ json_object_int_add(json_iface, "waitTime",
+ iface->wait_time);
+ json_object_int_add(json_iface, "waitTimeRemaining",
+ iface->wait_time_remaining);
+
+ if (iface->timer_running)
+ json_object_boolean_true_add(json_iface, "timerRunning");
+ else
+ json_object_boolean_false_add(json_iface, "timerRunning");
+
+ json_object_string_add(json_iface, "peerLdpId",
+ iface->peer_ldp_id.s_addr ?
+ inet_ntoa(iface->peer_ldp_id) : "");
+
+ json_object_object_add(json, iface->name, json_iface);
+ break;
+ case IMSG_CTL_END:
+ return (1);
+ default:
+ break;
+ }
+
+ return (0);
+}
+
+static int
show_discovery_msg(struct vty *vty, struct imsg *imsg,
struct show_params *params)
{
@@ -1437,6 +1522,20 @@ ldp_vty_dispatch_iface(struct vty *vty, struct imsg *imsg,
}
static int
+ldp_vty_dispatch_ldp_sync(struct vty *vty, struct imsg *imsg,
+ struct show_params *params, json_object *json)
+{
+ int ret;
+
+ if (params->json)
+ ret = show_ldp_sync_msg_json(imsg, params, json);
+ else
+ ret = show_ldp_sync_msg(vty, imsg, params);
+
+ return (ret);
+}
+
+static int
ldp_vty_dispatch_disc(struct vty *vty, struct imsg *imsg,
struct show_params *params, json_object *json)
{
@@ -1684,6 +1783,8 @@ ldp_vty_dispatch_msg(struct vty *vty, struct imsg *imsg, enum show_command cmd,
case SHOW_L2VPN_BINDING:
return (ldp_vty_dispatch_l2vpn_binding(vty, imsg, params,
json));
+ case SHOW_LDP_SYNC:
+ return (ldp_vty_dispatch_ldp_sync(vty, imsg, params, json));
default:
return (0);
}
@@ -1946,6 +2047,22 @@ ldp_vty_show_neighbor(struct vty *vty, const char *lsr_id, int capabilities,
}
int
+ldp_vty_show_ldp_sync(struct vty *vty, const char *json)
+{
+ struct imsgbuf ibuf;
+ struct show_params params;
+
+ if (ldp_vty_connect(&ibuf) < 0)
+ return (CMD_WARNING);
+
+ memset(&params, 0, sizeof(params));
+ params.json = (json) ? 1 : 0;
+
+ imsg_compose(&ibuf, IMSG_CTL_SHOW_LDP_SYNC, 0, 0, -1, NULL, 0);
+ return (ldp_vty_dispatch(vty, &ibuf, SHOW_LDP_SYNC, &params));
+}
+
+int
ldp_vty_show_atom_binding(struct vty *vty, const char *peer,
unsigned long local_label, unsigned long remote_label, const char *json)
{
diff --git a/ldpd/ldp_zebra.c b/ldpd/ldp_zebra.c
index d828fbe977..16e9adc9d9 100644
--- a/ldpd/ldp_zebra.c
+++ b/ldpd/ldp_zebra.c
@@ -31,6 +31,7 @@
#include "ldpd.h"
#include "ldpe.h"
#include "lde.h"
+#include "ldp_sync.h"
#include "log.h"
#include "ldp_debug.h"
@@ -46,6 +47,14 @@ static int ldp_zebra_read_pw_status_update(ZAPI_CALLBACK_ARGS);
static void ldp_zebra_connected(struct zclient *);
static void ldp_zebra_filter_update(struct access_list *access);
+static void ldp_zebra_opaque_register(void);
+static void ldp_zebra_opaque_unregister(void);
+static int ldp_sync_zebra_send_announce(void);
+static int ldp_zebra_opaque_msg_handler(ZAPI_CALLBACK_ARGS);
+static void ldp_sync_zebra_start_hello_timer(void);
+static int ldp_sync_zebra_hello(struct thread *thread);
+static void ldp_sync_zebra_init(void);
+
static struct zclient *zclient;
static void
@@ -103,6 +112,95 @@ pw2zpw(struct l2vpn_pw *pw, struct zapi_pw *zpw)
sizeof(zpw->data.ldp.vpn_name));
}
+static void
+ldp_zebra_opaque_register(void)
+{
+ zclient_register_opaque(zclient, LDP_IGP_SYNC_IF_STATE_REQUEST);
+}
+
+static void
+ldp_zebra_opaque_unregister(void)
+{
+ zclient_unregister_opaque(zclient, LDP_IGP_SYNC_IF_STATE_REQUEST);
+}
+
+int
+ldp_sync_zebra_send_state_update(struct ldp_igp_sync_if_state *state)
+{
+ return zclient_send_opaque(zclient, LDP_IGP_SYNC_IF_STATE_UPDATE,
+ (const uint8_t *) state, sizeof(*state));
+}
+
+static int
+ldp_sync_zebra_send_announce(void)
+{
+ struct ldp_igp_sync_announce announce;
+ announce.proto = ZEBRA_ROUTE_LDP;
+
+ return zclient_send_opaque(zclient, LDP_IGP_SYNC_ANNOUNCE_UPDATE,
+ (const uint8_t *) &announce, sizeof(announce));
+}
+
+static int
+ldp_zebra_opaque_msg_handler(ZAPI_CALLBACK_ARGS)
+{
+ struct stream *s;
+ struct zapi_opaque_msg info;
+ struct ldp_igp_sync_if_state_req state_req;
+
+ s = zclient->ibuf;
+
+ if (zclient_opaque_decode(s, &info) != 0)
+ return -1;
+
+ switch (info.type) {
+ case LDP_IGP_SYNC_IF_STATE_REQUEST:
+ STREAM_GET(&state_req, s, sizeof(state_req));
+ main_imsg_compose_ldpe(IMSG_LDP_SYNC_IF_STATE_REQUEST, 0, &state_req,
+ sizeof(state_req));
+ break;
+ default:
+ break;
+ }
+
+stream_failure:
+ return 0;
+}
+
+static void
+ldp_sync_zebra_start_hello_timer(void)
+{
+ thread_add_timer_msec(master, ldp_sync_zebra_hello, NULL, 250, NULL);
+}
+
+static int
+ldp_sync_zebra_hello(struct thread *thread)
+{
+ static unsigned int sequence = 0;
+ struct ldp_igp_sync_hello hello;
+
+ sequence++;
+
+ hello.proto = ZEBRA_ROUTE_LDP;
+ hello.sequence = sequence;
+
+ zclient_send_opaque(zclient, LDP_IGP_SYNC_HELLO_UPDATE,
+ (const uint8_t *) &hello, sizeof(hello));
+
+ ldp_sync_zebra_start_hello_timer();
+
+ return (0);
+}
+
+static void
+ldp_sync_zebra_init(void)
+{
+ ldp_sync_zebra_send_announce();
+
+ ldp_sync_zebra_start_hello_timer();
+}
+
+
static int
ldp_zebra_send_mpls_labels(int cmd, struct kroute *kr)
{
@@ -299,7 +397,7 @@ ldp_ifp_destroy(struct interface *ifp)
}
static int
-ldp_interface_status_change_helper(struct interface *ifp)
+ldp_interface_status_change(struct interface *ifp)
{
struct listnode *node;
struct connected *ifc;
@@ -330,12 +428,12 @@ ldp_interface_status_change_helper(struct interface *ifp)
static int ldp_ifp_up(struct interface *ifp)
{
- return ldp_interface_status_change_helper(ifp);
+ return ldp_interface_status_change(ifp);
}
static int ldp_ifp_down(struct interface *ifp)
{
- return ldp_interface_status_change_helper(ifp);
+ return ldp_interface_status_change(ifp);
}
static int
@@ -525,6 +623,10 @@ ldp_zebra_connected(struct zclient *zclient)
ZEBRA_ROUTE_ALL, 0, VRF_DEFAULT);
zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP6,
ZEBRA_ROUTE_ALL, 0, VRF_DEFAULT);
+
+ ldp_zebra_opaque_register();
+
+ ldp_sync_zebra_init();
}
static void
@@ -563,6 +665,7 @@ ldp_zebra_init(struct thread_master *master)
zclient->redistribute_route_add = ldp_zebra_read_route;
zclient->redistribute_route_del = ldp_zebra_read_route;
zclient->pw_status_update = ldp_zebra_read_pw_status_update;
+ zclient->opaque_msg_handler = ldp_zebra_opaque_msg_handler;
/* Access list initialize. */
access_list_add_hook(ldp_zebra_filter_update);
@@ -572,6 +675,7 @@ ldp_zebra_init(struct thread_master *master)
void
ldp_zebra_destroy(void)
{
+ ldp_zebra_opaque_unregister();
zclient_stop(zclient);
zclient_free(zclient);
zclient = NULL;
diff --git a/ldpd/ldpd.c b/ldpd/ldpd.c
index dca379e4eb..940333f83c 100644
--- a/ldpd/ldpd.c
+++ b/ldpd/ldpd.c
@@ -586,6 +586,13 @@ main_dispatch_ldpe(struct thread *thread)
fatalx("IMSG_ACL_CHECK imsg with wrong len");
ldp_acl_reply(iev, (struct acl_check *)imsg.data);
break;
+ case IMSG_LDP_SYNC_IF_STATE_UPDATE:
+ if (imsg.hdr.len != IMSG_HEADER_SIZE +
+ sizeof(struct ldp_igp_sync_if_state))
+ fatalx("IMSG_LDP_SYNC_IF_STATE_UPDATE imsg with wrong len");
+
+ ldp_sync_zebra_send_state_update((struct ldp_igp_sync_if_state *)imsg.data);
+ break;
default:
log_debug("%s: error handling imsg %d", __func__,
imsg.hdr.type);
@@ -1148,6 +1155,7 @@ ldp_config_reset_main(struct ldpd_conf *conf)
conf->lhello_interval = DEFAULT_HELLO_INTERVAL;
conf->thello_holdtime = TARGETED_DFLT_HOLDTIME;
conf->thello_interval = DEFAULT_HELLO_INTERVAL;
+ conf->wait_for_sync_interval = DFLT_WAIT_FOR_SYNC;
conf->trans_pref = DUAL_STACK_LDPOV6;
conf->flags = 0;
}
@@ -1278,6 +1286,14 @@ merge_config(struct ldpd_conf *conf, struct ldpd_conf *xconf)
static void
merge_global(struct ldpd_conf *conf, struct ldpd_conf *xconf)
{
+ /* Removing global LDP config requires resetting LDP IGP Sync FSM */
+ if ((conf->flags & F_LDPD_ENABLED) &&
+ (!(xconf->flags & F_LDPD_ENABLED)))
+ {
+ if (ldpd_process == PROC_LDP_ENGINE)
+ ldp_sync_fsm_reset_all();
+ }
+
/* change of router-id requires resetting all neighborships */
if (conf->rtr_id.s_addr != xconf->rtr_id.s_addr) {
if (ldpd_process == PROC_LDP_ENGINE) {
@@ -1303,6 +1319,7 @@ merge_global(struct ldpd_conf *conf, struct ldpd_conf *xconf)
conf->lhello_interval = xconf->lhello_interval;
conf->thello_holdtime = xconf->thello_holdtime;
conf->thello_interval = xconf->thello_interval;
+ conf->wait_for_sync_interval = xconf->wait_for_sync_interval;
if (conf->trans_pref != xconf->trans_pref) {
if (ldpd_process == PROC_LDP_ENGINE)
diff --git a/ldpd/ldpd.h b/ldpd/ldpd.h
index c1bcc56c44..f8a94b4e2a 100644
--- a/ldpd/ldpd.h
+++ b/ldpd/ldpd.h
@@ -34,6 +34,7 @@
#include "zclient.h"
#include "ldp.h"
+#include "lib/ldp_sync.h"
#define CONF_FILE "/etc/ldpd.conf"
#define LDPD_USER "_ldpd"
@@ -93,6 +94,7 @@ enum imsg_type {
IMSG_CTL_SHOW_LIB_END,
IMSG_CTL_SHOW_L2VPN_PW,
IMSG_CTL_SHOW_L2VPN_BINDING,
+ IMSG_CTL_SHOW_LDP_SYNC,
IMSG_CTL_CLEAR_NBR,
IMSG_CTL_FIB_COUPLE,
IMSG_CTL_FIB_DECOUPLE,
@@ -153,7 +155,9 @@ enum imsg_type {
IMSG_INIT,
IMSG_PW_UPDATE,
IMSG_FILTER_UPDATE,
- IMSG_NBR_SHUTDOWN
+ IMSG_NBR_SHUTDOWN,
+ IMSG_LDP_SYNC_IF_STATE_REQUEST,
+ IMSG_LDP_SYNC_IF_STATE_UPDATE
};
struct ldpd_init {
@@ -227,6 +231,34 @@ enum nbr_action {
NBR_ACT_CLOSE_SESSION
};
+/* LDP IGP Sync states */
+#define LDP_SYNC_STA_UNKNOWN 0x0000
+#define LDP_SYNC_STA_NOT_ACH 0x0001
+#define LDP_SYNC_STA_ACH 0x0002
+
+/* LDP IGP Sync events */
+enum ldp_sync_event {
+ LDP_SYNC_EVT_NOTHING,
+ LDP_SYNC_EVT_LDP_SYNC_START,
+ LDP_SYNC_EVT_LDP_SYNC_COMPLETE,
+ LDP_SYNC_EVT_CONFIG_LDP_OFF,
+ LDP_SYNC_EVT_ADJ_DEL,
+ LDP_SYNC_EVT_ADJ_NEW,
+ LDP_SYNC_EVT_SESSION_CLOSE,
+ LDP_SYNC_EVT_CONFIG_LDP_ON,
+ LDP_SYNC_EVT_IFACE_SHUTDOWN
+};
+
+/* LDP IGP Sync actions */
+enum ldp_sync_action {
+ LDP_SYNC_ACT_NOTHING,
+ LDP_SYNC_ACT_IFACE_START_SYNC,
+ LDP_SYNC_ACT_LDP_START_SYNC,
+ LDP_SYNC_ACT_LDP_COMPLETE_SYNC,
+ LDP_SYNC_ACT_CONFIG_LDP_OFF,
+ LDP_SYNC_ACT_IFACE_SHUTDOWN
+};
+
/* forward declarations */
RB_HEAD(global_adj_head, adj);
RB_HEAD(nbr_adj_head, adj);
@@ -310,6 +342,11 @@ struct iface_af {
uint16_t hello_interval;
};
+struct iface_ldp_sync {
+ int state;
+ struct thread *wait_for_sync_timer;
+};
+
struct iface {
RB_ENTRY(iface) entry;
char name[IF_NAMESIZE];
@@ -320,6 +357,7 @@ struct iface {
int operative;
struct iface_af ipv4;
struct iface_af ipv6;
+ struct iface_ldp_sync ldp_sync;
QOBJ_FIELDS
};
RB_HEAD(iface_head, iface);
@@ -518,6 +556,7 @@ struct ldpd_conf {
uint16_t thello_holdtime;
uint16_t thello_interval;
uint16_t trans_pref;
+ uint16_t wait_for_sync_interval;
int flags;
QOBJ_FIELDS
};
@@ -672,6 +711,16 @@ struct ctl_pw {
uint8_t reason;
};
+struct ctl_ldp_sync {
+ char name[IF_NAMESIZE];
+ ifindex_t ifindex;
+ bool in_sync;
+ bool timer_running;
+ uint16_t wait_time;
+ uint16_t wait_time_remaining;
+ struct in_addr peer_ldp_id;
+};
+
extern struct ldpd_conf *ldpd_conf, *vty_conf;
extern struct ldpd_global global;
extern struct ldpd_init init;
@@ -825,6 +874,7 @@ extern char ctl_sock_path[MAXPATHLEN];
/* ldp_zebra.c */
void ldp_zebra_init(struct thread_master *);
void ldp_zebra_destroy(void);
+int ldp_sync_zebra_send_state_update(struct ldp_igp_sync_if_state *);
/* compatibility */
#ifndef __OpenBSD__
diff --git a/ldpd/ldpe.c b/ldpd/ldpe.c
index 9078e711fb..d3374a62db 100644
--- a/ldpd/ldpe.c
+++ b/ldpd/ldpe.c
@@ -297,6 +297,7 @@ ldpe_dispatch_main(struct thread *thread)
#endif
int n, shut = 0;
struct ldp_access *laccess;
+ struct ldp_igp_sync_if_state_req *ldp_sync_if_state_req;
iev->ev_read = NULL;
@@ -559,6 +560,15 @@ ldpe_dispatch_main(struct thread *thread)
ldpe_check_filter_af(AF_INET6, &leconf->ipv6,
laccess->name);
break;
+ case IMSG_LDP_SYNC_IF_STATE_REQUEST:
+ if (imsg.hdr.len != IMSG_HEADER_SIZE +
+ sizeof(struct ldp_igp_sync_if_state_req)) {
+ log_warnx("%s: wrong imsg len", __func__);
+ break;
+ }
+ ldp_sync_if_state_req = imsg.data;
+ ldp_sync_fsm_state_req(ldp_sync_if_state_req);
+ break;
default:
log_debug("ldpe_dispatch_main: error handling imsg %d",
imsg.hdr.type);
@@ -975,6 +985,20 @@ ldpe_nbr_ctl(struct ctl_conn *c)
}
void
+ldpe_ldp_sync_ctl(struct ctl_conn *c)
+{
+ struct iface *iface;
+ struct ctl_ldp_sync *ictl;
+
+ RB_FOREACH(iface, iface_head, &leconf->iface_tree) {
+ ictl = ldp_sync_to_ctl(iface);
+ imsg_compose_event(&c->iev, IMSG_CTL_SHOW_LDP_SYNC,
+ 0, 0, -1, ictl, sizeof(struct ctl_ldp_sync));
+ }
+ imsg_compose_event(&c->iev, IMSG_CTL_END, 0, 0, -1, NULL, 0);
+}
+
+void
mapping_list_add(struct mapping_head *mh, struct map *map)
{
struct mapping_entry *me;
diff --git a/ldpd/ldpe.h b/ldpd/ldpe.h
index 11650069b7..ef4702341b 100644
--- a/ldpd/ldpe.h
+++ b/ldpd/ldpe.h
@@ -28,6 +28,7 @@
#endif
#include "ldpd.h"
+#include "lib/ldp_sync.h"
#define min(x,y) ((x) <= (y) ? (x) : (y))
#define max(x,y) ((x) > (y) ? (x) : (y))
@@ -212,6 +213,7 @@ void ldpe_iface_ctl(struct ctl_conn *c, ifindex_t ifidx);
void ldpe_adj_ctl(struct ctl_conn *);
void ldpe_adj_detail_ctl(struct ctl_conn *);
void ldpe_nbr_ctl(struct ctl_conn *);
+void ldpe_ldp_sync_ctl(struct ctl_conn *);
void mapping_list_add(struct mapping_head *, struct map *);
void mapping_list_clr(struct mapping_head *);
@@ -229,8 +231,17 @@ void ldp_if_update(struct iface *, int);
void if_update_all(int);
uint16_t if_get_hello_holdtime(struct iface_af *);
uint16_t if_get_hello_interval(struct iface_af *);
+uint16_t if_get_wait_for_sync_interval(void);
struct ctl_iface *if_to_ctl(struct iface_af *);
in_addr_t if_get_ipv4_addr(struct iface *);
+int ldp_sync_fsm_adj_event(struct adj *, enum ldp_sync_event);
+int ldp_sync_fsm_nbr_event(struct nbr *, enum ldp_sync_event);
+int ldp_sync_fsm_state_req(struct ldp_igp_sync_if_state_req *);
+int ldp_sync_fsm(struct iface *, enum ldp_sync_event);
+void ldp_sync_fsm_reset_all(void);
+const char *ldp_sync_state_name(int);
+const char *ldp_sync_event_name(int);
+struct ctl_ldp_sync *ldp_sync_to_ctl(struct iface *);
/* adjacency.c */
struct adj *adj_new(struct in_addr, struct hello_source *,
diff --git a/ldpd/neighbor.c b/ldpd/neighbor.c
index 6143beb6b9..236d3eaa58 100644
--- a/ldpd/neighbor.c
+++ b/ldpd/neighbor.c
@@ -764,6 +764,8 @@ nbr_act_session_operational(struct nbr *nbr)
/* this is necessary to avoid ipc synchronization issues */
nbr_update_peerid(nbr);
+ ldp_sync_fsm_nbr_event(nbr, LDP_SYNC_EVT_LDP_SYNC_START);
+
memset(&lde_nbr, 0, sizeof(lde_nbr));
lde_nbr.id = nbr->id;
lde_nbr.v4_enabled = nbr->v4_enabled;
diff --git a/ldpd/packet.c b/ldpd/packet.c
index c00008d120..3f73f8cd88 100644
--- a/ldpd/packet.c
+++ b/ldpd/packet.c
@@ -683,6 +683,8 @@ session_close(struct nbr *nbr)
log_debug("%s: closing session with lsr-id %s", __func__,
inet_ntoa(nbr->id));
+ ldp_sync_fsm_nbr_event(nbr, LDP_SYNC_EVT_SESSION_CLOSE);
+
tcp_close(nbr->tcp);
nbr_stop_ktimer(nbr);
nbr_stop_ktimeout(nbr);
diff --git a/lib/command.h b/lib/command.h
index e20bfe3318..d828989118 100644
--- a/lib/command.h
+++ b/lib/command.h
@@ -421,6 +421,11 @@ struct cmd_node {
#define CMD_VNI_RANGE "(1-16777215)"
#define CONF_BACKUP_EXT ".sav"
+#define MPLS_LDP_SYNC_STR "Enable MPLS LDP-SYNC\n"
+#define NO_MPLS_LDP_SYNC_STR "Disable MPLS LDP-SYNC\n"
+#define MPLS_LDP_SYNC_HOLDDOWN_STR \
+ "Time to wait for LDP-SYNC to occur before restoring if cost\n"
+#define NO_MPLS_LDP_SYNC_HOLDDOWN_STR "holddown timer disable\n"
/* Command warnings. */
#define NO_PASSWD_CMD_WARNING \
diff --git a/lib/ldp_sync.c b/lib/ldp_sync.c
new file mode 100644
index 0000000000..5dd045d88d
--- /dev/null
+++ b/lib/ldp_sync.c
@@ -0,0 +1,93 @@
+/*
+ * ldp_sync.c: LDP-SYNC handling routines
+ * Copyright (C) 2020 Volta Networks, 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 "command.h"
+#include "memory.h"
+#include "prefix.h"
+#include "log.h"
+#include "thread.h"
+#include "stream.h"
+#include "zclient.h"
+#include "table.h"
+#include "vty.h"
+#include "ldp_sync.h"
+
+/* Library code */
+DEFINE_MTYPE_STATIC(LIB, LDP_SYNC_INFO, "LDP SYNC info")
+
+/*
+ * ldp_sync_info_create - Allocate the LDP_SYNC information
+ */
+struct ldp_sync_info *ldp_sync_info_create(void)
+{
+ struct ldp_sync_info *ldp_sync_info;
+
+ ldp_sync_info = XCALLOC(MTYPE_LDP_SYNC_INFO,
+ sizeof(struct ldp_sync_info));
+ assert(ldp_sync_info);
+
+ ldp_sync_info->flags = 0;
+ ldp_sync_info->enabled = LDP_IGP_SYNC_DEFAULT;
+ ldp_sync_info->state = LDP_IGP_SYNC_STATE_NOT_REQUIRED;
+ ldp_sync_info->holddown = LDP_IGP_SYNC_HOLDDOWN_DEFAULT;
+ ldp_sync_info->t_holddown = NULL;
+ return ldp_sync_info;
+}
+
+/*
+ * ldp_sync_info_free - Free the LDP_SYNC information.
+ */
+void ldp_sync_info_free(struct ldp_sync_info **ldp_sync_info)
+{
+ if (*ldp_sync_info)
+ XFREE(MTYPE_LDP_SYNC_INFO, *ldp_sync_info);
+}
+
+bool ldp_sync_if_is_enabled(struct ldp_sync_info *ldp_sync_info)
+{
+ /* return true if LDP-SYNC is configured on this interface */
+ if (ldp_sync_info &&
+ ldp_sync_info->enabled == LDP_IGP_SYNC_ENABLED &&
+ ldp_sync_info->state == LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP)
+ return true;
+
+ return false;
+}
+
+bool ldp_sync_if_down(struct ldp_sync_info *ldp_sync_info)
+{
+ /* Stop LDP-SYNC on this interface:
+ * if holddown timer is running stop it
+ * update state
+ */
+ if (ldp_sync_info && ldp_sync_info->enabled == LDP_IGP_SYNC_ENABLED) {
+ if (ldp_sync_info->t_holddown != NULL) {
+ THREAD_TIMER_OFF(ldp_sync_info->t_holddown);
+ ldp_sync_info->t_holddown = NULL;
+ }
+ if (ldp_sync_info->state == LDP_IGP_SYNC_STATE_REQUIRED_UP)
+ ldp_sync_info->state =
+ LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP;
+ return true;
+ }
+
+ return false;
+}
diff --git a/lib/ldp_sync.h b/lib/ldp_sync.h
new file mode 100644
index 0000000000..daede566f0
--- /dev/null
+++ b/lib/ldp_sync.h
@@ -0,0 +1,91 @@
+/*
+ * Defines and structures common to LDP-Sync for OSPFv2 and OSPFv3 and ISIS
+ * Copyright (C) 2020 Volta Networks, 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 _LIBLDPSYNC_H
+#define _LIBLDPSYNC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* LDP-IGP Sync values */
+#define LDP_SYNC_FLAG_ENABLE (1 << 0) /* LDP-SYNC enabled */
+#define LDP_SYNC_FLAG_HOLDDOWN (1 << 1) /* Holddown timer enabled */
+#define LDP_SYNC_FLAG_IF_CONFIG (1 << 2) /* LDP-SYNC enabled on interface */
+#define LDP_SYNC_FLAG_SET_METRIC (1 << 3) /* Metric has been set on ISIS intf */
+
+#define LDP_IGP_SYNC_DEFAULT 0
+#define LDP_IGP_SYNC_ENABLED 1
+
+#define LDP_IGP_SYNC_STATE_NOT_REQUIRED 0
+#define LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP 1
+#define LDP_IGP_SYNC_STATE_REQUIRED_UP 2
+
+#define LDP_IGP_SYNC_HOLDDOWN_DEFAULT 0
+
+#define LDP_IGP_SYNC_HELLO_TIMEOUT 1
+
+/* LDP-IGP Sync structures */
+struct ldp_sync_info_cmd {
+ uint16_t flags;
+ uint16_t holddown; /* timer value */
+ uint32_t sequence; /* hello sequence number */
+ struct thread *t_hello; /* hello timer for detecting LDP going down */
+};
+
+struct ldp_sync_info {
+ uint16_t flags; /* indicate if set on interface or globally */
+ uint8_t enabled; /* enabled */
+ uint8_t state; /* running state */
+ uint16_t holddown; /* timer value */
+ struct thread *t_holddown; /* holddown timer*/
+ uint32_t metric[2]; /* isis interface metric */
+};
+
+/* Prototypes. */
+extern struct ldp_sync_info *ldp_sync_info_create(void);
+extern bool ldp_sync_if_is_enabled(struct ldp_sync_info *ldp_sync_info);
+extern bool ldp_sync_if_down(struct ldp_sync_info *ldp_sync_info);
+extern void ldp_sync_info_free(struct ldp_sync_info **ldp_sync_info);
+
+struct ldp_igp_sync_announce {
+ int proto;
+};
+
+struct ldp_igp_sync_if_state {
+ ifindex_t ifindex;
+ bool sync_start;
+};
+
+struct ldp_igp_sync_if_state_req {
+ int proto;
+ ifindex_t ifindex;
+ char name[INTERFACE_NAMSIZ];
+};
+
+struct ldp_igp_sync_hello {
+ int proto;
+ unsigned int sequence;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBLDPSYNC_H */
diff --git a/lib/libfrr.c b/lib/libfrr.c
index 500a02aacd..800596c563 100644
--- a/lib/libfrr.c
+++ b/lib/libfrr.c
@@ -45,6 +45,7 @@
#include "defaults.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, (), ())
@@ -913,6 +914,8 @@ static int frr_config_read_in(struct thread *t)
__func__, nb_err_name(ret), errmsg);
}
+ hook_call(frr_very_late_init, master);
+
return 0;
}
diff --git a/lib/libfrr.h b/lib/libfrr.h
index 9d91ea9154..ab72299206 100644
--- a/lib/libfrr.h
+++ b/lib/libfrr.h
@@ -136,6 +136,7 @@ extern const char *frr_get_progname(void);
extern enum frr_cli_mode frr_get_cli_mode(void);
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);
diff --git a/lib/netns_linux.c b/lib/netns_linux.c
index 98f359401e..e8d549b4e0 100644
--- a/lib/netns_linux.c
+++ b/lib/netns_linux.c
@@ -379,12 +379,20 @@ struct ns *ns_lookup(ns_id_t ns_id)
return ns_lookup_internal(ns_id);
}
-void ns_walk_func(int (*func)(struct ns *))
+void ns_walk_func(int (*func)(struct ns *,
+ void *param_in,
+ void **param_out),
+ void *param_in,
+ void **param_out)
{
struct ns *ns = NULL;
+ int ret;
- RB_FOREACH (ns, ns_head, &ns_tree)
- func(ns);
+ RB_FOREACH (ns, ns_head, &ns_tree) {
+ ret = func(ns, param_in, param_out);
+ if (ret == NS_WALK_STOP)
+ return;
+ }
}
const char *ns_get_name(struct ns *ns)
@@ -584,9 +592,35 @@ int ns_socket(int domain, int type, int protocol, ns_id_t ns_id)
return ret;
}
+/* if relative link_nsid matches default netns,
+ * then return default absolute netns value
+ * otherwise, return NS_UNKNOWN
+ */
+ns_id_t ns_id_get_absolute(ns_id_t ns_id_reference, ns_id_t link_nsid)
+{
+ struct ns *ns;
+
+ ns = ns_lookup(ns_id_reference);
+ if (!ns)
+ return NS_UNKNOWN;
+
+ if (ns->relative_default_ns != link_nsid)
+ return NS_UNKNOWN;
+
+ ns = ns_get_default();
+ assert(ns);
+ return ns->ns_id;
+}
+
ns_id_t ns_get_default_id(void)
{
if (default_ns)
return default_ns->ns_id;
return NS_DEFAULT_INTERNAL;
}
+
+struct ns *ns_get_default(void)
+{
+ return default_ns;
+}
+
diff --git a/lib/northbound.c b/lib/northbound.c
index 18500a8bd2..99c6ab57ec 100644
--- a/lib/northbound.c
+++ b/lib/northbound.c
@@ -122,8 +122,8 @@ static int nb_node_new_cb(const struct lys_node *snode, void *arg)
if (CHECK_FLAG(snode->nodetype, LYS_CONTAINER | LYS_LIST)) {
bool config_only = true;
- yang_snodes_iterate_subtree(snode, nb_node_check_config_only,
- YANG_ITER_ALLOW_AUGMENTATIONS,
+ yang_snodes_iterate_subtree(snode, NULL,
+ nb_node_check_config_only, 0,
&config_only);
if (config_only)
SET_FLAG(nb_node->flags, F_NB_NODE_CONFIG_ONLY);
@@ -141,6 +141,7 @@ static int nb_node_new_cb(const struct lys_node *snode, void *arg)
* another.
*/
nb_node->snode = snode;
+ assert(snode->priv == NULL);
lys_set_private(snode, nb_node);
return YANG_ITER_CONTINUE;
@@ -383,6 +384,10 @@ static void nb_config_diff_add_change(struct nb_config_cbs *changes,
{
struct nb_config_change *change;
+ /* Ignore unimplemented nodes. */
+ if (!dnode->schema->priv)
+ return;
+
change = XCALLOC(MTYPE_TMP, sizeof(*change));
change->cb.operation = operation;
change->cb.seq = *seq;
@@ -416,6 +421,10 @@ static void nb_config_diff_created(const struct lyd_node *dnode, uint32_t *seq,
enum nb_operation operation;
struct lyd_node *child;
+ /* Ignore unimplemented nodes. */
+ if (!dnode->schema->priv)
+ return;
+
switch (dnode->schema->nodetype) {
case LYS_LEAF:
case LYS_LEAFLIST:
@@ -450,6 +459,10 @@ static void nb_config_diff_created(const struct lyd_node *dnode, uint32_t *seq,
static void nb_config_diff_deleted(const struct lyd_node *dnode, uint32_t *seq,
struct nb_config_cbs *changes)
{
+ /* Ignore unimplemented nodes. */
+ if (!dnode->schema->priv)
+ return;
+
if (nb_operation_is_valid(NB_OP_DESTROY, dnode->schema))
nb_config_diff_add_change(changes, NB_OP_DESTROY, seq, dnode);
else if (CHECK_FLAG(dnode->schema->nodetype, LYS_CONTAINER)) {
@@ -618,7 +631,7 @@ static int nb_candidate_validate_code(struct nb_context *context,
struct nb_node *nb_node;
nb_node = child->schema->priv;
- if (!nb_node->cbs.pre_validate)
+ if (!nb_node || !nb_node->cbs.pre_validate)
goto next;
ret = nb_callback_pre_validate(context, nb_node, child,
@@ -1385,7 +1398,7 @@ static void nb_transaction_apply_finish(struct nb_transaction *transaction,
struct nb_node *nb_node;
nb_node = dnode->schema->priv;
- if (!nb_node->cbs.apply_finish)
+ if (!nb_node || !nb_node->cbs.apply_finish)
goto next;
/*
diff --git a/lib/northbound_cli.c b/lib/northbound_cli.c
index ee080bca3f..6ce520149a 100644
--- a/lib/northbound_cli.c
+++ b/lib/northbound_cli.c
@@ -573,7 +573,7 @@ void nb_cli_show_dnode_cmds(struct vty *vty, struct lyd_node *root,
struct nb_node *nb_node;
nb_node = child->schema->priv;
- if (!nb_node->cbs.cli_show)
+ if (!nb_node || !nb_node->cbs.cli_show)
goto next;
/* Skip default values. */
@@ -591,7 +591,7 @@ void nb_cli_show_dnode_cmds(struct vty *vty, struct lyd_node *root,
parent = ly_iter_next_up(child);
if (parent != NULL) {
nb_node = parent->schema->priv;
- if (nb_node->cbs.cli_show_end)
+ if (nb_node && nb_node->cbs.cli_show_end)
(*nb_node->cbs.cli_show_end)(vty, parent);
}
diff --git a/lib/northbound_sysrepo.c b/lib/northbound_sysrepo.c
index 3dec685927..b5ef040a3f 100644
--- a/lib/northbound_sysrepo.c
+++ b/lib/northbound_sysrepo.c
@@ -174,6 +174,9 @@ static int frr_sr_process_change(struct nb_config *candidate,
xpath = sr_data->xpath;
+ DEBUGD(&nb_dbg_client_sysrepo, "sysrepo: processing change [xpath %s]",
+ xpath);
+
/* Non-presence container - nothing to do. */
if (sr_data->type == SR_CONTAINER_T)
return NB_OK;
@@ -223,7 +226,7 @@ static int frr_sr_process_change(struct nb_config *candidate,
ret = nb_candidate_edit(candidate, nb_node, nb_op, xpath, NULL, data);
yang_data_free(data);
- if (ret != NB_OK) {
+ if (ret != NB_OK && ret != NB_ERR_NOT_FOUND) {
flog_warn(
EC_LIB_NB_CANDIDATE_EDIT_ERROR,
"%s: failed to edit candidate configuration: operation [%s] xpath [%s]",
@@ -235,8 +238,7 @@ static int frr_sr_process_change(struct nb_config *candidate,
}
static int frr_sr_config_change_cb_prepare(sr_session_ctx_t *session,
- const char *module_name,
- bool startup_config)
+ const char *module_name)
{
sr_change_iter_t *it;
int ret;
@@ -275,33 +277,17 @@ static int frr_sr_config_change_cb_prepare(sr_session_ctx_t *session,
transaction = NULL;
context.client = NB_CLIENT_SYSREPO;
- if (startup_config) {
- /*
- * sysrepod sends the entire startup configuration using a
- * single event (SR_EV_ENABLED). This means we need to perform
- * the full two-phase commit protocol in one go here.
- */
- ret = nb_candidate_commit(&context, candidate, true, NULL, NULL,
- errmsg, sizeof(errmsg));
- if (ret != NB_OK && ret != NB_ERR_NO_CHANGES)
- flog_warn(
- EC_LIB_LIBSYSREPO,
- "%s: failed to apply startup configuration: %s (%s)",
- __func__, nb_err_name(ret), errmsg);
- } else {
- /*
- * Validate the configuration changes and allocate all resources
- * required to apply them.
- */
- ret = nb_candidate_commit_prepare(&context, candidate, NULL,
- &transaction, errmsg,
- sizeof(errmsg));
- if (ret != NB_OK && ret != NB_ERR_NO_CHANGES)
- flog_warn(
- EC_LIB_LIBSYSREPO,
- "%s: failed to prepare configuration transaction: %s (%s)",
- __func__, nb_err_name(ret), errmsg);
- }
+ /*
+ * Validate the configuration changes and allocate all resources
+ * required to apply them.
+ */
+ ret = nb_candidate_commit_prepare(&context, candidate, NULL,
+ &transaction, errmsg, sizeof(errmsg));
+ if (ret != NB_OK && ret != NB_ERR_NO_CHANGES)
+ flog_warn(
+ EC_LIB_LIBSYSREPO,
+ "%s: failed to prepare configuration transaction: %s (%s)",
+ __func__, nb_err_name(ret), errmsg);
if (!transaction)
nb_config_free(candidate);
@@ -360,11 +346,8 @@ static int frr_sr_config_change_cb(sr_session_ctx_t *session,
{
switch (sr_ev) {
case SR_EV_ENABLED:
- return frr_sr_config_change_cb_prepare(session, module_name,
- true);
case SR_EV_CHANGE:
- return frr_sr_config_change_cb_prepare(session, module_name,
- false);
+ return frr_sr_config_change_cb_prepare(session, module_name);
case SR_EV_DONE:
return frr_sr_config_change_cb_apply(session, module_name);
case SR_EV_ABORT:
@@ -563,6 +546,10 @@ static void frr_sr_subscribe_config(struct yang_module *module)
{
int ret;
+ DEBUGD(&nb_dbg_client_sysrepo,
+ "sysrepo: subscribing for configuration changes made in the '%s' module",
+ module->name);
+
ret = sr_module_change_subscribe(
session, module->name, NULL, frr_sr_config_change_cb, NULL, 0,
SR_SUBSCR_DEFAULT | SR_SUBSCR_ENABLED | SR_SUBSCR_NO_THREAD,
@@ -586,7 +573,7 @@ static int frr_sr_subscribe_state(const struct lys_node *snode, void *arg)
nb_node = snode->priv;
- DEBUGD(&nb_dbg_client_sysrepo, "%s: providing data to '%s'", __func__,
+ DEBUGD(&nb_dbg_client_sysrepo, "sysrepo: providing data to '%s'",
nb_node->xpath);
ret = sr_oper_get_items_subscribe(
@@ -610,7 +597,7 @@ static int frr_sr_subscribe_rpc(const struct lys_node *snode, void *arg)
nb_node = snode->priv;
- DEBUGD(&nb_dbg_client_sysrepo, "%s: providing RPC to '%s'", __func__,
+ DEBUGD(&nb_dbg_client_sysrepo, "sysrepo: providing RPC to '%s'",
nb_node->xpath);
ret = sr_rpc_subscribe(session, nb_node->xpath, frr_sr_config_rpc_cb,
@@ -742,7 +729,7 @@ static int frr_sr_finish(void)
return 0;
}
-static int frr_sr_module_late_init(struct thread_master *tm)
+static int frr_sr_module_very_late_init(struct thread_master *tm)
{
master = tm;
@@ -753,6 +740,12 @@ static int frr_sr_module_late_init(struct thread_master *tm)
}
hook_register(frr_fini, frr_sr_finish);
+
+ return 0;
+}
+
+static int frr_sr_module_late_init(struct thread_master *tm)
+{
frr_sr_cli_init();
return 0;
@@ -761,6 +754,7 @@ static int frr_sr_module_late_init(struct thread_master *tm)
static int frr_sr_module_init(void)
{
hook_register(frr_late_init, frr_sr_module_late_init);
+ hook_register(frr_very_late_init, frr_sr_module_very_late_init);
return 0;
}
diff --git a/lib/ns.h b/lib/ns.h
index 20e0a38e3b..286ff5b295 100644
--- a/lib/ns.h
+++ b/lib/ns.h
@@ -53,6 +53,11 @@ struct ns {
/* Identifier, mapped on the NSID value */
ns_id_t internal_ns_id;
+ /* Identifier, value of NSID of default netns,
+ * relative value in that local netns
+ */
+ ns_id_t relative_default_ns;
+
/* Name */
char *name;
@@ -120,7 +125,14 @@ int ns_socket(int domain, int type, int protocol, ns_id_t ns_id);
extern char *ns_netns_pathname(struct vty *vty, const char *name);
/* Parse and execute a function on all the NETNS */
-extern void ns_walk_func(int (*func)(struct ns *));
+#define NS_WALK_CONTINUE 0
+#define NS_WALK_STOP 1
+
+extern void ns_walk_func(int (*func)(struct ns *,
+ void *,
+ void **),
+ void *param_in,
+ void **param_out);
/* API to get the NETNS name, from the ns pointer */
extern const char *ns_get_name(struct ns *ns);
@@ -174,7 +186,9 @@ extern struct ns *ns_lookup_name(const char *name);
*/
extern int ns_enable(struct ns *ns, void (*func)(ns_id_t, void *));
extern struct ns *ns_get_created(struct ns *ns, char *name, ns_id_t ns_id);
+extern ns_id_t ns_id_get_absolute(ns_id_t ns_id_reference, ns_id_t link_nsid);
extern void ns_disable(struct ns *ns);
+extern struct ns *ns_get_default(void);
#ifdef __cplusplus
}
diff --git a/lib/pbr.h b/lib/pbr.h
index 53a63122cc..e365888662 100644
--- a/lib/pbr.h
+++ b/lib/pbr.h
@@ -97,7 +97,8 @@ struct pbr_rule {
uint32_t unique;
struct pbr_filter filter;
struct pbr_action action;
- ifindex_t ifindex;
+
+ char ifname[INTERFACE_NAMSIZ + 1];
};
/* TCP flags value shared
diff --git a/lib/subdir.am b/lib/subdir.am
index 1feaa56d13..b8bcee139b 100644
--- a/lib/subdir.am
+++ b/lib/subdir.am
@@ -42,6 +42,7 @@ lib_libfrr_la_SOURCES = \
lib/jhash.c \
lib/json.c \
lib/keychain.c \
+ lib/ldp_sync.c \
lib/lib_errors.c \
lib/lib_vty.c \
lib/libfrr.c \
@@ -198,6 +199,7 @@ pkginclude_HEADERS += \
lib/jhash.h \
lib/json.h \
lib/keychain.h \
+ lib/ldp_sync.h \
lib/lib_errors.h \
lib/lib_vty.h \
lib/libfrr.h \
diff --git a/lib/thread.c b/lib/thread.c
index 19e4827283..db35a3f031 100644
--- a/lib/thread.c
+++ b/lib/thread.c
@@ -438,7 +438,8 @@ struct thread_master *thread_master_create(const char *name)
pthread_cond_init(&rv->cancel_cond, NULL);
/* Set name */
- rv->name = name ? XSTRDUP(MTYPE_THREAD_MASTER, name) : NULL;
+ name = name ? name : "default";
+ rv->name = XSTRDUP(MTYPE_THREAD_MASTER, name);
/* Initialize I/O task data structures */
getrlimit(RLIMIT_NOFILE, &limit);
@@ -449,10 +450,13 @@ struct thread_master *thread_master_create(const char *name)
rv->write = XCALLOC(MTYPE_THREAD_POLL,
sizeof(struct thread *) * rv->fd_limit);
+ char tmhashname[strlen(name) + 32];
+ snprintf(tmhashname, sizeof(tmhashname), "%s - threadmaster event hash",
+ name);
rv->cpu_record = hash_create_size(
8, (unsigned int (*)(const void *))cpu_record_hash_key,
(bool (*)(const void *, const void *))cpu_record_hash_cmp,
- "Thread Hash");
+ tmhashname);
thread_list_init(&rv->event);
thread_list_init(&rv->ready);
diff --git a/lib/vrf.c b/lib/vrf.c
index 2a3ce2a315..cc7445558c 100644
--- a/lib/vrf.c
+++ b/lib/vrf.c
@@ -159,10 +159,6 @@ struct vrf *vrf_get(vrf_id_t vrf_id, const char *name)
struct vrf *vrf = NULL;
int new = 0;
- if (debug_vrf)
- zlog_debug("VRF_GET: %s(%u)", name == NULL ? "(NULL)" : name,
- vrf_id);
-
/* Nothing to see, move along here */
if (!name && vrf_id == VRF_UNKNOWN)
return NULL;
@@ -225,7 +221,8 @@ struct vrf *vrf_get(vrf_id_t vrf_id, const char *name)
void vrf_delete(struct vrf *vrf)
{
if (debug_vrf)
- zlog_debug("VRF %u is to be deleted.", vrf->vrf_id);
+ zlog_debug("VRF %s(%u) is to be deleted.", vrf->name,
+ vrf->vrf_id);
if (vrf_is_enabled(vrf))
vrf_disable(vrf);
@@ -282,7 +279,7 @@ int vrf_enable(struct vrf *vrf)
return 1;
if (debug_vrf)
- zlog_debug("VRF %u is enabled.", vrf->vrf_id);
+ zlog_debug("VRF %s(%u) is enabled.", vrf->name, vrf->vrf_id);
SET_FLAG(vrf->status, VRF_ACTIVE);
@@ -312,11 +309,20 @@ void vrf_disable(struct vrf *vrf)
UNSET_FLAG(vrf->status, VRF_ACTIVE);
if (debug_vrf)
- zlog_debug("VRF %u is to be disabled.", vrf->vrf_id);
+ zlog_debug("VRF %s(%u) is to be disabled.", vrf->name,
+ vrf->vrf_id);
/* Till now, nothing to be done for the default VRF. */
// Pending: see why this statement.
+
+ /*
+ * When the vrf is disabled let's
+ * handle all nexthop-groups associated
+ * with this vrf
+ */
+ nexthop_group_disable_vrf(vrf);
+
if (vrf_master.vrf_disable_hook)
(*vrf_master.vrf_disable_hook)(vrf);
}
@@ -653,7 +659,8 @@ int vrf_handler_create(struct vty *vty, const char *vrfname,
}
int vrf_netns_handler_create(struct vty *vty, struct vrf *vrf, char *pathname,
- ns_id_t ns_id, ns_id_t internal_ns_id)
+ ns_id_t ns_id, ns_id_t internal_ns_id,
+ ns_id_t rel_def_ns_id)
{
struct ns *ns = NULL;
@@ -700,6 +707,7 @@ int vrf_netns_handler_create(struct vty *vty, struct vrf *vrf, char *pathname,
}
ns = ns_get_created(ns, pathname, ns_id);
ns->internal_ns_id = internal_ns_id;
+ ns->relative_default_ns = rel_def_ns_id;
ns->vrf_ctxt = (void *)vrf;
vrf->ns_ctxt = (void *)ns;
/* update VRF netns NAME */
@@ -795,7 +803,9 @@ DEFUN_NOSH (vrf_netns,
frr_with_privs(vrf_daemon_privs) {
ret = vrf_netns_handler_create(vty, vrf, pathname,
- NS_UNKNOWN, NS_UNKNOWN);
+ NS_UNKNOWN,
+ NS_UNKNOWN,
+ NS_UNKNOWN);
}
return ret;
}
diff --git a/lib/vrf.h b/lib/vrf.h
index 83ed16b48e..a8514d74ed 100644
--- a/lib/vrf.h
+++ b/lib/vrf.h
@@ -315,7 +315,7 @@ extern int vrf_handler_create(struct vty *vty, const char *name,
*/
extern int vrf_netns_handler_create(struct vty *vty, struct vrf *vrf,
char *pathname, ns_id_t ext_ns_id,
- ns_id_t ns_id);
+ ns_id_t ns_id, ns_id_t rel_def_ns_id);
/* used internally to enable or disable VRF.
* Notify a change in the VRF ID of the VRF
diff --git a/lib/yang.c b/lib/yang.c
index 9bfdcb858c..5bf7758e18 100644
--- a/lib/yang.c
+++ b/lib/yang.c
@@ -147,11 +147,15 @@ struct yang_module *yang_module_find(const char *module_name)
}
int yang_snodes_iterate_subtree(const struct lys_node *snode,
+ const struct lys_module *module,
yang_iterate_cb cb, uint16_t flags, void *arg)
{
struct lys_node *child;
int ret = YANG_ITER_CONTINUE;
+ if (module && snode->module != module)
+ goto next;
+
if (CHECK_FLAG(flags, YANG_ITER_FILTER_IMPLICIT)) {
switch (snode->nodetype) {
case LYS_CASE:
@@ -214,11 +218,8 @@ next:
return YANG_ITER_CONTINUE;
LY_TREE_FOR (snode->child, child) {
- if (!CHECK_FLAG(flags, YANG_ITER_ALLOW_AUGMENTATIONS)
- && child->parent != snode)
- continue;
-
- ret = yang_snodes_iterate_subtree(child, cb, flags, arg);
+ ret = yang_snodes_iterate_subtree(child, module, cb, flags,
+ arg);
if (ret == YANG_ITER_STOP)
return ret;
}
@@ -233,15 +234,16 @@ int yang_snodes_iterate_module(const struct lys_module *module,
int ret = YANG_ITER_CONTINUE;
LY_TREE_FOR (module->data, snode) {
- ret = yang_snodes_iterate_subtree(snode, cb, flags, arg);
+ ret = yang_snodes_iterate_subtree(snode, module, cb, flags,
+ arg);
if (ret == YANG_ITER_STOP)
return ret;
}
for (uint8_t i = 0; i < module->augment_size; i++) {
ret = yang_snodes_iterate_subtree(
- (const struct lys_node *)&module->augment[i], cb, flags,
- arg);
+ (const struct lys_node *)&module->augment[i], module,
+ cb, flags, arg);
if (ret == YANG_ITER_STOP)
return ret;
}
@@ -255,9 +257,14 @@ int yang_snodes_iterate_all(yang_iterate_cb cb, uint16_t flags, void *arg)
int ret = YANG_ITER_CONTINUE;
RB_FOREACH (module, yang_modules, &yang_modules) {
- ret = yang_snodes_iterate_module(module->info, cb, flags, arg);
- if (ret == YANG_ITER_STOP)
- return ret;
+ struct lys_node *snode;
+
+ LY_TREE_FOR (module->info->data, snode) {
+ ret = yang_snodes_iterate_subtree(snode, NULL, cb,
+ flags, arg);
+ if (ret == YANG_ITER_STOP)
+ return ret;
+ }
}
return ret;
diff --git a/lib/yang.h b/lib/yang.h
index 94bbed233d..867ade9676 100644
--- a/lib/yang.h
+++ b/lib/yang.h
@@ -102,9 +102,6 @@ enum yang_iter_flags {
/* Filter implicitely created nodes. */
YANG_ITER_FILTER_IMPLICIT = (1<<3),
-
- /* Allow iteration over augmentations. */
- YANG_ITER_ALLOW_AUGMENTATIONS = (1<<4),
};
/* Callback used by the yang_snodes_iterate_*() family of functions. */
@@ -168,6 +165,9 @@ extern void yang_module_embed(struct yang_module_embed *embed);
* snode
* YANG schema node to operate on.
*
+ * module
+ * When set, iterate over all nodes of the specified module only.
+ *
* cb
* Function to call with each schema node.
*
@@ -181,6 +181,7 @@ extern void yang_module_embed(struct yang_module_embed *embed);
* The return value of the last called callback.
*/
extern int yang_snodes_iterate_subtree(const struct lys_node *snode,
+ const struct lys_module *module,
yang_iterate_cb cb, uint16_t flags,
void *arg);
diff --git a/lib/zclient.c b/lib/zclient.c
index b842e7c31b..c5016d22e2 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -1424,7 +1424,7 @@ int zapi_pbr_rule_encode(uint8_t cmd, struct stream *s, struct pbr_rule *zrule)
stream_putw(s, zrule->filter.fwmark); /* fwmark */
stream_putl(s, zrule->action.table);
- stream_putl(s, zrule->ifindex);
+ stream_put(s, zrule->ifname, INTERFACE_NAMSIZ);
/* Put length at the first point of the stream. */
stream_putw_at(s, 0, stream_get_endp(s));
@@ -1454,26 +1454,23 @@ stream_failure:
}
bool zapi_rule_notify_decode(struct stream *s, uint32_t *seqno,
- uint32_t *priority, uint32_t *unique,
- ifindex_t *ifindex,
+ uint32_t *priority, uint32_t *unique, char *ifname,
enum zapi_rule_notify_owner *note)
{
uint32_t prio, seq, uni;
- ifindex_t ifi;
STREAM_GET(note, s, sizeof(*note));
STREAM_GETL(s, seq);
STREAM_GETL(s, prio);
STREAM_GETL(s, uni);
- STREAM_GETL(s, ifi);
+ STREAM_GET(ifname, s, INTERFACE_NAMSIZ);
if (zclient_debug)
- zlog_debug("%s: %u %u %u %u", __func__, seq, prio, uni, ifi);
+ zlog_debug("%s: %u %u %u %s", __func__, seq, prio, uni, ifname);
*seqno = seq;
*priority = prio;
*unique = uni;
- *ifindex = ifi;
return true;
diff --git a/lib/zclient.h b/lib/zclient.h
index c6a67790a1..f99b3ad743 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -844,8 +844,7 @@ bool zapi_route_notify_decode(struct stream *s, struct prefix *p,
uint32_t *tableid,
enum zapi_route_notify_owner *note);
bool zapi_rule_notify_decode(struct stream *s, uint32_t *seqno,
- uint32_t *priority, uint32_t *unique,
- ifindex_t *ifindex,
+ uint32_t *priority, uint32_t *unique, char *ifname,
enum zapi_rule_notify_owner *note);
bool zapi_ipset_notify_decode(struct stream *s,
uint32_t *unique,
@@ -955,6 +954,14 @@ enum zapi_opaque_registry {
LINK_STATE_REQUEST = 1,
/* Update containing link-state db info */
LINK_STATE_UPDATE = 2,
+ /* Request LDP-SYNC state from LDP */
+ LDP_IGP_SYNC_IF_STATE_REQUEST = 3,
+ /* Update containing LDP IGP Sync State info */
+ LDP_IGP_SYNC_IF_STATE_UPDATE = 4,
+ /* Announce that LDP is up */
+ LDP_IGP_SYNC_ANNOUNCE_UPDATE = 5,
+ /* Heartbeat indicating that LDP is running */
+ LDP_IGP_SYNC_HELLO_UPDATE = 6,
};
/* Send the hello message.
diff --git a/lib/zlog_targets.c b/lib/zlog_targets.c
index b23ab073b4..8f4c2a46a8 100644
--- a/lib/zlog_targets.c
+++ b/lib/zlog_targets.c
@@ -225,10 +225,11 @@ static bool zlog_file_cycle(struct zlog_cfg_file *zcf)
zlt->zt.logfn_sigsafe = zlog_fd_sigsafe;
} while (0);
- old = zlog_target_replace(&zcf->active->zt, &zlt->zt);
+ old = zlog_target_replace(zcf->active ? &zcf->active->zt : NULL,
+ zlt ? &zlt->zt : NULL);
zcf->active = zlt;
- zlog_file_target_free(container_of(old, struct zlt_fd, zt));
+ zlog_file_target_free(container_of_null(old, struct zlt_fd, zt));
return rv;
}
diff --git a/ospfd/ospf_abr.c b/ospfd/ospf_abr.c
index f6c0504999..5a9adcba0d 100644
--- a/ospfd/ospf_abr.c
+++ b/ospfd/ospf_abr.c
@@ -642,6 +642,15 @@ static int ospf_abr_translate_nssa(struct ospf_area *area, struct ospf_lsa *lsa)
old = ospf_external_info_find_lsa(area->ospf, &p);
if (old) {
+ /* Do not continue if type 5 LSA not approved */
+ if (!CHECK_FLAG(old->flags, OSPF_LSA_APPROVED)) {
+ if (IS_DEBUG_OSPF_NSSA)
+ zlog_debug(
+ "ospf_abr_translate_nssa(): LSA Id %s type 5 is not approved",
+ inet_ntoa(old->data->id));
+ return 1;
+ }
+
if (IS_DEBUG_OSPF_NSSA)
zlog_debug(
"ospf_abr_translate_nssa(): found old translated LSA Id %s, refreshing",
diff --git a/ospfd/ospf_dump.c b/ospfd/ospf_dump.c
index dcc479def6..e8798e023e 100644
--- a/ospfd/ospf_dump.c
+++ b/ospfd/ospf_dump.c
@@ -54,6 +54,7 @@ unsigned long conf_debug_ospf_te = 0;
unsigned long conf_debug_ospf_ext = 0;
unsigned long conf_debug_ospf_sr = 0;
unsigned long conf_debug_ospf_defaultinfo = 0;
+unsigned long conf_debug_ospf_ldp_sync = 0;
/* Enable debug option variables -- valid only session. */
unsigned long term_debug_ospf_packet[5] = {0, 0, 0, 0, 0};
@@ -67,6 +68,7 @@ unsigned long term_debug_ospf_te = 0;
unsigned long term_debug_ospf_ext = 0;
unsigned long term_debug_ospf_sr = 0;
unsigned long term_debug_ospf_defaultinfo;
+unsigned long term_debug_ospf_ldp_sync;
const char *ospf_redist_string(unsigned int route_type)
{
@@ -1476,6 +1478,32 @@ DEFUN (no_debug_ospf_default_info,
return CMD_SUCCESS;
}
+DEFUN(debug_ospf_ldp_sync,
+ debug_ospf_ldp_sync_cmd,
+ "debug ospf ldp-sync",
+ DEBUG_STR OSPF_STR
+ "OSPF LDP-Sync information\n")
+{
+ if (vty->node == CONFIG_NODE)
+ CONF_DEBUG_ON(ldp_sync, LDP_SYNC);
+ TERM_DEBUG_ON(ldp_sync, LDP_SYNC);
+ return CMD_SUCCESS;
+}
+
+DEFUN(no_debug_ospf_ldp_sync,
+ no_debug_ospf_ldp_sync_cmd,
+ "no debug ospf ldp-sync",
+ NO_STR
+ DEBUG_STR
+ OSPF_STR
+ "OSPF LDP-Sync information\n")
+{
+ if (vty->node == CONFIG_NODE)
+ CONF_DEBUG_OFF(ldp_sync, LDP_SYNC);
+ TERM_DEBUG_OFF(ldp_sync, LDP_SYNC);
+ return CMD_SUCCESS;
+}
+
DEFUN (no_debug_ospf,
no_debug_ospf_cmd,
"no debug ospf",
@@ -1505,6 +1533,7 @@ DEFUN (no_debug_ospf,
DEBUG_OFF(zebra, ZEBRA_INTERFACE);
DEBUG_OFF(zebra, ZEBRA_REDISTRIBUTE);
DEBUG_OFF(defaultinfo, DEFAULTINFO);
+ DEBUG_OFF(ldp_sync, LDP_SYNC);
for (i = 0; i < 5; i++)
DEBUG_PACKET_OFF(i, flag);
@@ -1532,6 +1561,7 @@ DEFUN (no_debug_ospf,
TERM_DEBUG_OFF(zebra, ZEBRA_INTERFACE);
TERM_DEBUG_OFF(zebra, ZEBRA_REDISTRIBUTE);
TERM_DEBUG_OFF(defaultinfo, DEFAULTINFO);
+ TERM_DEBUG_OFF(ldp_sync, LDP_SYNC);
return CMD_SUCCESS;
}
@@ -1633,6 +1663,10 @@ static int show_debugging_ospf_common(struct vty *vty, struct ospf *ospf)
if (IS_DEBUG_OSPF(nssa, NSSA) == OSPF_DEBUG_NSSA)
vty_out(vty, " OSPF NSSA debugging is on\n");
+ /* Show debug status for LDP-SYNC. */
+ if (IS_DEBUG_OSPF(ldp_sync, LDP_SYNC) == OSPF_DEBUG_LDP_SYNC)
+ vty_out(vty, " OSPF ldp-sync debugging is on\n");
+
vty_out(vty, "\n");
return CMD_SUCCESS;
@@ -1814,6 +1848,11 @@ static int config_write_debug(struct vty *vty)
write = 1;
}
+ /* debug ospf ldp-sync */
+ if (IS_CONF_DEBUG_OSPF(ldp_sync, LDP_SYNC) == OSPF_DEBUG_LDP_SYNC) {
+ vty_out(vty, "debug ospf%s ldp-sync\n", str);
+ write = 1;
+ }
return write;
}
@@ -1832,6 +1871,7 @@ void ospf_debug_init(void)
install_element(ENABLE_NODE, &debug_ospf_te_cmd);
install_element(ENABLE_NODE, &debug_ospf_sr_cmd);
install_element(ENABLE_NODE, &debug_ospf_default_info_cmd);
+ install_element(ENABLE_NODE, &debug_ospf_ldp_sync_cmd);
install_element(ENABLE_NODE, &no_debug_ospf_ism_cmd);
install_element(ENABLE_NODE, &no_debug_ospf_nsm_cmd);
install_element(ENABLE_NODE, &no_debug_ospf_lsa_cmd);
@@ -1841,6 +1881,7 @@ void ospf_debug_init(void)
install_element(ENABLE_NODE, &no_debug_ospf_te_cmd);
install_element(ENABLE_NODE, &no_debug_ospf_sr_cmd);
install_element(ENABLE_NODE, &no_debug_ospf_default_info_cmd);
+ install_element(ENABLE_NODE, &no_debug_ospf_ldp_sync_cmd);
install_element(ENABLE_NODE, &show_debugging_ospf_instance_cmd);
install_element(ENABLE_NODE, &debug_ospf_packet_cmd);
@@ -1871,6 +1912,7 @@ void ospf_debug_init(void)
install_element(CONFIG_NODE, &debug_ospf_te_cmd);
install_element(CONFIG_NODE, &debug_ospf_sr_cmd);
install_element(CONFIG_NODE, &debug_ospf_default_info_cmd);
+ install_element(CONFIG_NODE, &debug_ospf_ldp_sync_cmd);
install_element(CONFIG_NODE, &no_debug_ospf_nsm_cmd);
install_element(CONFIG_NODE, &no_debug_ospf_lsa_cmd);
install_element(CONFIG_NODE, &no_debug_ospf_zebra_cmd);
@@ -1879,6 +1921,7 @@ void ospf_debug_init(void)
install_element(CONFIG_NODE, &no_debug_ospf_te_cmd);
install_element(CONFIG_NODE, &no_debug_ospf_sr_cmd);
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_instance_nsm_cmd);
install_element(CONFIG_NODE, &debug_ospf_instance_lsa_cmd);
diff --git a/ospfd/ospf_dump.h b/ospfd/ospf_dump.h
index 8c01977ff8..faae27e2cf 100644
--- a/ospfd/ospf_dump.h
+++ b/ospfd/ospf_dump.h
@@ -60,6 +60,7 @@
#define OSPF_DEBUG_EXT 0x08
#define OSPF_DEBUG_SR 0x10
#define OSPF_DEBUG_DEFAULTINFO 0x20
+#define OSPF_DEBUG_LDP_SYNC 0x40
/* Macro for setting debug option. */
#define CONF_DEBUG_PACKET_ON(a, b) conf_debug_ospf_packet[a] |= (b)
@@ -107,6 +108,8 @@
#define IS_DEBUG_OSPF_DEFAULT_INFO IS_DEBUG_OSPF(defaultinfo, DEFAULTINFO)
+#define IS_DEBUG_OSPF_LDP_SYNC IS_DEBUG_OSPF(ldp_sync, LDP_SYNC)
+
#define IS_CONF_DEBUG_OSPF_PACKET(a, b) \
(conf_debug_ospf_packet[a] & OSPF_DEBUG_##b)
#define IS_CONF_DEBUG_OSPF(a, b) (conf_debug_ospf_##a & OSPF_DEBUG_##b)
@@ -126,6 +129,7 @@ extern unsigned long term_debug_ospf_te;
extern unsigned long term_debug_ospf_ext;
extern unsigned long term_debug_ospf_sr;
extern unsigned long term_debug_ospf_defaultinfo;
+extern unsigned long term_debug_ospf_ldp_sync;
/* Message Strings. */
extern char *ospf_lsa_type_str[];
diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c
index af801da8d7..adc3037598 100644
--- a/ospfd/ospf_interface.c
+++ b/ospfd/ospf_interface.c
@@ -32,6 +32,7 @@
#include "log.h"
#include "zclient.h"
#include "bfd.h"
+#include "ldp_sync.h"
#include "ospfd/ospfd.h"
#include "ospfd/ospf_spf.h"
@@ -46,6 +47,7 @@
#include "ospfd/ospf_abr.h"
#include "ospfd/ospf_network.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))
@@ -81,6 +83,12 @@ int ospf_if_get_output_cost(struct ospf_interface *oi)
uint32_t cost;
uint32_t bw, refbw;
+ /* if LDP-IGP Sync is running on interface set cost so interface
+ * is used only as last resort
+ */
+ if (ldp_sync_if_is_enabled(IF_DEF_PARAMS(oi->ifp)->ldp_sync_info))
+ return (LDP_OSPF_LSINFINITY);
+
/* ifp speed and bw can be 0 in some platforms, use ospf default bw
if bw is configured under interface it would be used.
*/
@@ -539,6 +547,7 @@ void ospf_del_if_params(struct ospf_if_params *oip)
{
list_delete(&oip->auth_crypt);
bfd_info_free(&(oip->bfd_info));
+ ldp_sync_info_free(&(oip->ldp_sync_info));
XFREE(MTYPE_OSPF_IF_PARAMS, oip);
}
diff --git a/ospfd/ospf_interface.h b/ospfd/ospf_interface.h
index 4b3dbcc5c2..1d28eac6b3 100644
--- a/ospfd/ospf_interface.h
+++ b/ospfd/ospf_interface.h
@@ -104,6 +104,9 @@ struct ospf_if_params {
/* BFD configuration */
struct bfd_info *bfd_info;
+
+ /* MPLS LDP-IGP Sync configuration */
+ struct ldp_sync_info *ldp_sync_info;
};
enum { MEMBER_ALLROUTERS = 0,
diff --git a/ospfd/ospf_ldp_sync.c b/ospfd/ospf_ldp_sync.c
new file mode 100644
index 0000000000..a8c9df1c56
--- /dev/null
+++ b/ospfd/ospf_ldp_sync.c
@@ -0,0 +1,1142 @@
+/*
+ * ospf_ldp_sync.c: OSPF LDP-IGP Sync handling routines
+ * Copyright (C) 2020 Volta Networks, 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 <string.h>
+
+#include "monotime.h"
+#include "memory.h"
+#include "thread.h"
+#include "prefix.h"
+#include "table.h"
+#include "vty.h"
+#include "command.h"
+#include "plist.h"
+#include "log.h"
+#include "zclient.h"
+#include <lib/json.h>
+#include "defaults.h"
+#include "ldp_sync.h"
+
+#include "ospfd.h"
+#include "ospf_interface.h"
+#include "ospf_vty.h"
+#include "ospf_ldp_sync.h"
+#include "ospf_dump.h"
+#include "ospf_ism.h"
+
+extern struct zclient *zclient;
+
+/*
+ * LDP-SYNC msg between IGP and LDP
+ */
+int ospf_ldp_sync_state_update(struct ldp_igp_sync_if_state state)
+{
+ struct ospf *ospf;
+ struct interface *ifp;
+
+ /* if ospf is not enabled or LDP-SYNC is not configured ignore */
+ ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
+ if (ospf == NULL ||
+ !CHECK_FLAG(ospf->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE))
+ return 0;
+
+ /* received ldp-sync interface state from LDP */
+ ifp = if_lookup_by_index(state.ifindex, VRF_DEFAULT);
+ if (ifp == NULL || if_is_loopback(ifp))
+ return 0;
+
+ ols_debug("ldp_sync: rcvd %s from LDP if %s",
+ state.sync_start ? "sync-start" : "sync-complete",
+ ifp->name);
+ if (state.sync_start)
+ ospf_ldp_sync_if_start(ifp, false);
+ else
+ ospf_ldp_sync_if_complete(ifp);
+
+ return 0;
+}
+
+int ospf_ldp_sync_announce_update(struct ldp_igp_sync_announce announce)
+{
+ struct ospf *ospf;
+ struct vrf *vrf;
+ struct interface *ifp;
+
+ /* if ospf is not enabled or LDP-SYNC is not configured ignore */
+ ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
+ if (ospf == NULL ||
+ !CHECK_FLAG(ospf->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE))
+ return 0;
+
+ if (announce.proto != ZEBRA_ROUTE_LDP)
+ return 0;
+
+ ols_debug("ldp_sync: rcvd announce from LDP");
+
+ /* LDP just started up:
+ * set cost to LSInfinity
+ * send request to LDP for LDP-SYNC state for each interface
+ * start hello timer
+ */
+ vrf = vrf_lookup_by_id(ospf->vrf_id);
+ FOR_ALL_INTERFACES (vrf, ifp)
+ ospf_ldp_sync_if_start(ifp, true);
+
+ THREAD_TIMER_OFF(ospf->ldp_sync_cmd.t_hello);
+ ospf->ldp_sync_cmd.t_hello = NULL;
+ ospf->ldp_sync_cmd.sequence = 0;
+ ospf_ldp_sync_hello_timer_add(ospf);
+
+ return 0;
+}
+
+int ospf_ldp_sync_hello_update(struct ldp_igp_sync_hello hello)
+{
+ struct ospf *ospf;
+ struct vrf *vrf;
+ struct interface *ifp;
+
+ /* if ospf is not enabled or LDP-SYNC is not configured ignore */
+ ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
+ if (ospf == NULL ||
+ !CHECK_FLAG(ospf->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE))
+ return 0;
+
+ if (hello.proto != ZEBRA_ROUTE_LDP)
+ return 0;
+
+ /* Received Hello from LDP:
+ * if current sequence number is greater than received hello
+ * sequence number then assume LDP restarted
+ * set cost to LSInfinity
+ * send request to LDP for LDP-SYNC state for each interface
+ * else all is fine just restart hello timer
+ */
+ if (hello.sequence == 0)
+ /* rolled over */
+ ospf->ldp_sync_cmd.sequence = 0;
+
+ if (ospf->ldp_sync_cmd.sequence > hello.sequence) {
+ zlog_err("ldp_sync: LDP restarted");
+
+ vrf = vrf_lookup_by_id(ospf->vrf_id);
+ FOR_ALL_INTERFACES (vrf, ifp)
+ ospf_ldp_sync_if_start(ifp, true);
+ } else {
+ THREAD_TIMER_OFF(ospf->ldp_sync_cmd.t_hello);
+ ospf_ldp_sync_hello_timer_add(ospf);
+ }
+ ospf->ldp_sync_cmd.sequence = hello.sequence;
+
+ return 0;
+}
+
+void ospf_ldp_sync_state_req_msg(struct interface *ifp)
+{
+ struct ldp_igp_sync_if_state_req request;
+
+ ols_debug("ldp_sync: send state request to LDP for %s", ifp->name);
+
+ strlcpy(request.name, ifp->name, sizeof(ifp->name));
+ request.proto = LDP_IGP_SYNC_IF_STATE_REQUEST;
+ request.ifindex = ifp->ifindex;
+
+ zclient_send_opaque(zclient, LDP_IGP_SYNC_IF_STATE_REQUEST,
+ (uint8_t *)&request, sizeof(request));
+}
+
+/*
+ * LDP-SYNC general interface routines
+ */
+void ospf_ldp_sync_if_init(struct ospf_interface *oi)
+{
+ struct ospf_if_params *params;
+ struct ldp_sync_info *ldp_sync_info;
+ struct interface *ifp = oi->ifp;
+
+ /* called when OSPF is configured on an interface:
+ * if LDP-IGP Sync is configured globally set state
+ * if ptop interface inform LDP LDP-SYNC is enabled
+ */
+ if (if_is_loopback(ifp) || (ifp->vrf_id != VRF_DEFAULT) ||
+ !(CHECK_FLAG(oi->ospf->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE)))
+ return;
+
+ ols_debug("ldp_sync: init if %s",ifp->name);
+ params = IF_DEF_PARAMS(ifp);
+ if (params->ldp_sync_info == NULL)
+ params->ldp_sync_info = ldp_sync_info_create();
+
+ ldp_sync_info = params->ldp_sync_info;
+
+ /* specifed on interface overrides global config. */
+ if (!CHECK_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_HOLDDOWN))
+ ldp_sync_info->holddown = oi->ospf->ldp_sync_cmd.holddown;
+
+ if (!CHECK_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_IF_CONFIG))
+ ldp_sync_info->enabled = LDP_IGP_SYNC_ENABLED;
+
+ if ((params->type == OSPF_IFTYPE_POINTOPOINT ||
+ if_is_pointopoint(ifp)) &&
+ ldp_sync_info->enabled == LDP_IGP_SYNC_ENABLED)
+ ldp_sync_info->state = LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP;
+}
+
+void ospf_ldp_sync_if_start(struct interface *ifp, bool send_state_req)
+{
+ struct ospf_if_params *params;
+ struct ldp_sync_info *ldp_sync_info;
+
+ if (if_is_loopback(ifp))
+ return;
+
+ params = IF_DEF_PARAMS(ifp);
+ ldp_sync_info = params->ldp_sync_info;
+
+ /* Start LDP-SYNC on this interface:
+ * set cost of interface to LSInfinity so traffic will use different
+ * interface until LDP has learned all labels from peer
+ * start holddown timer if configured
+ * send msg to LDP to get LDP-SYNC state
+ */
+ if (ldp_sync_info &&
+ ldp_sync_info->enabled == LDP_IGP_SYNC_ENABLED &&
+ ldp_sync_info->state != LDP_IGP_SYNC_STATE_NOT_REQUIRED) {
+ ols_debug("ldp_sync: start on if %s state: %s",
+ ifp->name, "Holding down until Sync");
+ ldp_sync_info->state = LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP;
+ ospf_if_recalculate_output_cost(ifp);
+ ospf_ldp_sync_holddown_timer_add(ifp);
+
+ if (send_state_req)
+ ospf_ldp_sync_state_req_msg(ifp);
+ }
+}
+
+void ospf_ldp_sync_if_complete(struct interface *ifp)
+{
+ struct ospf_if_params *params;
+ struct ldp_sync_info *ldp_sync_info;
+
+ if (if_is_loopback(ifp))
+ return;
+
+ params = IF_DEF_PARAMS(ifp);
+ ldp_sync_info = params->ldp_sync_info;
+
+ /* received sync-complete from LDP:
+ * set state to up
+ * stop timer
+ * restore interface cost to original value
+ */
+ if (ldp_sync_info && ldp_sync_info->enabled == LDP_IGP_SYNC_ENABLED) {
+ if (ldp_sync_info->state == LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP)
+ ldp_sync_info->state = LDP_IGP_SYNC_STATE_REQUIRED_UP;
+ THREAD_TIMER_OFF(ldp_sync_info->t_holddown);
+ ldp_sync_info->t_holddown = NULL;
+ ospf_if_recalculate_output_cost(ifp);
+ }
+}
+
+void ospf_ldp_sync_ldp_fail(struct interface *ifp)
+{
+ struct ospf_if_params *params;
+ struct ldp_sync_info *ldp_sync_info;
+
+ if (if_is_loopback(ifp))
+ return;
+
+ params = IF_DEF_PARAMS(ifp);
+ ldp_sync_info = params->ldp_sync_info;
+
+ /* LDP failed to send hello:
+ * stop holddown timer
+ * set cost of interface to LSInfinity so traffic will use different
+ * interface until LDP has learned all labels from peer
+ */
+ if (ldp_sync_info &&
+ ldp_sync_info->enabled == LDP_IGP_SYNC_ENABLED &&
+ ldp_sync_info->state != LDP_IGP_SYNC_STATE_NOT_REQUIRED) {
+ if (ldp_sync_info->t_holddown != NULL) {
+ THREAD_TIMER_OFF(ldp_sync_info->t_holddown);
+ ldp_sync_info->t_holddown = NULL;
+ }
+ ldp_sync_info->state = LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP;
+ ospf_if_recalculate_output_cost(ifp);
+ }
+}
+
+void ospf_ldp_sync_if_down(struct interface *ifp)
+{
+ struct ospf_if_params *params;
+ struct ldp_sync_info *ldp_sync_info;
+
+ if (if_is_loopback(ifp))
+ return;
+
+ params = IF_DEF_PARAMS(ifp);
+ ldp_sync_info = params->ldp_sync_info;
+
+ if (ldp_sync_if_down(ldp_sync_info) == false)
+ return;
+
+ ols_debug("ldp_sync: down on if %s", ifp->name);
+
+ /* Interface down:
+ * can occur from a link down or changing config
+ * ospf network type change interface is brought down/up
+ */
+ switch (ldp_sync_info->state) {
+ case LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP:
+ case LDP_IGP_SYNC_STATE_REQUIRED_UP:
+ if (params->type != OSPF_IFTYPE_POINTOPOINT &&
+ !if_is_pointopoint(ifp))
+ /* LDP-SYNC not able to run on non-ptop interface */
+ ldp_sync_info->state = LDP_IGP_SYNC_STATE_NOT_REQUIRED;
+ break;
+ case LDP_IGP_SYNC_STATE_NOT_REQUIRED:
+ if (params->type == OSPF_IFTYPE_POINTOPOINT ||
+ if_is_pointopoint(ifp))
+ /* LDP-SYNC is able to run on ptop interface */
+ ldp_sync_info->state =
+ LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP;
+ break;
+ default:
+ break;
+ }
+}
+
+void ospf_ldp_sync_if_remove(struct interface *ifp, bool remove)
+{
+ struct ospf_if_params *params;
+ struct ldp_sync_info *ldp_sync_info;
+
+ params = IF_DEF_PARAMS(ifp);
+ if (params->ldp_sync_info == NULL)
+ return;
+
+ ldp_sync_info = params->ldp_sync_info;
+
+ /* Stop LDP-SYNC on this interface:
+ * if holddown timer is running stop it
+ * delete ldp instance on interface
+ * restore cost
+ */
+ ols_debug("ldp_sync: Removed from if %s", ifp->name);
+ if (ldp_sync_info->t_holddown)
+ THREAD_TIMER_OFF(ldp_sync_info->t_holddown);
+ ldp_sync_info->state = LDP_IGP_SYNC_STATE_NOT_REQUIRED;
+ ospf_if_recalculate_output_cost(ifp);
+ if (!CHECK_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_IF_CONFIG))
+ ldp_sync_info->enabled = LDP_IGP_SYNC_DEFAULT;
+ if (remove) {
+ ldp_sync_info_free((struct ldp_sync_info **)&(ldp_sync_info));
+ params->ldp_sync_info = NULL;
+ }
+}
+
+static int ospf_ldp_sync_ism_change(struct ospf_interface *oi, int state,
+ int old_state)
+{
+ /* Terminal state or regression */
+ switch (state) {
+ case ISM_PointToPoint:
+ /* If LDP-SYNC is configure on interface then start */
+ ospf_ldp_sync_if_start(oi->ifp, true);
+ break;
+ case ISM_Down:
+ /* If LDP-SYNC is configure on this interface then stop it */
+ ospf_ldp_sync_if_down(oi->ifp);
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+/*
+ * LDP-SYNC holddown timer routines
+ */
+static int ospf_ldp_sync_holddown_timer(struct thread *thread)
+{
+ struct interface *ifp;
+ struct ospf_if_params *params;
+ struct ldp_sync_info *ldp_sync_info;
+
+ /* holddown timer expired:
+ * didn't receive msg from LDP indicating sync-complete
+ * restore interface cost to original value
+ */
+ ifp = THREAD_ARG(thread);
+ params = IF_DEF_PARAMS(ifp);
+ if (params->ldp_sync_info) {
+ ldp_sync_info = params->ldp_sync_info;
+
+ ldp_sync_info->state = LDP_IGP_SYNC_STATE_REQUIRED_UP;
+ ldp_sync_info->t_holddown = NULL;
+
+ ols_debug("ldp_sync: holddown timer expired for %s state: %s",
+ ifp->name, "Sync achieved");
+
+ ospf_if_recalculate_output_cost(ifp);
+ }
+ return 0;
+}
+
+void ospf_ldp_sync_holddown_timer_add(struct interface *ifp)
+{
+ struct ospf_if_params *params;
+ struct ldp_sync_info *ldp_sync_info;
+
+ params = IF_DEF_PARAMS(ifp);
+ ldp_sync_info = params->ldp_sync_info;
+
+ /* Start holddown timer:
+ * this timer is used to keep interface cost at LSInfinity
+ * once expires returns cost to original value
+ * if timer is already running or holddown time is off just return
+ */
+ if (ldp_sync_info->t_holddown ||
+ ldp_sync_info->holddown == LDP_IGP_SYNC_HOLDDOWN_DEFAULT)
+ return;
+
+ ols_debug("ldp_sync: start holddown timer for %s time %d",
+ ifp->name, ldp_sync_info->holddown);
+
+ thread_add_timer(master, ospf_ldp_sync_holddown_timer,
+ ifp, ldp_sync_info->holddown,
+ &ldp_sync_info->t_holddown);
+}
+
+/*
+ * LDP-SYNC hello timer routines
+ */
+static int ospf_ldp_sync_hello_timer(struct thread *thread)
+{
+ struct ospf *ospf;
+ struct vrf *vrf;
+ struct interface *ifp;
+
+ /* hello timer expired:
+ * didn't receive hello msg from LDP
+ * set cost of all interfaces to LSInfinity
+ */
+ ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
+ if (ospf) {
+ ospf->ldp_sync_cmd.t_hello = NULL;
+ vrf = vrf_lookup_by_id(ospf->vrf_id);
+
+ FOR_ALL_INTERFACES (vrf, ifp)
+ ospf_ldp_sync_ldp_fail(ifp);
+
+ zlog_err("ldp_sync: hello timer expired, LDP down");
+ }
+ return 0;
+}
+
+void ospf_ldp_sync_hello_timer_add(struct ospf *ospf)
+{
+
+ /* Start hello timer:
+ * this timer is used to make sure LDP is up
+ * if expires set interface cost to LSInfinity
+ */
+ if (!CHECK_FLAG(ospf->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE))
+ return;
+
+ thread_add_timer(master, ospf_ldp_sync_hello_timer,
+ NULL, LDP_IGP_SYNC_HELLO_TIMEOUT,
+ &ospf->ldp_sync_cmd.t_hello);
+}
+
+/*
+ * LDP-SYNC exit routes.
+ */
+void ospf_ldp_sync_gbl_exit(struct ospf *ospf, bool remove)
+{
+ struct interface *ifp;
+ struct vrf *vrf;
+
+ /* ospf is being removed
+ * stop hello timer
+ * stop any holddown timers
+ */
+ if (CHECK_FLAG(ospf->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE)) {
+ /* unregister with opaque client to recv LDP-IGP Sync msgs */
+ zclient_unregister_opaque(zclient,
+ LDP_IGP_SYNC_IF_STATE_UPDATE);
+ zclient_unregister_opaque(zclient,
+ LDP_IGP_SYNC_ANNOUNCE_UPDATE);
+ zclient_unregister_opaque(zclient, LDP_IGP_SYNC_HELLO_UPDATE);
+
+ /* disable LDP globally */
+ UNSET_FLAG(ospf->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE);
+ UNSET_FLAG(ospf->ldp_sync_cmd.flags, LDP_SYNC_FLAG_HOLDDOWN);
+ ospf->ldp_sync_cmd.holddown = LDP_IGP_SYNC_HOLDDOWN_DEFAULT;
+ THREAD_TIMER_OFF(ospf->ldp_sync_cmd.t_hello);
+ ospf->ldp_sync_cmd.t_hello = NULL;
+
+ /* turn off LDP-IGP Sync on all OSPF interfaces */
+ vrf = vrf_lookup_by_id(ospf->vrf_id);
+ FOR_ALL_INTERFACES (vrf, ifp)
+ ospf_ldp_sync_if_remove(ifp, remove);
+ }
+}
+
+/*
+ * LDP-SYNC routes used by set commands.
+ */
+void ospf_if_set_ldp_sync_enable(struct ospf *ospf, struct interface *ifp)
+{
+ struct ospf_if_params *params;
+ struct ldp_sync_info *ldp_sync_info;
+
+ /* called when setting LDP-SYNC at the global level:
+ * specifed on interface overrides global config
+ * if ptop link send msg to LDP indicating ldp-sync enabled
+ */
+ if (if_is_loopback(ifp))
+ return;
+
+ params = IF_DEF_PARAMS(ifp);
+ if (params->ldp_sync_info == NULL)
+ params->ldp_sync_info = ldp_sync_info_create();
+ ldp_sync_info = params->ldp_sync_info;
+
+ /* config on interface, overrides global config. */
+ if (CHECK_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_IF_CONFIG))
+ if (ldp_sync_info->enabled != LDP_IGP_SYNC_ENABLED)
+ return;
+
+ ldp_sync_info->enabled = LDP_IGP_SYNC_ENABLED;
+
+ ols_debug("ldp_sync: enable if %s", ifp->name);
+
+ /* send message to LDP if ptop link */
+ if (params->type == OSPF_IFTYPE_POINTOPOINT ||
+ if_is_pointopoint(ifp)) {
+ ldp_sync_info->state = LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP;
+ ospf_ldp_sync_state_req_msg(ifp);
+ } else {
+ ldp_sync_info->state = LDP_IGP_SYNC_STATE_NOT_REQUIRED;
+ zlog_debug("ldp_sync: Sync only runs on P2P links %s",
+ ifp->name);
+ }
+}
+
+void ospf_if_set_ldp_sync_holddown(struct ospf *ospf, struct interface *ifp)
+{
+ struct ospf_if_params *params;
+ struct ldp_sync_info *ldp_sync_info;
+
+ /* called when setting LDP-SYNC at the global level:
+ * specifed on interface overrides global config.
+ */
+ if (if_is_loopback(ifp))
+ return;
+
+ params = IF_DEF_PARAMS(ifp);
+ if (params->ldp_sync_info == NULL)
+ params->ldp_sync_info = ldp_sync_info_create();
+ ldp_sync_info = params->ldp_sync_info;
+
+ /* config on interface, overrides global config. */
+ if (CHECK_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_HOLDDOWN))
+ return;
+ if (CHECK_FLAG(ospf->ldp_sync_cmd.flags, LDP_SYNC_FLAG_HOLDDOWN))
+ ldp_sync_info->holddown = ospf->ldp_sync_cmd.holddown;
+ else
+ ldp_sync_info->holddown = LDP_IGP_SYNC_HOLDDOWN_DEFAULT;
+}
+
+/*
+ * LDP-SYNC routines used by show commands.
+ */
+
+void ospf_ldp_sync_show_info(struct vty *vty, struct ospf *ospf,
+ json_object *json_vrf, bool use_json)
+{
+
+ if (CHECK_FLAG(ospf->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE)) {
+ if (use_json) {
+ json_object_boolean_true_add(json_vrf,
+ "MplsLdpIgpSyncEnabled");
+ json_object_int_add(json_vrf, "MplsLdpIgpSyncHolddown",
+ ospf->ldp_sync_cmd.holddown);
+ } else {
+ vty_out(vty, " MPLS LDP-IGP Sync is enabled\n");
+ if (ospf->ldp_sync_cmd.holddown == 0)
+ vty_out(vty,
+ " MPLS LDP-IGP Sync holddown timer is disabled\n");
+ else
+ vty_out(vty,
+ " MPLS LDP-IGP Sync holddown timer %d sec\n",
+ ospf->ldp_sync_cmd.holddown);
+ }
+ }
+}
+
+static void show_ip_ospf_mpls_ldp_interface_sub(struct vty *vty,
+ struct ospf_interface *oi,
+ struct interface *ifp,
+ json_object *json_interface_sub,
+ bool use_json)
+{
+ const char *ldp_state;
+ struct ospf_if_params *params;
+ char timebuf[OSPF_TIME_DUMP_SIZE];
+ struct ldp_sync_info *ldp_sync_info;
+
+ params = IF_DEF_PARAMS(oi->ifp);
+ if (params->ldp_sync_info == NULL)
+ return;
+
+ ldp_sync_info = params->ldp_sync_info;
+ if (use_json) {
+ if (ldp_sync_info->enabled == LDP_IGP_SYNC_ENABLED)
+ json_object_boolean_true_add(json_interface_sub,
+ "ldpIgpSyncEnabled");
+ else
+ json_object_boolean_false_add(json_interface_sub,
+ "ldpIgpSyncEnabled");
+
+ json_object_int_add(json_interface_sub, "holdDownTimeInSec",
+ ldp_sync_info->holddown);
+
+ } else {
+ vty_out(vty, "%-10s\n", ifp->name);
+ vty_out(vty, " LDP-IGP Synchronization enabled: %s\n",
+ ldp_sync_info->enabled == LDP_IGP_SYNC_ENABLED
+ ? "yes"
+ : "no");
+ vty_out(vty, " Holddown timer in seconds: %u\n",
+ ldp_sync_info->holddown);
+ }
+
+ switch (ldp_sync_info->state) {
+ case LDP_IGP_SYNC_STATE_REQUIRED_UP:
+ if (use_json)
+ json_object_string_add(json_interface_sub,
+ "ldpIgpSyncState",
+ "Sync achieved");
+ else
+ vty_out(vty, " State: Sync achieved\n");
+ break;
+ case LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP:
+ if (ldp_sync_info->t_holddown != NULL) {
+ if (use_json) {
+ long time_store;
+
+ time_store = monotime_until(
+ &ldp_sync_info->t_holddown->u.sands,
+ NULL)
+ /1000LL;
+
+ json_object_int_add(json_interface_sub,
+ "ldpIgpSyncTimeRemainInMsec",
+ time_store);
+
+ json_object_string_add(json_interface_sub,
+ "ldpIgpSyncState",
+ "Holding down until Sync");
+ } else {
+ vty_out(vty,
+ " Holddown timer is running %s remaining\n",
+ ospf_timer_dump(
+ ldp_sync_info->t_holddown,
+ timebuf,
+ sizeof(timebuf)));
+
+ vty_out(vty,
+ " State: Holding down until Sync\n");
+ }
+ } else {
+ if (use_json)
+ json_object_string_add(json_interface_sub,
+ "ldpIgpSyncState",
+ "Sync not achieved");
+ else
+ vty_out(vty, " State: Sync not achieved\n");
+ }
+ break;
+ case LDP_IGP_SYNC_STATE_NOT_REQUIRED:
+ default:
+ if (IF_DEF_PARAMS(ifp)->type != OSPF_IFTYPE_POINTOPOINT &&
+ !if_is_pointopoint(ifp))
+ ldp_state = "Sync not required: non-p2p link";
+ else
+ ldp_state = "Sync not required";
+
+ if (use_json)
+ json_object_string_add(json_interface_sub,
+ "ldpIgpSyncState",
+ ldp_state);
+ else
+ vty_out(vty, " State: %s\n", ldp_state);
+ break;
+ }
+}
+
+static int show_ip_ospf_mpls_ldp_interface_common(struct vty *vty,
+ struct ospf *ospf,
+ char *intf_name,
+ json_object *json,
+ bool use_json)
+{
+ struct interface *ifp;
+ struct vrf *vrf = vrf_lookup_by_id(ospf->vrf_id);
+ json_object *json_interface_sub = NULL;
+
+ if (intf_name == NULL) {
+ /* Show All Interfaces.*/
+ FOR_ALL_INTERFACES (vrf, ifp) {
+ struct route_node *rn;
+ struct ospf_interface *oi;
+
+ if (ospf_oi_count(ifp) == 0)
+ continue;
+ for (rn = route_top(IF_OIFS(ifp)); rn;
+ rn = route_next(rn)) {
+ oi = rn->info;
+
+ if (use_json) {
+ json_interface_sub =
+ json_object_new_object();
+ }
+ show_ip_ospf_mpls_ldp_interface_sub(
+ vty, oi, ifp, json_interface_sub,
+ use_json);
+
+ if (use_json) {
+ json_object_object_add(
+ json, ifp->name,
+ json_interface_sub);
+ }
+ }
+ }
+ } else {
+ /* Interface name is specified. */
+ ifp = if_lookup_by_name(intf_name, ospf->vrf_id);
+ if (ifp != NULL) {
+ struct route_node *rn;
+ struct ospf_interface *oi;
+
+ if (ospf_oi_count(ifp) == 0 && !use_json) {
+ vty_out(vty,
+ " OSPF not enabled on this interface %s\n",
+ ifp->name);
+ return CMD_SUCCESS;
+ }
+ for (rn = route_top(IF_OIFS(ifp)); rn;
+ rn = route_next(rn)) {
+ oi = rn->info;
+
+ if (use_json)
+ json_interface_sub =
+ json_object_new_object();
+
+ show_ip_ospf_mpls_ldp_interface_sub(
+ vty, oi, ifp, json_interface_sub,
+ use_json);
+
+ if (use_json) {
+ json_object_object_add(
+ json, ifp->name,
+ json_interface_sub);
+ }
+ }
+ }
+ }
+ return CMD_SUCCESS;
+}
+
+/*
+ * Write the global LDP-SYNC configuration.
+ */
+void ospf_ldp_sync_write_config(struct vty *vty, struct ospf *ospf)
+{
+ if (CHECK_FLAG(ospf->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE))
+ vty_out(vty, " mpls ldp-sync\n");
+ if (CHECK_FLAG(ospf->ldp_sync_cmd.flags, LDP_SYNC_FLAG_HOLDDOWN))
+ vty_out(vty, " mpls ldp-sync holddown %u\n",
+ ospf->ldp_sync_cmd.holddown);
+}
+
+/*
+ * Write the interface LDP-SYNC configuration.
+ */
+void ospf_ldp_sync_if_write_config(struct vty *vty,
+ struct ospf_if_params *params)
+
+{
+ struct ldp_sync_info *ldp_sync_info;
+
+ ldp_sync_info = params->ldp_sync_info;
+ if (ldp_sync_info == NULL)
+ return;
+
+ if (CHECK_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_IF_CONFIG)) {
+ if (ldp_sync_info->enabled == LDP_IGP_SYNC_ENABLED)
+ vty_out(vty, " ip ospf mpls ldp-sync\n");
+ else
+ vty_out(vty, " no ip ospf mpls ldp-sync\n");
+ }
+ if (CHECK_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_HOLDDOWN))
+ vty_out(vty, " ip ospf mpls ldp-sync holddown %u\n",
+ ldp_sync_info->holddown);
+}
+
+/*
+ * LDP-SYNC commands.
+ */
+#ifndef VTYSH_EXTRACT_PL
+#include "ospfd/ospf_ldp_sync_clippy.c"
+#endif
+
+DEFPY (ospf_mpls_ldp_sync,
+ ospf_mpls_ldp_sync_cmd,
+ "mpls ldp-sync",
+ "MPLS specific commands\n"
+ "Enable MPLS LDP-IGP Sync\n")
+{
+ VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
+ struct vrf *vrf = vrf_lookup_by_id(ospf->vrf_id);
+ struct interface *ifp;
+
+ if (ospf->vrf_id != VRF_DEFAULT) {
+ vty_out(vty, "ldp-sync only runs on DEFAULT VRF\n");
+ return CMD_ERR_NOTHING_TODO;
+ }
+
+ /* register with opaque client to recv LDP-IGP Sync msgs */
+ zclient_register_opaque(zclient, LDP_IGP_SYNC_IF_STATE_UPDATE);
+ zclient_register_opaque(zclient, LDP_IGP_SYNC_ANNOUNCE_UPDATE);
+ zclient_register_opaque(zclient, LDP_IGP_SYNC_HELLO_UPDATE);
+
+ if (!CHECK_FLAG(ospf->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE)) {
+ SET_FLAG(ospf->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE);
+ /* turn on LDP-IGP Sync on all ptop OSPF interfaces */
+ FOR_ALL_INTERFACES (vrf, ifp)
+ ospf_if_set_ldp_sync_enable(ospf, ifp);
+ }
+ return CMD_SUCCESS;
+}
+
+DEFPY (no_ospf_mpls_ldp_sync,
+ no_ospf_mpls_ldp_sync_cmd,
+ "no mpls ldp-sync",
+ NO_STR
+ "MPLS specific commands\n"
+ "Disable MPLS LDP-IGP Sync\n")
+{
+ VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
+ ospf_ldp_sync_gbl_exit(ospf, false);
+ return CMD_SUCCESS;
+}
+
+DEFPY (ospf_mpls_ldp_sync_holddown,
+ ospf_mpls_ldp_sync_holddown_cmd,
+ "mpls ldp-sync holddown (1-10000)",
+ "MPLS specific commands\n"
+ "Enable MPLS LDP-IGP Sync\n"
+ "Set holddown timer\n"
+ "seconds\n")
+{
+ VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
+ struct vrf *vrf = vrf_lookup_by_id(ospf->vrf_id);
+ struct interface *ifp;
+
+ if (ospf->vrf_id != VRF_DEFAULT) {
+ vty_out(vty, "ldp-sync only runs on DEFAULT VRF\n");
+ return CMD_ERR_NOTHING_TODO;
+ }
+
+ SET_FLAG(ospf->ldp_sync_cmd.flags, LDP_SYNC_FLAG_HOLDDOWN);
+ ospf->ldp_sync_cmd.holddown = holddown;
+ /* set holddown time on all OSPF interfaces */
+ FOR_ALL_INTERFACES (vrf, ifp)
+ ospf_if_set_ldp_sync_holddown(ospf, ifp);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY (no_ospf_mpls_ldp_sync_holddown,
+ no_ospf_mpls_ldp_sync_holddown_cmd,
+ "no mpls ldp-sync holddown [<(1-10000)>]",
+ NO_STR
+ "MPLS specific commands\n"
+ "Disable MPLS LDP-IGP Sync\n"
+ "holddown timer disable\n")
+{
+ VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
+ struct vrf *vrf = vrf_lookup_by_id(ospf->vrf_id);
+ struct interface *ifp;
+
+ if (CHECK_FLAG(ospf->ldp_sync_cmd.flags, LDP_SYNC_FLAG_HOLDDOWN)) {
+ UNSET_FLAG(ospf->ldp_sync_cmd.flags, LDP_SYNC_FLAG_HOLDDOWN);
+ ospf->ldp_sync_cmd.holddown = LDP_IGP_SYNC_HOLDDOWN_DEFAULT;
+ /* turn off holddown timer on all OSPF interfaces */
+ FOR_ALL_INTERFACES (vrf, ifp)
+ ospf_if_set_ldp_sync_holddown(ospf, ifp);
+ }
+ return CMD_SUCCESS;
+}
+
+
+DEFPY (mpls_ldp_sync,
+ mpls_ldp_sync_cmd,
+ "ip ospf mpls ldp-sync",
+ IP_STR
+ "OSPF interface commands\n"
+ MPLS_STR
+ MPLS_LDP_SYNC_STR
+ MPLS_LDP_SYNC_STR)
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ struct ospf_if_params *params;
+ struct ldp_sync_info *ldp_sync_info;
+
+ if (if_is_loopback(ifp)) {
+ vty_out(vty, "ldp-sync does not run on loopback interface\n");
+ return CMD_ERR_NOTHING_TODO;
+ }
+
+ if (ifp->vrf_id != VRF_DEFAULT) {
+ vty_out(vty, "ldp-sync only runs on DEFAULT VRF\n");
+ return CMD_ERR_NOTHING_TODO;
+ }
+
+ params = IF_DEF_PARAMS(ifp);
+ if (params->ldp_sync_info == NULL)
+ params->ldp_sync_info = ldp_sync_info_create();
+
+ ldp_sync_info = params->ldp_sync_info;
+
+ SET_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_IF_CONFIG);
+ ldp_sync_info->enabled = LDP_IGP_SYNC_ENABLED;
+ if (params->type == OSPF_IFTYPE_POINTOPOINT || if_is_pointopoint(ifp)) {
+ ldp_sync_info->state = LDP_IGP_SYNC_STATE_REQUIRED_NOT_UP;
+ ospf_ldp_sync_state_req_msg(ifp);
+ } else {
+ zlog_debug("ldp_sync: only runs on P2P links %s", ifp->name);
+ ldp_sync_info->state = LDP_IGP_SYNC_STATE_NOT_REQUIRED;
+ }
+ return CMD_SUCCESS;
+}
+
+DEFPY (no_mpls_ldp_sync,
+ no_mpls_ldp_sync_cmd,
+ "no ip ospf mpls ldp-sync",
+ NO_STR
+ IP_STR
+ "OSPF interface commands\n"
+ MPLS_STR
+ NO_MPLS_LDP_SYNC_STR)
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ struct ospf_if_params *params;
+ struct ldp_sync_info *ldp_sync_info;
+
+ if (if_is_loopback(ifp)) {
+ vty_out(vty, "ldp-sync: does not run on loopback interface\n");
+ return CMD_ERR_NOTHING_TODO;
+ }
+
+ if (ifp->vrf_id != VRF_DEFAULT) {
+ vty_out(vty, "ldp-sync only runs on DEFAULT VRF\n");
+ return CMD_ERR_NOTHING_TODO;
+ }
+
+ params = IF_DEF_PARAMS(ifp);
+ if (params->ldp_sync_info == NULL)
+ params->ldp_sync_info = ldp_sync_info_create();
+
+ ldp_sync_info = params->ldp_sync_info;
+
+ /* disable LDP-SYNC on an interface
+ * stop holddown timer if running
+ * restore ospf cost
+ */
+ SET_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_IF_CONFIG);
+ ldp_sync_info->enabled = LDP_IGP_SYNC_DEFAULT;
+ ldp_sync_info->state = LDP_IGP_SYNC_STATE_NOT_REQUIRED;
+ THREAD_TIMER_OFF(ldp_sync_info->t_holddown);
+ ldp_sync_info->t_holddown = NULL;
+ ospf_if_recalculate_output_cost(ifp);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY (mpls_ldp_sync_holddown,
+ mpls_ldp_sync_holddown_cmd,
+ "ip ospf mpls ldp-sync holddown (0-10000)",
+ IP_STR
+ "OSPF interface commands\n"
+ MPLS_STR
+ MPLS_LDP_SYNC_STR
+ "Time to wait for LDP-SYNC to occur before restoring interface cost\n"
+ "Time in seconds\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ struct ospf_if_params *params;
+ struct ldp_sync_info *ldp_sync_info;
+
+ if (if_is_loopback(ifp)) {
+ vty_out(vty, "ldp-sync: does not run on loopback interface\n");
+ return CMD_ERR_NOTHING_TODO;
+ }
+
+ if (ifp->vrf_id != VRF_DEFAULT) {
+ vty_out(vty, "ldp-sync only runs on DEFAULT VRF\n");
+ return CMD_ERR_NOTHING_TODO;
+ }
+
+ params = IF_DEF_PARAMS(ifp);
+ if (params->ldp_sync_info == NULL)
+ params->ldp_sync_info = ldp_sync_info_create();
+
+ ldp_sync_info = params->ldp_sync_info;
+
+ SET_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_HOLDDOWN);
+ ldp_sync_info->holddown = holddown;
+
+ return CMD_SUCCESS;
+}
+
+DEFPY (no_mpls_ldp_sync_holddown,
+ no_mpls_ldp_sync_holddown_cmd,
+ "no ip ospf mpls ldp-sync holddown [<(1-10000)>]",
+ NO_STR
+ IP_STR
+ "OSPF interface commands\n"
+ MPLS_STR
+ NO_MPLS_LDP_SYNC_STR
+ NO_MPLS_LDP_SYNC_HOLDDOWN_STR)
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ struct ospf_if_params *params;
+ struct ldp_sync_info *ldp_sync_info;
+ struct ospf *ospf;
+
+ if (if_is_loopback(ifp)) {
+ vty_out(vty, "ldp-sync: does not run on loopback interface\n");
+ return CMD_ERR_NOTHING_TODO;
+ }
+
+ if (ifp->vrf_id != VRF_DEFAULT) {
+ vty_out(vty, "ldp-sync only runs on DEFAULT VRF\n");
+ return CMD_ERR_NOTHING_TODO;
+ }
+
+ params = IF_DEF_PARAMS(ifp);
+ ldp_sync_info = params->ldp_sync_info;
+ if (ldp_sync_info == NULL)
+ return CMD_SUCCESS;
+
+ /* use global configured value if set */
+ if (CHECK_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_HOLDDOWN)) {
+ UNSET_FLAG(ldp_sync_info->flags, LDP_SYNC_FLAG_HOLDDOWN);
+ ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
+ if (ospf && CHECK_FLAG(ospf->ldp_sync_cmd.flags,
+ LDP_SYNC_FLAG_HOLDDOWN))
+ ldp_sync_info->holddown = ospf->ldp_sync_cmd.holddown;
+ else
+ ldp_sync_info->holddown = LDP_IGP_SYNC_HOLDDOWN_DEFAULT;
+ }
+ return CMD_SUCCESS;
+}
+
+DEFPY (show_ip_ospf_mpls_ldp_interface,
+ show_ip_ospf_mpls_ldp_interface_cmd,
+ "show ip ospf mpls ldp-sync [interface <INTERFACE|all>] [json]",
+ SHOW_STR
+ IP_STR
+ "OSPF information\n"
+ MPLS_STR
+ "LDP-IGP Sync information\n"
+ "Interface name\n"
+ JSON_STR)
+{
+ struct ospf *ospf;
+ bool uj = use_json(argc, argv);
+ char *intf_name = NULL;
+ int ret = CMD_SUCCESS;
+ int idx_intf = 0;
+ json_object *json = NULL;
+
+ if (argv_find(argv, argc, "INTERFACE", &idx_intf))
+ intf_name = argv[idx_intf]->arg;
+
+ if (uj)
+ json = json_object_new_object();
+
+ /* Display default ospf (instance 0) info */
+ ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
+ if (ospf == NULL || !ospf->oi_running) {
+ 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, "%% OSPF instance not found\n");
+ return CMD_SUCCESS;
+ }
+
+ if (!CHECK_FLAG(ospf->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE)) {
+ 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, "LDP-sync is disabled\n");
+ return CMD_SUCCESS;
+ }
+
+ ret = show_ip_ospf_mpls_ldp_interface_common(vty, ospf, intf_name,
+ 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 ret;
+}
+
+void ospf_ldp_sync_init(void)
+{
+ /* Install global ldp-igp sync commands */
+ install_element(OSPF_NODE, &ospf_mpls_ldp_sync_cmd);
+ install_element(OSPF_NODE, &no_ospf_mpls_ldp_sync_cmd);
+ install_element(OSPF_NODE, &ospf_mpls_ldp_sync_holddown_cmd);
+ install_element(OSPF_NODE, &no_ospf_mpls_ldp_sync_holddown_cmd);
+
+ /* Interface lsp-igp sync commands */
+ install_element(INTERFACE_NODE, &mpls_ldp_sync_cmd);
+ install_element(INTERFACE_NODE, &no_mpls_ldp_sync_cmd);
+ install_element(INTERFACE_NODE, &mpls_ldp_sync_holddown_cmd);
+ install_element(INTERFACE_NODE, &no_mpls_ldp_sync_holddown_cmd);
+
+ /* "show ip ospf mpls ldp interface" commands. */
+ install_element(VIEW_NODE, &show_ip_ospf_mpls_ldp_interface_cmd);
+
+ hook_register(ospf_ism_change, ospf_ldp_sync_ism_change);
+
+}
diff --git a/ospfd/ospf_ldp_sync.h b/ospfd/ospf_ldp_sync.h
new file mode 100644
index 0000000000..d4efa55311
--- /dev/null
+++ b/ospfd/ospf_ldp_sync.h
@@ -0,0 +1,56 @@
+/*
+ * ospf_ldp_sync.h: OSPF LDP-IGP Sync handling routines
+ * Copyright (C) 2020 Volta Networks, 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 _ZEBRA_OSPF_LDP_SYNC_H
+#define _ZEBRA_OSPF_LDP_SYNC_H
+
+#define LDP_OSPF_LSINFINITY 65535
+
+/* Macro to log debug message */
+#define ols_debug(...) \
+ do { \
+ if (IS_DEBUG_OSPF_LDP_SYNC) \
+ zlog_debug(__VA_ARGS__); \
+ } while (0)
+
+
+extern void ospf_if_set_ldp_sync_enable(struct ospf *ospf,
+ struct interface *ifp);
+extern void ospf_if_set_ldp_sync_holddown(struct ospf *ospf,
+ struct interface *ifp);
+extern void ospf_ldp_sync_if_init(struct ospf_interface *ospf);
+extern void ospf_ldp_sync_if_start(struct interface *ifp, bool send_state_req);
+extern void ospf_ldp_sync_if_remove(struct interface *ifp, bool remove);
+extern void ospf_ldp_sync_if_down(struct interface *ifp);
+extern void ospf_ldp_sync_if_complete(struct interface *ifp);
+extern void ospf_ldp_sync_holddown_timer_add(struct interface *ifp);
+extern void ospf_ldp_sync_hello_timer_add(struct ospf *ospf);
+extern void ospf_ldp_sync_ldp_fail(struct interface *ifp);
+extern void ospf_ldp_sync_show_info(struct vty *vty, struct ospf *ospf,
+ json_object *json_vrf, bool use_json);
+extern void ospf_ldp_sync_write_config(struct vty *vty, struct ospf *ospf);
+extern void ospf_ldp_sync_if_write_config(struct vty *vty,
+ struct ospf_if_params *params);
+extern int ospf_ldp_sync_state_update(struct ldp_igp_sync_if_state state);
+extern int ospf_ldp_sync_announce_update(struct ldp_igp_sync_announce announce);
+extern int ospf_ldp_sync_hello_update(struct ldp_igp_sync_hello hello);
+extern void ospf_ldp_sync_state_req_msg(struct interface *ifp);
+extern void ospf_ldp_sync_init(void);
+extern void ospf_ldp_sync_gbl_exit(struct ospf *ospf, bool remove);
+#endif /* _ZEBRA_OSPF_LDP_SYNC_H */
diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c
index 376310e4ff..8095219146 100644
--- a/ospfd/ospf_lsa.c
+++ b/ospfd/ospf_lsa.c
@@ -1796,7 +1796,15 @@ struct ospf_lsa *ospf_translated_nssa_originate(struct ospf *ospf,
return NULL;
}
- extnew = (struct as_external_lsa *)new;
+ extnew = (struct as_external_lsa *)new->data;
+
+ if ((new = ospf_lsa_install(ospf, NULL, new)) == NULL) {
+ flog_warn(
+ EC_OSPF_LSA_INSTALL_FAILURE,
+ "ospf_lsa_translated_nssa_originate(): Could not install LSA id %s",
+ inet_ntoa(type7->data->id));
+ return NULL;
+ }
if (IS_DEBUG_OSPF_NSSA) {
zlog_debug(
@@ -1807,13 +1815,6 @@ struct ospf_lsa *ospf_translated_nssa_originate(struct ospf *ospf,
inet_ntoa(extnew->e[0].fwd_addr));
}
- if ((new = ospf_lsa_install(ospf, NULL, new)) == NULL) {
- flog_warn(EC_OSPF_LSA_INSTALL_FAILURE,
- "ospf_lsa_translated_nssa_originate(): Could not install LSA id %s",
- inet_ntoa(type7->data->id));
- return NULL;
- }
-
ospf->lsa_originate_count++;
ospf_flood_through_as(ospf, NULL, new);
diff --git a/ospfd/ospf_main.c b/ospfd/ospf_main.c
index 45382e48d3..6be5486b55 100644
--- a/ospfd/ospf_main.c
+++ b/ospfd/ospf_main.c
@@ -54,6 +54,7 @@
#include "ospfd/ospf_vty.h"
#include "ospfd/ospf_bfd.h"
#include "ospfd/ospf_errors.h"
+#include "ospfd/ospf_ldp_sync.h"
/* ospfd privileges */
zebra_capabilities_t _caps_p[] = {ZCAP_NET_RAW, ZCAP_BIND, ZCAP_NET_ADMIN,
@@ -217,6 +218,9 @@ int main(int argc, char **argv)
/* OSPF BFD init */
ospf_bfd_init();
+ /* OSPF LDP IGP Sync init */
+ ospf_ldp_sync_init();
+
ospf_route_map_init();
ospf_opaque_init();
diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c
index 8be7748c87..9d00ff65f9 100644
--- a/ospfd/ospf_vty.c
+++ b/ospfd/ospf_vty.c
@@ -52,6 +52,7 @@
#include "ospfd/ospf_vty.h"
#include "ospfd/ospf_dump.h"
#include "ospfd/ospf_bfd.h"
+#include "ospfd/ospf_ldp_sync.h"
FRR_CFG_DEFAULT_BOOL(OSPF_LOG_ADJACENCY_CHANGES,
{ .val_bool = true, .match_profile = "datacenter", },
@@ -3222,6 +3223,10 @@ static int show_ip_ospf_common(struct vty *vty, struct ospf *ospf,
vty_out(vty, " Adjacency changes are logged\n");
}
}
+
+ /* show LDP-Sync status */
+ ospf_ldp_sync_show_info(vty, ospf, json_vrf, json ? 1 : 0);
+
/* Show each area status. */
for (ALL_LIST_ELEMENTS(ospf->areas, node, nnode, area))
show_ip_ospf_area(vty, area, json_areas, json ? 1 : 0);
@@ -9975,6 +9980,9 @@ static int config_write_interface_one(struct vty *vty, struct vrf *vrf)
vty_out(vty, "\n");
}
+ /* LDP-Sync print */
+ if (params && params->ldp_sync_info)
+ ospf_ldp_sync_if_write_config(vty, params);
while (1) {
if (rn == NULL)
@@ -10498,6 +10506,9 @@ static int ospf_config_write_one(struct vty *vty, struct ospf *ospf)
ospf_opaque_config_write_router(vty, ospf);
+ /* LDP-Sync print */
+ ospf_ldp_sync_write_config(vty, ospf);
+
write++;
return write;
}
diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c
index 8cf8430247..dc8a8dccd2 100644
--- a/ospfd/ospf_zebra.c
+++ b/ospfd/ospf_zebra.c
@@ -51,6 +51,7 @@
#include "ospfd/ospf_zebra.h"
#include "ospfd/ospf_te.h"
#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")
@@ -1354,16 +1355,26 @@ static int ospf_distribute_list_update_timer(struct thread *thread)
else if (
(lsa = ospf_external_info_find_lsa(
ospf, &ei->p))) {
- if (!CHECK_FLAG(
- lsa->flags,
- OSPF_LSA_IN_MAXAGE))
- ospf_external_lsa_refresh(
- ospf, lsa, ei,
- LSA_REFRESH_IF_CHANGED);
- else
- ospf_external_lsa_refresh(
- ospf, lsa, ei,
- LSA_REFRESH_FORCE);
+ int force =
+ LSA_REFRESH_IF_CHANGED;
+ /* If this is a MaxAge LSA, we
+ * need to force refresh it
+ * because distribute settings
+ * might have changed and now,
+ * this LSA needs to be
+ * originated, not be removed.
+ * If we don't force refresh it,
+ * it will remain a MaxAge LSA
+ * because it will look like it
+ * hasn't changed. Neighbors
+ * will not receive updates for
+ * this LSA.
+ */
+ if (IS_LSA_MAXAGE(lsa))
+ force = LSA_REFRESH_FORCE;
+
+ ospf_external_lsa_refresh(
+ ospf, lsa, ei, force);
} else
ospf_external_lsa_originate(
ospf, ei);
@@ -1833,6 +1844,45 @@ static void ospf_zebra_connected(struct zclient *zclient)
zclient_send_reg_requests(zclient, VRF_DEFAULT);
}
+/*
+ * opaque messages between processes
+ */
+static int ospf_opaque_msg_handler(ZAPI_CALLBACK_ARGS)
+{
+ struct stream *s;
+ struct zapi_opaque_msg info;
+ struct ldp_igp_sync_if_state state;
+ struct ldp_igp_sync_announce announce;
+ struct ldp_igp_sync_hello hello;
+ int ret = 0;
+
+ s = zclient->ibuf;
+
+ if (zclient_opaque_decode(s, &info) != 0)
+ return -1;
+
+ switch (info.type) {
+ case LDP_IGP_SYNC_IF_STATE_UPDATE:
+ STREAM_GET(&state, s, sizeof(state));
+ ret = ospf_ldp_sync_state_update(state);
+ break;
+ case LDP_IGP_SYNC_ANNOUNCE_UPDATE:
+ STREAM_GET(&announce, s, sizeof(announce));
+ ret = ospf_ldp_sync_announce_update(announce);
+ break;
+ case LDP_IGP_SYNC_HELLO_UPDATE:
+ STREAM_GET(&hello, s, sizeof(hello));
+ ret = ospf_ldp_sync_hello_update(hello);
+ break;
+ default:
+ break;
+ }
+
+stream_failure:
+
+ return ret;
+}
+
void ospf_zebra_init(struct thread_master *master, unsigned short instance)
{
/* Allocate zebra structure. */
@@ -1866,6 +1916,8 @@ void ospf_zebra_init(struct thread_master *master, unsigned short instance)
access_list_delete_hook(ospf_filter_update);
prefix_list_add_hook(ospf_prefix_list_update);
prefix_list_delete_hook(ospf_prefix_list_update);
+
+ zclient->opaque_msg_handler = ospf_opaque_msg_handler;
}
void ospf_zebra_send_arp(const struct interface *ifp, const struct prefix *p)
diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c
index 31d8417eb6..cc5839a810 100644
--- a/ospfd/ospfd.c
+++ b/ospfd/ospfd.c
@@ -39,6 +39,7 @@
#include "libfrr.h"
#include "defaults.h"
#include "lib_errors.h"
+#include "ldp_sync.h"
#include "ospfd/ospfd.h"
#include "ospfd/ospf_network.h"
@@ -57,6 +58,7 @@
#include "ospfd/ospf_abr.h"
#include "ospfd/ospf_flood.h"
#include "ospfd/ospf_ase.h"
+#include "ospfd/ospf_ldp_sync.h"
DEFINE_QOBJ_TYPE(ospf)
@@ -619,6 +621,10 @@ static void ospf_finish_final(struct ospf *ospf)
list_delete(&ospf->vlinks);
+ /* shutdown LDP-Sync */
+ if (ospf->vrf_id == VRF_DEFAULT)
+ ospf_ldp_sync_gbl_exit(ospf, true);
+
/* Remove any ospf interface config params */
FOR_ALL_INTERFACES (vrf, ifp) {
struct ospf_if_params *params;
@@ -948,6 +954,9 @@ static void add_ospf_interface(struct connected *co, struct ospf_area *area)
ospf_area_add_if(oi->area, oi);
+ /* if LDP-IGP Sync is configured globally inherit config */
+ ospf_ldp_sync_if_init(oi);
+
/*
* if router_id is not configured, dont bring up
* interfaces.
diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h
index e5e07875e8..55bc64317e 100644
--- a/ospfd/ospfd.h
+++ b/ospfd/ospfd.h
@@ -25,6 +25,7 @@
#include <zebra.h>
#include "qobj.h"
#include "libospf.h"
+#include "ldp_sync.h"
#include "filter.h"
#include "log.h"
@@ -320,6 +321,9 @@ struct ospf {
struct list *external[ZEBRA_ROUTE_MAX + 1];
#define EXTERNAL_INFO(E) (E->external_info)
+ /* MPLS LDP-IGP Sync */
+ struct ldp_sync_info_cmd ldp_sync_cmd;
+
QOBJ_FIELDS
};
DECLARE_QOBJ_TYPE(ospf)
diff --git a/ospfd/subdir.am b/ospfd/subdir.am
index 447ddf9cbb..236b76a1f7 100644
--- a/ospfd/subdir.am
+++ b/ospfd/subdir.am
@@ -9,6 +9,7 @@ dist_examples_DATA += ospfd/ospfd.conf.sample
vtysh_scan += \
ospfd/ospf_bfd.c \
ospfd/ospf_dump.c \
+ ospfd/ospf_ldp_sync.c \
ospfd/ospf_opaque.c \
ospfd/ospf_ri.c \
ospfd/ospf_routemap.c \
@@ -37,6 +38,7 @@ ospfd_libfrrospf_a_SOURCES = \
ospfd/ospf_ia.c \
ospfd/ospf_interface.c \
ospfd/ospf_ism.c \
+ ospfd/ospf_ldp_sync.c \
ospfd/ospf_lsa.c \
ospfd/ospf_lsdb.c \
ospfd/ospf_memory.c \
@@ -74,6 +76,7 @@ endif
clippy_scan += \
ospfd/ospf_vty.c \
+ ospfd/ospf_ldp_sync.c \
# end
noinst_HEADERS += \
@@ -86,6 +89,7 @@ noinst_HEADERS += \
ospfd/ospf_flood.h \
ospfd/ospf_ia.h \
ospfd/ospf_interface.h \
+ ospfd/ospf_ldp_sync.h \
ospfd/ospf_memory.h \
ospfd/ospf_neighbor.h \
ospfd/ospf_network.h \
diff --git a/pbrd/pbr_map.c b/pbrd/pbr_map.c
index 058881cbfc..fe2778c877 100644
--- a/pbrd/pbr_map.c
+++ b/pbrd/pbr_map.c
@@ -293,7 +293,7 @@ void pbr_map_policy_interface_update(const struct interface *ifp, bool state_up)
for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms))
for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, inode, pmi))
if (pmi->ifp == ifp && pbr_map_interface_is_valid(pmi))
- pbr_send_pbr_map(pbrms, pmi, state_up, false);
+ pbr_send_pbr_map(pbrms, pmi, state_up, true);
}
static void pbrms_vrf_update(struct pbr_map_sequence *pbrms,
@@ -398,7 +398,7 @@ void pbr_map_delete_vrf(struct pbr_map_sequence *pbrms)
pbr_map_delete_common(pbrms);
}
-struct pbr_map_sequence *pbrms_lookup_unique(uint32_t unique, ifindex_t ifindex,
+struct pbr_map_sequence *pbrms_lookup_unique(uint32_t unique, char *ifname,
struct pbr_map_interface **ppmi)
{
struct pbr_map_sequence *pbrms;
@@ -408,7 +408,8 @@ struct pbr_map_sequence *pbrms_lookup_unique(uint32_t unique, ifindex_t ifindex,
RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps) {
for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, inode, pmi)) {
- if (pmi->ifp->ifindex != ifindex)
+ if (strncmp(pmi->ifp->name, ifname, INTERFACE_NAMSIZ)
+ != 0)
continue;
if (ppmi)
diff --git a/pbrd/pbr_map.h b/pbrd/pbr_map.h
index 43266f21e9..ad2db146b7 100644
--- a/pbrd/pbr_map.h
+++ b/pbrd/pbr_map.h
@@ -158,7 +158,7 @@ extern struct pbr_map_entry_head pbr_maps;
extern struct pbr_map_sequence *pbrms_get(const char *name, uint32_t seqno);
extern struct pbr_map_sequence *
-pbrms_lookup_unique(uint32_t unique, ifindex_t ifindex,
+pbrms_lookup_unique(uint32_t unique, char *ifname,
struct pbr_map_interface **ppmi);
extern struct pbr_map *pbrm_find(const char *name);
diff --git a/pbrd/pbr_zebra.c b/pbrd/pbr_zebra.c
index a7420974a9..269bd6da8d 100644
--- a/pbrd/pbr_zebra.c
+++ b/pbrd/pbr_zebra.c
@@ -208,15 +208,15 @@ static int rule_notify_owner(ZAPI_CALLBACK_ARGS)
enum zapi_rule_notify_owner note;
struct pbr_map_sequence *pbrms;
struct pbr_map_interface *pmi;
- ifindex_t ifi;
+ char ifname[INTERFACE_NAMSIZ + 1];
uint64_t installed;
if (!zapi_rule_notify_decode(zclient->ibuf, &seqno, &priority, &unique,
- &ifi, &note))
+ ifname, &note))
return -1;
pmi = NULL;
- pbrms = pbrms_lookup_unique(unique, ifi, &pmi);
+ pbrms = pbrms_lookup_unique(unique, ifname, &pmi);
if (!pbrms) {
DEBUGD(&pbr_dbg_zebra,
"%s: Failure to lookup pbrms based upon %u", __func__,
@@ -546,7 +546,7 @@ static void pbr_encode_pbr_map_sequence(struct stream *s,
stream_putl(s, pbr_nht_get_table(pbrms->nhgrp_name));
else if (pbrms->nhg)
stream_putl(s, pbr_nht_get_table(pbrms->internal_nhg_name));
- stream_putl(s, ifp->ifindex);
+ stream_put(s, ifp->name, INTERFACE_NAMSIZ);
}
void pbr_send_pbr_map(struct pbr_map_sequence *pbrms,
diff --git a/pimd/pimd.c b/pimd/pimd.c
index 6c354a3cc8..811dc96b56 100644
--- a/pimd/pimd.c
+++ b/pimd/pimd.c
@@ -44,6 +44,10 @@
#include "pim_zebra.h"
#include "pim_mlag.h"
+#if MAXVIFS > 256
+CPP_NOTICE("Work needs to be done to make this work properly via the pim mroute socket\n");
+#endif /* MAXVIFS > 256 */
+
const char *const PIM_ALL_SYSTEMS = MCAST_ALL_SYSTEMS;
const char *const PIM_ALL_ROUTERS = MCAST_ALL_ROUTERS;
const char *const PIM_ALL_PIM_ROUTERS = MCAST_ALL_PIM_ROUTERS;
diff --git a/redhat/frr.spec.in b/redhat/frr.spec.in
index 929214a142..bd0d5b27f4 100644
--- a/redhat/frr.spec.in
+++ b/redhat/frr.spec.in
@@ -170,7 +170,7 @@ BuildRequires: make
BuildRequires: ncurses-devel
BuildRequires: readline-devel
BuildRequires: texinfo
-BuildRequires: libyang-devel >= 0.16.74
+BuildRequires: libyang-devel >= 1.0.184
%if 0%{?rhel} && 0%{?rhel} < 7
#python27-devel is available from ius community repo for RedHat/CentOS 6
BuildRequires: python27-devel
diff --git a/snapcraft/snapcraft.yaml.in b/snapcraft/snapcraft.yaml.in
index b06e841f74..c0c31b5fd1 100644
--- a/snapcraft/snapcraft.yaml.in
+++ b/snapcraft/snapcraft.yaml.in
@@ -273,12 +273,12 @@ parts:
- libpcre3
source: https://github.com/CESNET/libyang.git
source-type: git
- source-tag: v0.16-r3
+ source-tag: v1.0.184
plugin: cmake
configflags:
- -DCMAKE_INSTALL_PREFIX:PATH=/usr
- -DENABLE_LYD_PRIV=ON
- - -DENABLE_CACHE=OFF
+ - -DENABLE_CACHE=ON
- -DCMAKE_BUILD_TYPE:String="Release"
frr:
after: [rtrlib,libyang]
diff --git a/staticd/static_vty.c b/staticd/static_vty.c
index 4763406934..4821671554 100644
--- a/staticd/static_vty.c
+++ b/staticd/static_vty.c
@@ -81,11 +81,7 @@ static int static_route_leak(struct vty *vty, const char *svrf,
ret = str2prefix(dest_str, &p);
if (ret <= 0) {
- if (vty)
- vty_out(vty, "%% Malformed address\n");
- else
- zlog_warn("%s: Malformed address: %s", __func__,
- dest_str);
+ vty_out(vty, "%% Malformed address\n");
return CMD_WARNING_CONFIG_FAILED;
}
@@ -95,11 +91,7 @@ static int static_route_leak(struct vty *vty, const char *svrf,
if (mask_str) {
ret = inet_aton(mask_str, &mask);
if (ret == 0) {
- if (vty)
- vty_out(vty, "%% Malformed address\n");
- else
- zlog_warn("%s: Malformed address: %s",
- __func__, mask_str);
+ vty_out(vty, "%% Malformed address\n");
return CMD_WARNING_CONFIG_FAILED;
}
p.prefixlen = ip_masklen(mask);
@@ -110,13 +102,7 @@ static int static_route_leak(struct vty *vty, const char *svrf,
if (src_str) {
ret = str2prefix(src_str, &src);
if (ret <= 0 || src.family != AF_INET6) {
- if (vty)
- vty_out(vty,
- "%% Malformed source address\n");
- else
- zlog_warn(
- "%s: Malformed source address: %s",
- __func__, src_str);
+ vty_out(vty, "%% Malformed source address\n");
return CMD_WARNING_CONFIG_FAILED;
}
}
@@ -437,7 +423,8 @@ int static_config(struct vty *vty, struct static_vrf *svrf, afi_t afi,
nh->snh_label.label,
buf, sizeof(buf), 0));
- if (nh->nh_vrf_id != GET_STABLE_VRF_ID(info))
+ if (!strmatch(nh->nh_vrfname,
+ info->svrf->vrf->name))
vty_out(vty, " nexthop-vrf %s",
nh->nh_vrfname);
diff --git a/tests/topotests/all-protocol-startup/r1/bgpd.conf b/tests/topotests/all-protocol-startup/r1/bgpd.conf
index e000b4e625..d287b86175 100644
--- a/tests/topotests/all-protocol-startup/r1/bgpd.conf
+++ b/tests/topotests/all-protocol-startup/r1/bgpd.conf
@@ -7,9 +7,13 @@ router bgp 100
no bgp ebgp-requires-policy
no bgp network import-check
neighbor 192.168.7.10 remote-as 100
+ neighbor 192.168.7.10 timers 3 10
neighbor 192.168.7.20 remote-as 200
+ neighbor 192.168.7.20 timers 3 10
neighbor fc00:0:0:8::1000 remote-as 100
+ neighbor fc00:0:0:8::1000 timers 3 10
neighbor fc00:0:0:8::2000 remote-as 200
+ neighbor fc00:0:0:8::2000 timers 3 10
!
address-family ipv4 unicast
network 192.168.0.0/24
diff --git a/tests/topotests/bfd-bgp-cbit-topo3/r1/bgpd.conf b/tests/topotests/bfd-bgp-cbit-topo3/r1/bgpd.conf
index 82b189b292..689797a5e6 100644
--- a/tests/topotests/bfd-bgp-cbit-topo3/r1/bgpd.conf
+++ b/tests/topotests/bfd-bgp-cbit-topo3/r1/bgpd.conf
@@ -6,6 +6,7 @@ router bgp 101
timers bgp 8 24
bgp graceful-restart
neighbor 2001:db8:4::1 remote-as 102
+ neighbor 2001:db8:4::1 timers 3 10
neighbor 2001:db8:4::1 remote-as external
neighbor 2001:db8:4::1 bfd
neighbor 2001:db8:4::1 bfd check-control-plane-failure
diff --git a/tests/topotests/bfd-bgp-cbit-topo3/r3/bgpd.conf b/tests/topotests/bfd-bgp-cbit-topo3/r3/bgpd.conf
index e566e08f7d..1f5aac42ed 100644
--- a/tests/topotests/bfd-bgp-cbit-topo3/r3/bgpd.conf
+++ b/tests/topotests/bfd-bgp-cbit-topo3/r3/bgpd.conf
@@ -10,6 +10,7 @@ router bgp 102
bgp graceful-restart stalepath-time 900
bgp graceful-restart restart-time 900
neighbor 2001:db8:1::1 remote-as 101
+ neighbor 2001:db8:1::1 timers 3 10
neighbor 2001:db8:1::1 remote-as external
neighbor 2001:db8:1::1 update-source 2001:db8:4::1
neighbor 2001:db8:1::1 bfd
diff --git a/tests/topotests/bfd-bgp-cbit-topo3/test_bfd_bgp_cbit_topo3.py b/tests/topotests/bfd-bgp-cbit-topo3/test_bfd_bgp_cbit_topo3.py
index 186dac31a0..7d1521c8b2 100755..100644
--- a/tests/topotests/bfd-bgp-cbit-topo3/test_bfd_bgp_cbit_topo3.py
+++ b/tests/topotests/bfd-bgp-cbit-topo3/test_bfd_bgp_cbit_topo3.py
@@ -72,7 +72,7 @@ def setup_module(mod):
router_list = tgen.routers()
- for rname, router in router_list.iteritems():
+ for rname, router in router_list.items():
router.load_config(
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)),
)
diff --git a/tests/topotests/bfd-isis-topo1/test_bfd_isis_topo1.py b/tests/topotests/bfd-isis-topo1/test_bfd_isis_topo1.py
index a1ed0cc2af..1adfec76d8 100755..100644
--- a/tests/topotests/bfd-isis-topo1/test_bfd_isis_topo1.py
+++ b/tests/topotests/bfd-isis-topo1/test_bfd_isis_topo1.py
@@ -136,7 +136,7 @@ def setup_module(mod):
router_list = tgen.routers()
# For all registered routers, load the zebra configuration file
- for rname, router in router_list.iteritems():
+ for rname, router in router_list.items():
router.load_config(
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
)
diff --git a/tests/topotests/bfd-profiles-topo1/r2/bgpd.conf b/tests/topotests/bfd-profiles-topo1/r2/bgpd.conf
index 824d01983f..0c3db97bc1 100644
--- a/tests/topotests/bfd-profiles-topo1/r2/bgpd.conf
+++ b/tests/topotests/bfd-profiles-topo1/r2/bgpd.conf
@@ -4,8 +4,10 @@ router bgp 100
bgp router-id 10.254.254.2
no bgp ebgp-requires-policy
neighbor 172.16.1.1 remote-as 100
+ neighbor 172.16.1.1 timers 3 10
neighbor 172.16.1.1 bfd profile fasttx
neighbor 2001:db8:2::2 remote-as 200
+ neighbor 2001:db8:2::2 timers 3 10
neighbor 2001:db8:2::2 ebgp-multihop 2
neighbor 2001:db8:2::2 bfd profile slowtx
address-family ipv4 unicast
diff --git a/tests/topotests/bfd-profiles-topo1/r3/bgpd.conf b/tests/topotests/bfd-profiles-topo1/r3/bgpd.conf
index c7b75d2fde..65647b39e5 100644
--- a/tests/topotests/bfd-profiles-topo1/r3/bgpd.conf
+++ b/tests/topotests/bfd-profiles-topo1/r3/bgpd.conf
@@ -1,6 +1,7 @@
router bgp 100
bgp router-id 10.254.254.3
neighbor 172.16.1.2 remote-as 100
+ neighbor 172.16.1.2 timers 3 10
neighbor 172.16.1.2 bfd profile DOES_NOT_EXIST
address-family ipv4 unicast
redistribute connected
diff --git a/tests/topotests/bfd-profiles-topo1/r4/bgpd.conf b/tests/topotests/bfd-profiles-topo1/r4/bgpd.conf
index aff1016dee..200937a9a5 100644
--- a/tests/topotests/bfd-profiles-topo1/r4/bgpd.conf
+++ b/tests/topotests/bfd-profiles-topo1/r4/bgpd.conf
@@ -4,6 +4,7 @@ router bgp 200
bgp router-id 10.254.254.4
no bgp ebgp-requires-policy
neighbor 2001:db8:1::2 remote-as 100
+ neighbor 2001:db8:1::2 timers 3 10
neighbor 2001:db8:1::2 ebgp-multihop 2
neighbor 2001:db8:1::2 bfd profile DOES_NOT_EXIST
address-family ipv4 unicast
diff --git a/tests/topotests/bfd-profiles-topo1/test_bfd_profiles_topo1.py b/tests/topotests/bfd-profiles-topo1/test_bfd_profiles_topo1.py
index 02385b32e5..514933b891 100755..100644
--- a/tests/topotests/bfd-profiles-topo1/test_bfd_profiles_topo1.py
+++ b/tests/topotests/bfd-profiles-topo1/test_bfd_profiles_topo1.py
@@ -84,7 +84,7 @@ def setup_module(mod):
tgen.start_topology()
router_list = tgen.routers()
- for rname, router in router_list.iteritems():
+ for rname, router in router_list.items():
daemon_file = "{}/{}/bfdd.conf".format(CWD, rname)
if os.path.isfile(daemon_file):
router.load_config(TopoRouter.RD_BFD, daemon_file)
diff --git a/tests/topotests/bfd-topo1/r1/bgpd.conf b/tests/topotests/bfd-topo1/r1/bgpd.conf
index 25e16a6e0c..57bde1f234 100644
--- a/tests/topotests/bfd-topo1/r1/bgpd.conf
+++ b/tests/topotests/bfd-topo1/r1/bgpd.conf
@@ -2,6 +2,7 @@ router bgp 101
no bgp ebgp-requires-policy
no bgp network import-check
neighbor 192.168.0.2 remote-as 102
+ neighbor 192.168.0.2 timers 3 10
neighbor 192.168.0.2 bfd
address-family ipv4 unicast
network 10.254.254.1/32
diff --git a/tests/topotests/bfd-topo1/r2/bgpd.conf b/tests/topotests/bfd-topo1/r2/bgpd.conf
index 693fb93411..50d75ab67f 100644
--- a/tests/topotests/bfd-topo1/r2/bgpd.conf
+++ b/tests/topotests/bfd-topo1/r2/bgpd.conf
@@ -2,10 +2,13 @@ router bgp 102
no bgp ebgp-requires-policy
no bgp network import-check
neighbor 192.168.0.1 remote-as 101
+ neighbor 192.168.0.1 timers 3 10
neighbor 192.168.0.1 bfd
neighbor 192.168.1.1 remote-as 103
+ neighbor 192.168.1.1 timers 3 10
neighbor 192.168.1.1 bfd
neighbor 192.168.2.1 remote-as 104
+ neighbor 192.168.2.1 timers 3 10
neighbor 192.168.2.1 bfd
address-family ipv4 unicast
network 10.254.254.2/32
diff --git a/tests/topotests/bfd-topo1/r3/bgpd.conf b/tests/topotests/bfd-topo1/r3/bgpd.conf
index 7584f98803..ce6055d518 100644
--- a/tests/topotests/bfd-topo1/r3/bgpd.conf
+++ b/tests/topotests/bfd-topo1/r3/bgpd.conf
@@ -2,6 +2,7 @@ router bgp 103
no bgp ebgp-requires-policy
no bgp network import-check
neighbor 192.168.1.2 remote-as 102
+ neighbor 192.168.1.2 timers 3 10
neighbor 192.168.1.2 bfd
address-family ipv4 unicast
network 10.254.254.3/32
diff --git a/tests/topotests/bfd-topo1/r4/bgpd.conf b/tests/topotests/bfd-topo1/r4/bgpd.conf
index 3c68e7eec9..0d032b4cdd 100644
--- a/tests/topotests/bfd-topo1/r4/bgpd.conf
+++ b/tests/topotests/bfd-topo1/r4/bgpd.conf
@@ -2,6 +2,7 @@ router bgp 104
no bgp ebgp-requires-policy
no bgp network import-check
neighbor 192.168.2.2 remote-as 102
+ neighbor 192.168.2.2 timers 3 10
neighbor 192.168.2.2 bfd
address-family ipv4 unicast
network 10.254.254.4/32
diff --git a/tests/topotests/bfd-topo1/test_bfd_topo1.py b/tests/topotests/bfd-topo1/test_bfd_topo1.py
index e1865dc5a8..5306fdf353 100644
--- a/tests/topotests/bfd-topo1/test_bfd_topo1.py
+++ b/tests/topotests/bfd-topo1/test_bfd_topo1.py
@@ -76,7 +76,7 @@ def setup_module(mod):
tgen.start_topology()
router_list = tgen.routers()
- for rname, router in router_list.iteritems():
+ for rname, router in router_list.items():
router.load_config(
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
)
diff --git a/tests/topotests/bfd-topo2/r1/bgpd.conf b/tests/topotests/bfd-topo2/r1/bgpd.conf
index 4d96bec2cb..0918796e95 100644
--- a/tests/topotests/bfd-topo2/r1/bgpd.conf
+++ b/tests/topotests/bfd-topo2/r1/bgpd.conf
@@ -5,6 +5,7 @@ router bgp 101
neighbor r2g remote-as external
neighbor r2g bfd
neighbor r1-eth0 interface peer-group r2g
+ neighbor r1-eth0 timers 3 10
address-family ipv4 unicast
redistribute connected
exit-address-family
diff --git a/tests/topotests/bfd-topo2/r2/bgpd.conf b/tests/topotests/bfd-topo2/r2/bgpd.conf
index 4d02fc4f29..55d48560e7 100644
--- a/tests/topotests/bfd-topo2/r2/bgpd.conf
+++ b/tests/topotests/bfd-topo2/r2/bgpd.conf
@@ -5,6 +5,7 @@ router bgp 102
neighbor r2g remote-as external
neighbor r2g bfd
neighbor r2-eth0 interface peer-group r2g
+ neighbor r2-eth0 timers 3 10
!
address-family ipv4 unicast
redistribute connected
diff --git a/tests/topotests/bfd-topo2/test_bfd_topo2.py b/tests/topotests/bfd-topo2/test_bfd_topo2.py
index 3e87e8485a..2c5ce3e4c3 100644
--- a/tests/topotests/bfd-topo2/test_bfd_topo2.py
+++ b/tests/topotests/bfd-topo2/test_bfd_topo2.py
@@ -77,7 +77,7 @@ def setup_module(mod):
tgen.start_topology()
router_list = tgen.routers()
- for rname, router in router_list.iteritems():
+ for rname, router in router_list.items():
router.load_config(
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
)
diff --git a/tests/topotests/bfd-topo3/r1/bgpd.conf b/tests/topotests/bfd-topo3/r1/bgpd.conf
index a0281d50c6..4c75d669c5 100644
--- a/tests/topotests/bfd-topo3/r1/bgpd.conf
+++ b/tests/topotests/bfd-topo3/r1/bgpd.conf
@@ -1,11 +1,14 @@
router bgp 100
no bgp ebgp-requires-policy
neighbor 2001:db8:1::2 remote-as internal
+ neighbor 2001:db8:1::2 timers 3 10
neighbor 2001:db8:1::2 bfd profile fast-tx
neighbor 192.168.2.1 remote-as external
+ neighbor 192.168.2.1 timers 3 10
neighbor 192.168.2.1 ebgp-multihop 2
neighbor 192.168.2.1 bfd profile slow-tx
neighbor 2001:db8:3::1 remote-as external
+ neighbor 2001:db8:3::1 timers 3 10
neighbor 2001:db8:3::1 ebgp-multihop 3
neighbor 2001:db8:3::1 bfd profile slow-tx
address-family ipv4 unicast
diff --git a/tests/topotests/bfd-topo3/r2/bgpd.conf b/tests/topotests/bfd-topo3/r2/bgpd.conf
index 0e96033023..75225765e1 100644
--- a/tests/topotests/bfd-topo3/r2/bgpd.conf
+++ b/tests/topotests/bfd-topo3/r2/bgpd.conf
@@ -1,8 +1,10 @@
router bgp 100
no bgp ebgp-requires-policy
neighbor 2001:db8:1::1 remote-as internal
+ neighbor 2001:db8:1::1 timers 3 10
neighbor 2001:db8:1::1 bfd profile fast-tx
neighbor 2001:db8:2::1 remote-as external
+ neighbor 2001:db8:2::1 timers 3 10
neighbor 2001:db8:2::1 bfd profile slow-tx
address-family ipv4 unicast
redistribute connected
diff --git a/tests/topotests/bfd-topo3/r3/bgpd.conf b/tests/topotests/bfd-topo3/r3/bgpd.conf
index e14d2011a0..82adf8be9e 100644
--- a/tests/topotests/bfd-topo3/r3/bgpd.conf
+++ b/tests/topotests/bfd-topo3/r3/bgpd.conf
@@ -1,11 +1,14 @@
router bgp 300
no bgp ebgp-requires-policy
neighbor 192.168.1.1 remote-as external
+ neighbor 192.168.1.1 timers 3 10
neighbor 192.168.1.1 ebgp-multihop 2
neighbor 192.168.1.1 bfd profile slow-tx
neighbor 2001:db8:2::2 remote-as external
+ neighbor 2001:db8:2::2 timers 3 10
neighbor 2001:db8:2::2 bfd profile slow-tx
neighbor 2001:db8:3::1 remote-as external
+ neighbor 2001:db8:3::1 timers 3 10
neighbor 2001:db8:3::1 bfd profile slow-tx
address-family ipv4 unicast
redistribute connected
diff --git a/tests/topotests/bfd-topo3/r4/bgpd.conf b/tests/topotests/bfd-topo3/r4/bgpd.conf
index 3e81008d5d..0aab6e3017 100644
--- a/tests/topotests/bfd-topo3/r4/bgpd.conf
+++ b/tests/topotests/bfd-topo3/r4/bgpd.conf
@@ -1,8 +1,10 @@
router bgp 400
no bgp ebgp-requires-policy
neighbor 2001:db8:3::2 remote-as external
+ neighbor 2001:db8:3::2 timers 3 10
neighbor 2001:db8:3::2 bfd profile slow-tx
neighbor 2001:db8:1::1 remote-as external
+ neighbor 2001:db8:1::1 timers 3 10
neighbor 2001:db8:1::1 ebgp-multihop 3
neighbor 2001:db8:1::1 bfd profile slow-tx-mh
address-family ipv4 unicast
diff --git a/tests/topotests/bfd-topo3/test_bfd_topo3.py b/tests/topotests/bfd-topo3/test_bfd_topo3.py
index bcee338a92..fa68ace59d 100644
--- a/tests/topotests/bfd-topo3/test_bfd_topo3.py
+++ b/tests/topotests/bfd-topo3/test_bfd_topo3.py
@@ -76,7 +76,7 @@ def setup_module(mod):
tgen.start_topology()
router_list = tgen.routers()
- for rname, router in router_list.iteritems():
+ for rname, router in router_list.items():
daemon_file = "{}/{}/bfdd.conf".format(CWD, rname)
if os.path.isfile(daemon_file):
router.load_config(TopoRouter.RD_BFD, daemon_file)
diff --git a/tests/topotests/bfd-vrf-topo1/r1/bgpd.conf b/tests/topotests/bfd-vrf-topo1/r1/bgpd.conf
index 439c58fb2a..5bb45b9863 100644
--- a/tests/topotests/bfd-vrf-topo1/r1/bgpd.conf
+++ b/tests/topotests/bfd-vrf-topo1/r1/bgpd.conf
@@ -2,6 +2,7 @@ router bgp 101 vrf r1-cust1
no bgp ebgp-requires-policy
no bgp network import-check
neighbor 192.168.0.2 remote-as 102
+ neighbor 192.168.0.2 timers 3 10
! neighbor 192.168.0.2 ebgp-multihop 10
neighbor 192.168.0.2 bfd
address-family ipv4 unicast
diff --git a/tests/topotests/bfd-vrf-topo1/r2/bgpd.conf b/tests/topotests/bfd-vrf-topo1/r2/bgpd.conf
index 4fac25d7bb..b2aac74685 100644
--- a/tests/topotests/bfd-vrf-topo1/r2/bgpd.conf
+++ b/tests/topotests/bfd-vrf-topo1/r2/bgpd.conf
@@ -2,10 +2,13 @@ router bgp 102 vrf r2-cust1
no bgp ebgp-requires-policy
no bgp network import-check
neighbor 192.168.0.1 remote-as 101
+ neighbor 192.168.0.1 timers 3 10
neighbor 192.168.0.1 bfd
neighbor 192.168.1.1 remote-as 103
+ neighbor 192.168.1.1 timers 3 10
neighbor 192.168.1.1 bfd
neighbor 192.168.2.1 remote-as 104
+ neighbor 192.168.2.1 timers 3 10
neighbor 192.168.2.1 bfd
address-family ipv4 unicast
network 10.254.254.2/32
diff --git a/tests/topotests/bfd-vrf-topo1/r3/bgpd.conf b/tests/topotests/bfd-vrf-topo1/r3/bgpd.conf
index 052707ae1b..1d7c730395 100644
--- a/tests/topotests/bfd-vrf-topo1/r3/bgpd.conf
+++ b/tests/topotests/bfd-vrf-topo1/r3/bgpd.conf
@@ -2,6 +2,7 @@ router bgp 103 vrf r3-cust1
no bgp ebgp-requires-policy
no bgp network import-check
neighbor 192.168.1.2 remote-as 102
+ neighbor 192.168.1.2 timers 3 10
neighbor 192.168.1.2 bfd
address-family ipv4 unicast
network 10.254.254.3/32
diff --git a/tests/topotests/bfd-vrf-topo1/r4/bgpd.conf b/tests/topotests/bfd-vrf-topo1/r4/bgpd.conf
index bcb0a17c01..f34035d460 100644
--- a/tests/topotests/bfd-vrf-topo1/r4/bgpd.conf
+++ b/tests/topotests/bfd-vrf-topo1/r4/bgpd.conf
@@ -2,6 +2,7 @@ router bgp 104 vrf r4-cust1
no bgp ebgp-requires-policy
no bgp network import-check
neighbor 192.168.2.2 remote-as 102
+ neighbor 192.168.2.2 timers 3 10
neighbor 192.168.2.2 bfd
address-family ipv4 unicast
network 10.254.254.4/32
diff --git a/tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.py b/tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.py
index b1f755ad06..95595ecba4 100755..100644
--- a/tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.py
+++ b/tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.py
@@ -79,7 +79,7 @@ def setup_module(mod):
router_list = tgen.routers()
# check for zebra capability
- for rname, router in router_list.iteritems():
+ for rname, router in router_list.items():
if router.check_capability(TopoRouter.RD_ZEBRA, "--vrfwnetns") == False:
return pytest.skip(
"Skipping BFD Topo1 VRF NETNS feature. VRF NETNS backend not available on FRR"
@@ -105,7 +105,7 @@ def setup_module(mod):
"ip netns exec {0}-cust1 ifconfig {0}-eth2 up",
]
- for rname, router in router_list.iteritems():
+ for rname, router in router_list.items():
# create VRF rx-cust1 and link rx-eth0 to rx-cust1
for cmd in cmds:
output = tgen.net[rname].cmd(cmd.format(rname))
@@ -113,7 +113,7 @@ def setup_module(mod):
for cmd in cmds2:
output = tgen.net[rname].cmd(cmd.format(rname))
- for rname, router in router_list.iteritems():
+ for rname, router in router_list.items():
router.load_config(
TopoRouter.RD_ZEBRA,
os.path.join(CWD, "{}/zebra.conf".format(rname)),
@@ -145,7 +145,7 @@ def teardown_module(_mod):
]
router_list = tgen.routers()
- for rname, router in router_list.iteritems():
+ for rname, router in router_list.items():
if rname == "r2":
for cmd in cmds2:
tgen.net[rname].cmd(cmd.format(rname))
diff --git a/tests/topotests/bgp-auth/test_bgp_auth.py b/tests/topotests/bgp-auth/test_bgp_auth.py
index 6198997b86..286af3bf65 100755..100644
--- a/tests/topotests/bgp-auth/test_bgp_auth.py
+++ b/tests/topotests/bgp-auth/test_bgp_auth.py
@@ -217,7 +217,7 @@ def setup_module(mod):
router_list = tgen.routers()
# For all registred routers, load the zebra configuration file
- for rname, router in router_list.iteritems():
+ for rname, router in router_list.items():
router.load_config(
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
)
@@ -273,7 +273,7 @@ def print_diag(vrf):
tgen = get_topogen()
router_list = tgen.routers()
- for rname, router in router_list.iteritems():
+ for rname, router in router_list.items():
print(rname + ":")
print(router.vtysh_cmd("show run"))
print(router.vtysh_cmd("show ip route {}".format(vrf_str(vrf))))
@@ -285,7 +285,7 @@ def configure(conf_file):
tgen = get_topogen()
router_list = tgen.routers()
- for rname, router in router_list.iteritems():
+ for rname, router in router_list.items():
with open(
os.path.join(CWD, "{}/{}").format(router.name, conf_file), "r+"
) as cfg:
@@ -321,7 +321,7 @@ def clear_ospf(vrf=""):
tgen = get_topogen()
router_list = tgen.routers()
- for rname, router in router_list.iteritems():
+ for rname, router in router_list.items():
if vrf == "":
router.vtysh_cmd("conf t\nno router ospf")
else:
diff --git a/tests/topotests/bgp-basic-functionality-topo1/test_bgp_basic_functionality.py b/tests/topotests/bgp-basic-functionality-topo1/test_bgp_basic_functionality.py
index 69e050caed..41fa7c0a09 100755
--- a/tests/topotests/bgp-basic-functionality-topo1/test_bgp_basic_functionality.py
+++ b/tests/topotests/bgp-basic-functionality-topo1/test_bgp_basic_functionality.py
@@ -76,6 +76,7 @@ from lib.common_config import (
create_prefix_lists,
create_route_maps,
verify_bgp_community,
+ required_linux_kernel_version
)
from lib.topolog import logger
from lib.bgp import (
@@ -137,6 +138,11 @@ def setup_module(mod):
* `mod`: module name
"""
+ # 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")
+
testsuite_run_time = time.asctime(time.localtime(time.time()))
logger.info("Testsuite start time: {}".format(testsuite_run_time))
logger.info("=" * 40)
diff --git a/tests/topotests/bgp-ecmp-topo1/r1/bgpd.conf b/tests/topotests/bgp-ecmp-topo1/r1/bgpd.conf
index d3beb2d320..49981ac589 100644
--- a/tests/topotests/bgp-ecmp-topo1/r1/bgpd.conf
+++ b/tests/topotests/bgp-ecmp-topo1/r1/bgpd.conf
@@ -7,25 +7,45 @@ router bgp 100
bgp bestpath as-path multipath-relax
no bgp ebgp-requires-policy
neighbor 10.0.1.101 remote-as 99
+ neighbor 10.0.1.101 timers 3 10
neighbor 10.0.1.102 remote-as 99
+ neighbor 10.0.1.102 timers 3 10
neighbor 10.0.1.103 remote-as 99
+ neighbor 10.0.1.103 timers 3 10
neighbor 10.0.1.104 remote-as 99
+ neighbor 10.0.1.104 timers 3 10
neighbor 10.0.1.105 remote-as 99
+ neighbor 10.0.1.105 timers 3 10
neighbor 10.0.2.106 remote-as 99
+ neighbor 10.0.2.106 timers 3 10
neighbor 10.0.2.107 remote-as 99
+ neighbor 10.0.2.107 timers 3 10
neighbor 10.0.2.108 remote-as 99
+ neighbor 10.0.2.108 timers 3 10
neighbor 10.0.2.109 remote-as 99
+ neighbor 10.0.2.109 timers 3 10
neighbor 10.0.2.110 remote-as 99
+ neighbor 10.0.2.110 timers 3 10
neighbor 10.0.3.111 remote-as 111
+ neighbor 10.0.3.111 timers 3 10
neighbor 10.0.3.112 remote-as 112
+ neighbor 10.0.3.112 timers 3 10
neighbor 10.0.3.113 remote-as 113
+ neighbor 10.0.3.113 timers 3 10
neighbor 10.0.3.114 remote-as 114
+ neighbor 10.0.3.114 timers 3 10
neighbor 10.0.3.115 remote-as 115
+ neighbor 10.0.3.115 timers 3 10
neighbor 10.0.4.116 remote-as 116
+ neighbor 10.0.4.116 timers 3 10
neighbor 10.0.4.117 remote-as 117
+ neighbor 10.0.4.117 timers 3 10
neighbor 10.0.4.118 remote-as 118
+ neighbor 10.0.4.118 timers 3 10
neighbor 10.0.4.119 remote-as 119
+ neighbor 10.0.4.119 timers 3 10
neighbor 10.0.4.120 remote-as 120
+ neighbor 10.0.4.120 timers 3 10
!
!
diff --git a/tests/topotests/bgp-ecmp-topo1/test_bgp_ecmp_topo1.py b/tests/topotests/bgp-ecmp-topo1/test_bgp_ecmp_topo1.py
index c37f818b0f..400e7e9bf5 100755..100644
--- a/tests/topotests/bgp-ecmp-topo1/test_bgp_ecmp_topo1.py
+++ b/tests/topotests/bgp-ecmp-topo1/test_bgp_ecmp_topo1.py
@@ -95,7 +95,7 @@ def setup_module(module):
# Starting Routers
router_list = tgen.routers()
- for rname, router in router_list.iteritems():
+ for rname, router in router_list.items():
router.load_config(
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
)
@@ -107,7 +107,7 @@ def setup_module(module):
# Starting Hosts and init ExaBGP on each of them
topotest.sleep(10, "starting BGP on all {} peers".format(total_ebgp_peers))
peer_list = tgen.exabgp_peers()
- for pname, peer in peer_list.iteritems():
+ for pname, peer in peer_list.items():
peer_dir = os.path.join(CWD, pname)
env_file = os.path.join(CWD, "exabgp.env")
peer.start(peer_dir, env_file)
diff --git a/tests/topotests/bgp-ecmp-topo2/test_ebgp_ecmp_topo2.py b/tests/topotests/bgp-ecmp-topo2/test_ebgp_ecmp_topo2.py
index 948f641afb..eed118ebdc 100755..100644
--- a/tests/topotests/bgp-ecmp-topo2/test_ebgp_ecmp_topo2.py
+++ b/tests/topotests/bgp-ecmp-topo2/test_ebgp_ecmp_topo2.py
@@ -61,6 +61,7 @@ from lib.common_config import (
check_address_types,
interface_status,
reset_config_on_routers,
+ required_linux_kernel_version
)
from lib.topolog import logger
from lib.bgp import verify_bgp_convergence, create_router_bgp, clear_bgp
@@ -108,6 +109,11 @@ def setup_module(mod):
global NEXT_HOPS, INTF_LIST_R3, INTF_LIST_R2, TEST_STATIC
global ADDR_TYPES
+ # 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")
+
testsuite_run_time = time.asctime(time.localtime(time.time()))
logger.info("Testsuite start time: {}".format(testsuite_run_time))
logger.info("=" * 40)
@@ -139,7 +145,7 @@ def setup_module(mod):
link_data = [
val
- for links, val in topo["routers"]["r2"]["links"].iteritems()
+ for links, val in topo["routers"]["r2"]["links"].items()
if "r3" in links
]
for adt in ADDR_TYPES:
@@ -156,7 +162,7 @@ def setup_module(mod):
link_data = [
val
- for links, val in topo["routers"]["r3"]["links"].iteritems()
+ for links, val in topo["routers"]["r3"]["links"].items()
if "r2" in links
]
INTF_LIST_R3 = [val["interface"].split("/")[0] for val in link_data]
diff --git a/tests/topotests/bgp-ecmp-topo2/test_ibgp_ecmp_topo2.py b/tests/topotests/bgp-ecmp-topo2/test_ibgp_ecmp_topo2.py
index 5b997fdd16..7357c33824 100755..100644
--- a/tests/topotests/bgp-ecmp-topo2/test_ibgp_ecmp_topo2.py
+++ b/tests/topotests/bgp-ecmp-topo2/test_ibgp_ecmp_topo2.py
@@ -61,6 +61,7 @@ from lib.common_config import (
check_address_types,
interface_status,
reset_config_on_routers,
+ required_linux_kernel_version
)
from lib.topolog import logger
from lib.bgp import verify_bgp_convergence, create_router_bgp, clear_bgp
@@ -108,6 +109,11 @@ def setup_module(mod):
global NEXT_HOPS, INTF_LIST_R3, INTF_LIST_R2, TEST_STATIC
global ADDR_TYPES
+ # 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")
+
testsuite_run_time = time.asctime(time.localtime(time.time()))
logger.info("Testsuite start time: {}".format(testsuite_run_time))
logger.info("=" * 40)
@@ -140,7 +146,7 @@ def setup_module(mod):
link_data = [
val
- for links, val in topo["routers"]["r2"]["links"].iteritems()
+ for links, val in topo["routers"]["r2"]["links"].items()
if "r3" in links
]
for adt in ADDR_TYPES:
@@ -157,7 +163,7 @@ def setup_module(mod):
link_data = [
val
- for links, val in topo["routers"]["r3"]["links"].iteritems()
+ for links, val in topo["routers"]["r3"]["links"].items()
if "r2" in links
]
INTF_LIST_R3 = [val["interface"].split("/")[0] for val in link_data]
diff --git a/tests/topotests/bgp-evpn-mh/test_evpn_mh.py b/tests/topotests/bgp-evpn-mh/test_evpn_mh.py
index fe28f79bd4..ee50a422a7 100755..100644
--- a/tests/topotests/bgp-evpn-mh/test_evpn_mh.py
+++ b/tests/topotests/bgp-evpn-mh/test_evpn_mh.py
@@ -384,7 +384,7 @@ def setup_module(module):
# tgen.mininet_cli()
# This is a sample of configuration loading.
router_list = tgen.routers()
- for rname, router in router_list.iteritems():
+ for rname, router in router_list.items():
router.load_config(
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
)
@@ -416,7 +416,7 @@ def check_local_es(esi, vtep_ips, dut_name, down_vteps):
else:
tor_ips_rack = tor_ips_rack_2
- for tor_name, tor_ip in tor_ips_rack.iteritems():
+ for tor_name, tor_ip in tor_ips_rack.items():
if dut_name not in tor_name:
peer_ips.append(tor_ip)
@@ -442,7 +442,7 @@ def check_remote_es(esi, vtep_ips, dut_name, down_vteps):
else:
tor_ips_rack = tor_ips_rack_1
- for tor_name, tor_ip in tor_ips_rack.iteritems():
+ for tor_name, tor_ip in tor_ips_rack.items():
remote_ips.append(tor_ip)
# remove down VTEPs from the remote check list
@@ -464,7 +464,7 @@ def check_es(dut):
result = None
- expected_es_set = set([v for k, v in host_es_map.iteritems()])
+ expected_es_set = set([v for k, v in host_es_map.items()])
curr_es_set = []
# check is ES content is correct
@@ -588,7 +588,7 @@ def check_mac(dut, vni, mac, m_type, esi, intf):
out = dut.vtysh_cmd("show evpn mac vni %d mac %s json" % (vni, mac))
mac_js = json.loads(out)
- for mac, info in mac_js.iteritems():
+ for mac, info in mac_js.items():
tmp_esi = info.get("esi", "")
tmp_m_type = info.get("type", "")
tmp_intf = info.get("intf", "") if tmp_m_type == "local" else ""
diff --git a/tests/topotests/bgp-evpn-vxlan_topo1/test_bgp_evpn_vxlan.py b/tests/topotests/bgp-evpn-vxlan_topo1/test_bgp_evpn_vxlan.py
index 90144f5c66..2a14105383 100755..100644
--- a/tests/topotests/bgp-evpn-vxlan_topo1/test_bgp_evpn_vxlan.py
+++ b/tests/topotests/bgp-evpn-vxlan_topo1/test_bgp_evpn_vxlan.py
@@ -122,7 +122,7 @@ def setup_module(mod):
router_list = tgen.routers()
# For all registred routers, load the zebra configuration file
- for rname, router in router_list.iteritems():
+ for rname, router in router_list.items():
router.load_config(
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
)
diff --git a/tests/topotests/bgp-vrf-route-leak-basic/test_bgp-vrf-route-leak-basic.py b/tests/topotests/bgp-vrf-route-leak-basic/test_bgp-vrf-route-leak-basic.py
index 6178bfc63a..5aa1bdf329 100755..100644
--- a/tests/topotests/bgp-vrf-route-leak-basic/test_bgp-vrf-route-leak-basic.py
+++ b/tests/topotests/bgp-vrf-route-leak-basic/test_bgp-vrf-route-leak-basic.py
@@ -57,7 +57,7 @@ def setup_module(mod):
tgen.start_topology()
# For all registered routers, load the zebra configuration file
- for rname, router in tgen.routers().iteritems():
+ for rname, router in tgen.routers().items():
router.run("/bin/bash {}/setup_vrfs".format(CWD))
router.load_config(
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
diff --git a/tests/topotests/bgp_aggregate-address_origin/r1/bgpd.conf b/tests/topotests/bgp_aggregate-address_origin/r1/bgpd.conf
index 9d519fae88..3486c64c55 100644
--- a/tests/topotests/bgp_aggregate-address_origin/r1/bgpd.conf
+++ b/tests/topotests/bgp_aggregate-address_origin/r1/bgpd.conf
@@ -1,6 +1,7 @@
router bgp 65000
no bgp ebgp-requires-policy
neighbor 192.168.255.2 remote-as 65001
+ neighbor 192.168.255.2 timers 3 10
address-family ipv4 unicast
redistribute connected
aggregate-address 172.16.255.0/24 origin igp
diff --git a/tests/topotests/bgp_aggregate-address_origin/r2/bgpd.conf b/tests/topotests/bgp_aggregate-address_origin/r2/bgpd.conf
index 38cf5aaca7..b2d945583c 100644
--- a/tests/topotests/bgp_aggregate-address_origin/r2/bgpd.conf
+++ b/tests/topotests/bgp_aggregate-address_origin/r2/bgpd.conf
@@ -1,5 +1,6 @@
router bgp 65001
no bgp ebgp-requires-policy
neighbor 192.168.255.1 remote-as 65000
+ neighbor 192.168.255.1 timers 3 10
exit-address-family
!
diff --git a/tests/topotests/bgp_aggregate-address_origin/test_bgp_aggregate-address_origin.py b/tests/topotests/bgp_aggregate-address_origin/test_bgp_aggregate-address_origin.py
index fa799f8256..86fd4b601f 100644
--- a/tests/topotests/bgp_aggregate-address_origin/test_bgp_aggregate-address_origin.py
+++ b/tests/topotests/bgp_aggregate-address_origin/test_bgp_aggregate-address_origin.py
@@ -66,7 +66,7 @@ def setup_module(mod):
router_list = tgen.routers()
- for i, (rname, router) in enumerate(router_list.iteritems(), 1):
+ for i, (rname, router) in enumerate(router_list.items(), 1):
router.load_config(
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
)
diff --git a/tests/topotests/bgp_aggregate-address_route-map/r1/bgpd.conf b/tests/topotests/bgp_aggregate-address_route-map/r1/bgpd.conf
index 292f0e967f..7fb55cf001 100644
--- a/tests/topotests/bgp_aggregate-address_route-map/r1/bgpd.conf
+++ b/tests/topotests/bgp_aggregate-address_route-map/r1/bgpd.conf
@@ -1,6 +1,7 @@
router bgp 65000
no bgp ebgp-requires-policy
neighbor 192.168.255.2 remote-as 65001
+ neighbor 192.168.255.2 timers 3 10
address-family ipv4 unicast
redistribute connected
aggregate-address 172.16.255.0/24 route-map aggr-rmap
diff --git a/tests/topotests/bgp_aggregate-address_route-map/r2/bgpd.conf b/tests/topotests/bgp_aggregate-address_route-map/r2/bgpd.conf
index 38cf5aaca7..b2d945583c 100644
--- a/tests/topotests/bgp_aggregate-address_route-map/r2/bgpd.conf
+++ b/tests/topotests/bgp_aggregate-address_route-map/r2/bgpd.conf
@@ -1,5 +1,6 @@
router bgp 65001
no bgp ebgp-requires-policy
neighbor 192.168.255.1 remote-as 65000
+ neighbor 192.168.255.1 timers 3 10
exit-address-family
!
diff --git a/tests/topotests/bgp_aggregate-address_route-map/test_bgp_aggregate-address_route-map.py b/tests/topotests/bgp_aggregate-address_route-map/test_bgp_aggregate-address_route-map.py
index 9c06c9d382..c7d9f13f3f 100644
--- a/tests/topotests/bgp_aggregate-address_route-map/test_bgp_aggregate-address_route-map.py
+++ b/tests/topotests/bgp_aggregate-address_route-map/test_bgp_aggregate-address_route-map.py
@@ -69,7 +69,7 @@ def setup_module(mod):
router_list = tgen.routers()
- for i, (rname, router) in enumerate(router_list.iteritems(), 1):
+ for i, (rname, router) in enumerate(router_list.items(), 1):
router.load_config(
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
)
diff --git a/tests/topotests/bgp_as_allow_in/test_bgp_as_allow_in.py b/tests/topotests/bgp_as_allow_in/test_bgp_as_allow_in.py
index 89b15c46d3..f9d22a3a36 100755
--- a/tests/topotests/bgp_as_allow_in/test_bgp_as_allow_in.py
+++ b/tests/topotests/bgp_as_allow_in/test_bgp_as_allow_in.py
@@ -65,6 +65,7 @@ from lib.common_config import (
create_route_maps,
check_address_types,
step,
+ required_linux_kernel_version
)
from lib.topolog import logger
from lib.bgp import (
@@ -112,6 +113,11 @@ def setup_module(mod):
* `mod`: module name
"""
+ # 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")
+
testsuite_run_time = time.asctime(time.localtime(time.time()))
logger.info("Testsuite start time: {}".format(testsuite_run_time))
logger.info("=" * 40)
diff --git a/tests/topotests/bgp_as_wide_bgp_identifier/r1/bgpd.conf b/tests/topotests/bgp_as_wide_bgp_identifier/r1/bgpd.conf
index 75741a3c3e..cb04749b92 100644
--- a/tests/topotests/bgp_as_wide_bgp_identifier/r1/bgpd.conf
+++ b/tests/topotests/bgp_as_wide_bgp_identifier/r1/bgpd.conf
@@ -3,4 +3,5 @@ router bgp 65001
bgp router-id 10.10.10.10
no bgp ebgp-requires-policy
neighbor 192.168.255.1 remote-as 65002
+ neighbor 192.168.255.1 timers 3 10
!
diff --git a/tests/topotests/bgp_as_wide_bgp_identifier/r2/bgpd.conf b/tests/topotests/bgp_as_wide_bgp_identifier/r2/bgpd.conf
index 18a6c66f69..bed68858fd 100644
--- a/tests/topotests/bgp_as_wide_bgp_identifier/r2/bgpd.conf
+++ b/tests/topotests/bgp_as_wide_bgp_identifier/r2/bgpd.conf
@@ -3,5 +3,7 @@ router bgp 65002
bgp router-id 10.10.10.10
no bgp ebgp-requires-policy
neighbor 192.168.255.2 remote-as 65001
+ neighbor 192.168.255.2 timers 3 10
neighbor 192.168.255.3 remote-as 65002
+ neighbor 192.168.255.3 timers 3 10
!
diff --git a/tests/topotests/bgp_as_wide_bgp_identifier/r3/bgpd.conf b/tests/topotests/bgp_as_wide_bgp_identifier/r3/bgpd.conf
index 27bf126000..384e617d02 100644
--- a/tests/topotests/bgp_as_wide_bgp_identifier/r3/bgpd.conf
+++ b/tests/topotests/bgp_as_wide_bgp_identifier/r3/bgpd.conf
@@ -3,4 +3,5 @@ router bgp 65002
bgp router-id 10.10.10.10
no bgp ebgp-requires-policy
neighbor 192.168.255.1 remote-as 65002
+ neighbor 192.168.255.1 timers 3 10
!
diff --git a/tests/topotests/bgp_as_wide_bgp_identifier/test_bgp_as_wide_bgp_identifier.py b/tests/topotests/bgp_as_wide_bgp_identifier/test_bgp_as_wide_bgp_identifier.py
index 459af486ff..02edb62ca0 100644
--- a/tests/topotests/bgp_as_wide_bgp_identifier/test_bgp_as_wide_bgp_identifier.py
+++ b/tests/topotests/bgp_as_wide_bgp_identifier/test_bgp_as_wide_bgp_identifier.py
@@ -65,7 +65,7 @@ def setup_module(mod):
router_list = tgen.routers()
- for i, (rname, router) in enumerate(router_list.iteritems(), 1):
+ for i, (rname, router) in enumerate(router_list.items(), 1):
router.load_config(
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
)
diff --git a/tests/topotests/bgp_comm-list_delete/r1/bgpd.conf b/tests/topotests/bgp_comm-list_delete/r1/bgpd.conf
index 9518894351..12161d2fa2 100644
--- a/tests/topotests/bgp_comm-list_delete/r1/bgpd.conf
+++ b/tests/topotests/bgp_comm-list_delete/r1/bgpd.conf
@@ -1,6 +1,7 @@
router bgp 65000
no bgp ebgp-requires-policy
neighbor 192.168.255.2 remote-as 65001
+ neighbor 192.168.255.2 timers 3 10
address-family ipv4 unicast
redistribute connected route-map r2-out
exit-address-family
diff --git a/tests/topotests/bgp_comm-list_delete/r2/bgpd.conf b/tests/topotests/bgp_comm-list_delete/r2/bgpd.conf
index e4c1167745..33231b5274 100644
--- a/tests/topotests/bgp_comm-list_delete/r2/bgpd.conf
+++ b/tests/topotests/bgp_comm-list_delete/r2/bgpd.conf
@@ -1,6 +1,7 @@
router bgp 65001
no bgp ebgp-requires-policy
neighbor 192.168.255.1 remote-as 65000
+ neighbor 192.168.255.1 timers 3 10
address-family ipv4
neighbor 192.168.255.1 route-map r1-in in
exit-address-family
diff --git a/tests/topotests/bgp_comm-list_delete/test_bgp_comm-list_delete.py b/tests/topotests/bgp_comm-list_delete/test_bgp_comm-list_delete.py
index 314ad12a6d..fe7052b80f 100644
--- a/tests/topotests/bgp_comm-list_delete/test_bgp_comm-list_delete.py
+++ b/tests/topotests/bgp_comm-list_delete/test_bgp_comm-list_delete.py
@@ -64,7 +64,7 @@ def setup_module(mod):
router_list = tgen.routers()
- for i, (rname, router) in enumerate(router_list.iteritems(), 1):
+ for i, (rname, router) in enumerate(router_list.items(), 1):
router.load_config(
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
)
diff --git a/tests/topotests/bgp_communities_topo1/test_bgp_communities.py b/tests/topotests/bgp_communities_topo1/test_bgp_communities.py
index 7d960d6916..57e8e0d34a 100644
--- a/tests/topotests/bgp_communities_topo1/test_bgp_communities.py
+++ b/tests/topotests/bgp_communities_topo1/test_bgp_communities.py
@@ -54,6 +54,7 @@ from lib.common_config import (
create_route_maps,
create_prefix_lists,
create_route_maps,
+ required_linux_kernel_version
)
from lib.topolog import logger
from lib.bgp import (
@@ -102,6 +103,11 @@ def setup_module(mod):
* `mod`: module name
"""
+ # 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")
+
testsuite_run_time = time.asctime(time.localtime(time.time()))
logger.info("Testsuite start time: {}".format(testsuite_run_time))
logger.info("=" * 40)
diff --git a/tests/topotests/bgp_default-route_route-map/r1/bgpd.conf b/tests/topotests/bgp_default-route_route-map/r1/bgpd.conf
index 12e56e27c4..cb07ea9fdf 100644
--- a/tests/topotests/bgp_default-route_route-map/r1/bgpd.conf
+++ b/tests/topotests/bgp_default-route_route-map/r1/bgpd.conf
@@ -1,6 +1,7 @@
router bgp 65000
no bgp ebgp-requires-policy
neighbor 192.168.255.2 remote-as 65001
+ neighbor 192.168.255.2 timers 3 10
address-family ipv4 unicast
neighbor 192.168.255.2 default-originate route-map default
exit-address-family
diff --git a/tests/topotests/bgp_default-route_route-map/r2/bgpd.conf b/tests/topotests/bgp_default-route_route-map/r2/bgpd.conf
index b6b560aa4d..00c96cc58b 100644
--- a/tests/topotests/bgp_default-route_route-map/r2/bgpd.conf
+++ b/tests/topotests/bgp_default-route_route-map/r2/bgpd.conf
@@ -1,6 +1,7 @@
router bgp 65001
no bgp ebgp-requires-policy
neighbor 192.168.255.1 remote-as 65000
+ neighbor 192.168.255.1 timers 3 10
address-family ipv4 unicast
redistribute connected
exit-address-family
diff --git a/tests/topotests/bgp_default-route_route-map/test_bgp_default-originate_route-map.py b/tests/topotests/bgp_default-route_route-map/test_bgp_default-originate_route-map.py
index ba9a6dffb5..a72c3a4cbf 100644
--- a/tests/topotests/bgp_default-route_route-map/test_bgp_default-originate_route-map.py
+++ b/tests/topotests/bgp_default-route_route-map/test_bgp_default-originate_route-map.py
@@ -69,7 +69,7 @@ def setup_module(mod):
router_list = tgen.routers()
- for i, (rname, router) in enumerate(router_list.iteritems(), 1):
+ for i, (rname, router) in enumerate(router_list.items(), 1):
router.load_config(
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
)
diff --git a/tests/topotests/bgp_distance_change/r1/bgpd.conf b/tests/topotests/bgp_distance_change/r1/bgpd.conf
index cd2ef675fc..07cfe2e2f1 100644
--- a/tests/topotests/bgp_distance_change/r1/bgpd.conf
+++ b/tests/topotests/bgp_distance_change/r1/bgpd.conf
@@ -1,5 +1,6 @@
router bgp 65000
no bgp ebgp-requires-policy
neighbor 192.168.255.2 remote-as 65001
+ neighbor 192.168.255.2 timers 3 10
exit-address-family
!
diff --git a/tests/topotests/bgp_distance_change/r2/bgpd.conf b/tests/topotests/bgp_distance_change/r2/bgpd.conf
index 0faec85032..9cd86dc284 100644
--- a/tests/topotests/bgp_distance_change/r2/bgpd.conf
+++ b/tests/topotests/bgp_distance_change/r2/bgpd.conf
@@ -1,6 +1,7 @@
router bgp 65001
no bgp ebgp-requires-policy
neighbor 192.168.255.1 remote-as 65000
+ neighbor 192.168.255.1 timers 3 10
address-family ipv4
redistribute connected
exit-address-family
diff --git a/tests/topotests/bgp_distance_change/test_bgp_distance_change.py b/tests/topotests/bgp_distance_change/test_bgp_distance_change.py
index 6d09cd2e8c..f338d52e70 100644
--- a/tests/topotests/bgp_distance_change/test_bgp_distance_change.py
+++ b/tests/topotests/bgp_distance_change/test_bgp_distance_change.py
@@ -68,7 +68,7 @@ def setup_module(mod):
router_list = tgen.routers()
- for i, (rname, router) in enumerate(router_list.iteritems(), 1):
+ for i, (rname, router) in enumerate(router_list.items(), 1):
router.load_config(
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
)
diff --git a/tests/topotests/bgp_ebgp_requires_policy/r1/bgpd.conf b/tests/topotests/bgp_ebgp_requires_policy/r1/bgpd.conf
index aaa01ebcf9..add37ee58d 100644
--- a/tests/topotests/bgp_ebgp_requires_policy/r1/bgpd.conf
+++ b/tests/topotests/bgp_ebgp_requires_policy/r1/bgpd.conf
@@ -1,5 +1,6 @@
router bgp 65000
neighbor 192.168.255.2 remote-as 1000
+ neighbor 192.168.255.2 timers 3 10
neighbor 192.168.255.2 local-as 500
address-family ipv4 unicast
redistribute connected
diff --git a/tests/topotests/bgp_ebgp_requires_policy/r2/bgpd.conf b/tests/topotests/bgp_ebgp_requires_policy/r2/bgpd.conf
index 27427a9aaa..802c32714b 100644
--- a/tests/topotests/bgp_ebgp_requires_policy/r2/bgpd.conf
+++ b/tests/topotests/bgp_ebgp_requires_policy/r2/bgpd.conf
@@ -1,3 +1,5 @@
router bgp 1000
no bgp ebgp-requires-policy
neighbor 192.168.255.1 remote-as 500
+ neighbor 192.168.255.1 timers 3 10
+!
diff --git a/tests/topotests/bgp_ebgp_requires_policy/r3/bgpd.conf b/tests/topotests/bgp_ebgp_requires_policy/r3/bgpd.conf
index 2deb4b663d..1280b427ad 100644
--- a/tests/topotests/bgp_ebgp_requires_policy/r3/bgpd.conf
+++ b/tests/topotests/bgp_ebgp_requires_policy/r3/bgpd.conf
@@ -1,5 +1,6 @@
router bgp 65000
neighbor 192.168.255.2 remote-as 1000
+ neighbor 192.168.255.2 timers 3 10
neighbor 192.168.255.2 local-as 500
address-family ipv4 unicast
redistribute connected
diff --git a/tests/topotests/bgp_ebgp_requires_policy/r4/bgpd.conf b/tests/topotests/bgp_ebgp_requires_policy/r4/bgpd.conf
index 27427a9aaa..802c32714b 100644
--- a/tests/topotests/bgp_ebgp_requires_policy/r4/bgpd.conf
+++ b/tests/topotests/bgp_ebgp_requires_policy/r4/bgpd.conf
@@ -1,3 +1,5 @@
router bgp 1000
no bgp ebgp-requires-policy
neighbor 192.168.255.1 remote-as 500
+ neighbor 192.168.255.1 timers 3 10
+!
diff --git a/tests/topotests/bgp_ebgp_requires_policy/r5/bgpd.conf b/tests/topotests/bgp_ebgp_requires_policy/r5/bgpd.conf
index 92a2797921..60b29f6f1b 100644
--- a/tests/topotests/bgp_ebgp_requires_policy/r5/bgpd.conf
+++ b/tests/topotests/bgp_ebgp_requires_policy/r5/bgpd.conf
@@ -1,6 +1,7 @@
router bgp 65000
no bgp ebgp-requires-policy
neighbor 192.168.255.2 remote-as 65000
+ neighbor 192.168.255.2 timers 3 10
address-family ipv4 unicast
redistribute connected
!
diff --git a/tests/topotests/bgp_ebgp_requires_policy/r6/bgpd.conf b/tests/topotests/bgp_ebgp_requires_policy/r6/bgpd.conf
index 342f53d4c7..7ad5d927a7 100644
--- a/tests/topotests/bgp_ebgp_requires_policy/r6/bgpd.conf
+++ b/tests/topotests/bgp_ebgp_requires_policy/r6/bgpd.conf
@@ -1,2 +1,4 @@
router bgp 65000
neighbor 192.168.255.1 remote-as 65000
+ neighbor 192.168.255.1 timers 3 10
+!
diff --git a/tests/topotests/bgp_ebgp_requires_policy/test_bgp_ebgp_requires_policy.py b/tests/topotests/bgp_ebgp_requires_policy/test_bgp_ebgp_requires_policy.py
index 5c2af2b30b..2520763bda 100644
--- a/tests/topotests/bgp_ebgp_requires_policy/test_bgp_ebgp_requires_policy.py
+++ b/tests/topotests/bgp_ebgp_requires_policy/test_bgp_ebgp_requires_policy.py
@@ -82,7 +82,7 @@ def setup_module(mod):
router_list = tgen.routers()
- for i, (rname, router) in enumerate(router_list.iteritems(), 1):
+ for i, (rname, router) in enumerate(router_list.items(), 1):
router.load_config(
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
)
diff --git a/tests/topotests/bgp_evpn_rt5/__init__.py b/tests/topotests/bgp_evpn_rt5/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_evpn_rt5/__init__.py
diff --git a/tests/topotests/bgp_evpn_rt5/r1/bgpd.conf b/tests/topotests/bgp_evpn_rt5/r1/bgpd.conf
new file mode 100644
index 0000000000..9237682067
--- /dev/null
+++ b/tests/topotests/bgp_evpn_rt5/r1/bgpd.conf
@@ -0,0 +1,26 @@
+debug bgp neighbor-events
+debug bgp updates
+debug bgp zebra
+router bgp 65000
+ bgp router-id 192.168.100.21
+ bgp log-neighbor-changes
+ no bgp default ipv4-unicast
+ neighbor 192.168.100.41 remote-as 65000
+ neighbor 192.168.100.41 capability extended-nexthop
+ !
+ address-family l2vpn evpn
+ neighbor 192.168.100.41 activate
+ advertise-all-vni
+ exit-address-family
+!
+router bgp 65000 vrf r1-vrf-101
+ bgp router-id 192.168.102.21
+ bgp log-neighbor-changes
+ no bgp network import-check
+ address-family ipv4 unicast
+ network 192.168.102.21/32
+ exit-address-family
+ address-family l2vpn evpn
+ advertise ipv4 unicast
+ exit-address-family
+ !
diff --git a/tests/topotests/bgp_evpn_rt5/r1/zebra.conf b/tests/topotests/bgp_evpn_rt5/r1/zebra.conf
new file mode 100644
index 0000000000..f5eaab1953
--- /dev/null
+++ b/tests/topotests/bgp_evpn_rt5/r1/zebra.conf
@@ -0,0 +1,22 @@
+log stdout
+
+hostname r1
+password zebra
+
+debug zebra vxlan
+debug zebra kernel
+debug zebra dplane
+debug zebra rib
+log stdout
+vrf r1-vrf-101
+ vni 101
+ exit-vrf
+!
+interface r1-eth0
+ ip address 192.168.100.21/24
+!
+interface loop101 vrf r1-vrf-101
+ ip address 192.168.102.21/32
+!
+
+
diff --git a/tests/topotests/bgp_evpn_rt5/r2/bgpd.conf b/tests/topotests/bgp_evpn_rt5/r2/bgpd.conf
new file mode 100644
index 0000000000..6dcacd288d
--- /dev/null
+++ b/tests/topotests/bgp_evpn_rt5/r2/bgpd.conf
@@ -0,0 +1,27 @@
+debug bgp neighbor-events
+debug bgp updates
+debug bgp zebra
+router bgp 65000
+ bgp router-id 192.168.100.41
+ bgp log-neighbor-changes
+ no bgp default ipv4-unicast
+ neighbor 192.168.100.21 peer-group
+ neighbor 192.168.100.21 remote-as 65000
+ neighbor 192.168.100.21 capability extended-nexthop
+ !
+ address-family l2vpn evpn
+ neighbor 192.168.100.21 activate
+ advertise-all-vni
+ exit-address-family
+!
+router bgp 65000 vrf r2-vrf-101
+ bgp router-id 192.168.101.41
+ bgp log-neighbor-changes
+ no bgp network import-check
+ address-family ipv4 unicast
+ network 192.168.101.41/32
+ exit-address-family
+ address-family l2vpn evpn
+ advertise ipv4 unicast
+ exit-address-family
+ !
diff --git a/tests/topotests/bgp_evpn_rt5/r2/zebra.conf b/tests/topotests/bgp_evpn_rt5/r2/zebra.conf
new file mode 100644
index 0000000000..e5f962d254
--- /dev/null
+++ b/tests/topotests/bgp_evpn_rt5/r2/zebra.conf
@@ -0,0 +1,18 @@
+log stdout
+
+hostname r2
+password zebra
+
+debug zebra vxlan
+
+vrf r2-vrf-101
+ vni 101
+ exit-vrf
+!
+interface loop101 vrf r2-vrf-101
+ ip address 192.168.101.41/32
+!
+interface r2-eth0
+ ip address 192.168.100.41/24
+!
+
diff --git a/tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py b/tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py
new file mode 100755
index 0000000000..69ef7e9fae
--- /dev/null
+++ b/tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py
@@ -0,0 +1,234 @@
+#!/usr/bin/env python
+
+#
+# test_bgp_evpn.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2019 by 6WIND
+#
+# 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_bgp_evpn.py: Test the FRR/Quagga BGP daemon with BGP IPv6 interface
+ with route advertisements on a separate netns.
+"""
+
+import os
+import sys
+import json
+from functools import partial
+import pytest
+import platform
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, '../'))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+
+# Required to instantiate the topology builder class.
+from mininet.topo import Topo
+
+l3mdev_accept = 0
+krel = ''
+
+class BGPEVPNTopo(Topo):
+ "Test topology builder"
+ def build(self, *_args, **_opts):
+ "Build function"
+ tgen = get_topogen(self)
+
+ tgen.add_router('r1')
+ tgen.add_router('r2')
+
+ switch = tgen.add_switch('s1')
+ switch.add_link(tgen.gears['r1'])
+ switch.add_link(tgen.gears['r2'])
+
+ switch = tgen.add_switch('s2')
+ switch.add_link(tgen.gears['r1'])
+
+ switch = tgen.add_switch('s3')
+ switch.add_link(tgen.gears['r2'])
+
+def setup_module(mod):
+ "Sets up the pytest environment"
+ global l3mdev_accept
+ global krel
+
+ tgen = Topogen(BGPEVPNTopo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ krel = platform.release()
+ if topotest.version_cmp(krel, '4.18') < 0:
+ logger.info('BGP EVPN RT5 NETNS tests will not run (have kernel "{}", but it requires 4.18)'.format(krel))
+ return pytest.skip('Skipping BGP EVPN RT5 NETNS Test. Kernel not supported')
+
+ l3mdev_accept = 1
+ logger.info('setting net.ipv4.tcp_l3mdev_accept={}'.format(l3mdev_accept))
+
+ # create VRF vrf-101 on R1 and R2
+ # create loop101
+ cmds_vrflite = ['sysctl -w net.ipv4.tcp_l3mdev_accept={}'.format(l3mdev_accept),
+ 'ip link add {}-vrf-101 type vrf table 101',
+ 'ip ru add oif {}-vrf-101 table 101',
+ 'ip ru add iif {}-vrf-101 table 101',
+ 'ip link set dev {}-vrf-101 up',
+ 'sysctl -w net.ipv4.tcp_l3mdev_accept={}'.format(l3mdev_accept),
+ 'ip link add loop101 type dummy',
+ 'ip link set dev loop101 master {}-vrf-101',
+ 'ip link set dev loop101 up']
+ cmds_netns = ['ip netns add {}-vrf-101',
+ 'ip link add loop101 type dummy',
+ 'ip link set dev loop101 netns {}-vrf-101',
+ 'ip netns exec {}-vrf-101 ip link set dev loop101 up']
+
+ cmds_r2 = [ # config routing 101
+ 'ip link add name bridge-101 up type bridge stp_state 0',
+ 'ip link set bridge-101 master {}-vrf-101',
+ 'ip link set dev bridge-101 up',
+ 'ip link add name vxlan-101 type vxlan id 101 dstport 4789 dev r2-eth0 local 192.168.100.41',
+ 'ip link set dev vxlan-101 master bridge-101',
+ 'ip link set vxlan-101 up type bridge_slave learning off flood off mcast_flood off']
+
+ cmds_r1_netns_method3 = ['ip link add name vxlan-{1} type vxlan id {1} dstport 4789 dev {0}-eth0 local 192.168.100.21',
+ 'ip link set dev vxlan-{1} netns {0}-vrf-{1}',
+ 'ip netns exec {0}-vrf-{1} ip li set dev lo up',
+ 'ip netns exec {0}-vrf-{1} ip link add name bridge-{1} up type bridge stp_state 0',
+ 'ip netns exec {0}-vrf-{1} ip link set dev vxlan-{1} master bridge-{1}',
+ 'ip netns exec {0}-vrf-{1} ip link set bridge-{1} up',
+ 'ip netns exec {0}-vrf-{1} ip link set vxlan-{1} up']
+
+ router = tgen.gears['r1']
+ for cmd in cmds_netns:
+ logger.info('cmd to r1: '+cmd);
+ output = router.run(cmd.format('r1'))
+ logger.info('result: '+output);
+
+ router = tgen.gears['r2']
+ for cmd in cmds_vrflite:
+ logger.info('cmd to r2: '+cmd.format('r2'));
+ output = router.run(cmd.format('r2'))
+ logger.info('result: '+output);
+
+ for cmd in cmds_r2:
+ logger.info('cmd to r2: '+cmd.format('r2'));
+ output = router.run(cmd.format('r2'))
+ logger.info('result: '+output);
+
+ router = tgen.gears['r1']
+ bridge_id = '101'
+ for cmd in cmds_r1_netns_method3:
+ logger.info('cmd to r1: '+cmd.format('r1', bridge_id));
+ output = router.run(cmd.format('r1', bridge_id))
+ logger.info('result: '+output);
+ router = tgen.gears['r1']
+
+ for rname, router in router_list.iteritems():
+ if rname == 'r1':
+ router.load_config(
+ TopoRouter.RD_ZEBRA,
+ os.path.join(CWD, '{}/zebra.conf'.format(rname)),
+ '--vrfwnetns -o vrf0'
+ )
+ else:
+ 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))
+ )
+
+ # Initialize all routers.
+ tgen.start_router()
+
+def teardown_module(_mod):
+ "Teardown the pytest environment"
+ tgen = get_topogen()
+ cmds_rx_netns = ['ip netns del {}-vrf-101']
+
+ router = tgen.gears['r1']
+ for cmd in cmds_rx_netns:
+ logger.info('cmd to r1: '+cmd.format('r1'));
+ output = router.run(cmd.format('r1'))
+ tgen.stop_topology()
+
+
+def test_protocols_convergence():
+ """
+ Assert that all protocols have converged
+ statuses as they depend on it.
+ """
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ topotest.sleep(4, 'waiting 4 seconds for bgp convergence')
+ # Check IPv4/IPv6 routing tables.
+ output = tgen.gears['r1'].vtysh_cmd('show bgp l2vpn evpn', isjson=False)
+ logger.info('==== result from show bgp l2vpn evpn')
+ logger.info(output)
+ output = tgen.gears['r1'].vtysh_cmd('show bgp l2vpn evpn route detail', isjson=False)
+ logger.info('==== result from show bgp l2vpn evpn route detail')
+ logger.info(output)
+ output = tgen.gears['r1'].vtysh_cmd('show bgp vrf r1-vrf-101 ipv4', isjson=False)
+ logger.info('==== result from show bgp vrf r1-vrf-101 ipv4')
+ logger.info(output)
+ output = tgen.gears['r1'].vtysh_cmd('show bgp vrf r1-vrf-101', isjson=False)
+ logger.info('==== result from show bgp vrf r1-vrf-101 ')
+ logger.info(output)
+ output = tgen.gears['r1'].vtysh_cmd('show ip route vrf r1-vrf-101', isjson=False)
+ logger.info('==== result from show ip route vrf r1-vrf-101')
+ logger.info(output)
+ output = tgen.gears['r1'].vtysh_cmd('show evpn vni detail', isjson=False)
+ logger.info('==== result from show evpn vni detail')
+ logger.info(output)
+ output = tgen.gears['r1'].vtysh_cmd('show evpn next-hops vni all', isjson=False)
+ logger.info('==== result from show evpn next-hops vni all')
+ logger.info(output)
+ output = tgen.gears['r1'].vtysh_cmd('show evpn rmac vni all', isjson=False)
+ logger.info('==== result from show evpn next-hops vni all')
+ logger.info(output)
+ # Check IPv4 and IPv6 connectivity between r1 and r2 ( routing vxlan evpn)
+ pingrouter = tgen.gears['r1']
+ logger.info('Check Ping IPv4 from R1(r1-vrf-101) to R2(r2-vrf-101 = 192.168.101.41)')
+ output = pingrouter.run('ip netns exec r1-vrf-101 ping 192.168.101.41 -f -c 1000')
+ logger.info(output)
+ if '1000 packets transmitted, 1000 received' not in output:
+ assertmsg = 'expected ping IPv4 from R1(r1-vrf-101) to R2(192.168.101.41) should be ok'
+ assert 0, assertmsg
+ else:
+ logger.info('Check Ping IPv4 from R1(r1-vrf-101) to R2(192.168.101.41) OK')
+
+def test_memory_leak():
+ "Run the memory leak test and report results."
+ tgen = get_topogen()
+ if not tgen.is_memleak_enabled():
+ pytest.skip('Memory leak test/report is disabled')
+
+ tgen.report_memory_leaks()
+
+
+if __name__ == '__main__':
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_features/r1/bgpd.conf b/tests/topotests/bgp_features/r1/bgpd.conf
index 7aea2dc161..74d1993af0 100644
--- a/tests/topotests/bgp_features/r1/bgpd.conf
+++ b/tests/topotests/bgp_features/r1/bgpd.conf
@@ -9,10 +9,12 @@ router bgp 65000
bgp log-neighbor-changes
no bgp ebgp-requires-policy
neighbor 192.168.0.2 remote-as 65000
+ neighbor 192.168.0.2 timers 3 10
neighbor 192.168.0.2 description Router R2 (iBGP)
neighbor 192.168.0.2 update-source lo
neighbor 192.168.0.2 timers connect 5
neighbor 192.168.101.2 remote-as 65100
+ neighbor 192.168.101.2 timers 3 10
neighbor 192.168.101.2 description Router R4 (eBGP AS 65100)
neighbor 192.168.101.2 timers connect 5
!
diff --git a/tests/topotests/bgp_features/r2/bgpd.conf b/tests/topotests/bgp_features/r2/bgpd.conf
index 3daf9842ce..99cec98811 100644
--- a/tests/topotests/bgp_features/r2/bgpd.conf
+++ b/tests/topotests/bgp_features/r2/bgpd.conf
@@ -9,10 +9,12 @@ router bgp 65000
bgp log-neighbor-changes
no bgp ebgp-requires-policy
neighbor 192.168.0.1 remote-as 65000
+ neighbor 192.168.0.1 timers 3 10
neighbor 192.168.0.1 description Router R1 (iBGP)
neighbor 192.168.0.1 update-source lo
neighbor 192.168.0.1 timers connect 5
neighbor 192.168.201.2 remote-as 65200
+ neighbor 192.168.201.2 timers 3 10
neighbor 192.168.201.2 description Router R5 (eBGP AS 65200)
neighbor 192.168.201.2 timers connect 5
!
diff --git a/tests/topotests/bgp_features/r4/bgpd.conf b/tests/topotests/bgp_features/r4/bgpd.conf
index fe1a4d4ffe..cdf8f4e8f6 100644
--- a/tests/topotests/bgp_features/r4/bgpd.conf
+++ b/tests/topotests/bgp_features/r4/bgpd.conf
@@ -9,6 +9,7 @@ router bgp 65100
bgp log-neighbor-changes
no bgp ebgp-requires-policy
neighbor 192.168.101.1 remote-as 65000
+ neighbor 192.168.101.1 timers 3 10
neighbor 192.168.101.1 description Router R1 (eBGP AS 65000)
neighbor 192.168.101.1 timers connect 5
!
diff --git a/tests/topotests/bgp_features/r5/bgpd.conf b/tests/topotests/bgp_features/r5/bgpd.conf
index 8504213b41..6368fedd39 100644
--- a/tests/topotests/bgp_features/r5/bgpd.conf
+++ b/tests/topotests/bgp_features/r5/bgpd.conf
@@ -9,6 +9,7 @@ router bgp 65200
bgp log-neighbor-changes
no bgp ebgp-requires-policy
neighbor 192.168.201.1 remote-as 65000
+ neighbor 192.168.201.1 timers 3 10
neighbor 192.168.201.1 description Router R2 (eBGP AS 65000)
neighbor 192.168.201.1 timers connect 5
!
diff --git a/tests/topotests/bgp_features/test_bgp_features.py b/tests/topotests/bgp_features/test_bgp_features.py
index 21cc8d227b..7c45ca8a29 100755..100644
--- a/tests/topotests/bgp_features/test_bgp_features.py
+++ b/tests/topotests/bgp_features/test_bgp_features.py
@@ -102,7 +102,7 @@ def setup_module(module):
# Starting Routers
router_list = tgen.routers()
- for rname, router in router_list.iteritems():
+ for rname, router in router_list.items():
router.load_config(
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
)
diff --git a/tests/topotests/bgp_flowspec/r1/bgpd.conf b/tests/topotests/bgp_flowspec/r1/bgpd.conf
index 6dc91b24a9..4b7a20f958 100644
--- a/tests/topotests/bgp_flowspec/r1/bgpd.conf
+++ b/tests/topotests/bgp_flowspec/r1/bgpd.conf
@@ -5,6 +5,7 @@ log stdout debugging
router bgp 100
bgp router-id 10.0.1.1
neighbor 10.0.1.101 remote-as 100
+ neighbor 10.0.1.101 timers 3 10
neighbor 10.0.1.101 update-source 10.0.1.1
address-family ipv6 flowspec
local-install r1-eth0
diff --git a/tests/topotests/bgp_flowspec/test_bgp_flowspec_topo.py b/tests/topotests/bgp_flowspec/test_bgp_flowspec_topo.py
index a7e2c31cde..7e6bfc8b2b 100755..100644
--- a/tests/topotests/bgp_flowspec/test_bgp_flowspec_topo.py
+++ b/tests/topotests/bgp_flowspec/test_bgp_flowspec_topo.py
@@ -124,7 +124,7 @@ def setup_module(module):
router.start()
peer_list = tgen.exabgp_peers()
- for pname, peer in peer_list.iteritems():
+ for pname, peer in peer_list.items():
peer_dir = os.path.join(CWD, pname)
env_file = os.path.join(CWD, "exabgp.env")
peer.start(peer_dir, env_file)
diff --git a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1.py b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1.py
index fdc1bed522..fdbd317093 100755
--- a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1.py
+++ b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1.py
@@ -135,6 +135,7 @@ from lib.common_config import (
kill_mininet_routers_process,
get_frr_ipv6_linklocal,
create_route_maps,
+ required_linux_kernel_version
)
# Reading the data from JSON File for topology and configuration creation
@@ -186,6 +187,11 @@ def setup_module(mod):
global ADDR_TYPES
+ # 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")
+
testsuite_run_time = time.asctime(time.localtime(time.time()))
logger.info("Testsuite start time: {}".format(testsuite_run_time))
logger.info("=" * 40)
diff --git a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2.py b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2.py
index 83a04f491f..e1ec0ea81b 100755
--- a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2.py
+++ b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2.py
@@ -135,6 +135,7 @@ from lib.common_config import (
kill_mininet_routers_process,
get_frr_ipv6_linklocal,
create_route_maps,
+ required_linux_kernel_version
)
# Reading the data from JSON File for topology and configuration creation
@@ -183,6 +184,11 @@ def setup_module(mod):
* `mod`: module name
"""
+ # 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")
+
global ADDR_TYPES
testsuite_run_time = time.asctime(time.localtime(time.time()))
diff --git a/tests/topotests/bgp_ipv6_rtadv/r1/bgpd.conf b/tests/topotests/bgp_ipv6_rtadv/r1/bgpd.conf
index 4d96bec2cb..0918796e95 100644
--- a/tests/topotests/bgp_ipv6_rtadv/r1/bgpd.conf
+++ b/tests/topotests/bgp_ipv6_rtadv/r1/bgpd.conf
@@ -5,6 +5,7 @@ router bgp 101
neighbor r2g remote-as external
neighbor r2g bfd
neighbor r1-eth0 interface peer-group r2g
+ neighbor r1-eth0 timers 3 10
address-family ipv4 unicast
redistribute connected
exit-address-family
diff --git a/tests/topotests/bgp_ipv6_rtadv/r2/bgpd.conf b/tests/topotests/bgp_ipv6_rtadv/r2/bgpd.conf
index 4d02fc4f29..55d48560e7 100644
--- a/tests/topotests/bgp_ipv6_rtadv/r2/bgpd.conf
+++ b/tests/topotests/bgp_ipv6_rtadv/r2/bgpd.conf
@@ -5,6 +5,7 @@ router bgp 102
neighbor r2g remote-as external
neighbor r2g bfd
neighbor r2-eth0 interface peer-group r2g
+ neighbor r2-eth0 timers 3 10
!
address-family ipv4 unicast
redistribute connected
diff --git a/tests/topotests/bgp_ipv6_rtadv/test_bgp_ipv6_rtadv.py b/tests/topotests/bgp_ipv6_rtadv/test_bgp_ipv6_rtadv.py
index 10b2f3595f..0acf8d2dbc 100644
--- a/tests/topotests/bgp_ipv6_rtadv/test_bgp_ipv6_rtadv.py
+++ b/tests/topotests/bgp_ipv6_rtadv/test_bgp_ipv6_rtadv.py
@@ -69,7 +69,7 @@ def setup_module(mod):
router_list = tgen.routers()
- for rname, router in router_list.iteritems():
+ for rname, router in router_list.items():
router.load_config(
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
)
diff --git a/tests/topotests/bgp_large_community/test_bgp_large_community_topo_1.py b/tests/topotests/bgp_large_community/test_bgp_large_community_topo_1.py
index 334aaebb4b..dc06b7131a 100755
--- a/tests/topotests/bgp_large_community/test_bgp_large_community_topo_1.py
+++ b/tests/topotests/bgp_large_community/test_bgp_large_community_topo_1.py
@@ -67,6 +67,7 @@ from lib.common_config import (
verify_bgp_community,
step,
check_address_types,
+ required_linux_kernel_version
)
from lib.topolog import logger
from lib.bgp import verify_bgp_convergence, create_router_bgp, clear_bgp_and_verify
@@ -142,6 +143,11 @@ def setup_module(mod):
* `mod`: module name
"""
+ # 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")
+
global ADDR_TYPES
testsuite_run_time = time.asctime(time.localtime(time.time()))
logger.info("Testsuite start time: {}".format(testsuite_run_time))
diff --git a/tests/topotests/bgp_large_community/test_bgp_large_community_topo_2.py b/tests/topotests/bgp_large_community/test_bgp_large_community_topo_2.py
index 502a9a9ec4..bb88e47415 100755
--- a/tests/topotests/bgp_large_community/test_bgp_large_community_topo_2.py
+++ b/tests/topotests/bgp_large_community/test_bgp_large_community_topo_2.py
@@ -91,6 +91,7 @@ from lib.common_config import (
verify_route_maps,
create_static_routes,
check_address_types,
+ required_linux_kernel_version
)
from lib.topolog import logger
from lib.bgp import verify_bgp_convergence, create_router_bgp, clear_bgp_and_verify
@@ -133,6 +134,11 @@ def setup_module(mod):
* `mod`: module name
"""
+ # 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")
+
testsuite_run_time = time.asctime(time.localtime(time.time()))
logger.info("Testsuite start time: {}".format(testsuite_run_time))
logger.info("=" * 40)
diff --git a/tests/topotests/bgp_link_bw_ip/r1/bgpd.conf b/tests/topotests/bgp_link_bw_ip/r1/bgpd.conf
index 40c19062a2..0e46687100 100644
--- a/tests/topotests/bgp_link_bw_ip/r1/bgpd.conf
+++ b/tests/topotests/bgp_link_bw_ip/r1/bgpd.conf
@@ -5,5 +5,7 @@ router bgp 65101
no bgp ebgp-requires-policy
bgp bestpath as-path multipath-relax
neighbor 11.1.1.2 remote-as external
+ neighbor 11.1.1.2 timers 3 10
neighbor 11.1.1.6 remote-as external
+ neighbor 11.1.1.6 timers 3 10
!
diff --git a/tests/topotests/bgp_link_bw_ip/r10/bgpd.conf b/tests/topotests/bgp_link_bw_ip/r10/bgpd.conf
index 80588e7961..022270ff8a 100644
--- a/tests/topotests/bgp_link_bw_ip/r10/bgpd.conf
+++ b/tests/topotests/bgp_link_bw_ip/r10/bgpd.conf
@@ -9,6 +9,7 @@ router bgp 65354
bgp router-id 11.1.6.2
no bgp ebgp-requires-policy
neighbor 11.1.6.1 remote-as external
+ neighbor 11.1.6.1 timers 3 10
!
address-family ipv4 unicast
redistribute connected route-map redist
diff --git a/tests/topotests/bgp_link_bw_ip/r2/bgpd.conf b/tests/topotests/bgp_link_bw_ip/r2/bgpd.conf
index 6fec1913c8..0c0e859cab 100644
--- a/tests/topotests/bgp_link_bw_ip/r2/bgpd.conf
+++ b/tests/topotests/bgp_link_bw_ip/r2/bgpd.conf
@@ -5,6 +5,9 @@ router bgp 65201
bgp bestpath as-path multipath-relax
no bgp ebgp-requires-policy
neighbor 11.1.1.1 remote-as external
+ neighbor 11.1.1.1 timers 3 10
neighbor 11.1.2.2 remote-as external
+ neighbor 11.1.2.2 timers 3 10
neighbor 11.1.2.6 remote-as external
+ neighbor 11.1.2.6 timers 3 10
!
diff --git a/tests/topotests/bgp_link_bw_ip/r3/bgpd.conf b/tests/topotests/bgp_link_bw_ip/r3/bgpd.conf
index 1c2ca88306..3f20eb10a3 100644
--- a/tests/topotests/bgp_link_bw_ip/r3/bgpd.conf
+++ b/tests/topotests/bgp_link_bw_ip/r3/bgpd.conf
@@ -5,5 +5,7 @@ router bgp 65202
bgp bestpath as-path multipath-relax
no bgp ebgp-requires-policy
neighbor 11.1.1.5 remote-as external
+ neighbor 11.1.1.5 timers 3 10
neighbor 11.1.3.2 remote-as external
+ neighbor 11.1.3.2 timers 3 10
!
diff --git a/tests/topotests/bgp_link_bw_ip/r4/bgpd.conf b/tests/topotests/bgp_link_bw_ip/r4/bgpd.conf
index 022a230643..d34db982c9 100644
--- a/tests/topotests/bgp_link_bw_ip/r4/bgpd.conf
+++ b/tests/topotests/bgp_link_bw_ip/r4/bgpd.conf
@@ -20,8 +20,11 @@ router bgp 65301
bgp bestpath as-path multipath-relax
no bgp ebgp-requires-policy
neighbor 11.1.2.1 remote-as external
+ neighbor 11.1.2.1 timers 3 10
neighbor 11.1.4.2 remote-as external
+ neighbor 11.1.4.2 timers 3 10
neighbor 11.1.4.6 remote-as external
+ neighbor 11.1.4.6 timers 3 10
!
address-family ipv4 unicast
neighbor 11.1.2.1 route-map anycast_ip out
diff --git a/tests/topotests/bgp_link_bw_ip/r5/bgpd.conf b/tests/topotests/bgp_link_bw_ip/r5/bgpd.conf
index fc4e3888d8..4014bfbc8b 100644
--- a/tests/topotests/bgp_link_bw_ip/r5/bgpd.conf
+++ b/tests/topotests/bgp_link_bw_ip/r5/bgpd.conf
@@ -13,7 +13,9 @@ router bgp 65302
bgp bestpath as-path multipath-relax
no bgp ebgp-requires-policy
neighbor 11.1.2.5 remote-as external
+ neighbor 11.1.2.5 timers 3 10
neighbor 11.1.5.2 remote-as external
+ neighbor 11.1.5.2 timers 3 10
!
address-family ipv4 unicast
neighbor 11.1.2.5 route-map anycast_ip out
diff --git a/tests/topotests/bgp_link_bw_ip/r6/bgpd.conf b/tests/topotests/bgp_link_bw_ip/r6/bgpd.conf
index f08f6337f4..18e7eb9285 100644
--- a/tests/topotests/bgp_link_bw_ip/r6/bgpd.conf
+++ b/tests/topotests/bgp_link_bw_ip/r6/bgpd.conf
@@ -13,7 +13,9 @@ router bgp 65303
bgp bestpath as-path multipath-relax
no bgp ebgp-requires-policy
neighbor 11.1.3.1 remote-as external
+ neighbor 11.1.3.1 timers 3 10
neighbor 11.1.6.2 remote-as external
+ neighbor 11.1.6.2 timers 3 10
!
address-family ipv4 unicast
neighbor 11.1.3.1 route-map anycast_ip out
diff --git a/tests/topotests/bgp_link_bw_ip/r7/bgpd.conf b/tests/topotests/bgp_link_bw_ip/r7/bgpd.conf
index 98dfe2471a..39c0c81950 100644
--- a/tests/topotests/bgp_link_bw_ip/r7/bgpd.conf
+++ b/tests/topotests/bgp_link_bw_ip/r7/bgpd.conf
@@ -9,6 +9,7 @@ router bgp 65351
bgp router-id 11.1.4.2
no bgp ebgp-requires-policy
neighbor 11.1.4.1 remote-as external
+ neighbor 11.1.4.1 timers 3 10
!
address-family ipv4 unicast
redistribute connected route-map redist
diff --git a/tests/topotests/bgp_link_bw_ip/r8/bgpd.conf b/tests/topotests/bgp_link_bw_ip/r8/bgpd.conf
index b4ba8e8a72..ea1d546017 100644
--- a/tests/topotests/bgp_link_bw_ip/r8/bgpd.conf
+++ b/tests/topotests/bgp_link_bw_ip/r8/bgpd.conf
@@ -9,6 +9,7 @@ router bgp 65352
bgp router-id 11.1.4.6
no bgp ebgp-requires-policy
neighbor 11.1.4.5 remote-as external
+ neighbor 11.1.4.5 timers 3 10
!
address-family ipv4 unicast
redistribute connected route-map redist
diff --git a/tests/topotests/bgp_link_bw_ip/r9/bgpd.conf b/tests/topotests/bgp_link_bw_ip/r9/bgpd.conf
index 31f971dd08..a6066ee766 100644
--- a/tests/topotests/bgp_link_bw_ip/r9/bgpd.conf
+++ b/tests/topotests/bgp_link_bw_ip/r9/bgpd.conf
@@ -9,6 +9,7 @@ router bgp 65353
bgp router-id 11.1.5.2
no bgp ebgp-requires-policy
neighbor 11.1.5.1 remote-as external
+ neighbor 11.1.5.1 timers 3 10
!
address-family ipv4 unicast
redistribute connected route-map redist
diff --git a/tests/topotests/bgp_link_bw_ip/test_bgp_linkbw_ip.py b/tests/topotests/bgp_link_bw_ip/test_bgp_linkbw_ip.py
index 86eb2969ce..dff69e3a27 100755..100644
--- a/tests/topotests/bgp_link_bw_ip/test_bgp_linkbw_ip.py
+++ b/tests/topotests/bgp_link_bw_ip/test_bgp_linkbw_ip.py
@@ -119,7 +119,7 @@ def setup_module(mod):
tgen.start_topology()
router_list = tgen.routers()
- for rname, router in router_list.iteritems():
+ for rname, router in router_list.items():
router.load_config(
TopoRouter.RD_ZEBRA,
os.path.join(CWD, '{}/zebra.conf'.format(rname))
diff --git a/tests/topotests/bgp_local_as_private_remove/r1/bgpd.conf b/tests/topotests/bgp_local_as_private_remove/r1/bgpd.conf
index 6f8fcd753d..16a9eeadd1 100644
--- a/tests/topotests/bgp_local_as_private_remove/r1/bgpd.conf
+++ b/tests/topotests/bgp_local_as_private_remove/r1/bgpd.conf
@@ -1,6 +1,7 @@
router bgp 65000
no bgp ebgp-requires-policy
neighbor 192.168.255.2 remote-as 1000
+ neighbor 192.168.255.2 timers 3 10
neighbor 192.168.255.2 local-as 500
address-family ipv4 unicast
neighbor 192.168.255.2 remove-private-AS
diff --git a/tests/topotests/bgp_local_as_private_remove/r2/bgpd.conf b/tests/topotests/bgp_local_as_private_remove/r2/bgpd.conf
index 27427a9aaa..802c32714b 100644
--- a/tests/topotests/bgp_local_as_private_remove/r2/bgpd.conf
+++ b/tests/topotests/bgp_local_as_private_remove/r2/bgpd.conf
@@ -1,3 +1,5 @@
router bgp 1000
no bgp ebgp-requires-policy
neighbor 192.168.255.1 remote-as 500
+ neighbor 192.168.255.1 timers 3 10
+!
diff --git a/tests/topotests/bgp_local_as_private_remove/r3/bgpd.conf b/tests/topotests/bgp_local_as_private_remove/r3/bgpd.conf
index f2050ddfdb..9a831270b4 100644
--- a/tests/topotests/bgp_local_as_private_remove/r3/bgpd.conf
+++ b/tests/topotests/bgp_local_as_private_remove/r3/bgpd.conf
@@ -1,6 +1,7 @@
router bgp 3000
no bgp ebgp-requires-policy
neighbor 192.168.255.2 remote-as 1000
+ neighbor 192.168.255.2 timers 3 10
neighbor 192.168.255.2 local-as 500
address-family ipv4 unicast
neighbor 192.168.255.2 remove-private-AS
diff --git a/tests/topotests/bgp_local_as_private_remove/r4/bgpd.conf b/tests/topotests/bgp_local_as_private_remove/r4/bgpd.conf
index 27427a9aaa..802c32714b 100644
--- a/tests/topotests/bgp_local_as_private_remove/r4/bgpd.conf
+++ b/tests/topotests/bgp_local_as_private_remove/r4/bgpd.conf
@@ -1,3 +1,5 @@
router bgp 1000
no bgp ebgp-requires-policy
neighbor 192.168.255.1 remote-as 500
+ neighbor 192.168.255.1 timers 3 10
+!
diff --git a/tests/topotests/bgp_local_as_private_remove/test_bgp_local_as_private_remove.py b/tests/topotests/bgp_local_as_private_remove/test_bgp_local_as_private_remove.py
index 56bb14411a..32e7a4df61 100644
--- a/tests/topotests/bgp_local_as_private_remove/test_bgp_local_as_private_remove.py
+++ b/tests/topotests/bgp_local_as_private_remove/test_bgp_local_as_private_remove.py
@@ -66,7 +66,7 @@ def setup_module(mod):
router_list = tgen.routers()
- for i, (rname, router) in enumerate(router_list.iteritems(), 1):
+ for i, (rname, router) in enumerate(router_list.items(), 1):
router.load_config(
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
)
diff --git a/tests/topotests/bgp_maximum_prefix_invalid_update/r1/bgpd.conf b/tests/topotests/bgp_maximum_prefix_invalid_update/r1/bgpd.conf
index f0df56e947..62110429cf 100644
--- a/tests/topotests/bgp_maximum_prefix_invalid_update/r1/bgpd.conf
+++ b/tests/topotests/bgp_maximum_prefix_invalid_update/r1/bgpd.conf
@@ -1,5 +1,6 @@
router bgp 65000
no bgp ebgp-requires-policy
neighbor 192.168.255.2 remote-as 65001
+ neighbor 192.168.255.2 timers 3 10
address-family ipv4 unicast
redistribute connected
diff --git a/tests/topotests/bgp_maximum_prefix_invalid_update/r2/bgpd.conf b/tests/topotests/bgp_maximum_prefix_invalid_update/r2/bgpd.conf
index ef50dd0d7f..005425e850 100644
--- a/tests/topotests/bgp_maximum_prefix_invalid_update/r2/bgpd.conf
+++ b/tests/topotests/bgp_maximum_prefix_invalid_update/r2/bgpd.conf
@@ -1,5 +1,6 @@
router bgp 65001
no bgp ebgp-requires-policy
neighbor 192.168.255.1 remote-as 65000
+ neighbor 192.168.255.1 timers 3 10
address-family ipv4
neighbor 192.168.255.1 maximum-prefix 1
diff --git a/tests/topotests/bgp_maximum_prefix_invalid_update/test_bgp_maximum_prefix_invalid_update.py b/tests/topotests/bgp_maximum_prefix_invalid_update/test_bgp_maximum_prefix_invalid_update.py
index 5e7c6d4b63..8494653dfe 100644
--- a/tests/topotests/bgp_maximum_prefix_invalid_update/test_bgp_maximum_prefix_invalid_update.py
+++ b/tests/topotests/bgp_maximum_prefix_invalid_update/test_bgp_maximum_prefix_invalid_update.py
@@ -66,7 +66,7 @@ def setup_module(mod):
router_list = tgen.routers()
- for i, (rname, router) in enumerate(router_list.iteritems(), 1):
+ for i, (rname, router) in enumerate(router_list.items(), 1):
router.load_config(
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
)
diff --git a/tests/topotests/bgp_maximum_prefix_out/r1/bgpd.conf b/tests/topotests/bgp_maximum_prefix_out/r1/bgpd.conf
index 03e3eb6e08..adb594b3dd 100644
--- a/tests/topotests/bgp_maximum_prefix_out/r1/bgpd.conf
+++ b/tests/topotests/bgp_maximum_prefix_out/r1/bgpd.conf
@@ -2,6 +2,7 @@
router bgp 65001
no bgp ebgp-requires-policy
neighbor 192.168.255.1 remote-as 65002
+ neighbor 192.168.255.1 timers 3 10
address-family ipv4 unicast
redistribute connected
neighbor 192.168.255.1 maximum-prefix-out 2
diff --git a/tests/topotests/bgp_maximum_prefix_out/r2/bgpd.conf b/tests/topotests/bgp_maximum_prefix_out/r2/bgpd.conf
index 2d47b2f661..229de2e2f2 100644
--- a/tests/topotests/bgp_maximum_prefix_out/r2/bgpd.conf
+++ b/tests/topotests/bgp_maximum_prefix_out/r2/bgpd.conf
@@ -2,6 +2,7 @@
router bgp 65002
no bgp ebgp-requires-policy
neighbor 192.168.255.2 remote-as 65001
+ neighbor 192.168.255.2 timers 3 10
exit-address-family
!
!
diff --git a/tests/topotests/bgp_maximum_prefix_out/test_bgp_maximum_prefix_out.py b/tests/topotests/bgp_maximum_prefix_out/test_bgp_maximum_prefix_out.py
index 708684f696..b99664e700 100644
--- a/tests/topotests/bgp_maximum_prefix_out/test_bgp_maximum_prefix_out.py
+++ b/tests/topotests/bgp_maximum_prefix_out/test_bgp_maximum_prefix_out.py
@@ -62,7 +62,7 @@ def setup_module(mod):
router_list = tgen.routers()
- for i, (rname, router) in enumerate(router_list.iteritems(), 1):
+ for i, (rname, router) in enumerate(router_list.items(), 1):
router.load_config(
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
)
diff --git a/tests/topotests/bgp_multi_vrf_topo1/test_bgp_multi_vrf_topo1.py b/tests/topotests/bgp_multi_vrf_topo1/test_bgp_multi_vrf_topo1.py
index a37e3f36a3..c15b88d371 100755
--- a/tests/topotests/bgp_multi_vrf_topo1/test_bgp_multi_vrf_topo1.py
+++ b/tests/topotests/bgp_multi_vrf_topo1/test_bgp_multi_vrf_topo1.py
@@ -132,6 +132,7 @@ from lib.common_config import (
create_bgp_community_lists,
check_router_status,
apply_raw_config,
+ required_linux_kernel_version
)
from lib.topolog import logger
@@ -209,6 +210,10 @@ def setup_module(mod):
* `mod`: module name
"""
+ # 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")
testsuite_run_time = time.asctime(time.localtime(time.time()))
logger.info("Testsuite start time: {}".format(testsuite_run_time))
diff --git a/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py b/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py
index c36e66a60e..bb13d54019 100755
--- a/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py
+++ b/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py
@@ -78,6 +78,7 @@ from lib.common_config import (
get_frr_ipv6_linklocal,
check_router_status,
apply_raw_config,
+ required_linux_kernel_version
)
from lib.topolog import logger
@@ -141,6 +142,10 @@ def setup_module(mod):
* `mod`: module name
"""
+ # 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")
testsuite_run_time = time.asctime(time.localtime(time.time()))
logger.info("Testsuite start time: {}".format(testsuite_run_time))
diff --git a/tests/topotests/bgp_multiview_topo1/r1/bgpd.conf b/tests/topotests/bgp_multiview_topo1/r1/bgpd.conf
index 5f65a54d7f..d44c3e18e6 100644
--- a/tests/topotests/bgp_multiview_topo1/r1/bgpd.conf
+++ b/tests/topotests/bgp_multiview_topo1/r1/bgpd.conf
@@ -17,8 +17,11 @@ router bgp 100 view 1
network 172.20.0.0/28 route-map local1
timers bgp 60 180
neighbor 172.16.1.1 remote-as 65001
+ neighbor 172.16.1.1 timers 3 10
neighbor 172.16.1.2 remote-as 65002
+ neighbor 172.16.1.2 timers 3 10
neighbor 172.16.1.5 remote-as 65005
+ neighbor 172.16.1.5 timers 3 10
!
router bgp 100 view 2
bgp router-id 172.30.1.1
@@ -26,7 +29,9 @@ router bgp 100 view 2
network 172.20.0.0/28 route-map local2
timers bgp 60 180
neighbor 172.16.1.3 remote-as 65003
+ neighbor 172.16.1.3 timers 3 10
neighbor 172.16.1.4 remote-as 65004
+ neighbor 172.16.1.4 timers 3 10
!
router bgp 100 view 3
bgp router-id 172.30.1.1
@@ -34,8 +39,11 @@ router bgp 100 view 3
network 172.20.0.0/28
timers bgp 60 180
neighbor 172.16.1.6 remote-as 65006
+ neighbor 172.16.1.6 timers 3 10
neighbor 172.16.1.7 remote-as 65007
+ neighbor 172.16.1.7 timers 3 10
neighbor 172.16.1.8 remote-as 65008
+ neighbor 172.16.1.8 timers 3 10
!
route-map local1 permit 10
set community 100:9999 additive
diff --git a/tests/topotests/bgp_prefix_sid/r1/bgpd.conf b/tests/topotests/bgp_prefix_sid/r1/bgpd.conf
index 06bdc31f8c..e02226f2fd 100644
--- a/tests/topotests/bgp_prefix_sid/r1/bgpd.conf
+++ b/tests/topotests/bgp_prefix_sid/r1/bgpd.conf
@@ -6,7 +6,9 @@ router bgp 1
no bgp default ipv4-unicast
no bgp ebgp-requires-policy
neighbor 10.0.0.101 remote-as 2
+ neighbor 10.0.0.101 timers 3 10
neighbor 10.0.0.102 remote-as 3
+ neighbor 10.0.0.102 timers 3 10
!
address-family ipv4 labeled-unicast
neighbor 10.0.0.101 activate
diff --git a/tests/topotests/bgp_prefix_sid/test_bgp_prefix_sid.py b/tests/topotests/bgp_prefix_sid/test_bgp_prefix_sid.py
index 3a6aefe7ee..6d7131e1e5 100755..100644
--- a/tests/topotests/bgp_prefix_sid/test_bgp_prefix_sid.py
+++ b/tests/topotests/bgp_prefix_sid/test_bgp_prefix_sid.py
@@ -75,7 +75,7 @@ def setup_module(module):
logger.info("starting exaBGP on peer1")
peer_list = tgen.exabgp_peers()
- for pname, peer in peer_list.iteritems():
+ for pname, peer in peer_list.items():
peer_dir = os.path.join(CWD, pname)
env_file = os.path.join(CWD, "exabgp.env")
logger.info("Running ExaBGP peer")
diff --git a/tests/topotests/bgp_reject_as_sets/r1/bgpd.conf b/tests/topotests/bgp_reject_as_sets/r1/bgpd.conf
index 94bfc5e561..a28b612e00 100644
--- a/tests/topotests/bgp_reject_as_sets/r1/bgpd.conf
+++ b/tests/topotests/bgp_reject_as_sets/r1/bgpd.conf
@@ -2,6 +2,7 @@
router bgp 65001
no bgp ebgp-requires-policy
neighbor 192.168.255.1 remote-as 65002
+ neighbor 192.168.255.1 timers 3 10
address-family ipv4 unicast
redistribute connected
exit-address-family
diff --git a/tests/topotests/bgp_reject_as_sets/r2/bgpd.conf b/tests/topotests/bgp_reject_as_sets/r2/bgpd.conf
index f217b7f794..453961762a 100644
--- a/tests/topotests/bgp_reject_as_sets/r2/bgpd.conf
+++ b/tests/topotests/bgp_reject_as_sets/r2/bgpd.conf
@@ -3,7 +3,9 @@ router bgp 65002
bgp reject-as-sets
no bgp ebgp-requires-policy
neighbor 192.168.255.2 remote-as 65001
+ neighbor 192.168.255.2 timers 3 10
neighbor 192.168.254.2 remote-as 65003
+ neighbor 192.168.254.2 timers 3 10
address-family ipv4 unicast
aggregate-address 172.16.0.0/16 as-set summary-only
exit-address-family
diff --git a/tests/topotests/bgp_reject_as_sets/r3/bgpd.conf b/tests/topotests/bgp_reject_as_sets/r3/bgpd.conf
index 8d085a0e4b..1dde4f0f69 100644
--- a/tests/topotests/bgp_reject_as_sets/r3/bgpd.conf
+++ b/tests/topotests/bgp_reject_as_sets/r3/bgpd.conf
@@ -2,6 +2,7 @@
router bgp 65003
no bgp ebgp-requires-policy
neighbor 192.168.254.1 remote-as 65002
+ neighbor 192.168.254.1 timers 3 10
address-family ipv4 unicast
neighbor 192.168.254.1 allowas-in
redistribute connected
diff --git a/tests/topotests/bgp_reject_as_sets/test_bgp_reject_as_sets.py b/tests/topotests/bgp_reject_as_sets/test_bgp_reject_as_sets.py
index b49a57b308..d514dccd4a 100644
--- a/tests/topotests/bgp_reject_as_sets/test_bgp_reject_as_sets.py
+++ b/tests/topotests/bgp_reject_as_sets/test_bgp_reject_as_sets.py
@@ -73,7 +73,7 @@ def setup_module(mod):
router_list = tgen.routers()
- for i, (rname, router) in enumerate(router_list.iteritems(), 1):
+ for i, (rname, router) in enumerate(router_list.items(), 1):
router.load_config(
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
)
diff --git a/tests/topotests/bgp_rfapi_basic_sanity/r1/bgpd.conf b/tests/topotests/bgp_rfapi_basic_sanity/r1/bgpd.conf
index ada354bd62..f6e0baa43d 100644
--- a/tests/topotests/bgp_rfapi_basic_sanity/r1/bgpd.conf
+++ b/tests/topotests/bgp_rfapi_basic_sanity/r1/bgpd.conf
@@ -9,6 +9,7 @@ router bgp 5226
bgp cluster-id 1.1.1.1
no bgp ebgp-requires-policy
neighbor 2.2.2.2 remote-as 5226
+ neighbor 2.2.2.2 timers 3 10
neighbor 2.2.2.2 update-source 1.1.1.1
!
address-family ipv4 unicast
diff --git a/tests/topotests/bgp_rfapi_basic_sanity/r2/bgpd.conf b/tests/topotests/bgp_rfapi_basic_sanity/r2/bgpd.conf
index 95890f25b9..19050e67f6 100644
--- a/tests/topotests/bgp_rfapi_basic_sanity/r2/bgpd.conf
+++ b/tests/topotests/bgp_rfapi_basic_sanity/r2/bgpd.conf
@@ -9,10 +9,13 @@ router bgp 5226
bgp cluster-id 2.2.2.2
no bgp ebgp-requires-policy
neighbor 1.1.1.1 remote-as 5226
+ neighbor 1.1.1.1 timers 3 10
neighbor 1.1.1.1 update-source 2.2.2.2
neighbor 3.3.3.3 remote-as 5226
+ neighbor 3.3.3.3 timers 3 10
neighbor 3.3.3.3 update-source 2.2.2.2
neighbor 4.4.4.4 remote-as 5226
+ neighbor 4.4.4.4 timers 3 10
neighbor 4.4.4.4 update-source 2.2.2.2
address-family ipv4 unicast
no neighbor 1.1.1.1 activate
diff --git a/tests/topotests/bgp_rfapi_basic_sanity/r3/bgpd.conf b/tests/topotests/bgp_rfapi_basic_sanity/r3/bgpd.conf
index 4932d63d4f..2210f24589 100644
--- a/tests/topotests/bgp_rfapi_basic_sanity/r3/bgpd.conf
+++ b/tests/topotests/bgp_rfapi_basic_sanity/r3/bgpd.conf
@@ -9,6 +9,7 @@ router bgp 5226
bgp cluster-id 3.3.3.3
no bgp ebgp-requires-policy
neighbor 2.2.2.2 remote-as 5226
+ neighbor 2.2.2.2 timers 3 10
neighbor 2.2.2.2 update-source 3.3.3.3
!
address-family ipv4 unicast
diff --git a/tests/topotests/bgp_rfapi_basic_sanity/r4/bgpd.conf b/tests/topotests/bgp_rfapi_basic_sanity/r4/bgpd.conf
index 1a5e41aae6..28b5f9cfc5 100644
--- a/tests/topotests/bgp_rfapi_basic_sanity/r4/bgpd.conf
+++ b/tests/topotests/bgp_rfapi_basic_sanity/r4/bgpd.conf
@@ -9,6 +9,7 @@ router bgp 5226
bgp cluster-id 4.4.4.4
no bgp ebgp-requires-policy
neighbor 2.2.2.2 remote-as 5226
+ neighbor 2.2.2.2 timers 3 10
neighbor 2.2.2.2 update-source 4.4.4.4
!
address-family ipv4 unicast
diff --git a/tests/topotests/bgp_rfapi_basic_sanity_config2/r1/bgpd.conf b/tests/topotests/bgp_rfapi_basic_sanity_config2/r1/bgpd.conf
index a38afd632f..3196a16626 100644
--- a/tests/topotests/bgp_rfapi_basic_sanity_config2/r1/bgpd.conf
+++ b/tests/topotests/bgp_rfapi_basic_sanity_config2/r1/bgpd.conf
@@ -9,6 +9,7 @@ router bgp 5226
bgp cluster-id 1.1.1.1
no bgp ebgp-requires-policy
neighbor 2.2.2.2 remote-as 5226
+ neighbor 2.2.2.2 timers 3 10
neighbor 2.2.2.2 update-source 1.1.1.1
!
address-family ipv4 unicast
diff --git a/tests/topotests/bgp_rfapi_basic_sanity_config2/r2/bgpd.conf b/tests/topotests/bgp_rfapi_basic_sanity_config2/r2/bgpd.conf
index 95890f25b9..19050e67f6 100644
--- a/tests/topotests/bgp_rfapi_basic_sanity_config2/r2/bgpd.conf
+++ b/tests/topotests/bgp_rfapi_basic_sanity_config2/r2/bgpd.conf
@@ -9,10 +9,13 @@ router bgp 5226
bgp cluster-id 2.2.2.2
no bgp ebgp-requires-policy
neighbor 1.1.1.1 remote-as 5226
+ neighbor 1.1.1.1 timers 3 10
neighbor 1.1.1.1 update-source 2.2.2.2
neighbor 3.3.3.3 remote-as 5226
+ neighbor 3.3.3.3 timers 3 10
neighbor 3.3.3.3 update-source 2.2.2.2
neighbor 4.4.4.4 remote-as 5226
+ neighbor 4.4.4.4 timers 3 10
neighbor 4.4.4.4 update-source 2.2.2.2
address-family ipv4 unicast
no neighbor 1.1.1.1 activate
diff --git a/tests/topotests/bgp_rfapi_basic_sanity_config2/r3/bgpd.conf b/tests/topotests/bgp_rfapi_basic_sanity_config2/r3/bgpd.conf
index dbeb2c4665..e74fc0b3de 100644
--- a/tests/topotests/bgp_rfapi_basic_sanity_config2/r3/bgpd.conf
+++ b/tests/topotests/bgp_rfapi_basic_sanity_config2/r3/bgpd.conf
@@ -9,6 +9,7 @@ router bgp 5226
bgp cluster-id 3.3.3.3
no bgp ebgp-requires-policy
neighbor 2.2.2.2 remote-as 5226
+ neighbor 2.2.2.2 timers 3 10
neighbor 2.2.2.2 update-source 3.3.3.3
!
address-family ipv4 unicast
diff --git a/tests/topotests/bgp_rfapi_basic_sanity_config2/r4/bgpd.conf b/tests/topotests/bgp_rfapi_basic_sanity_config2/r4/bgpd.conf
index ae1787718c..56474aad9c 100644
--- a/tests/topotests/bgp_rfapi_basic_sanity_config2/r4/bgpd.conf
+++ b/tests/topotests/bgp_rfapi_basic_sanity_config2/r4/bgpd.conf
@@ -9,6 +9,7 @@ router bgp 5226
bgp cluster-id 4.4.4.4
no bgp ebgp-requires-policy
neighbor 2.2.2.2 remote-as 5226
+ neighbor 2.2.2.2 timers 3 10
neighbor 2.2.2.2 update-source 4.4.4.4
!
address-family ipv4 unicast
diff --git a/tests/topotests/bgp_route_aggregation/bgp_aggregation.json b/tests/topotests/bgp_route_aggregation/bgp_aggregation.json
new file mode 100644
index 0000000000..5520f67d0d
--- /dev/null
+++ b/tests/topotests/bgp_route_aggregation/bgp_aggregation.json
@@ -0,0 +1,249 @@
+{
+ "address_types": [
+ "ipv4",
+ "ipv6"
+ ],
+ "ipv4base": "192.168.0.0",
+ "ipv4mask": 24,
+ "ipv6base": "fd00::",
+ "ipv6mask": 64,
+ "link_ip_start": {
+ "ipv4": "192.168.0.0",
+ "v4mask": 24,
+ "ipv6": "fd00::",
+ "v6mask": 64
+ },
+ "lo_prefix": {
+ "ipv4": "1.0.",
+ "v4mask": 32,
+ "ipv6": "2001:db8:f::",
+ "v6mask": 128
+ },
+ "routers": {
+ "r1": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r2": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r3": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ },
+ "bgp": {
+ "local_as": "100",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r1": {
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1": {
+ }
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r1": {
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "r2": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r4": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ },
+ "bgp": {
+ "local_as": "100",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2": {}
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r2": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2": {
+ }
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r2": {
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "r3": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r4": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ },
+ "bgp": {
+ "local_as": "300",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {}
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r3": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {
+ }
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r3": {
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "r4": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r2": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r3": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ },
+ "bgp": {
+ "local_as": "400",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r4": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r4": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r4": {
+ }
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r4": {
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/tests/topotests/bgp_route_aggregation/test_bgp_aggregation.py b/tests/topotests/bgp_route_aggregation/test_bgp_aggregation.py
new file mode 100755
index 0000000000..0fabd90341
--- /dev/null
+++ b/tests/topotests/bgp_route_aggregation/test_bgp_aggregation.py
@@ -0,0 +1,1167 @@
+#!/usr/bin/python
+#
+# Copyright (c) 2020 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation,
+# Inc. ("NetDEF") in this file.
+#
+# 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 VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE 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.
+#
+
+"""
+Following tests are covered to test bgp aggregation functionality:
+
+1. Verify route summarisation with summary-only for redistributed as well as
+ locally generated routes.
+2. Verify route summarisation with as-set for redistributed routes.
+
+"""
+
+import os
+import sys
+import time
+import json
+import pytest
+from time import sleep
+from copy import deepcopy
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib import topotest
+from mininet.topo import Topo
+from lib.topogen import Topogen, get_topogen
+
+# Import topoJson from lib, to create topology and initial configuration
+from lib.common_config import (
+ start_topology,
+ write_test_header,
+ apply_raw_config,
+ write_test_footer,
+ reset_config_on_routers,
+ verify_rib,
+ create_static_routes,
+ check_address_types,
+ step,
+ create_route_maps,
+ create_prefix_lists,
+)
+from lib.topolog import logger
+from lib.bgp import (
+ verify_bgp_convergence,
+ create_router_bgp,
+ verify_bgp_rib,
+ verify_bgp_community,
+ verify_bgp_timers_and_functionality,
+)
+from lib.topojson import build_topo_from_json, build_config_from_json
+
+# Reading the data from JSON File for topology and configuration creation
+jsonFile = "{}/bgp_aggregation.json".format(CWD)
+try:
+ with open(jsonFile, "r") as topoJson:
+ topo = json.load(topoJson)
+except IOError:
+ logger.info("Could not read file:", jsonFile)
+
+# Global variables
+BGP_CONVERGENCE = False
+ADDR_TYPES = check_address_types()
+
+NETWORK_1_1 = {"ipv4": "10.1.1.0/24", "ipv6": "10:1::1:0/120"}
+NETWORK_1_2 = {"ipv4": "10.1.2.0/24", "ipv6": "10:1::2:0/120"}
+NETWORK_1_3 = {"ipv4": "10.1.3.0/24", "ipv6": "10:1::3:0/120"}
+NETWORK_1_4 = {"ipv4": "10.1.4.0/24", "ipv6": "10:1::4:0/120"}
+NETWORK_1_5 = {"ipv4": "10.1.5.0/24", "ipv6": "10:1::5:0/120"}
+NETWORK_2_1 = {"ipv4": "10.1.1.100/32", "ipv6": "10:1::1:0/124"}
+NETWORK_2_2 = {"ipv4": "10.1.5.0/24", "ipv6": "10:1::5:0/120"}
+NETWORK_2_3 = {"ipv4": "10.1.6.0/24", "ipv6": "10:1::6:0/120"}
+NETWORK_2_4 = {"ipv4": "10.1.7.0/24", "ipv6": "10:1::7:0/120"}
+NETWORK_3_1 = {"ipv4": "10.1.8.0/24", "ipv6": "10:1::8:0/120"}
+NETWORK_4_1 = {"ipv4": "10.2.1.0/24", "ipv6": "10:2::1:0/120"}
+NEXT_HOP = {"ipv4": "Null0", "ipv6": "Null0"}
+AGGREGATE_NW = {"ipv4": "10.1.0.0/20", "ipv6": "10:1::/96"}
+
+COMMUNITY = [
+ "0:1 0:10 0:100",
+ "0:2 0:20 0:200",
+ "0:3 0:30 0:300",
+ "0:4 0:40 0:400",
+ "0:5 0:50 0:500",
+ "0:1 0:2 0:3 0:4 0:5 0:10 0:20 0:30 0:40 0:50 0:100 0:200 0:300 0:400 0:500",
+ "0:3 0:4 0:5 0:30 0:40 0:50 0:300 0:400 0:500",
+ "0:6 0:60 0:600",
+ "0:7 0:70 0:700",
+ "0:3 0:4 0:5 0:6 0:30 0:40 0:50 0:60 0:300 0:400 0:500 0:600",
+]
+
+
+class CreateTopo(Topo):
+ """
+ Test BasicTopo - topology 1
+
+ * `Topo`: Topology object
+ """
+
+ def build(self, *_args, **_opts):
+ """Build function"""
+ tgen = get_topogen(self)
+
+ # Building topology from json file
+ build_topo_from_json(tgen, topo)
+
+
+def setup_module(mod):
+ """
+ Sets up the pytest environment
+
+ * `mod`: module name
+ """
+
+ testsuite_run_time = time.asctime(time.localtime(time.time()))
+ logger.info("Testsuite start time: {}".format(testsuite_run_time))
+ logger.info("=" * 40)
+
+ logger.info("Running setup_module to create topology")
+
+ # This function initiates the topology build with Topogen...
+ tgen = Topogen(CreateTopo, mod.__name__)
+ # ... and here it calls Mininet initialization functions.
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start deamons and then start routers
+ start_topology(tgen)
+
+ # Creating configuration from JSON
+ build_config_from_json(tgen, topo)
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Api call verify whether BGP is converged
+ ADDR_TYPES = check_address_types()
+
+ for addr_type in ADDR_TYPES:
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "setup_module :Failed \n Error:" " {}".format(
+ BGP_CONVERGENCE
+ )
+
+ logger.info("Running setup_module() done")
+
+
+def teardown_module(mod):
+ """
+ Teardown the pytest environment
+
+ * `mod`: module name
+ """
+
+ logger.info("Running teardown_module to delete topology")
+
+ tgen = get_topogen()
+
+ # Stop toplogy and Remove tmp files
+ tgen.stop_topology()
+
+ logger.info(
+ "Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
+ )
+ logger.info("=" * 40)
+
+
+#####################################################
+#
+# Tests starting
+#
+#####################################################
+
+
+def test_route_summarisation_with_summary_only_p1(request):
+ """
+ Verify route summarisation with summary-only for redistributed as well as
+ locally generated routes.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ reset_config_on_routers(tgen)
+ write_test_header(tc_name)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ step("Configure static routes on router R1 and redistribute in " "BGP process.")
+
+ for addr_type in ADDR_TYPES:
+ input_static = {
+ "r1": {
+ "static_routes": [
+ {
+ "network": [
+ NETWORK_1_1[addr_type],
+ NETWORK_1_2[addr_type],
+ NETWORK_1_3[addr_type],
+ ],
+ "next_hop": NEXT_HOP[addr_type],
+ }
+ ]
+ }
+ }
+ input_redistribute = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ }
+ }
+
+ step("Configuring {} static routes on router R1 ".format(addr_type))
+
+ result = create_static_routes(tgen, input_static)
+ assert result is True, "Testcase : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Configuring redistribute static for {} address-family on router R1 ".format(
+ addr_type
+ )
+ )
+
+ result = create_router_bgp(tgen, topo, input_redistribute)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Verify that Static routes are redistributed in BGP process")
+
+ for addr_type in ADDR_TYPES:
+ input_static = {
+ "r1": {
+ "static_routes": [
+ {
+ "network": [
+ NETWORK_1_1[addr_type],
+ NETWORK_1_2[addr_type],
+ NETWORK_1_3[addr_type],
+ ]
+ }
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, "r3", input_static)
+ assert result is True, "Testcase : Failed \n Error: {}".format(tc_name, result)
+
+ step("Advertise some prefixes using network command")
+ step(
+ "Additionally advertise 10.1.4.0/24 & 10.1.5.0/24 and "
+ "10:1::4:0/120 & 10:1::5:0/120 from R4 to R1."
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_advertise = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "advertise_networks": [
+ {
+ "network": [
+ NETWORK_2_1[addr_type],
+ NETWORK_2_2[addr_type],
+ NETWORK_2_3[addr_type],
+ NETWORK_2_4[addr_type],
+ ]
+ }
+ ]
+ }
+ }
+ }
+ }
+ },
+ "r4": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "advertise_networks": [
+ {
+ "network": [
+ NETWORK_1_4[addr_type],
+ NETWORK_1_5[addr_type],
+ ]
+ }
+ ]
+ }
+ }
+ }
+ }
+ },
+ }
+
+ result = create_router_bgp(tgen, topo, input_advertise)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify that advertised prefixes using network command are being "
+ "advertised in BGP process"
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_advertise = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "advertise_networks": [
+ {
+ "network": [
+ NETWORK_2_1[addr_type],
+ NETWORK_2_2[addr_type],
+ NETWORK_2_3[addr_type],
+ NETWORK_2_4[addr_type],
+ ]
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, "r3", input_advertise)
+ assert result is True, "Testcase : Failed \n Error: {}".format(tc_name, result)
+
+ step("Configure aggregate-address to summarise all the advertised routes.")
+
+ for addr_type in ADDR_TYPES:
+ route_aggregate = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "aggregate_address": [
+ {
+ "network": AGGREGATE_NW[addr_type],
+ "summary": True,
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, route_aggregate)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify that we see 1 summarised route and remaining suppressed "
+ "routes on advertising router R1 and only 1 summarised route on "
+ "receiving router R3 for both AFIs."
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_static_agg = {
+ "r1": {"static_routes": [{"network": AGGREGATE_NW[addr_type]}]}
+ }
+
+ input_static = {
+ "r1": {
+ "static_routes": [
+ {
+ "network": [
+ NETWORK_1_1[addr_type],
+ NETWORK_1_2[addr_type],
+ NETWORK_1_3[addr_type],
+ ]
+ }
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, "r3", input_static_agg, protocol="bgp")
+ assert result is True, "Testcase : Failed \n Error: {}".format(tc_name, result)
+
+ result = verify_rib(
+ tgen, addr_type, "r3", input_static, protocol="bgp", expected=False
+ )
+ assert result is not True, (
+ "Testcase : Failed \n "
+ "Routes are still present \n Error: {}".format(tc_name, result)
+ )
+
+ result = verify_rib(tgen, addr_type, "r1", input_static_agg, protocol="bgp")
+ assert result is True, "Testcase : Failed \n Error: {}".format(tc_name, result)
+
+ result = verify_rib(tgen, addr_type, "r1", input_static)
+ assert result is True, "Testcase : Failed \n Error: {}".format(tc_name, result)
+
+ for action, value in zip(["removed", "add"], [True, False]):
+
+ step(
+ "{} static routes as below: "
+ "(no) ip route 10.1.1.0/24 and (no) ip route 10.1.2.0/24"
+ "(no) ipv6 route 10:1::1:0/120 and (no) ip route 10:1::2:0/120".format(
+ action
+ )
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_static = {
+ "r1": {
+ "static_routes": [
+ {
+ "network": [NETWORK_1_1[addr_type], NETWORK_1_2[addr_type]],
+ "next_hop": NEXT_HOP[addr_type],
+ "delete": value,
+ }
+ ]
+ }
+ }
+
+ result = create_static_routes(tgen, input_static)
+ assert result is True, "Testcase : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify that there is no impact on R3, as summarised route remains "
+ "intact. However suppressed routes on R1 disappear and re-appear "
+ "based on {} static routes.".format(action)
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_static_1 = {
+ "r1": {
+ "static_routes": [
+ {"network": [NETWORK_1_1[addr_type], NETWORK_1_2[addr_type]]}
+ ]
+ }
+ }
+
+ input_static_2 = {
+ "r1": {"static_routes": [{"network": AGGREGATE_NW[addr_type]}]}
+ }
+
+ if value:
+ result = verify_rib(
+ tgen, addr_type, "r1", input_static_1, expected=False
+ )
+ assert result is not True, (
+ "Testcase : Failed \n "
+ "Routes are still present \n Error: {}".format(tc_name, result)
+ )
+ else:
+ result = verify_rib(tgen, addr_type, "r1", input_static_1)
+ assert result is True, "Testcase : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(tgen, addr_type, "r3", input_static_2, protocol="bgp")
+ assert result is True, "Testcase : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "{} prefixes using network command as below:"
+ "(no) network 10.1.6.1/24 and (no) network 10.1.7.1/24"
+ "(no) network 10:1::6:0/120 and (no) network 10:1::7:0/120".format(action)
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_advertise = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "advertise_networks": [
+ {
+ "network": [
+ NETWORK_2_3[addr_type],
+ NETWORK_2_4[addr_type],
+ ],
+ "delete": value,
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_advertise)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify that there is no impact on R3, as summarised route remains "
+ "intact. However suppressed routes on R1 disappear and re-appear "
+ "based on {} of network command.".format(action)
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_advertise_1 = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "advertise_networks": [
+ {
+ "network": [
+ NETWORK_2_3[addr_type],
+ NETWORK_2_4[addr_type],
+ ]
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+
+ input_advertise_2 = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "advertise_networks": [
+ {"network": AGGREGATE_NW[addr_type]}
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if value:
+ result = verify_bgp_rib(
+ tgen, addr_type, "r1", input_advertise_1, expected=False
+ )
+ assert result is not True, (
+ "Testcase : Failed \n "
+ "Routes are still present \n Error: {}".format(tc_name, result)
+ )
+ else:
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_advertise_1)
+ assert result is True, "Testcase : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(tgen, addr_type, "r3", input_advertise_2)
+ assert result is True, "Testcase : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Add a new network each one from out of aggregation range and "
+ "other within aggregation range. "
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_static = {
+ "r1": {
+ "static_routes": [
+ {"network": NETWORK_3_1[addr_type], "next_hop": NEXT_HOP[addr_type]}
+ ]
+ }
+ }
+
+ result = create_static_routes(tgen, input_static)
+ assert result is True, "Testcase : Failed \n Error: {}".format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+ input_advertise = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "advertise_networks": [
+ {"network": NETWORK_4_1[addr_type],}
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_advertise)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify that when a network within aggregation range is added, "
+ "there is no impact on receiving router. However if a network "
+ "outside aggregation range is added/removed, R3 receives and "
+ "withdraws it accordingly."
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_static = {"r1": {"static_routes": [{"network": AGGREGATE_NW[addr_type]}]}}
+
+ result = verify_rib(tgen, addr_type, "r3", input_static, protocol="bgp")
+ assert result is True, "Testcase : Failed \n Error: {}".format(tc_name, result)
+
+ input_advertise_2 = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "advertise_networks": [
+ {
+ "network": [
+ NETWORK_4_1[addr_type],
+ AGGREGATE_NW[addr_type],
+ ]
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, "r3", input_advertise_2, protocol="bgp")
+ assert result is True, "Testcase : Failed \n Error: {}".format(tc_name, result)
+
+ for action, value in zip(["Delete", "Re-add"], [True, False]):
+ step("{} aggregation command from R1.".format(action))
+
+ for addr_type in ADDR_TYPES:
+ route_aggregate = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "aggregate_address": [
+ {
+ "network": AGGREGATE_NW[addr_type],
+ "summary": True,
+ "delete": value,
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, route_aggregate)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify on both routers that summarised route is withdrawn from R1 "
+ "and R3 when aggregate-address command is removed and appears again "
+ "when aggregate-address command is re-added. Check for both AFIs."
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_static_agg = {
+ "r1": {"static_routes": [{"network": AGGREGATE_NW[addr_type]}]}
+ }
+
+ if value:
+ result = verify_rib(
+ tgen, addr_type, "r1", input_static_agg, expected=False
+ )
+ assert result is not True, (
+ "Testcase : Failed \n "
+ "Aggregated route is still present \n Error: {}".format(
+ tc_name, result
+ )
+ )
+
+ result = verify_rib(
+ tgen, addr_type, "r3", input_static_agg, expected=False
+ )
+ assert result is not True, (
+ "Testcase : Failed \n "
+ "Aggregated route is still present \n Error: {}".format(
+ tc_name, result
+ )
+ )
+ else:
+ result = verify_rib(tgen, addr_type, "r1", input_static_agg)
+ assert result is True, "Testcase : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(tgen, addr_type, "r3", input_static_agg)
+ assert result is True, "Testcase : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_route_summarisation_with_as_set_p1(request):
+ """
+ Verify route summarisation with as-set for redistributed routes.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ reset_config_on_routers(tgen)
+ write_test_header(tc_name)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ step("Configure static routes on router R1 and redistribute in " "BGP process.")
+
+ for addr_type in ADDR_TYPES:
+ input_static = {
+ "r1": {
+ "static_routes": [
+ {
+ "network": [
+ NETWORK_1_1[addr_type],
+ NETWORK_1_2[addr_type],
+ NETWORK_1_3[addr_type],
+ NETWORK_1_4[addr_type],
+ NETWORK_1_5[addr_type],
+ ],
+ "next_hop": NEXT_HOP[addr_type],
+ }
+ ]
+ }
+ }
+ input_redistribute = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ }
+ }
+
+ step("Configuring {} static routes on router R1 ".format(addr_type))
+
+ result = create_static_routes(tgen, input_static)
+ assert result is True, "Testcase : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Configuring redistribute static for {} address-family on router R1 ".format(
+ addr_type
+ )
+ )
+
+ result = create_router_bgp(tgen, topo, input_redistribute)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Verify that Static routes are redistributed in BGP process")
+
+ for addr_type in ADDR_TYPES:
+ input_static = {
+ "r1": {
+ "static_routes": [
+ {
+ "network": [
+ NETWORK_1_1[addr_type],
+ NETWORK_1_2[addr_type],
+ NETWORK_1_3[addr_type],
+ NETWORK_1_4[addr_type],
+ NETWORK_1_5[addr_type],
+ ]
+ }
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, "r3", input_static)
+ assert result is True, "Testcase : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Configure a route-map to attach a unique community attribute value "
+ "to each of these prefixes, while re-distributing static."
+ )
+
+ for addr_type in ADDR_TYPES:
+ for pfx, seq_id, network, in zip(
+ [1, 2, 3, 4, 5],
+ [10, 20, 30, 40, 50],
+ [NETWORK_1_1, NETWORK_1_2, NETWORK_1_3, NETWORK_1_4, NETWORK_1_5],
+ ):
+ prefix_list = {
+ "r1": {
+ "prefix_lists": {
+ addr_type: {
+ "pf_list_{}_{}".format(addr_type, pfx): [
+ {
+ "seqid": seq_id,
+ "network": network[addr_type],
+ "action": "permit",
+ }
+ ]
+ }
+ }
+ }
+ }
+ result = create_prefix_lists(tgen, prefix_list)
+ assert result is True, "Test case {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Create route-map for applying prefix-list on r1")
+
+ for addr_type in ADDR_TYPES:
+ for pfx, comm_id in zip([1, 2, 3, 4, 5], [0, 1, 2, 3, 4]):
+ route_map = {
+ "r1": {
+ "route_maps": {
+ "rmap_{}".format(addr_type): [
+ {
+ "action": "permit",
+ "match": {
+ addr_type: {
+ "prefix_lists": "pf_list_{}_{}".format(
+ addr_type, pfx
+ )
+ }
+ },
+ "set": {"community": {"num": COMMUNITY[comm_id]}},
+ }
+ ]
+ }
+ }
+ }
+
+ result = create_route_maps(tgen, route_map)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Re-configure redistribute static with route-map")
+
+ for addr_type in ADDR_TYPES:
+ input_redistribute = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "redistribute": [
+ {
+ "redist_type": "static",
+ "attribute": {
+ "route-map": "rmap_{}".format(addr_type)
+ },
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_redistribute)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure aggregate-address to summarise all the advertised routes.")
+
+ for addr_type in ADDR_TYPES:
+ route_aggregate = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "aggregate_address": [
+ {"network": AGGREGATE_NW[addr_type], "as_set": True}
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, route_aggregate)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify that we see summarised route on router R3 with all the "
+ "community attribute values combined with that aggregate route."
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict = {"community": COMMUNITY[5]}
+ result = verify_bgp_community(
+ tgen, addr_type, "r3", [AGGREGATE_NW[addr_type]], input_dict
+ )
+ assert result is True, "Test case {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Remove static routes as below: "
+ "(no) ip route 10.1.1.0/24 blackhole "
+ "(no) ip route 10.1.2.0/24 blackhole "
+ "(no) ipv6 route 10:1::1:0/120 blackhole "
+ "(no) ipv6 route 10:1::2:0/120 blackhole "
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_static = {
+ "r1": {
+ "static_routes": [
+ {
+ "network": [NETWORK_1_1[addr_type], NETWORK_1_2[addr_type]],
+ "next_hop": NEXT_HOP[addr_type],
+ "delete": True,
+ }
+ ]
+ }
+ }
+
+ result = create_static_routes(tgen, input_static)
+ assert result is True, "Testcase : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify on R3 that whenever we remove the static routes, we still"
+ " see aggregated route however the corresponding community attribute"
+ "values are withdrawn."
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict = {"community": COMMUNITY[6]}
+ result = verify_bgp_community(
+ tgen, addr_type, "r3", [AGGREGATE_NW[addr_type]], input_dict
+ )
+ assert result is True, "Test case {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Add/remove a new network with community value, each one from out of "
+ "aggregation range and other within aggregation range. "
+ )
+
+ step(
+ "Add a new network each one from out of aggregation range and "
+ "other within aggregation range. "
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_static = {
+ "r1": {
+ "static_routes": [
+ {
+ "network": [NETWORK_3_1[addr_type], NETWORK_4_1[addr_type]],
+ "next_hop": NEXT_HOP[addr_type],
+ }
+ ]
+ }
+ }
+
+ result = create_static_routes(tgen, input_static)
+ assert result is True, "Testcase : Failed \n Error: {}".format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+ for pfx, seq_id, network, in zip([6, 7], [60, 70], [NETWORK_3_1, NETWORK_4_1]):
+ prefix_list = {
+ "r1": {
+ "prefix_lists": {
+ addr_type: {
+ "pf_list_{}_{}".format(addr_type, pfx): [
+ {
+ "seqid": seq_id,
+ "network": network[addr_type],
+ "action": "permit",
+ }
+ ]
+ }
+ }
+ }
+ }
+ result = create_prefix_lists(tgen, prefix_list)
+ assert result is True, "Test case {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Create route-map for applying prefix-list on r1")
+
+ for addr_type in ADDR_TYPES:
+ for pfx, comm_id in zip([6, 7], [7, 8]):
+ route_map = {
+ "r1": {
+ "route_maps": {
+ "rmap_{}".format(addr_type): [
+ {
+ "action": "permit",
+ "match": {
+ addr_type: {
+ "prefix_lists": "pf_list_{}_{}".format(
+ addr_type, pfx
+ )
+ }
+ },
+ "set": {"community": {"num": COMMUNITY[comm_id]}},
+ }
+ ]
+ }
+ }
+ }
+
+ result = create_route_maps(tgen, route_map)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify on R3 when route is added within the summary range, aggregated"
+ " route also has associated community value added. However if the route"
+ " is beyond the summary range the aggregated route would have no impact"
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict = {"community": COMMUNITY[9]}
+ result = verify_bgp_community(
+ tgen, addr_type, "r3", [AGGREGATE_NW[addr_type]], input_dict
+ )
+ assert result is True, "Test case {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for action, value in zip(["Delete", "Re-add"], [True, False]):
+ step("{} aggregation command from R1.".format(action))
+
+ for addr_type in ADDR_TYPES:
+ route_aggregate = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "aggregate_address": [
+ {
+ "network": AGGREGATE_NW[addr_type],
+ "as_set": True,
+ "delete": value,
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, route_aggregate)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify that when as-set command is removed, we do not see community "
+ "attribute added to summarised route on R3. However when as-set option "
+ "is re-added, all the community attribute values must appear with "
+ "summarised route."
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_static_agg = {
+ "r1": {"static_routes": [{"network": AGGREGATE_NW[addr_type]}]}
+ }
+
+ if value:
+ result = verify_rib(
+ tgen, addr_type, "r1", input_static_agg, expected=False
+ )
+ assert result is not True, (
+ "Testcase : Failed \n "
+ "Aggregated route is still present \n Error: {}".format(
+ tc_name, result
+ )
+ )
+
+ result = verify_rib(
+ tgen, addr_type, "r3", input_static_agg, expected=False
+ )
+ assert result is not True, (
+ "Testcase : Failed \n "
+ "Aggregated route is still present \n Error: {}".format(
+ tc_name, result
+ )
+ )
+ else:
+ result = verify_rib(tgen, addr_type, "r1", input_static_agg)
+ assert result is True, "Testcase : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(tgen, addr_type, "r3", input_static_agg)
+ assert result is True, "Testcase : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ input_dict = {"community": COMMUNITY[9]}
+ result = verify_bgp_community(
+ tgen, addr_type, "r3", [AGGREGATE_NW[addr_type]], input_dict
+ )
+ assert result is True, "Test case {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_rr_ibgp/spine1/bgpd.conf b/tests/topotests/bgp_rr_ibgp/spine1/bgpd.conf
index fa77cce073..cece3fc600 100644
--- a/tests/topotests/bgp_rr_ibgp/spine1/bgpd.conf
+++ b/tests/topotests/bgp_rr_ibgp/spine1/bgpd.conf
@@ -2,7 +2,9 @@ hostname spine1
router bgp 99
no bgp ebgp-requires-policy
neighbor 192.168.2.1 remote-as internal
+ neighbor 192.168.2.1 timers 3 10
neighbor 192.168.4.2 remote-as internal
+ neighbor 192.168.4.2 timers 3 10
address-family ipv4 uni
redistribute connected
neighbor 192.168.2.1 route-reflector-client
diff --git a/tests/topotests/bgp_rr_ibgp/test_bgp_rr_ibgp_topo1.py b/tests/topotests/bgp_rr_ibgp/test_bgp_rr_ibgp_topo1.py
index da45e73ab4..6a604765ca 100755..100644
--- a/tests/topotests/bgp_rr_ibgp/test_bgp_rr_ibgp_topo1.py
+++ b/tests/topotests/bgp_rr_ibgp/test_bgp_rr_ibgp_topo1.py
@@ -104,7 +104,7 @@ def setup_module(module):
# This is a sample of configuration loading.
router_list = tgen.routers()
- for rname, router in router_list.iteritems():
+ for rname, router in router_list.items():
router.load_config(
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
)
diff --git a/tests/topotests/bgp_rr_ibgp/tor1/bgpd.conf b/tests/topotests/bgp_rr_ibgp/tor1/bgpd.conf
index b028ab4e8b..1b9f15010a 100644
--- a/tests/topotests/bgp_rr_ibgp/tor1/bgpd.conf
+++ b/tests/topotests/bgp_rr_ibgp/tor1/bgpd.conf
@@ -2,4 +2,5 @@ hostname tor1
router bgp 99
no bgp ebgp-requires-policy
neighbor 192.168.2.3 remote-as internal
+ neighbor 192.168.2.3 timers 3 10
redistribute connected
diff --git a/tests/topotests/bgp_rr_ibgp/tor2/bgpd.conf b/tests/topotests/bgp_rr_ibgp/tor2/bgpd.conf
index 99c34158b9..3bdb35976c 100644
--- a/tests/topotests/bgp_rr_ibgp/tor2/bgpd.conf
+++ b/tests/topotests/bgp_rr_ibgp/tor2/bgpd.conf
@@ -2,4 +2,5 @@ hostname tor2
router bgp 99
no bgp ebgp-requires-policy
neighbor 192.168.4.3 remote-as internal
+ neighbor 192.168.4.3 timers 3 10
redistribute connected
diff --git a/tests/topotests/bgp_sender-as-path-loop-detection/r1/bgpd.conf b/tests/topotests/bgp_sender-as-path-loop-detection/r1/bgpd.conf
index b16e94d7c1..719d76392d 100644
--- a/tests/topotests/bgp_sender-as-path-loop-detection/r1/bgpd.conf
+++ b/tests/topotests/bgp_sender-as-path-loop-detection/r1/bgpd.conf
@@ -2,6 +2,7 @@
router bgp 65001
no bgp ebgp-requires-policy
neighbor 192.168.255.1 remote-as 65002
+ neighbor 192.168.255.1 timers 3 10
address-family ipv4 unicast
neighbor 192.168.255.1 route-map prepend out
redistribute connected
diff --git a/tests/topotests/bgp_sender-as-path-loop-detection/r2/bgpd.conf b/tests/topotests/bgp_sender-as-path-loop-detection/r2/bgpd.conf
index 674877edd3..a4a654d7b5 100644
--- a/tests/topotests/bgp_sender-as-path-loop-detection/r2/bgpd.conf
+++ b/tests/topotests/bgp_sender-as-path-loop-detection/r2/bgpd.conf
@@ -2,8 +2,10 @@
router bgp 65002
no bgp ebgp-requires-policy
neighbor 192.168.255.2 remote-as 65001
+ neighbor 192.168.255.2 timers 3 10
neighbor 192.168.255.2 solo
neighbor 192.168.254.2 remote-as 65003
+ neighbor 192.168.254.2 timers 3 10
neighbor 192.168.254.2 solo
neighbor 192.168.254.2 sender-as-path-loop-detection
!
diff --git a/tests/topotests/bgp_sender-as-path-loop-detection/r3/bgpd.conf b/tests/topotests/bgp_sender-as-path-loop-detection/r3/bgpd.conf
index 4ee7a39ab2..2e24de0b2d 100644
--- a/tests/topotests/bgp_sender-as-path-loop-detection/r3/bgpd.conf
+++ b/tests/topotests/bgp_sender-as-path-loop-detection/r3/bgpd.conf
@@ -2,4 +2,5 @@
router bgp 65003
no bgp ebgp-requires-policy
neighbor 192.168.254.1 remote-as 65002
+ neighbor 192.168.254.1 timers 3 10
!
diff --git a/tests/topotests/bgp_sender-as-path-loop-detection/test_bgp_sender-as-path-loop-detection.py b/tests/topotests/bgp_sender-as-path-loop-detection/test_bgp_sender-as-path-loop-detection.py
index 56a98c1ef8..88935ae4d1 100644
--- a/tests/topotests/bgp_sender-as-path-loop-detection/test_bgp_sender-as-path-loop-detection.py
+++ b/tests/topotests/bgp_sender-as-path-loop-detection/test_bgp_sender-as-path-loop-detection.py
@@ -66,7 +66,7 @@ def setup_module(mod):
router_list = tgen.routers()
- for i, (rname, router) in enumerate(router_list.iteritems(), 1):
+ for i, (rname, router) in enumerate(router_list.items(), 1):
router.load_config(
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
)
diff --git a/tests/topotests/bgp_set_local-preference_add_subtract/r1/bgpd.conf b/tests/topotests/bgp_set_local-preference_add_subtract/r1/bgpd.conf
index 7dab52fef0..57e2f5818a 100644
--- a/tests/topotests/bgp_set_local-preference_add_subtract/r1/bgpd.conf
+++ b/tests/topotests/bgp_set_local-preference_add_subtract/r1/bgpd.conf
@@ -1,6 +1,8 @@
router bgp 65000
no bgp ebgp-requires-policy
neighbor 192.168.255.2 remote-as 65000
+ neighbor 192.168.255.2 timers 3 10
neighbor 192.168.255.3 remote-as 65000
+ neighbor 192.168.255.3 timers 3 10
exit-address-family
!
diff --git a/tests/topotests/bgp_set_local-preference_add_subtract/r2/bgpd.conf b/tests/topotests/bgp_set_local-preference_add_subtract/r2/bgpd.conf
index a8a0384632..82a01d4570 100644
--- a/tests/topotests/bgp_set_local-preference_add_subtract/r2/bgpd.conf
+++ b/tests/topotests/bgp_set_local-preference_add_subtract/r2/bgpd.conf
@@ -1,6 +1,7 @@
router bgp 65000
no bgp ebgp-requires-policy
neighbor 192.168.255.1 remote-as 65000
+ neighbor 192.168.255.1 timers 3 10
address-family ipv4
redistribute connected
neighbor 192.168.255.1 route-map r1-out out
diff --git a/tests/topotests/bgp_set_local-preference_add_subtract/r3/bgpd.conf b/tests/topotests/bgp_set_local-preference_add_subtract/r3/bgpd.conf
index 2f5dceede2..65e092b0f2 100644
--- a/tests/topotests/bgp_set_local-preference_add_subtract/r3/bgpd.conf
+++ b/tests/topotests/bgp_set_local-preference_add_subtract/r3/bgpd.conf
@@ -1,6 +1,7 @@
router bgp 65000
no bgp ebgp-requires-policy
neighbor 192.168.255.1 remote-as 65000
+ neighbor 192.168.255.1 timers 3 10
address-family ipv4
redistribute connected
neighbor 192.168.255.1 route-map r1-out out
diff --git a/tests/topotests/bgp_set_local-preference_add_subtract/test_bgp_set_local-preference_add_subtract.py b/tests/topotests/bgp_set_local-preference_add_subtract/test_bgp_set_local-preference_add_subtract.py
index ce3165db25..af64648951 100644
--- a/tests/topotests/bgp_set_local-preference_add_subtract/test_bgp_set_local-preference_add_subtract.py
+++ b/tests/topotests/bgp_set_local-preference_add_subtract/test_bgp_set_local-preference_add_subtract.py
@@ -64,7 +64,7 @@ def setup_module(mod):
router_list = tgen.routers()
- for i, (rname, router) in enumerate(router_list.iteritems(), 1):
+ for i, (rname, router) in enumerate(router_list.items(), 1):
router.load_config(
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
)
diff --git a/tests/topotests/bgp_update_delay/__init__.py b/tests/topotests/bgp_update_delay/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_update_delay/__init__.py
diff --git a/tests/topotests/bgp_update_delay/r1/bgpd.conf b/tests/topotests/bgp_update_delay/r1/bgpd.conf
new file mode 100644
index 0000000000..8ebb509d6d
--- /dev/null
+++ b/tests/topotests/bgp_update_delay/r1/bgpd.conf
@@ -0,0 +1,10 @@
+! exit1
+router bgp 65001
+ no bgp ebgp-requires-policy
+ neighbor 192.168.255.1 remote-as 65002
+ neighbor 192.168.255.1 timers connect 10
+ address-family ipv4 unicast
+ redistribute connected
+ exit-address-family
+ !
+!
diff --git a/tests/topotests/bgp_update_delay/r1/zebra.conf b/tests/topotests/bgp_update_delay/r1/zebra.conf
new file mode 100644
index 0000000000..9904bb4e16
--- /dev/null
+++ b/tests/topotests/bgp_update_delay/r1/zebra.conf
@@ -0,0 +1,9 @@
+! exit1
+interface lo
+ ip address 172.16.255.254/32
+!
+interface r1-eth0
+ ip address 192.168.255.2/30
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_update_delay/r2/bgpd.conf b/tests/topotests/bgp_update_delay/r2/bgpd.conf
new file mode 100644
index 0000000000..438f9950a5
--- /dev/null
+++ b/tests/topotests/bgp_update_delay/r2/bgpd.conf
@@ -0,0 +1,18 @@
+! spine
+router bgp 65002
+ no bgp ebgp-requires-policy
+ timers bgp 3 9
+ neighbor 192.168.255.2 remote-as 65001
+ neighbor 192.168.254.2 remote-as 65003
+ neighbor 192.168.253.2 remote-as 65004
+ neighbor 192.168.255.2 timers connect 10
+ neighbor 192.168.254.2 timers connect 10
+ neighbor 192.168.253.2 timers connect 10
+!
+ router bgp 65002 vrf vrf1
+ no bgp ebgp-requires-policy
+ timers bgp 3 9
+ neighbor 192.168.252.2 remote-as 65005
+ neighbor 192.168.252.2 timers connect 10
+ !
+!
diff --git a/tests/topotests/bgp_update_delay/r2/zebra.conf b/tests/topotests/bgp_update_delay/r2/zebra.conf
new file mode 100644
index 0000000000..420f00d974
--- /dev/null
+++ b/tests/topotests/bgp_update_delay/r2/zebra.conf
@@ -0,0 +1,20 @@
+! spine
+interface r2-eth0
+ ip address 192.168.255.1/30
+!
+interface r2-eth1
+ ip address 192.168.254.1/30
+!
+interface r2-eth2
+ ip address 192.168.253.1/30
+!
+interface r2-eth3
+ ip address 192.168.252.1/30
+ vrf vrf1
+!
+auto vrf1
+iface vrf1
+ vrf-table auto
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_update_delay/r3/bgpd.conf b/tests/topotests/bgp_update_delay/r3/bgpd.conf
new file mode 100644
index 0000000000..53e51788f7
--- /dev/null
+++ b/tests/topotests/bgp_update_delay/r3/bgpd.conf
@@ -0,0 +1,10 @@
+! exit2
+router bgp 65003
+ no bgp ebgp-requires-policy
+ timers bgp 3 9
+ neighbor 192.168.254.1 remote-as 65002
+ neighbor 192.168.254.1 timers connect 10
+ address-family ipv4 unicast
+ redistribute connected
+ !
+!
diff --git a/tests/topotests/bgp_update_delay/r3/zebra.conf b/tests/topotests/bgp_update_delay/r3/zebra.conf
new file mode 100644
index 0000000000..f490d97afe
--- /dev/null
+++ b/tests/topotests/bgp_update_delay/r3/zebra.conf
@@ -0,0 +1,9 @@
+! exit2
+interface lo
+ ip address 172.16.254.254/32
+!
+interface r3-eth0
+ ip address 192.168.254.2/30
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_update_delay/r4/bgpd.conf b/tests/topotests/bgp_update_delay/r4/bgpd.conf
new file mode 100644
index 0000000000..34cb429c0a
--- /dev/null
+++ b/tests/topotests/bgp_update_delay/r4/bgpd.conf
@@ -0,0 +1,11 @@
+! exit2
+router bgp 65004
+ no bgp ebgp-requires-policy
+ timers bgp 3 9
+ neighbor 192.168.253.1 remote-as 65002
+ neighbor 192.168.253.1 timers connect 10
+ address-family ipv4 unicast
+ redistribute connected
+ exit-address-family
+ !
+!
diff --git a/tests/topotests/bgp_update_delay/r4/zebra.conf b/tests/topotests/bgp_update_delay/r4/zebra.conf
new file mode 100644
index 0000000000..baba04c160
--- /dev/null
+++ b/tests/topotests/bgp_update_delay/r4/zebra.conf
@@ -0,0 +1,9 @@
+! exit2
+interface lo
+ ip address 172.16.253.254/32
+!
+interface r4-eth0
+ ip address 192.168.253.2/30
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_update_delay/r5/bgpd.conf b/tests/topotests/bgp_update_delay/r5/bgpd.conf
new file mode 100644
index 0000000000..66ecc703cd
--- /dev/null
+++ b/tests/topotests/bgp_update_delay/r5/bgpd.conf
@@ -0,0 +1,11 @@
+! exit1
+router bgp 65005
+ no bgp ebgp-requires-policy
+ timers bgp 3 9
+ neighbor 192.168.252.1 remote-as 65002
+ neighbor 192.168.252.1 timers connect 10
+ address-family ipv4 unicast
+ redistribute connected
+ exit-address-family
+ !
+!
diff --git a/tests/topotests/bgp_update_delay/r5/zebra.conf b/tests/topotests/bgp_update_delay/r5/zebra.conf
new file mode 100644
index 0000000000..8adf6f89e0
--- /dev/null
+++ b/tests/topotests/bgp_update_delay/r5/zebra.conf
@@ -0,0 +1,9 @@
+! exit1
+interface lo
+ ip address 172.16.252.254/32
+!
+interface r1-eth0
+ ip address 192.168.252.2/30
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_update_delay/test_bgp_update_delay.py b/tests/topotests/bgp_update_delay/test_bgp_update_delay.py
new file mode 100644
index 0000000000..4de7184c8e
--- /dev/null
+++ b/tests/topotests/bgp_update_delay/test_bgp_update_delay.py
@@ -0,0 +1,295 @@
+#!/usr/bin/env python
+
+#
+# test_bgp_update_delay.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2019 by
+# Don Slice <dslice@nvidia.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 the ability to define update-delay to delay bestpath, rib install
+and advertisement to peers when frr is started, restarted or "clear ip
+bgp *" is performed. Test both the vrf-specific and global configuration
+and operation.
+
+r1
+|
+r2----r3
+| \
+| \
+r5 r4
+
+
+r2 is UUT and peers with r1, r3, and r4 in default bgp instance.
+r2 peers with r5 in vrf vrf1.
+
+Check r2 initial convergence in default table
+Define update-delay with max-delay in the default bgp instance on r2
+Shutdown peering on r1 toward r2 so that delay timers can be exercised
+Clear bgp neighbors on r2 and then check for the 'in progress' indicator
+Check that r2 only installs route learned from r4 after the max-delay timer expires
+Define update-delay with max-delay and estabish-wait and check json output showing set
+Clear neighbors on r2 and check that r3 installs route from r4 after establish-wait time
+Remove update-delay timer on r2 to verify that it goes back to normal behavior
+Clear neighbors on r2 and check that route install time on r2 does not delay
+Define global bgp update-delay with max-delay and establish-wait on r2
+Check that r2 default instance and vrf1 have the max-delay and establish set
+Clear neighbors on r2 and check route-install time is after the establish-wait timer
+
+Note that the keepalive/hold times were changed to 3/9 and the connect retry timer
+to 10 to improve the odds the convergence timing in this test case is useful in the
+event of packet loss.
+"""
+
+import os
+import sys
+import json
+import time
+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
+
+
+class TemplateTopo(Topo):
+ def build(self, *_args, **_opts):
+ tgen = get_topogen(self)
+
+ for routern in range(1, 6):
+ tgen.add_router("r{}".format(routern))
+
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["r2"])
+
+ switch = tgen.add_switch("s2")
+ switch.add_link(tgen.gears["r2"])
+ switch.add_link(tgen.gears["r3"])
+
+ switch = tgen.add_switch("s3")
+ switch.add_link(tgen.gears["r2"])
+ switch.add_link(tgen.gears["r4"])
+
+ switch = tgen.add_switch("s4")
+ switch.add_link(tgen.gears["r2"])
+ switch.add_link(tgen.gears["r5"])
+
+
+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_update_delay():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ router1 = tgen.gears["r1"]
+ router2 = tgen.gears["r2"]
+ router3 = tgen.gears["r3"]
+
+ # initial convergence without update-delay defined
+ def _bgp_converge(router):
+ output = json.loads(router.vtysh_cmd("show ip bgp neighbor 192.168.255.2 json"))
+ expected = {
+ "192.168.255.2": {
+ "bgpState": "Established",
+ "addressFamilyInfo": {"ipv4Unicast": {"acceptedPrefixCounter": 2}},
+ }
+ }
+ return topotest.json_cmp(output, expected)
+
+ def _bgp_check_update_delay(router):
+ output = json.loads(router.vtysh_cmd("show ip bgp sum json"))
+ expected = {"ipv4Unicast": {"updateDelayLimit": 20}}
+
+ return topotest.json_cmp(output, expected)
+
+ def _bgp_check_update_delay_in_progress(router):
+ output = json.loads(router.vtysh_cmd("show ip bgp sum json"))
+ expected = {"ipv4Unicast": {"updateDelayInProgress":True}}
+
+ return topotest.json_cmp(output, expected)
+
+ def _bgp_check_route_install(router):
+ output = json.loads(router.vtysh_cmd("show ip route 172.16.253.254/32 json"))
+ expected = {"172.16.253.254/32": [ {"protocol": "bgp"}]}
+
+ return topotest.json_cmp(output, expected)
+
+ def _bgp_check_update_delay_and_wait(router):
+ output = json.loads(router.vtysh_cmd("show ip bgp sum json"))
+ expected = {
+ "ipv4Unicast": {
+ "updateDelayLimit": 20,
+ "updateDelayEstablishWait": 10}}
+
+ return topotest.json_cmp(output, expected)
+
+ def _bgp_check_update_delay(router):
+ output = json.loads(router.vtysh_cmd("show ip bgp sum json"))
+ expected = {"ipv4Unicast": {"updateDelayLimit": 20}}
+
+ return topotest.json_cmp(output, expected)
+
+ def _bgp_check_vrf_update_delay_and_wait(router):
+ output = json.loads(router.vtysh_cmd("show ip bgp vrf vrf1 sum json"))
+ expected = {
+ "ipv4Unicast": {
+ "updateDelayLimit": 20,
+ "updateDelayEstablishWait": 10}}
+
+
+ return topotest.json_cmp(output, expected)
+
+
+ # Check r2 initial convergence in default table
+ test_func = functools.partial(_bgp_converge, router2)
+ success, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+
+ assert result is None, 'Failed bgp convergence in "{}"'.format(router2)
+
+ # Define update-delay with max-delay in the default bgp instance on r2
+ router2.vtysh_cmd(
+ """
+ configure terminal
+ router bgp 65002
+ update-delay 20
+ """
+ )
+
+ # Shutdown peering on r1 toward r2 so that delay timers can be exercised
+ router1.vtysh_cmd(
+ """
+ configure terminal
+ router bgp 65001
+ neighbor 192.168.255.1 shut
+ """
+ )
+
+ # Clear bgp neighbors on r2 and then check for the 'in progress' indicator
+ router2.vtysh_cmd("""clear ip bgp *""")
+
+ test_func = functools.partial(_bgp_check_update_delay_in_progress, router2)
+ success, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+
+ assert result is None, 'Failed to set update-delay max-delay timer "{}"'.format(router2)
+
+ # Check that r2 only installs route learned from r4 after the max-delay timer expires
+ test_func = functools.partial(_bgp_check_route_install, router2)
+ success, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+
+ assert result is None, 'Failed to install route after update-delay "{}"'.format(router2)
+
+ # Define update-delay with max-delay and estabish-wait and check json output showing set
+ router2.vtysh_cmd(
+ """
+ configure terminal
+ router bgp 65002
+ update-delay 20 10
+ """
+ )
+
+ test_func = functools.partial(_bgp_check_update_delay_and_wait, router2)
+ success, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+
+ assert result is None, 'Failed to set max-delay and establish-weight timers in "{}"'.format(router2)
+
+ # Define update-delay with max-delay and estabish-wait and check json output showing set
+ router2.vtysh_cmd("""clear ip bgp *""")
+
+ test_func = functools.partial(_bgp_check_route_install, router3)
+ success, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+
+ assert result is None, 'Failed to installed advertised route after establish-wait timer espired "{}"'.format(router2)
+
+ # Remove update-delay timer on r2 to verify that it goes back to normal behavior
+ router2.vtysh_cmd(
+ """
+ configure terminal
+ router bgp 65002
+ no update-delay
+ """
+ )
+
+ # Clear neighbors on r2 and check that route install time on r2 does not delay
+ router2.vtysh_cmd("""clear ip bgp *""")
+
+ test_func = functools.partial(_bgp_check_route_install, router2)
+ success, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+
+ assert result is None, 'Failed to remove update-delay delay timing "{}"'.format(router2)
+
+ # Define global bgp update-delay with max-delay and establish-wait on r2
+ router2.vtysh_cmd(
+ """
+ configure terminal
+ bgp update-delay 20 10
+ """
+ )
+
+ # Check that r2 default instance and vrf1 have the max-delay and establish set
+ test_func = functools.partial(_bgp_check_update_delay_and_wait, router2)
+ success, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+
+ assert result is None, 'Failed to set update-delay in default instance "{}"'.format(router2)
+
+ test_func = functools.partial(_bgp_check_vrf_update_delay_and_wait, router2)
+ success, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+
+ assert result is None, 'Failed to set update-delay in vrf1 "{}"'.format(router2)
+
+ # Clear neighbors on r2 and check route-install time is after the establish-wait timer
+ router2.vtysh_cmd("""clear ip bgp *""")
+
+ test_func = functools.partial(_bgp_check_route_install, router3)
+ success, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+
+ assert result is None, 'Failed to installed advertised route after establish-wait timer espired "{}"'.format(router2)
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r1/bgpd.conf b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r1/bgpd.conf
index 002cecd1fa..0033bc2a7a 100644
--- a/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r1/bgpd.conf
+++ b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r1/bgpd.conf
@@ -5,6 +5,7 @@ router bgp 101 vrf r1-cust1
neighbor r2g remote-as external
neighbor r2g bfd
neighbor r1-eth0 interface peer-group r2g
+ neighbor r1-eth0 timers 3 10
address-family ipv4 unicast
redistribute connected
exit-address-family
diff --git a/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r2/bgpd.conf b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r2/bgpd.conf
index 0878b9b995..183157eb46 100644
--- a/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r2/bgpd.conf
+++ b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r2/bgpd.conf
@@ -5,6 +5,7 @@ router bgp 102 vrf r2-cust1
neighbor r2g remote-as external
neighbor r2g bfd
neighbor r2-eth0 interface peer-group r2g
+ neighbor r2-eth0 timers 3 10
!
address-family ipv4 unicast
redistribute connected
diff --git a/tests/topotests/bgp_vrf_lite_ipv6_rtadv/test_bgp_vrf_lite_ipv6_rtadv.py b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/test_bgp_vrf_lite_ipv6_rtadv.py
index 5d8c80c6a2..50b9b092d6 100644
--- a/tests/topotests/bgp_vrf_lite_ipv6_rtadv/test_bgp_vrf_lite_ipv6_rtadv.py
+++ b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/test_bgp_vrf_lite_ipv6_rtadv.py
@@ -95,7 +95,7 @@ def setup_module(mod):
"ip link set {0}-eth0 master {0}-cust1",
]
- for rname, router in router_list.iteritems():
+ for rname, router in router_list.items():
for cmd in cmds:
output = tgen.net[rname].cmd(cmd.format(rname))
@@ -109,7 +109,7 @@ def setup_module(mod):
"sysctl -w net.ipv4.tcp_l3mdev_accept={}".format(l3mdev_accept)
)
- for rname, router in router_list.iteritems():
+ for rname, router in router_list.items():
router.load_config(
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
)
diff --git a/tests/topotests/bgp_vrf_netns/r1/bgpd.conf b/tests/topotests/bgp_vrf_netns/r1/bgpd.conf
index dabf9521ac..cfe3f2e2b5 100644
--- a/tests/topotests/bgp_vrf_netns/r1/bgpd.conf
+++ b/tests/topotests/bgp_vrf_netns/r1/bgpd.conf
@@ -4,6 +4,7 @@ router bgp 100 vrf r1-cust1
bgp bestpath as-path multipath-relax
no bgp ebgp-requires-policy
neighbor 10.0.1.101 remote-as 99
+ neighbor 10.0.1.101 timers 3 10
!
!
diff --git a/tests/topotests/bgp_vrf_netns/test_bgp_vrf_netns_topo.py b/tests/topotests/bgp_vrf_netns/test_bgp_vrf_netns_topo.py
index ae48f01a0e..30bb9595b7 100755..100644
--- a/tests/topotests/bgp_vrf_netns/test_bgp_vrf_netns_topo.py
+++ b/tests/topotests/bgp_vrf_netns/test_bgp_vrf_netns_topo.py
@@ -140,7 +140,7 @@ def setup_module(module):
# Starting Hosts and init ExaBGP on each of them
logger.info("starting exaBGP on peer1")
peer_list = tgen.exabgp_peers()
- for pname, peer in peer_list.iteritems():
+ for pname, peer in peer_list.items():
peer_dir = os.path.join(CWD, pname)
env_file = os.path.join(CWD, "exabgp.env")
logger.info("Running ExaBGP peer")
diff --git a/tests/topotests/eigrp-topo1/test_eigrp_topo1.py b/tests/topotests/eigrp-topo1/test_eigrp_topo1.py
index c1dd88823b..70666a3d61 100755..100644
--- a/tests/topotests/eigrp-topo1/test_eigrp_topo1.py
+++ b/tests/topotests/eigrp-topo1/test_eigrp_topo1.py
@@ -99,7 +99,7 @@ def setup_module(module):
# This is a sample of configuration loading.
router_list = tgen.routers()
- for rname, router in router_list.iteritems():
+ for rname, router in router_list.items():
router.load_config(
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
)
diff --git a/tests/topotests/evpn-pim-1/leaf1/bgpd.conf b/tests/topotests/evpn-pim-1/leaf1/bgpd.conf
index 4dedfecd61..97fd8662f4 100644
--- a/tests/topotests/evpn-pim-1/leaf1/bgpd.conf
+++ b/tests/topotests/evpn-pim-1/leaf1/bgpd.conf
@@ -2,6 +2,7 @@
router bgp 65002
no bgp ebgp-requires-policy
neighbor 192.168.1.1 remote-as external
+ neighbor 192.168.1.1 timers 3 10
redistribute connected
address-family l2vpn evpn
neighbor 192.168.1.1 activate
diff --git a/tests/topotests/evpn-pim-1/leaf2/bgpd.conf b/tests/topotests/evpn-pim-1/leaf2/bgpd.conf
index 5bc708240d..91d9bd8c8b 100644
--- a/tests/topotests/evpn-pim-1/leaf2/bgpd.conf
+++ b/tests/topotests/evpn-pim-1/leaf2/bgpd.conf
@@ -2,6 +2,7 @@
router bgp 65003
no bgp ebgp-requires-policy
neighbor 192.168.2.1 remote-as external
+ neighbor 192.168.2.1 timers 3 10
redistribute connected
address-family l2vpn evpn
neighbor 192.168.2.1 activate
diff --git a/tests/topotests/evpn-pim-1/spine/bgpd.conf b/tests/topotests/evpn-pim-1/spine/bgpd.conf
index 16c17b29cc..81ab802f35 100644
--- a/tests/topotests/evpn-pim-1/spine/bgpd.conf
+++ b/tests/topotests/evpn-pim-1/spine/bgpd.conf
@@ -2,7 +2,9 @@
router bgp 65001
no bgp ebgp-requires-policy
neighbor 192.168.1.2 remote-as external
+ neighbor 192.168.1.2 timers 3 10
neighbor 192.168.2.3 remote-as external
+ neighbor 192.168.2.3 timers 3 10
redistribute connected
address-family l2vpn evpn
neighbor 192.168.1.2 activate
diff --git a/tests/topotests/evpn-pim-1/test_evpn_pim_topo1.py b/tests/topotests/evpn-pim-1/test_evpn_pim_topo1.py
index 94bb91d49f..265124132f 100755..100644
--- a/tests/topotests/evpn-pim-1/test_evpn_pim_topo1.py
+++ b/tests/topotests/evpn-pim-1/test_evpn_pim_topo1.py
@@ -123,7 +123,7 @@ def setup_module(module):
# tgen.mininet_cli()
# This is a sample of configuration loading.
router_list = tgen.routers()
- for rname, router in router_list.iteritems():
+ for rname, router in router_list.items():
router.load_config(
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
)
diff --git a/tests/topotests/example-test/test_template.py b/tests/topotests/example-test/test_template.py
index afe974876a..4305e0199f 100755..100644
--- a/tests/topotests/example-test/test_template.py
+++ b/tests/topotests/example-test/test_template.py
@@ -82,7 +82,7 @@ def setup_module(mod):
router_list = tgen.routers()
# For all registred routers, load the zebra configuration file
- for rname, router in router_list.iteritems():
+ for rname, router in router_list.items():
router.load_config(
TopoRouter.RD_ZEBRA,
# Uncomment next line to load configuration from ./router/zebra.conf
diff --git a/tests/topotests/isis-sr-topo1/test_isis_sr_topo1.py b/tests/topotests/isis-sr-topo1/test_isis_sr_topo1.py
index 72bc96e4d0..d4ebe52bf6 100755..100644
--- a/tests/topotests/isis-sr-topo1/test_isis_sr_topo1.py
+++ b/tests/topotests/isis-sr-topo1/test_isis_sr_topo1.py
@@ -140,7 +140,7 @@ def setup_module(mod):
router_list = tgen.routers()
# For all registered routers, load the zebra configuration file
- for rname, router in router_list.iteritems():
+ for rname, router in router_list.items():
router.load_config(
TopoRouter.RD_ZEBRA,
os.path.join(CWD, '{}/zebra.conf'.format(rname))
diff --git a/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py b/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py
index a0e34b71b0..65515f22cc 100755..100644
--- a/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py
+++ b/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py
@@ -113,7 +113,7 @@ def setup_module(mod):
]
# For all registered routers, load the zebra configuration file
- for rname, router in tgen.routers().iteritems():
+ for rname, router in tgen.routers().items():
# create VRF rx-cust1 and link rx-eth0 to rx-cust1
for cmd in cmds:
output = tgen.net[rname].cmd(cmd.format(rname))
@@ -127,7 +127,7 @@ def setup_module(mod):
"sysctl -w net.ipv4.tcp_l3mdev_accept={}".format(l3mdev_accept)
)
- for rname, router in tgen.routers().iteritems():
+ for rname, router in tgen.routers().items():
router.load_config(
TopoRouter.RD_ZEBRA,
os.path.join(CWD, "{}/zebra.conf".format(rname))
@@ -164,7 +164,7 @@ def test_isis_convergence():
logger.info("waiting for ISIS protocol to converge")
- for rname, router in tgen.routers().iteritems():
+ for rname, router in tgen.routers().items():
filename = "{0}/{1}/{1}_topology.json".format(CWD, rname)
expected = json.loads(open(filename).read())
def compare_isis_topology(router, expected):
@@ -186,13 +186,13 @@ def test_isis_route_installation():
logger.info("Checking routers for installed ISIS vrf routes")
# Check for routes in 'show ip route vrf {}-cust1 json'
- for rname, router in tgen.routers().iteritems():
+ for rname, router in tgen.routers().items():
filename = "{0}/{1}/{1}_route.json".format(CWD, rname)
expected = json.loads(open(filename, "r").read())
actual = router.vtysh_cmd("show ip route vrf {0}-cust1 json".format(rname) , isjson=True)
# Older FRR versions don't list interfaces in some ISIS routes
if router.has_version("<", "3.1"):
- for network, routes in expected.iteritems():
+ for network, routes in expected.items():
for route in routes:
if route["protocol"] != "isis":
continue
@@ -220,14 +220,14 @@ def test_isis_linux_route_installation():
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().iteritems():
+ for rname, router in tgen.routers().items():
filename = "{0}/{1}/{1}_route_linux.json".format(CWD, rname)
expected = json.loads(open(filename, "r").read())
actual = topotest.ip4_vrf_route(router)
# Older FRR versions install routes using different proto
if router.has_version("<", "3.1"):
- for network, netoptions in expected.iteritems():
+ for network, netoptions in expected.items():
if "proto" in netoptions and netoptions["proto"] == "187":
netoptions["proto"] = "zebra"
@@ -243,14 +243,14 @@ def test_isis_route6_installation():
logger.info("Checking routers for installed ISIS vrf IPv6 routes")
# Check for routes in 'show ipv6 route vrf {}-cust1 json'
- for rname, router in tgen.routers().iteritems():
+ for rname, router in tgen.routers().items():
filename = "{0}/{1}/{1}_route6.json".format(CWD, rname)
expected = json.loads(open(filename, "r").read())
actual = router.vtysh_cmd("show ipv6 route vrf {}-cust1 json".format(rname) , isjson=True)
# Older FRR versions don't list interfaces in some ISIS routes
if router.has_version("<", "3.1"):
- for network, routes in expected.iteritems():
+ for network, routes in expected.items():
for route in routes:
if route["protocol"] != "isis":
continue
@@ -277,14 +277,14 @@ def test_isis_linux_route6_installation():
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().iteritems():
+ for rname, router in tgen.routers().items():
filename = "{0}/{1}/{1}_route6_linux.json".format(CWD, rname)
expected = json.loads(open(filename, "r").read())
actual = topotest.ip6_vrf_route(router)
# Older FRR versions install routes using different proto
if router.has_version("<", "3.1"):
- for network, netoptions in expected.iteritems():
+ for network, netoptions in expected.items():
if "proto" in netoptions and netoptions["proto"] == "187":
netoptions["proto"] = "zebra"
@@ -323,7 +323,7 @@ def dict_merge(dct, merge_dct):
Source:
https://gist.github.com/angstwad/bf22d1822c38a92ec0a9
"""
- for k, v in merge_dct.iteritems():
+ for k, v in merge_dct.items():
if (
k in dct
and isinstance(dct[k], dict)
diff --git a/tests/topotests/isis-topo1/test_isis_topo1.py b/tests/topotests/isis-topo1/test_isis_topo1.py
index 6b1d9a8964..71005a0362 100644
--- a/tests/topotests/isis-topo1/test_isis_topo1.py
+++ b/tests/topotests/isis-topo1/test_isis_topo1.py
@@ -91,7 +91,7 @@ def setup_module(mod):
tgen.start_topology()
# For all registered routers, load the zebra configuration file
- for rname, router in tgen.routers().iteritems():
+ for rname, router in tgen.routers().items():
router.load_config(
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
)
@@ -129,12 +129,12 @@ def test_isis_convergence():
logger.info("waiting for ISIS protocol to converge")
# Code to generate the json files.
- # for rname, router in tgen.routers().iteritems():
+ # for rname, router in tgen.routers().items():
# open('/tmp/{}_topology.json'.format(rname), 'w').write(
# json.dumps(show_isis_topology(router), indent=2, sort_keys=True)
# )
- for rname, router in tgen.routers().iteritems():
+ for rname, router in tgen.routers().items():
filename = "{0}/{1}/{1}_topology.json".format(CWD, rname)
expected = json.loads(open(filename).read())
@@ -158,14 +158,14 @@ def test_isis_route_installation():
logger.info("Checking routers for installed ISIS routes")
# Check for routes in 'show ip route json'
- for rname, router in tgen.routers().iteritems():
+ for rname, router in tgen.routers().items():
filename = "{0}/{1}/{1}_route.json".format(CWD, rname)
expected = json.loads(open(filename, "r").read())
actual = router.vtysh_cmd("show ip route json", isjson=True)
# Older FRR versions don't list interfaces in some ISIS routes
if router.has_version("<", "3.1"):
- for network, routes in expected.iteritems():
+ for network, routes in expected.items():
for route in routes:
if route["protocol"] != "isis":
continue
@@ -188,14 +188,14 @@ def test_isis_linux_route_installation():
logger.info("Checking routers for installed ISIS routes in OS")
# Check for routes in `ip route`
- for rname, router in tgen.routers().iteritems():
+ for rname, router in tgen.routers().items():
filename = "{0}/{1}/{1}_route_linux.json".format(CWD, rname)
expected = json.loads(open(filename, "r").read())
actual = topotest.ip4_route(router)
# Older FRR versions install routes using different proto
if router.has_version("<", "3.1"):
- for network, netoptions in expected.iteritems():
+ for network, netoptions in expected.items():
if "proto" in netoptions and netoptions["proto"] == "187":
netoptions["proto"] = "zebra"
@@ -213,14 +213,14 @@ def test_isis_route6_installation():
logger.info("Checking routers for installed ISIS IPv6 routes")
# Check for routes in 'show ip route json'
- for rname, router in tgen.routers().iteritems():
+ for rname, router in tgen.routers().items():
filename = "{0}/{1}/{1}_route6.json".format(CWD, rname)
expected = json.loads(open(filename, "r").read())
actual = router.vtysh_cmd("show ipv6 route json", isjson=True)
# Older FRR versions don't list interfaces in some ISIS routes
if router.has_version("<", "3.1"):
- for network, routes in expected.iteritems():
+ for network, routes in expected.items():
for route in routes:
# Older versions display different metrics for IPv6 routes
route.pop("metric", None)
@@ -246,14 +246,14 @@ def test_isis_linux_route6_installation():
logger.info("Checking routers for installed ISIS IPv6 routes in OS")
# Check for routes in `ip route`
- for rname, router in tgen.routers().iteritems():
+ for rname, router in tgen.routers().items():
filename = "{0}/{1}/{1}_route6_linux.json".format(CWD, rname)
expected = json.loads(open(filename, "r").read())
actual = topotest.ip6_route(router)
# Older FRR versions install routes using different proto
if router.has_version("<", "3.1"):
- for network, netoptions in expected.iteritems():
+ for network, netoptions in expected.items():
if "proto" in netoptions and netoptions["proto"] == "187":
netoptions["proto"] = "zebra"
@@ -293,7 +293,7 @@ def dict_merge(dct, merge_dct):
Source:
https://gist.github.com/angstwad/bf22d1822c38a92ec0a9
"""
- for k, v in merge_dct.iteritems():
+ for k, v in merge_dct.items():
if (
k in dct
and isinstance(dct[k], dict)
diff --git a/tests/topotests/ldp-oc-acl-topo1/test_ldp_oc_acl_topo1.py b/tests/topotests/ldp-oc-acl-topo1/test_ldp_oc_acl_topo1.py
index 450d35e16c..dadb2065e6 100755..100644
--- a/tests/topotests/ldp-oc-acl-topo1/test_ldp_oc_acl_topo1.py
+++ b/tests/topotests/ldp-oc-acl-topo1/test_ldp_oc_acl_topo1.py
@@ -117,7 +117,7 @@ def setup_module(mod):
router_list = tgen.routers()
# For all registered routers, load the zebra configuration file
- for rname, router in router_list.iteritems():
+ for rname, router in router_list.items():
router.load_config(
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
)
diff --git a/tests/topotests/ldp-oc-topo1/test_ldp_oc_topo1.py b/tests/topotests/ldp-oc-topo1/test_ldp_oc_topo1.py
index ac99eb1a26..ea449e4aba 100755..100644
--- a/tests/topotests/ldp-oc-topo1/test_ldp_oc_topo1.py
+++ b/tests/topotests/ldp-oc-topo1/test_ldp_oc_topo1.py
@@ -117,7 +117,7 @@ def setup_module(mod):
router_list = tgen.routers()
# For all registered routers, load the zebra configuration file
- for rname, router in router_list.iteritems():
+ for rname, router in router_list.items():
router.load_config(
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
)
diff --git a/tests/topotests/ldp-sync-isis-topo1/ce1/zebra.conf b/tests/topotests/ldp-sync-isis-topo1/ce1/zebra.conf
new file mode 100644
index 0000000000..6f165e2724
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/ce1/zebra.conf
@@ -0,0 +1,12 @@
+log file zebra.log
+!
+hostname ce1
+!
+interface ce1-eth0
+ ip address 172.16.1.1/24
+ no link-detect
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/ldp-sync-isis-topo1/ce2/zebra.conf b/tests/topotests/ldp-sync-isis-topo1/ce2/zebra.conf
new file mode 100644
index 0000000000..ac02d0f9a4
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/ce2/zebra.conf
@@ -0,0 +1,12 @@
+log file zebra.log
+!
+hostname ce2
+!
+interface ce2-eth0
+ ip address 172.16.1.2/24
+ no link-detect
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/ldp-sync-isis-topo1/ce3/zebra.conf b/tests/topotests/ldp-sync-isis-topo1/ce3/zebra.conf
new file mode 100644
index 0000000000..c6a5824d15
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/ce3/zebra.conf
@@ -0,0 +1,12 @@
+log file zebra.log
+!
+hostname ce3
+!
+interface ce3-eth0
+ ip address 172.16.1.3/24
+ no link-detect
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/ldp-sync-isis-topo1/r1/isisd.conf b/tests/topotests/ldp-sync-isis-topo1/r1/isisd.conf
new file mode 100644
index 0000000000..af8d117bc1
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r1/isisd.conf
@@ -0,0 +1,26 @@
+hostname r1
+log file isisd.log
+debug isis adj-packets
+debug isis events
+debug isis update-packets
+debug isis ldp-sync
+!
+router isis 1
+ net 10.0000.0000.0000.0000.0000.0000.0000.0000.0001.00
+ metric-style wide
+ redistribute ipv4 connected level-1
+ redistribute ipv6 connected level-1
+ mpls ldp-sync
+!
+interface r1-eth1
+ ip router isis 1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis circuit-type level-1
+!
+interface r1-eth2
+ ip router isis 1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis circuit-type level-1
+!
diff --git a/tests/topotests/ldp-sync-isis-topo1/r1/ldpd.conf b/tests/topotests/ldp-sync-isis-topo1/r1/ldpd.conf
new file mode 100644
index 0000000000..b9c32d3000
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r1/ldpd.conf
@@ -0,0 +1,33 @@
+hostname r1
+log file ldpd.log
+!
+debug mpls ldp zebra
+debug mpls ldp event
+debug mpls ldp errors
+debug mpls ldp sync
+!
+mpls ldp
+ router-id 1.1.1.1
+ !
+ address-family ipv4
+ discovery transport-address 1.1.1.1
+ label local allocate host-routes
+ !
+ ttl-security disable
+ !
+ interface r1-eth1
+ !
+ interface r1-eth2
+ !
+ !
+!
+l2vpn CUST_A type vpls
+ member interface r1-eth0
+ !
+ member pseudowire r1-mpw0
+ neighbor lsr-id 2.2.2.2
+ pw-id 100
+ !
+!
+line vty
+!
diff --git a/tests/topotests/ldp-sync-isis-topo1/r1/show_ip_route.ref b/tests/topotests/ldp-sync-isis-topo1/r1/show_ip_route.ref
new file mode 100644
index 0000000000..dc8f19dad0
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r1/show_ip_route.ref
@@ -0,0 +1,143 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"connected",
+ "selected":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceIndex":1,
+ "interfaceName":"lo",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "distance":115,
+ "metric":10,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceIndex":3,
+ "interfaceName":"r1-eth1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "distance":115,
+ "metric":10,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.3",
+ "afi":"ipv4",
+ "interfaceIndex":4,
+ "interfaceName":"r1-eth2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":10,
+ "nexthops":[
+ {
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceIndex":3,
+ "interfaceName":"r1-eth1"
+ }
+ ]
+ },
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"connected",
+ "selected":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceIndex":3,
+ "interfaceName":"r1-eth1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":10,
+ "nexthops":[
+ {
+ "ip":"10.0.2.3",
+ "afi":"ipv4",
+ "interfaceIndex":4,
+ "interfaceName":"r1-eth2"
+ }
+ ]
+ },
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"connected",
+ "selected":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceIndex":4,
+ "interfaceName":"r1-eth2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "distance":115,
+ "metric":10,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceIndex":3,
+ "interfaceName":"r1-eth1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.2.3",
+ "afi":"ipv4",
+ "interfaceIndex":4,
+ "interfaceName":"r1-eth2",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-sync-isis-topo1/r1/show_isis_interface_detail.ref b/tests/topotests/ldp-sync-isis-topo1/r1/show_isis_interface_detail.ref
new file mode 100644
index 0000000000..d8fb27af8c
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r1/show_isis_interface_detail.ref
@@ -0,0 +1,16 @@
+{
+ "1": {
+ "r1-eth1": [
+ {
+ "level": "Level-1",
+ "metric": "10"
+ }
+ ],
+ "r1-eth2": [
+ {
+ "level": "Level-1",
+ "metric": "10"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/ldp-sync-isis-topo1/r1/show_isis_interface_detail_r1_eth1_shutdown.ref b/tests/topotests/ldp-sync-isis-topo1/r1/show_isis_interface_detail_r1_eth1_shutdown.ref
new file mode 100644
index 0000000000..f77d65ebc1
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r1/show_isis_interface_detail_r1_eth1_shutdown.ref
@@ -0,0 +1,16 @@
+{
+ "1": {
+ "r1-eth1": [
+ {
+ "level": "Level-1",
+ "metric": "16777214"
+ }
+ ],
+ "r1-eth2": [
+ {
+ "level": "Level-1",
+ "metric": "10"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/ldp-sync-isis-topo1/r1/show_isis_interface_detail_r2_eth1_shutdown.ref b/tests/topotests/ldp-sync-isis-topo1/r1/show_isis_interface_detail_r2_eth1_shutdown.ref
new file mode 100644
index 0000000000..f77d65ebc1
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r1/show_isis_interface_detail_r2_eth1_shutdown.ref
@@ -0,0 +1,16 @@
+{
+ "1": {
+ "r1-eth1": [
+ {
+ "level": "Level-1",
+ "metric": "16777214"
+ }
+ ],
+ "r1-eth2": [
+ {
+ "level": "Level-1",
+ "metric": "10"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/ldp-sync-isis-topo1/r1/show_isis_ldp_sync.ref b/tests/topotests/ldp-sync-isis-topo1/r1/show_isis_ldp_sync.ref
new file mode 100644
index 0000000000..b699e8c145
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r1/show_isis_ldp_sync.ref
@@ -0,0 +1,13 @@
+{
+ "r1-eth1":{
+ "ldpIgpSyncEnabled":true,
+ "holdDownTimeInSec":0,
+ "ldpIgpSyncState":"Sync achieved"
+ },
+ "r1-eth2":{
+ "ldpIgpSyncEnabled":true,
+ "holdDownTimeInSec":0,
+ "ldpIgpSyncState":"Sync achieved"
+ }
+
+}
diff --git a/tests/topotests/ldp-sync-isis-topo1/r1/show_isis_ldp_sync_r1_eth1_shutdown.ref b/tests/topotests/ldp-sync-isis-topo1/r1/show_isis_ldp_sync_r1_eth1_shutdown.ref
new file mode 100644
index 0000000000..c63bbea77f
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r1/show_isis_ldp_sync_r1_eth1_shutdown.ref
@@ -0,0 +1,13 @@
+{
+ "r1-eth1":{
+ "ldpIgpSyncEnabled":true,
+ "holdDownTimeInSec":0,
+ "ldpIgpSyncState":"Sync not achieved"
+ },
+ "r1-eth2":{
+ "ldpIgpSyncEnabled":true,
+ "holdDownTimeInSec":0,
+ "ldpIgpSyncState":"Sync achieved"
+ }
+
+}
diff --git a/tests/topotests/ldp-sync-isis-topo1/r1/show_isis_ldp_sync_r2_eth1_shutdown.ref b/tests/topotests/ldp-sync-isis-topo1/r1/show_isis_ldp_sync_r2_eth1_shutdown.ref
new file mode 100644
index 0000000000..c63bbea77f
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r1/show_isis_ldp_sync_r2_eth1_shutdown.ref
@@ -0,0 +1,13 @@
+{
+ "r1-eth1":{
+ "ldpIgpSyncEnabled":true,
+ "holdDownTimeInSec":0,
+ "ldpIgpSyncState":"Sync not achieved"
+ },
+ "r1-eth2":{
+ "ldpIgpSyncEnabled":true,
+ "holdDownTimeInSec":0,
+ "ldpIgpSyncState":"Sync achieved"
+ }
+
+}
diff --git a/tests/topotests/ldp-sync-isis-topo1/r1/show_l2vpn_binding.ref b/tests/topotests/ldp-sync-isis-topo1/r1/show_l2vpn_binding.ref
new file mode 100644
index 0000000000..b3de7e2c66
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r1/show_l2vpn_binding.ref
@@ -0,0 +1,16 @@
+{
+ "2.2.2.2: 100":{
+ "destination":"2.2.2.2",
+ "vcId":100,
+ "localLabel":16,
+ "localControlWord":1,
+ "localVcType":"Ethernet",
+ "localGroupID":0,
+ "localIfMtu":1500,
+ "remoteLabel":16,
+ "remoteControlWord":1,
+ "remoteVcType":"Ethernet",
+ "remoteGroupID":0,
+ "remoteIfMtu":1500
+ }
+}
diff --git a/tests/topotests/ldp-sync-isis-topo1/r1/show_l2vpn_vc.ref b/tests/topotests/ldp-sync-isis-topo1/r1/show_l2vpn_vc.ref
new file mode 100644
index 0000000000..29e9df1089
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r1/show_l2vpn_vc.ref
@@ -0,0 +1,8 @@
+{
+ "r1-mpw0":{
+ "peerId":"2.2.2.2",
+ "vcId":100,
+ "VpnName":"CUST_A",
+ "status":"up"
+ }
+}
diff --git a/tests/topotests/ldp-sync-isis-topo1/r1/show_ldp_binding.ref b/tests/topotests/ldp-sync-isis-topo1/r1/show_ldp_binding.ref
new file mode 100644
index 0000000000..b3a12ec53f
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r1/show_ldp_binding.ref
@@ -0,0 +1,44 @@
+{
+ "bindings":[
+ {
+ "addressFamily":"ipv4",
+ "prefix":"1.1.1.1/32",
+ "neighborId":"2.2.2.2",
+ "localLabel":"imp-null",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"1.1.1.1/32",
+ "neighborId":"3.3.3.3",
+ "localLabel":"imp-null",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"2.2.2.2/32",
+ "neighborId":"2.2.2.2",
+ "remoteLabel":"imp-null",
+ "inUse":1
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"2.2.2.2/32",
+ "neighborId":"3.3.3.3",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"3.3.3.3/32",
+ "neighborId":"2.2.2.2",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"3.3.3.3/32",
+ "neighborId":"3.3.3.3",
+ "remoteLabel":"imp-null",
+ "inUse":1
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-sync-isis-topo1/r1/show_ldp_discovery.ref b/tests/topotests/ldp-sync-isis-topo1/r1/show_ldp_discovery.ref
new file mode 100644
index 0000000000..9301e60c67
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r1/show_ldp_discovery.ref
@@ -0,0 +1,25 @@
+{
+ "adjacencies":[
+ {
+ "addressFamily":"ipv4",
+ "neighborId":"2.2.2.2",
+ "type":"link",
+ "interface":"r1-eth1",
+ "helloHoldtime":15
+ },
+ {
+ "addressFamily":"ipv4",
+ "neighborId":"2.2.2.2",
+ "type":"targeted",
+ "peer":"2.2.2.2",
+ "helloHoldtime":45
+ },
+ {
+ "addressFamily":"ipv4",
+ "neighborId":"3.3.3.3",
+ "type":"link",
+ "interface":"r1-eth2",
+ "helloHoldtime":15
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-sync-isis-topo1/r1/show_ldp_igp_sync.ref b/tests/topotests/ldp-sync-isis-topo1/r1/show_ldp_igp_sync.ref
new file mode 100644
index 0000000000..54d015fef9
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r1/show_ldp_igp_sync.ref
@@ -0,0 +1,16 @@
+{
+ "r1-eth1":{
+ "state":"labelExchangeComplete",
+ "waitTime":10,
+ "waitTimeRemaining":0,
+ "timerRunning":false,
+ "peerLdpId":"2.2.2.2"
+ },
+ "r1-eth2":{
+ "state":"labelExchangeComplete",
+ "waitTime":10,
+ "waitTimeRemaining":0,
+ "timerRunning":false,
+ "peerLdpId":"3.3.3.3"
+ }
+}
diff --git a/tests/topotests/ldp-sync-isis-topo1/r1/show_ldp_igp_sync_r1_eth1_shutdown.ref b/tests/topotests/ldp-sync-isis-topo1/r1/show_ldp_igp_sync_r1_eth1_shutdown.ref
new file mode 100644
index 0000000000..2232069f68
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r1/show_ldp_igp_sync_r1_eth1_shutdown.ref
@@ -0,0 +1,16 @@
+{
+ "r1-eth1":{
+ "state":"labelExchangeNotComplete",
+ "waitTime":10,
+ "waitTimeRemaining":0,
+ "timerRunning":false,
+ "peerLdpId":""
+ },
+ "r1-eth2":{
+ "state":"labelExchangeComplete",
+ "waitTime":10,
+ "waitTimeRemaining":0,
+ "timerRunning":false,
+ "peerLdpId":"3.3.3.3"
+ }
+}
diff --git a/tests/topotests/ldp-sync-isis-topo1/r1/show_ldp_neighbor.ref b/tests/topotests/ldp-sync-isis-topo1/r1/show_ldp_neighbor.ref
new file mode 100644
index 0000000000..40d8ebeb90
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r1/show_ldp_neighbor.ref
@@ -0,0 +1,16 @@
+{
+ "neighbors":[
+ {
+ "addressFamily":"ipv4",
+ "neighborId":"2.2.2.2",
+ "state":"OPERATIONAL",
+ "transportAddress":"2.2.2.2"
+ },
+ {
+ "addressFamily":"ipv4",
+ "neighborId":"3.3.3.3",
+ "state":"OPERATIONAL",
+ "transportAddress":"3.3.3.3"
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-sync-isis-topo1/r1/show_yang_interface_isis_adjacencies.ref b/tests/topotests/ldp-sync-isis-topo1/r1/show_yang_interface_isis_adjacencies.ref
new file mode 100644
index 0000000000..6138d03672
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r1/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1,42 @@
+{
+ "frr-interface:lib": {
+ "interface": [
+ {
+ "name": "r1-eth1",
+ "vrf": "default",
+ "state": {
+ "frr-isisd:isis": {
+ "adjacencies": {
+ "adjacency": [
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0002",
+ "neighbor-extended-circuit-id": 0,
+ "state": "up"
+ }
+ ]
+ }
+ }
+ }
+ },
+ {
+ "name": "r1-eth2",
+ "vrf": "default",
+ "state": {
+ "frr-isisd:isis": {
+ "adjacencies": {
+ "adjacency": [
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0003",
+ "neighbor-extended-circuit-id": 0,
+ "state": "up"
+ }
+ ]
+ }
+ }
+ }
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/ldp-sync-isis-topo1/r1/zebra.conf b/tests/topotests/ldp-sync-isis-topo1/r1/zebra.conf
new file mode 100644
index 0000000000..ea047355ad
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r1/zebra.conf
@@ -0,0 +1,29 @@
+log file zebra.log
+!
+hostname r1
+!
+debug zebra kernel
+debug zebra rib detailed
+debug zebra dplane detailed
+debug zebra nht
+debug zebra pseudowires
+debug zebra mpls
+!
+interface lo
+ ip address 1.1.1.1/32
+!
+interface r1-eth0
+ description to s1
+!
+interface r1-eth1
+ description to s4
+ ip address 10.0.1.1/24
+!
+interface r1-eth2
+ description to s5
+ ip address 10.0.2.1/24
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/ldp-sync-isis-topo1/r2/isisd.conf b/tests/topotests/ldp-sync-isis-topo1/r2/isisd.conf
new file mode 100644
index 0000000000..e477bce827
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r2/isisd.conf
@@ -0,0 +1,27 @@
+hostname r2
+log file isisd.log
+debug isis adj-packets
+debug isis events
+debug isis update-packets
+debug isis ldp-sync
+!
+router isis 1
+ net 10.0000.0000.0000.0000.0000.0000.0000.0000.0002.00
+ metric-style wide
+ redistribute ipv4 connected level-1
+ redistribute ipv6 connected level-1
+ mpls ldp-sync
+!
+interface r2-eth1
+ ip router isis 1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis circuit-type level-1
+!
+interface r2-eth2
+ ip router isis 1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis circuit-type level-1
+ no isis mpls ldp-sync
+!
diff --git a/tests/topotests/ldp-sync-isis-topo1/r2/ldpd.conf b/tests/topotests/ldp-sync-isis-topo1/r2/ldpd.conf
new file mode 100644
index 0000000000..52398b1b72
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r2/ldpd.conf
@@ -0,0 +1,33 @@
+hostname r2
+log file ldpd.log
+!
+debug mpls ldp zebra
+debug mpls ldp event
+debug mpls ldp errors
+debug mpls ldp sync
+!
+mpls ldp
+ router-id 2.2.2.2
+ !
+ address-family ipv4
+ discovery transport-address 2.2.2.2
+ label local allocate host-routes
+ !
+ ttl-security disable
+ !
+ interface r2-eth1
+ !
+ interface r2-eth2
+ !
+ !
+!
+l2vpn CUST_A type vpls
+ member interface r2-eth0
+ !
+ member pseudowire r2-mpw0
+ neighbor lsr-id 1.1.1.1
+ pw-id 100
+ !
+!
+line vty
+!
diff --git a/tests/topotests/ldp-sync-isis-topo1/r2/ospfd.conf b/tests/topotests/ldp-sync-isis-topo1/r2/ospfd.conf
new file mode 100644
index 0000000000..f93f6aed56
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r2/ospfd.conf
@@ -0,0 +1,19 @@
+hostname r2
+log file ospfd.log
+debug ospf zebra interface
+debug ospf ldp-sync
+!
+router ospf
+ router-id 2.2.2.2
+ network 0.0.0.0/0 area 0
+ mpls ldp-sync
+ mpls ldp-sync holddown 50
+!
+interface r2-eth1
+ ip ospf network point-to-point
+ ip ospf mpls ldp-sync holddown 300
+!
+interface r2-eth2
+ ip ospf network point-to-point
+ no ip ospf mpls ldp-sync
+!
diff --git a/tests/topotests/ldp-sync-isis-topo1/r2/show_ip_route.ref b/tests/topotests/ldp-sync-isis-topo1/r2/show_ip_route.ref
new file mode 100644
index 0000000000..2bcee96064
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r2/show_ip_route.ref
@@ -0,0 +1,143 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "distance":115,
+ "metric":10,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.1",
+ "afi":"ipv4",
+ "interfaceIndex":3,
+ "interfaceName":"r2-eth1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"connected",
+ "selected":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceIndex":1,
+ "interfaceName":"lo",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "distance":115,
+ "metric":10,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.3.3",
+ "afi":"ipv4",
+ "interfaceIndex":4,
+ "interfaceName":"r2-eth2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":10,
+ "nexthops":[
+ {
+ "ip":"10.0.1.1",
+ "afi":"ipv4",
+ "interfaceIndex":3,
+ "interfaceName":"r2-eth1"
+ }
+ ]
+ },
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"connected",
+ "selected":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceIndex":3,
+ "interfaceName":"r2-eth1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "distance":115,
+ "metric":10,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.1",
+ "afi":"ipv4",
+ "interfaceIndex":3,
+ "interfaceName":"r2-eth1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.3",
+ "afi":"ipv4",
+ "interfaceIndex":4,
+ "interfaceName":"r2-eth2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":10,
+ "nexthops":[
+ {
+ "ip":"10.0.3.3",
+ "afi":"ipv4",
+ "interfaceIndex":4,
+ "interfaceName":"r2-eth2"
+ }
+ ]
+ },
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"connected",
+ "selected":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceIndex":4,
+ "interfaceName":"r2-eth2",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-sync-isis-topo1/r2/show_isis_interface_detail.ref b/tests/topotests/ldp-sync-isis-topo1/r2/show_isis_interface_detail.ref
new file mode 100644
index 0000000000..844aa9402a
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r2/show_isis_interface_detail.ref
@@ -0,0 +1,16 @@
+{
+ "1": {
+ "r2-eth1": [
+ {
+ "level": "Level-1",
+ "metric": "10"
+ }
+ ],
+ "r2-eth2": [
+ {
+ "level": "Level-1",
+ "metric": "10"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/ldp-sync-isis-topo1/r2/show_isis_interface_detail_r1_eth1_shutdown.ref b/tests/topotests/ldp-sync-isis-topo1/r2/show_isis_interface_detail_r1_eth1_shutdown.ref
new file mode 100644
index 0000000000..821ec70ba5
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r2/show_isis_interface_detail_r1_eth1_shutdown.ref
@@ -0,0 +1,16 @@
+{
+ "1": {
+ "r2-eth1": [
+ {
+ "level": "Level-1",
+ "metric": "16777214"
+ }
+ ],
+ "r2-eth2": [
+ {
+ "level": "Level-1",
+ "metric": "10"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/ldp-sync-isis-topo1/r2/show_isis_interface_detail_r2_eth1_shutdown.ref b/tests/topotests/ldp-sync-isis-topo1/r2/show_isis_interface_detail_r2_eth1_shutdown.ref
new file mode 100644
index 0000000000..821ec70ba5
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r2/show_isis_interface_detail_r2_eth1_shutdown.ref
@@ -0,0 +1,16 @@
+{
+ "1": {
+ "r2-eth1": [
+ {
+ "level": "Level-1",
+ "metric": "16777214"
+ }
+ ],
+ "r2-eth2": [
+ {
+ "level": "Level-1",
+ "metric": "10"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/ldp-sync-isis-topo1/r2/show_isis_ldp_sync.ref b/tests/topotests/ldp-sync-isis-topo1/r2/show_isis_ldp_sync.ref
new file mode 100644
index 0000000000..433d89bd16
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r2/show_isis_ldp_sync.ref
@@ -0,0 +1,13 @@
+{
+ "r2-eth1":{
+ "ldpIgpSyncEnabled":true,
+ "holdDownTimeInSec":0,
+ "ldpIgpSyncState":"Sync achieved"
+ },
+ "r2-eth2":{
+ "ldpIgpSyncEnabled":false,
+ "holdDownTimeInSec":0,
+ "ldpIgpSyncState":"Sync not required"
+ }
+
+}
diff --git a/tests/topotests/ldp-sync-isis-topo1/r2/show_isis_ldp_sync_r1_eth1_shutdown.ref b/tests/topotests/ldp-sync-isis-topo1/r2/show_isis_ldp_sync_r1_eth1_shutdown.ref
new file mode 100644
index 0000000000..2f3eae47c8
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r2/show_isis_ldp_sync_r1_eth1_shutdown.ref
@@ -0,0 +1,13 @@
+{
+ "r2-eth1":{
+ "ldpIgpSyncEnabled":true,
+ "holdDownTimeInSec":0,
+ "ldpIgpSyncState":"Sync not achieved"
+ },
+ "r2-eth2":{
+ "ldpIgpSyncEnabled":false,
+ "holdDownTimeInSec":0,
+ "ldpIgpSyncState":"Sync not required"
+ }
+
+}
diff --git a/tests/topotests/ldp-sync-isis-topo1/r2/show_isis_ldp_sync_r2_eth1_shutdown.ref b/tests/topotests/ldp-sync-isis-topo1/r2/show_isis_ldp_sync_r2_eth1_shutdown.ref
new file mode 100644
index 0000000000..2f3eae47c8
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r2/show_isis_ldp_sync_r2_eth1_shutdown.ref
@@ -0,0 +1,13 @@
+{
+ "r2-eth1":{
+ "ldpIgpSyncEnabled":true,
+ "holdDownTimeInSec":0,
+ "ldpIgpSyncState":"Sync not achieved"
+ },
+ "r2-eth2":{
+ "ldpIgpSyncEnabled":false,
+ "holdDownTimeInSec":0,
+ "ldpIgpSyncState":"Sync not required"
+ }
+
+}
diff --git a/tests/topotests/ldp-sync-isis-topo1/r2/show_l2vpn_binding.ref b/tests/topotests/ldp-sync-isis-topo1/r2/show_l2vpn_binding.ref
new file mode 100644
index 0000000000..42c5a1cbd9
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r2/show_l2vpn_binding.ref
@@ -0,0 +1,16 @@
+{
+ "1.1.1.1: 100":{
+ "destination":"1.1.1.1",
+ "vcId":100,
+ "localLabel":16,
+ "localControlWord":1,
+ "localVcType":"Ethernet",
+ "localGroupID":0,
+ "localIfMtu":1500,
+ "remoteLabel":16,
+ "remoteControlWord":1,
+ "remoteVcType":"Ethernet",
+ "remoteGroupID":0,
+ "remoteIfMtu":1500
+ }
+}
diff --git a/tests/topotests/ldp-sync-isis-topo1/r2/show_l2vpn_vc.ref b/tests/topotests/ldp-sync-isis-topo1/r2/show_l2vpn_vc.ref
new file mode 100644
index 0000000000..942ed23a1e
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r2/show_l2vpn_vc.ref
@@ -0,0 +1,8 @@
+{
+ "r2-mpw0":{
+ "peerId":"1.1.1.1",
+ "vcId":100,
+ "VpnName":"CUST_A",
+ "status":"up"
+ }
+}
diff --git a/tests/topotests/ldp-sync-isis-topo1/r2/show_ldp_binding.ref b/tests/topotests/ldp-sync-isis-topo1/r2/show_ldp_binding.ref
new file mode 100644
index 0000000000..c641fb47e6
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r2/show_ldp_binding.ref
@@ -0,0 +1,44 @@
+{
+ "bindings":[
+ {
+ "addressFamily":"ipv4",
+ "prefix":"1.1.1.1/32",
+ "neighborId":"1.1.1.1",
+ "remoteLabel":"imp-null",
+ "inUse":1
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"1.1.1.1/32",
+ "neighborId":"3.3.3.3",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"2.2.2.2/32",
+ "neighborId":"1.1.1.1",
+ "localLabel":"imp-null",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"2.2.2.2/32",
+ "neighborId":"3.3.3.3",
+ "localLabel":"imp-null",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"3.3.3.3/32",
+ "neighborId":"1.1.1.1",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"3.3.3.3/32",
+ "neighborId":"3.3.3.3",
+ "remoteLabel":"imp-null",
+ "inUse":1
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-sync-isis-topo1/r2/show_ldp_discovery.ref b/tests/topotests/ldp-sync-isis-topo1/r2/show_ldp_discovery.ref
new file mode 100644
index 0000000000..26801acade
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r2/show_ldp_discovery.ref
@@ -0,0 +1,25 @@
+{
+ "adjacencies":[
+ {
+ "addressFamily":"ipv4",
+ "neighborId":"1.1.1.1",
+ "type":"link",
+ "interface":"r2-eth1",
+ "helloHoldtime":15
+ },
+ {
+ "addressFamily":"ipv4",
+ "neighborId":"1.1.1.1",
+ "type":"targeted",
+ "peer":"1.1.1.1",
+ "helloHoldtime":45
+ },
+ {
+ "addressFamily":"ipv4",
+ "neighborId":"3.3.3.3",
+ "type":"link",
+ "interface":"r2-eth2",
+ "helloHoldtime":15
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-sync-isis-topo1/r2/show_ldp_igp_sync.ref b/tests/topotests/ldp-sync-isis-topo1/r2/show_ldp_igp_sync.ref
new file mode 100644
index 0000000000..f2b24d7d62
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r2/show_ldp_igp_sync.ref
@@ -0,0 +1,16 @@
+{
+ "r2-eth1":{
+ "state":"labelExchangeComplete",
+ "waitTime":10,
+ "waitTimeRemaining":0,
+ "timerRunning":false,
+ "peerLdpId":"1.1.1.1"
+ },
+ "r2-eth2":{
+ "state":"labelExchangeComplete",
+ "waitTime":10,
+ "waitTimeRemaining":0,
+ "timerRunning":false,
+ "peerLdpId":"3.3.3.3"
+ }
+}
diff --git a/tests/topotests/ldp-sync-isis-topo1/r2/show_ldp_igp_sync_r1_eth1_shutdown.ref b/tests/topotests/ldp-sync-isis-topo1/r2/show_ldp_igp_sync_r1_eth1_shutdown.ref
new file mode 100644
index 0000000000..b5508dd35c
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r2/show_ldp_igp_sync_r1_eth1_shutdown.ref
@@ -0,0 +1,16 @@
+{
+ "r2-eth1":{
+ "state":"labelExchangeNotComplete",
+ "waitTime":10,
+ "waitTimeRemaining":0,
+ "timerRunning":false,
+ "peerLdpId":""
+ },
+ "r2-eth2":{
+ "state":"labelExchangeComplete",
+ "waitTime":10,
+ "waitTimeRemaining":0,
+ "timerRunning":false,
+ "peerLdpId":"3.3.3.3"
+ }
+}
diff --git a/tests/topotests/ldp-sync-isis-topo1/r2/show_ldp_igp_sync_r2_eth1_shutdown.ref b/tests/topotests/ldp-sync-isis-topo1/r2/show_ldp_igp_sync_r2_eth1_shutdown.ref
new file mode 100644
index 0000000000..f2b24d7d62
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r2/show_ldp_igp_sync_r2_eth1_shutdown.ref
@@ -0,0 +1,16 @@
+{
+ "r2-eth1":{
+ "state":"labelExchangeComplete",
+ "waitTime":10,
+ "waitTimeRemaining":0,
+ "timerRunning":false,
+ "peerLdpId":"1.1.1.1"
+ },
+ "r2-eth2":{
+ "state":"labelExchangeComplete",
+ "waitTime":10,
+ "waitTimeRemaining":0,
+ "timerRunning":false,
+ "peerLdpId":"3.3.3.3"
+ }
+}
diff --git a/tests/topotests/ldp-sync-isis-topo1/r2/show_ldp_neighbor.ref b/tests/topotests/ldp-sync-isis-topo1/r2/show_ldp_neighbor.ref
new file mode 100644
index 0000000000..eed35289ea
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r2/show_ldp_neighbor.ref
@@ -0,0 +1,16 @@
+{
+ "neighbors":[
+ {
+ "addressFamily":"ipv4",
+ "neighborId":"1.1.1.1",
+ "state":"OPERATIONAL",
+ "transportAddress":"1.1.1.1"
+ },
+ {
+ "addressFamily":"ipv4",
+ "neighborId":"3.3.3.3",
+ "state":"OPERATIONAL",
+ "transportAddress":"3.3.3.3"
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-sync-isis-topo1/r2/show_yang_interface_isis_adjacencies.ref b/tests/topotests/ldp-sync-isis-topo1/r2/show_yang_interface_isis_adjacencies.ref
new file mode 100644
index 0000000000..4dd6ddd76b
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r2/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1,42 @@
+{
+ "frr-interface:lib": {
+ "interface": [
+ {
+ "name": "r2-eth1",
+ "vrf": "default",
+ "state": {
+ "frr-isisd:isis": {
+ "adjacencies": {
+ "adjacency": [
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0001",
+ "neighbor-extended-circuit-id": 0,
+ "state": "up"
+ }
+ ]
+ }
+ }
+ }
+ },
+ {
+ "name": "r2-eth2",
+ "vrf": "default",
+ "state": {
+ "frr-isisd:isis": {
+ "adjacencies": {
+ "adjacency": [
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0003",
+ "neighbor-extended-circuit-id": 0,
+ "state": "up"
+ }
+ ]
+ }
+ }
+ }
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/ldp-sync-isis-topo1/r2/zebra.conf b/tests/topotests/ldp-sync-isis-topo1/r2/zebra.conf
new file mode 100644
index 0000000000..c244442876
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r2/zebra.conf
@@ -0,0 +1,28 @@
+log file zebra.log
+!
+hostname r2
+!
+debug zebra rib detailed
+debug zebra dplane detailed
+debug zebra kernel
+debug zebra nht
+debug zebra pseudowires
+!
+interface lo
+ ip address 2.2.2.2/32
+!
+interface r2-eth0
+ description to s2
+!
+interface r2-eth1
+ description to s4
+ ip address 10.0.1.2/24
+!
+interface r2-eth2
+ description to s6
+ ip address 10.0.3.2/24
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/ldp-sync-isis-topo1/r3/isisd.conf b/tests/topotests/ldp-sync-isis-topo1/r3/isisd.conf
new file mode 100644
index 0000000000..e50fb077ba
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r3/isisd.conf
@@ -0,0 +1,28 @@
+hostname r3
+log file isisd.log
+debug isis adj-packets
+debug isis events
+debug isis update-packets
+debug isis ldp-sync
+!
+router isis 1
+ net 10.0000.0000.0000.0000.0000.0000.0000.0000.0003.00
+ metric-style wide
+ redistribute ipv4 connected level-1
+ redistribute ipv6 connected level-1
+ mpls ldp-sync
+ mpls ldp-sync holddown 50
+!
+interface r3-eth1
+ ip router isis 1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis circuit-type level-1
+ no isis mpls ldp-sync
+!
+interface r3-eth2
+ ip router isis 1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis circuit-type level-1
+!
diff --git a/tests/topotests/ldp-sync-isis-topo1/r3/ldpd.conf b/tests/topotests/ldp-sync-isis-topo1/r3/ldpd.conf
new file mode 100644
index 0000000000..2935caf13b
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r3/ldpd.conf
@@ -0,0 +1,25 @@
+hostname r3
+log file ldpd.log
+!
+debug mpls ldp zebra
+debug mpls ldp event
+debug mpls ldp errors
+debug mpls ldp sync
+!
+mpls ldp
+ router-id 3.3.3.3
+ !
+ address-family ipv4
+ discovery transport-address 3.3.3.3
+ label local allocate host-routes
+ !
+ ttl-security disable
+ !
+ interface r3-eth1
+ !
+ interface r3-eth2
+ !
+ !
+!
+line vty
+!
diff --git a/tests/topotests/ldp-sync-isis-topo1/r3/show_ip_route.ref b/tests/topotests/ldp-sync-isis-topo1/r3/show_ip_route.ref
new file mode 100644
index 0000000000..da46f1dfe2
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r3/show_ip_route.ref
@@ -0,0 +1,143 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "distance":115,
+ "metric":10,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.1",
+ "afi":"ipv4",
+ "interfaceIndex":3,
+ "interfaceName":"r3-eth1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "distance":115,
+ "metric":10,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceIndex":4,
+ "interfaceName":"r3-eth2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"connected",
+ "selected":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceIndex":1,
+ "interfaceName":"lo",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "distance":115,
+ "metric":10,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.1",
+ "afi":"ipv4",
+ "interfaceIndex":3,
+ "interfaceName":"r3-eth1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceIndex":4,
+ "interfaceName":"r3-eth2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":10,
+ "nexthops":[
+ {
+ "ip":"10.0.2.1",
+ "afi":"ipv4",
+ "interfaceIndex":3,
+ "interfaceName":"r3-eth1"
+ }
+ ]
+ },
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"connected",
+ "selected":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceIndex":3,
+ "interfaceName":"r3-eth1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":10,
+ "nexthops":[
+ {
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceIndex":4,
+ "interfaceName":"r3-eth2"
+ }
+ ]
+ },
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"connected",
+ "selected":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceIndex":4,
+ "interfaceName":"r3-eth2",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-sync-isis-topo1/r3/show_isis_interface_detail.ref b/tests/topotests/ldp-sync-isis-topo1/r3/show_isis_interface_detail.ref
new file mode 100644
index 0000000000..e323f61f25
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r3/show_isis_interface_detail.ref
@@ -0,0 +1,16 @@
+{
+ "1": {
+ "r3-eth1": [
+ {
+ "level": "Level-1",
+ "metric": "10"
+ }
+ ],
+ "r3-eth2": [
+ {
+ "level": "Level-1",
+ "metric": "10"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/ldp-sync-isis-topo1/r3/show_isis_interface_detail_r1_eth1_shutdown.ref b/tests/topotests/ldp-sync-isis-topo1/r3/show_isis_interface_detail_r1_eth1_shutdown.ref
new file mode 100644
index 0000000000..e323f61f25
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r3/show_isis_interface_detail_r1_eth1_shutdown.ref
@@ -0,0 +1,16 @@
+{
+ "1": {
+ "r3-eth1": [
+ {
+ "level": "Level-1",
+ "metric": "10"
+ }
+ ],
+ "r3-eth2": [
+ {
+ "level": "Level-1",
+ "metric": "10"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/ldp-sync-isis-topo1/r3/show_isis_interface_detail_r2_eth1_shutdown.ref b/tests/topotests/ldp-sync-isis-topo1/r3/show_isis_interface_detail_r2_eth1_shutdown.ref
new file mode 100644
index 0000000000..e323f61f25
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r3/show_isis_interface_detail_r2_eth1_shutdown.ref
@@ -0,0 +1,16 @@
+{
+ "1": {
+ "r3-eth1": [
+ {
+ "level": "Level-1",
+ "metric": "10"
+ }
+ ],
+ "r3-eth2": [
+ {
+ "level": "Level-1",
+ "metric": "10"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/ldp-sync-isis-topo1/r3/show_isis_ldp_sync.ref b/tests/topotests/ldp-sync-isis-topo1/r3/show_isis_ldp_sync.ref
new file mode 100644
index 0000000000..9cb70a4758
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r3/show_isis_ldp_sync.ref
@@ -0,0 +1,13 @@
+{
+ "r3-eth1":{
+ "ldpIgpSyncEnabled":false,
+ "holdDownTimeInSec":50,
+ "ldpIgpSyncState":"Sync not required"
+ },
+ "r3-eth2":{
+ "ldpIgpSyncEnabled":true,
+ "holdDownTimeInSec":50,
+ "ldpIgpSyncState":"Sync achieved"
+ }
+
+}
diff --git a/tests/topotests/ldp-sync-isis-topo1/r3/show_isis_ldp_sync_r1_eth1_shutdown.ref b/tests/topotests/ldp-sync-isis-topo1/r3/show_isis_ldp_sync_r1_eth1_shutdown.ref
new file mode 100644
index 0000000000..9cb70a4758
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r3/show_isis_ldp_sync_r1_eth1_shutdown.ref
@@ -0,0 +1,13 @@
+{
+ "r3-eth1":{
+ "ldpIgpSyncEnabled":false,
+ "holdDownTimeInSec":50,
+ "ldpIgpSyncState":"Sync not required"
+ },
+ "r3-eth2":{
+ "ldpIgpSyncEnabled":true,
+ "holdDownTimeInSec":50,
+ "ldpIgpSyncState":"Sync achieved"
+ }
+
+}
diff --git a/tests/topotests/ldp-sync-isis-topo1/r3/show_isis_ldp_sync_r2_eth1_shutdown.ref b/tests/topotests/ldp-sync-isis-topo1/r3/show_isis_ldp_sync_r2_eth1_shutdown.ref
new file mode 100644
index 0000000000..9cb70a4758
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r3/show_isis_ldp_sync_r2_eth1_shutdown.ref
@@ -0,0 +1,13 @@
+{
+ "r3-eth1":{
+ "ldpIgpSyncEnabled":false,
+ "holdDownTimeInSec":50,
+ "ldpIgpSyncState":"Sync not required"
+ },
+ "r3-eth2":{
+ "ldpIgpSyncEnabled":true,
+ "holdDownTimeInSec":50,
+ "ldpIgpSyncState":"Sync achieved"
+ }
+
+}
diff --git a/tests/topotests/ldp-sync-isis-topo1/r3/show_l2vpn_binding.ref b/tests/topotests/ldp-sync-isis-topo1/r3/show_l2vpn_binding.ref
new file mode 100644
index 0000000000..2c63c08510
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r3/show_l2vpn_binding.ref
@@ -0,0 +1,2 @@
+{
+}
diff --git a/tests/topotests/ldp-sync-isis-topo1/r3/show_l2vpn_vc.ref b/tests/topotests/ldp-sync-isis-topo1/r3/show_l2vpn_vc.ref
new file mode 100644
index 0000000000..2c63c08510
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r3/show_l2vpn_vc.ref
@@ -0,0 +1,2 @@
+{
+}
diff --git a/tests/topotests/ldp-sync-isis-topo1/r3/show_ldp_binding.ref b/tests/topotests/ldp-sync-isis-topo1/r3/show_ldp_binding.ref
new file mode 100644
index 0000000000..e54bd6e755
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r3/show_ldp_binding.ref
@@ -0,0 +1,44 @@
+{
+ "bindings":[
+ {
+ "addressFamily":"ipv4",
+ "prefix":"1.1.1.1/32",
+ "neighborId":"1.1.1.1",
+ "remoteLabel":"imp-null",
+ "inUse":1
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"1.1.1.1/32",
+ "neighborId":"2.2.2.2",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"2.2.2.2/32",
+ "neighborId":"1.1.1.1",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"2.2.2.2/32",
+ "neighborId":"2.2.2.2",
+ "remoteLabel":"imp-null",
+ "inUse":1
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"3.3.3.3/32",
+ "neighborId":"1.1.1.1",
+ "localLabel":"imp-null",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"3.3.3.3/32",
+ "neighborId":"2.2.2.2",
+ "localLabel":"imp-null",
+ "inUse":0
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-sync-isis-topo1/r3/show_ldp_discovery.ref b/tests/topotests/ldp-sync-isis-topo1/r3/show_ldp_discovery.ref
new file mode 100644
index 0000000000..42fa98d4da
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r3/show_ldp_discovery.ref
@@ -0,0 +1,18 @@
+{
+ "adjacencies":[
+ {
+ "addressFamily":"ipv4",
+ "neighborId":"1.1.1.1",
+ "type":"link",
+ "interface":"r3-eth1",
+ "helloHoldtime":15
+ },
+ {
+ "addressFamily":"ipv4",
+ "neighborId":"2.2.2.2",
+ "type":"link",
+ "interface":"r3-eth2",
+ "helloHoldtime":15
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-sync-isis-topo1/r3/show_ldp_igp_sync.ref b/tests/topotests/ldp-sync-isis-topo1/r3/show_ldp_igp_sync.ref
new file mode 100644
index 0000000000..73261830c9
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r3/show_ldp_igp_sync.ref
@@ -0,0 +1,16 @@
+{
+ "r3-eth1":{
+ "state":"labelExchangeComplete",
+ "waitTime":10,
+ "waitTimeRemaining":0,
+ "timerRunning":false,
+ "peerLdpId":"1.1.1.1"
+ },
+ "r3-eth2":{
+ "state":"labelExchangeComplete",
+ "waitTime":10,
+ "waitTimeRemaining":0,
+ "timerRunning":false,
+ "peerLdpId":"2.2.2.2"
+ }
+}
diff --git a/tests/topotests/ldp-sync-isis-topo1/r3/show_ldp_igp_sync_r1_eth1_shutdown.ref b/tests/topotests/ldp-sync-isis-topo1/r3/show_ldp_igp_sync_r1_eth1_shutdown.ref
new file mode 100644
index 0000000000..73261830c9
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r3/show_ldp_igp_sync_r1_eth1_shutdown.ref
@@ -0,0 +1,16 @@
+{
+ "r3-eth1":{
+ "state":"labelExchangeComplete",
+ "waitTime":10,
+ "waitTimeRemaining":0,
+ "timerRunning":false,
+ "peerLdpId":"1.1.1.1"
+ },
+ "r3-eth2":{
+ "state":"labelExchangeComplete",
+ "waitTime":10,
+ "waitTimeRemaining":0,
+ "timerRunning":false,
+ "peerLdpId":"2.2.2.2"
+ }
+}
diff --git a/tests/topotests/ldp-sync-isis-topo1/r3/show_ldp_neighbor.ref b/tests/topotests/ldp-sync-isis-topo1/r3/show_ldp_neighbor.ref
new file mode 100644
index 0000000000..5c482da697
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r3/show_ldp_neighbor.ref
@@ -0,0 +1,16 @@
+{
+ "neighbors":[
+ {
+ "addressFamily":"ipv4",
+ "neighborId":"1.1.1.1",
+ "state":"OPERATIONAL",
+ "transportAddress":"1.1.1.1"
+ },
+ {
+ "addressFamily":"ipv4",
+ "neighborId":"2.2.2.2",
+ "state":"OPERATIONAL",
+ "transportAddress":"2.2.2.2"
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-sync-isis-topo1/r3/show_yang_interface_isis_adjacencies.ref b/tests/topotests/ldp-sync-isis-topo1/r3/show_yang_interface_isis_adjacencies.ref
new file mode 100644
index 0000000000..0922192361
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r3/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1,42 @@
+{
+ "frr-interface:lib": {
+ "interface": [
+ {
+ "name": "r3-eth1",
+ "vrf": "default",
+ "state": {
+ "frr-isisd:isis": {
+ "adjacencies": {
+ "adjacency": [
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0001",
+ "neighbor-extended-circuit-id": 0,
+ "state": "up"
+ }
+ ]
+ }
+ }
+ }
+ },
+ {
+ "name": "r3-eth2",
+ "vrf": "default",
+ "state": {
+ "frr-isisd:isis": {
+ "adjacencies": {
+ "adjacency": [
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0002",
+ "neighbor-extended-circuit-id": 0,
+ "state": "up"
+ }
+ ]
+ }
+ }
+ }
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/ldp-sync-isis-topo1/r3/zebra.conf b/tests/topotests/ldp-sync-isis-topo1/r3/zebra.conf
new file mode 100644
index 0000000000..b1919bd296
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/r3/zebra.conf
@@ -0,0 +1,32 @@
+log file zebra.log
+!
+hostname r3
+!
+debug zebra rib detailed
+debug zebra dplane detailed
+debug zebra kernel
+debug zebra nht
+debug zebra pseudowires
+!
+interface lo
+ ip address 3.3.3.3/32
+!
+interface r3-eth0
+ description to s3
+!
+interface r3-eth1
+ description to s5
+ ip address 10.0.2.3/24
+!
+interface r3-eth2
+ description to s6
+ ip address 10.0.3.3/24
+!
+!!interface r3-eth3
+!! description to s4
+!! ip address 10.0.1.3/24
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/ldp-sync-isis-topo1/test_ldp_sync_isis_topo1.dot b/tests/topotests/ldp-sync-isis-topo1/test_ldp_sync_isis_topo1.dot
new file mode 100644
index 0000000000..4f1bd22f7c
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/test_ldp_sync_isis_topo1.dot
@@ -0,0 +1,111 @@
+## Color coding:
+#########################
+## Main FRR: #f08080 red
+## Switches: #d0e0d0 gray
+## RIP: #19e3d9 Cyan
+## RIPng: #fcb314 dark yellow
+## OSPFv2: #32b835 Green
+## OSPFv3: #19e3d9 Cyan
+## ISIS IPv4 #fcb314 dark yellow
+## ISIS IPv6 #9a81ec purple
+## BGP IPv4 #eee3d3 beige
+## BGP IPv6 #fdff00 yellow
+##### Colors (see http://www.color-hex.com/)
+
+graph template {
+ label="Test Topology - LDP-VPLS 1";
+
+ # Routers
+ ce1 [
+ shape=doubleoctagon,
+ label="ce1",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ ce2 [
+ shape=doubleoctagon
+ label="ce2",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ ce3 [
+ shape=doubleoctagon
+ label="ce3",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r1 [
+ shape=doubleoctagon,
+ label="r1",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r2 [
+ shape=doubleoctagon
+ label="r2",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r3 [
+ shape=doubleoctagon
+ label="r3",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+
+
+ # Switches
+ s1 [
+ shape=oval,
+ label="VPLS\n172.16.1.0/24",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+ s2 [
+ shape=oval,
+ label="VPLS\n172.16.1.0/24",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+ s3 [
+ shape=oval,
+ label="VPLS\n172.16.1.0/24",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+ s4 [
+ shape=oval,
+ label="s4\n10.0.1.0/24",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+ s5 [
+ shape=oval,
+ label="s5\n10.0.2.0/24",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+ s6 [
+ shape=oval,
+ label="s6\n10.0.3.0/24",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+
+ # Connections
+ ce1 -- s1 [label="eth0\n.1"];
+ ce2 -- s2 [label="eth0\n.2"];
+ ce3 -- s3 [label="eth0\n.3"];
+
+ r1 -- s1 [label="eth0"];
+ r1 -- s4 [label="eth1\n.1"];
+ r1 -- s5 [label="eth2\n.1"];
+
+ r2 -- s2 [label="eth0"];
+ r2 -- s4 [label="eth1\n.2"];
+ r2 -- s6 [label="eth2\n.2"];
+
+ r3 -- s3 [label="eth0"];
+ r3 -- s5 [label="eth1\n.3"];
+ r3 -- s6 [label="eth2\n.3"];
+}
diff --git a/tests/topotests/ldp-sync-isis-topo1/test_ldp_sync_isis_topo1.py b/tests/topotests/ldp-sync-isis-topo1/test_ldp_sync_isis_topo1.py
new file mode 100644
index 0000000000..01f895891c
--- /dev/null
+++ b/tests/topotests/ldp-sync-isis-topo1/test_ldp_sync_isis_topo1.py
@@ -0,0 +1,625 @@
+#!/usr/bin/env python
+
+#
+# test_ldp_isis_topo1.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2020 by Volta Networks
+#
+# 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_ldp_vpls_topo1.py:
+
+ +---------+ +---------+
+ | | | |
+ | CE1 | | CE2 |
+ | | | |
+ +---------+ +---------+
+ce1-eth0 (172.16.1.1/24)| |ce2-eth0 (172.16.1.2/24)
+ | |
+ | |
+ rt1-eth0| |rt2-eth0
+ +---------+ 10.0.1.0/24 +---------+
+ | |rt1-eth1 | |
+ | RT1 +----------------+ RT2 |
+ | 1.1.1.1 | rt2-eth1| 2.2.2.2 |
+ | | | |
+ +---------+ +---------+
+ rt1-eth2| |rt2-eth2
+ | |
+ | |
+ 10.0.2.0/24| +---------+ |10.0.3.0/24
+ | | | |
+ | | RT3 | |
+ +--------+ 3.3.3.3 +-------+
+ rt3-eth2| |rt3-eth1
+ +---------+
+ |rt3-eth0
+ |
+ |
+ ce3-eth0 (172.16.1.3/24)|
+ +---------+
+ | |
+ | CE3 |
+ | |
+ +---------+
+"""
+
+import os
+import re
+import sys
+import pytest
+import json
+from time import sleep
+from functools import partial
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+
+# Required to instantiate the topology builder class.
+from mininet.topo import Topo
+
+
+class TemplateTopo(Topo):
+ "Test topology builder"
+
+ def build(self, *_args, **_opts):
+ "Build function"
+ tgen = get_topogen(self)
+
+ #
+ # Define FRR Routers
+ #
+ for router in ["ce1", "ce2", "ce3", "r1", "r2", "r3"]:
+ tgen.add_router(router)
+
+ #
+ # Define connections
+ #
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["ce1"])
+ switch.add_link(tgen.gears["r1"])
+
+ switch = tgen.add_switch("s2")
+ switch.add_link(tgen.gears["ce2"])
+ switch.add_link(tgen.gears["r2"])
+
+ switch = tgen.add_switch("s3")
+ switch.add_link(tgen.gears["ce3"])
+ switch.add_link(tgen.gears["r3"])
+
+ switch = tgen.add_switch("s4")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["r2"])
+
+ switch = tgen.add_switch("s5")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["r3"])
+
+ switch = tgen.add_switch("s6")
+ switch.add_link(tgen.gears["r2"])
+ switch.add_link(tgen.gears["r3"])
+
+
+def setup_module(mod):
+ "Sets up the pytest environment"
+ tgen = Topogen(TemplateTopo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ # For all registered routers, load the zebra configuration file
+ for rname, router in router_list.items():
+ router.load_config(
+ TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
+ )
+ # Don't start isisd and ldpd in the CE nodes
+ if router.name[0] == "r":
+ router.load_config(
+ TopoRouter.RD_ISIS, os.path.join(CWD, "{}/isisd.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_LDP, os.path.join(CWD, "{}/ldpd.conf".format(rname))
+ )
+
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ "Teardown the pytest environment"
+ tgen = get_topogen()
+
+ # This function tears down the whole topology.
+ tgen.stop_topology()
+
+
+def router_compare_json_output(rname, command, reference):
+ "Compare router JSON output"
+
+ logger.info('Comparing router "%s" "%s" output', rname, command)
+
+ tgen = get_topogen()
+ filename = "{}/{}/{}".format(CWD, rname, reference)
+ expected = json.loads(open(filename).read())
+
+ # Run test function until we get an result.
+ test_func = partial(topotest.router_json_cmp, tgen.gears[rname], command, expected)
+ _, diff = topotest.run_and_expect(test_func, None, count=320, wait=0.5)
+ assertmsg = '"{}" JSON output mismatches the expected result'.format(rname)
+ assert diff is None, assertmsg
+
+
+def test_isis_convergence():
+ logger.info("Test: check ISIS adjacencies")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ["r1", "r2", "r3"]:
+ router_compare_json_output(
+ rname,
+ "show yang operational-data /frr-interface:lib isisd",
+ "show_yang_interface_isis_adjacencies.ref")
+
+def test_rib():
+ logger.info("Test: verify RIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ["r1", "r2", "r3"]:
+ router_compare_json_output(rname, "show ip route json", "show_ip_route.ref")
+
+
+def test_ldp_adjacencies():
+ logger.info("Test: verify LDP adjacencies")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ["r1", "r2", "r3"]:
+ router_compare_json_output(
+ rname, "show mpls ldp discovery json", "show_ldp_discovery.ref"
+ )
+
+
+def test_ldp_neighbors():
+ logger.info("Test: verify LDP neighbors")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ["r1", "r2", "r3"]:
+ router_compare_json_output(
+ rname, "show mpls ldp neighbor json", "show_ldp_neighbor.ref"
+ )
+
+
+def test_ldp_bindings():
+ logger.info("Test: verify LDP bindings")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ["r1", "r2", "r3"]:
+ router_compare_json_output(
+ rname, "show mpls ldp binding json", "show_ldp_binding.ref"
+ )
+
+
+def test_ldp_pwid_bindings():
+ logger.info("Test: verify LDP PW-ID bindings")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ["r1", "r2", "r3"]:
+ router_compare_json_output(
+ rname, "show l2vpn atom binding json", "show_l2vpn_binding.ref"
+ )
+
+
+def test_ldp_pseudowires():
+ logger.info("Test: verify LDP pseudowires")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ["r1", "r2", "r3"]:
+ router_compare_json_output(
+ rname, "show l2vpn atom vc json", "show_l2vpn_vc.ref"
+ )
+
+def test_ldp_igp_sync():
+ logger.info("Test: verify LDP igp-sync")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ["r1", "r2", "r3"]:
+ router_compare_json_output(
+ rname, "show mpls ldp igp-sync json", "show_ldp_igp_sync.ref"
+ )
+
+def test_isis_ldp_sync():
+ logger.info("Test: verify ISIS igp-sync")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ["r1", "r2", "r3"]:
+ (result, diff) = validate_show_isis_ldp_sync(
+ rname, "show_isis_ldp_sync.ref"
+ )
+ assert result, "ISIS did not converge on {}:\n{}".format(rname, diff)
+
+ for rname in ["r1", "r2", "r3"]:
+ (result, diff) = validate_show_isis_interface_detail(
+ rname, "show_isis_interface_detail.ref"
+ )
+ assert result, "ISIS interface did not converge on {}:\n{}".format(rname, diff)
+
+
+def test_r1_eth1_shutdown():
+ logger.info("Test: verify behaviour after r1-eth1 is shutdown")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Shut down r1-r2 link */
+ tgen = get_topogen()
+ tgen.gears["r1"].peer_link_enable("r1-eth1", False)
+ topotest.sleep(5, "Waiting for the network to reconverge")
+
+ # check if the pseudowire is still up (using an alternate path for nexthop resolution)
+ for rname in ["r1", "r2", "r3"]:
+ router_compare_json_output(
+ rname, "show l2vpn atom vc json", "show_l2vpn_vc.ref"
+ )
+
+ for rname in ["r1", "r2", "r3"]:
+ router_compare_json_output(
+ rname, "show mpls ldp igp-sync json", "show_ldp_igp_sync_r1_eth1_shutdown.ref"
+ )
+
+ for rname in ["r1", "r2", "r3"]:
+ (result, diff) = validate_show_isis_ldp_sync(
+ rname, "show_isis_ldp_sync_r1_eth1_shutdown.ref"
+ )
+ assert result, "ISIS did not converge on {}:\n{}".format(rname, diff)
+
+ for rname in ["r1", "r2", "r3"]:
+ (result, diff) = validate_show_isis_interface_detail(
+ rname, "show_isis_interface_detail_r1_eth1_shutdown.ref"
+ )
+ assert result, "ISIS interface did not converge on {}:\n{}".format(rname, diff)
+
+
+def test_r1_eth1_no_shutdown():
+ logger.info("Test: verify behaviour after r1-eth1 is no shutdown")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Run no shutdown on r1-eth1 interface */
+ tgen = get_topogen()
+ tgen.gears["r1"].peer_link_enable("r1-eth1", True)
+ topotest.sleep(5, "Waiting for the network to reconverge")
+
+ for rname in ["r1", "r2", "r3"]:
+ router_compare_json_output(
+ rname, "show mpls ldp igp-sync json", "show_ldp_igp_sync.ref"
+ )
+
+ for rname in ["r1", "r2", "r3"]:
+ (result, diff) = validate_show_isis_ldp_sync(
+ rname, "show_isis_ldp_sync.ref"
+ )
+ assert result, "ISIS did not converge on {}:\n{}".format(rname, diff)
+
+ for rname in ["r1", "r2", "r3"]:
+ (result, diff) = validate_show_isis_interface_detail(
+ rname, "show_isis_interface_detail.ref"
+ )
+ assert result, "ISIS interface did not converge on {}:\n{}".format(rname, diff)
+
+
+def test_r2_eth1_shutdown():
+ logger.info("Test: verify behaviour after r2-eth1 is shutdown")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Shut down r1-r2 link */
+ tgen = get_topogen()
+ tgen.gears["r2"].peer_link_enable("r2-eth1", False)
+ topotest.sleep(5, "Waiting for the network to reconverge")
+
+ for rname in ["r1", "r2", "r3"]:
+ router_compare_json_output(
+ rname, "show mpls ldp igp-sync json", "show_ldp_igp_sync_r1_eth1_shutdown.ref"
+ )
+
+ for rname in ["r1", "r2", "r3"]:
+ (result, diff) = validate_show_isis_ldp_sync(
+ rname, "show_isis_ldp_sync_r2_eth1_shutdown.ref"
+ )
+ assert result, "ISIS did not converge on {}:\n{}".format(rname, diff)
+
+ for rname in ["r1", "r2", "r3"]:
+ (result, diff) = validate_show_isis_interface_detail(
+ rname, "show_isis_interface_detail_r2_eth1_shutdown.ref"
+ )
+ assert result, "ISIS interface did not converge on {}:\n{}".format(rname, diff)
+
+
+def test_r2_eth1_no_shutdown():
+ logger.info("Test: verify behaviour after r2-eth1 is no shutdown")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Run no shutdown on r2-eth1 interface */
+ tgen = get_topogen()
+ tgen.gears["r2"].peer_link_enable("r2-eth1", True)
+ topotest.sleep(5, "Waiting for the network to reconverge")
+
+ for rname in ["r1", "r2", "r3"]:
+ router_compare_json_output(
+ rname, "show mpls ldp igp-sync json", "show_ldp_igp_sync.ref"
+ )
+
+ for rname in ["r1", "r2", "r3"]:
+ (result, diff) = validate_show_isis_ldp_sync(
+ rname, "show_isis_ldp_sync.ref"
+ )
+ assert result, "ISIS did not converge on {}:\n{}".format(rname, diff)
+
+ for rname in ["r1", "r2", "r3"]:
+ (result, diff) = validate_show_isis_interface_detail(
+ rname, "show_isis_interface_detail.ref"
+ )
+ assert result, "ISIS interface did not converge on {}:\n{}".format(rname, diff)
+
+
+# Memory leak test template
+def test_memory_leak():
+ "Run the memory leak test and report results."
+ tgen = get_topogen()
+ if not tgen.is_memleak_enabled():
+ pytest.skip("Memory leak test/report is disabled")
+
+ tgen.report_memory_leaks()
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
+
+
+#
+# Auxiliary functions
+#
+
+def parse_show_isis_ldp_sync(lines, rname):
+ """
+ Parse the output of 'show isis mpls ldp sync' into a Python dict.
+ """
+ interfaces = {}
+
+ it = iter(lines)
+
+ while True:
+ try:
+ interface = {}
+ interface_name = None
+
+ line = it.next();
+
+ if line.startswith(rname + "-eth"):
+ interface_name = line
+
+ line = it.next();
+
+ if line.startswith(" LDP-IGP Synchronization enabled: "):
+ interface["ldpIgpSyncEnabled"] = line.endswith("yes")
+
+ line = it.next();
+
+ if line.startswith(" holddown timer in seconds: "):
+ interface["holdDownTimeInSec"] = int(line.split(": ")[-1])
+
+ line = it.next();
+
+ if line.startswith(" State: "):
+ interface["ldpIgpSyncState"] = line.split(": ")[-1]
+
+ interfaces[interface_name] = interface
+
+ except StopIteration:
+ break
+
+ return interfaces
+
+
+def show_isis_ldp_sync(router, rname):
+ """
+ Get the show isis mpls ldp-sync info in a dictionary format.
+
+ """
+ out = topotest.normalize_text(
+ router.vtysh_cmd("show isis mpls ldp-sync")
+ ).splitlines()
+
+ parsed = parse_show_isis_ldp_sync(out, rname)
+
+ return parsed
+
+
+def validate_show_isis_ldp_sync(rname, fname):
+ tgen = get_topogen()
+
+ filename = "{0}/{1}/{2}".format(CWD, rname, fname)
+ expected = json.loads(open(filename).read())
+
+ router = tgen.gears[rname]
+
+ def compare_isis_ldp_sync(router, expected):
+ "Helper function to test show isis mpls ldp-sync"
+ actual = show_isis_ldp_sync(router, rname)
+ return topotest.json_cmp(actual, expected)
+
+ test_func = partial(compare_isis_ldp_sync, router, expected)
+ (result, diff) = topotest.run_and_expect(test_func, None, wait=0.5, count=160)
+
+ return (result, diff)
+
+
+def parse_show_isis_interface_detail(lines, rname):
+ """
+ Parse the output of 'show isis interface detail' into a Python dict.
+ """
+ areas = {}
+ area_id = None
+
+ it = iter(lines)
+
+ while True:
+ try:
+ line = it.next();
+
+ area_match = re.match(r"Area (.+):", line)
+ if not area_match:
+ continue
+
+ area_id = area_match.group(1)
+ area = {}
+
+ line = it.next();
+
+ while line.startswith(" Interface: "):
+ interface_name = re.split(':|,', line)[1].lstrip()
+
+ area[interface_name]= []
+
+ # Look for keyword: Level-1 or Level-2
+ while not line.startswith(" Level-"):
+ line = it.next();
+
+ while line.startswith(" Level-"):
+
+ level = {}
+
+ level_name = line.split()[0]
+ level['level'] = level_name
+
+ line = it.next();
+
+ if line.startswith(" Metric:"):
+ level['metric'] = re.split(':|,', line)[1].lstrip()
+
+ area[interface_name].append(level)
+
+ # Look for keyword: Level-1 or Level-2 or Interface:
+ while not line.startswith(" Level-") and not line.startswith(" Interface: "):
+ line = it.next();
+
+ if line.startswith(" Level-"):
+ continue
+
+ if line.startswith(" Interface: "):
+ break
+
+ areas[area_id] = area
+
+ except StopIteration:
+
+ areas[area_id] = area
+ break
+
+ return areas
+
+
+def show_isis_interface_detail(router, rname):
+ """
+ Get the show isis mpls ldp-sync info in a dictionary format.
+
+ """
+ out = topotest.normalize_text(
+ router.vtysh_cmd("show isis interface detail")
+ ).splitlines()
+
+ logger.warning(out)
+
+ parsed = parse_show_isis_interface_detail(out, rname)
+
+ logger.warning(parsed)
+
+ return parsed
+
+
+def validate_show_isis_interface_detail(rname, fname):
+ tgen = get_topogen()
+
+ filename = "{0}/{1}/{2}".format(CWD, rname, fname)
+ expected = json.loads(open(filename).read())
+
+ router = tgen.gears[rname]
+
+ def compare_isis_interface_detail(router, expected):
+ "Helper function to test show isis interface detail"
+ actual = show_isis_interface_detail(router, rname)
+ return topotest.json_cmp(actual, expected)
+
+ test_func = partial(compare_isis_interface_detail, router, expected)
+ (result, diff) = topotest.run_and_expect(test_func, None, wait=0.5, count=160)
+
+ return (result, diff)
+
diff --git a/tests/topotests/ldp-sync-ospf-topo1/ce1/zebra.conf b/tests/topotests/ldp-sync-ospf-topo1/ce1/zebra.conf
new file mode 100644
index 0000000000..6f165e2724
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/ce1/zebra.conf
@@ -0,0 +1,12 @@
+log file zebra.log
+!
+hostname ce1
+!
+interface ce1-eth0
+ ip address 172.16.1.1/24
+ no link-detect
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/ldp-sync-ospf-topo1/ce2/zebra.conf b/tests/topotests/ldp-sync-ospf-topo1/ce2/zebra.conf
new file mode 100644
index 0000000000..ac02d0f9a4
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/ce2/zebra.conf
@@ -0,0 +1,12 @@
+log file zebra.log
+!
+hostname ce2
+!
+interface ce2-eth0
+ ip address 172.16.1.2/24
+ no link-detect
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/ldp-sync-ospf-topo1/ce3/zebra.conf b/tests/topotests/ldp-sync-ospf-topo1/ce3/zebra.conf
new file mode 100644
index 0000000000..c6a5824d15
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/ce3/zebra.conf
@@ -0,0 +1,12 @@
+log file zebra.log
+!
+hostname ce3
+!
+interface ce3-eth0
+ ip address 172.16.1.3/24
+ no link-detect
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/ldp-sync-ospf-topo1/r1/ldpd.conf b/tests/topotests/ldp-sync-ospf-topo1/r1/ldpd.conf
new file mode 100644
index 0000000000..b9c32d3000
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/r1/ldpd.conf
@@ -0,0 +1,33 @@
+hostname r1
+log file ldpd.log
+!
+debug mpls ldp zebra
+debug mpls ldp event
+debug mpls ldp errors
+debug mpls ldp sync
+!
+mpls ldp
+ router-id 1.1.1.1
+ !
+ address-family ipv4
+ discovery transport-address 1.1.1.1
+ label local allocate host-routes
+ !
+ ttl-security disable
+ !
+ interface r1-eth1
+ !
+ interface r1-eth2
+ !
+ !
+!
+l2vpn CUST_A type vpls
+ member interface r1-eth0
+ !
+ member pseudowire r1-mpw0
+ neighbor lsr-id 2.2.2.2
+ pw-id 100
+ !
+!
+line vty
+!
diff --git a/tests/topotests/ldp-sync-ospf-topo1/r1/ospf-nbrs.txt b/tests/topotests/ldp-sync-ospf-topo1/r1/ospf-nbrs.txt
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/r1/ospf-nbrs.txt
diff --git a/tests/topotests/ldp-sync-ospf-topo1/r1/ospfd.conf b/tests/topotests/ldp-sync-ospf-topo1/r1/ospfd.conf
new file mode 100644
index 0000000000..eefcd1e71c
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/r1/ospfd.conf
@@ -0,0 +1,20 @@
+hostname r1
+log file ospfd.log
+debug ospf zebra interface
+debug ospf ldp-sync
+!
+router ospf
+ router-id 1.1.1.1
+ network 10.0.1.1/24 area 0
+ network 10.0.2.1/24 area 0
+ network 1.1.1.1/32 area 0
+ mpls ldp-sync
+ ! mpls ldp-sync holddown 50
+!
+interface r1-eth1
+ ip ospf network point-to-point
+ ! ip ospf mpls ldp-sync holddown 40
+!
+interface r1-eth2
+ ip ospf network point-to-point
+!
diff --git a/tests/topotests/ldp-sync-ospf-topo1/r1/show_ip_ospf_interface.ref b/tests/topotests/ldp-sync-ospf-topo1/r1/show_ip_ospf_interface.ref
new file mode 100644
index 0000000000..8b2884786d
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/r1/show_ip_ospf_interface.ref
@@ -0,0 +1,11 @@
+{
+ "interfaces":{
+ "r1-eth1":{
+ "cost":10
+ },
+ "r1-eth2":{
+ "cost":10
+ }
+ }
+}
+
diff --git a/tests/topotests/ldp-sync-ospf-topo1/r1/show_ip_ospf_interface_r1_eth1_shutdown.ref b/tests/topotests/ldp-sync-ospf-topo1/r1/show_ip_ospf_interface_r1_eth1_shutdown.ref
new file mode 100644
index 0000000000..b1a263e422
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/r1/show_ip_ospf_interface_r1_eth1_shutdown.ref
@@ -0,0 +1,8 @@
+{
+ "interfaces":{
+ "r1-eth2":{
+ "cost":10
+ }
+ }
+}
+
diff --git a/tests/topotests/ldp-sync-ospf-topo1/r1/show_ip_ospf_interface_r2_eth1_shutdown.ref b/tests/topotests/ldp-sync-ospf-topo1/r1/show_ip_ospf_interface_r2_eth1_shutdown.ref
new file mode 100644
index 0000000000..0c147338e3
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/r1/show_ip_ospf_interface_r2_eth1_shutdown.ref
@@ -0,0 +1,11 @@
+{
+ "interfaces":{
+ "r1-eth1":{
+ "cost":65535
+ },
+ "r1-eth2":{
+ "cost":10
+ }
+ }
+}
+
diff --git a/tests/topotests/ldp-sync-ospf-topo1/r1/show_ip_ospf_neighbor.json b/tests/topotests/ldp-sync-ospf-topo1/r1/show_ip_ospf_neighbor.json
new file mode 100644
index 0000000000..3bfda39071
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/r1/show_ip_ospf_neighbor.json
@@ -0,0 +1,26 @@
+{
+ "neighbors": {
+ "2.2.2.2": [
+ {
+ "dbSummaryCounter": 0,
+ "retransmitCounter": 0,
+ "priority": 1,
+ "state": "Full/DROther",
+ "address": "10.0.1.2",
+ "ifaceName": "r1-eth1:10.0.1.1",
+ "requestCounter": 0
+ }
+ ],
+ "3.3.3.3": [
+ {
+ "dbSummaryCounter": 0,
+ "retransmitCounter": 0,
+ "priority": 1,
+ "state": "Full/DROther",
+ "address": "10.0.2.3",
+ "ifaceName": "r1-eth2:10.0.2.1",
+ "requestCounter": 0
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/ldp-sync-ospf-topo1/r1/show_ip_route.ref b/tests/topotests/ldp-sync-ospf-topo1/r1/show_ip_route.ref
new file mode 100644
index 0000000000..8ccd60ca41
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/r1/show_ip_route.ref
@@ -0,0 +1,157 @@
+{
+ "1.1.1.1/32":[
+ {
+ "prefix":"1.1.1.1/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":0,
+ "nexthops":[
+ {
+ "directlyConnected":true,
+ "interfaceIndex":1,
+ "interfaceName":"lo",
+ "active":true
+ }
+ ]
+ },
+ {
+ "prefix":"1.1.1.1/32",
+ "protocol":"connected",
+ "selected":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceIndex":1,
+ "interfaceName":"lo",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "2.2.2.2/32":[
+ {
+ "prefix":"2.2.2.2/32",
+ "protocol":"ospf",
+ "selected":true,
+ "distance":110,
+ "metric":10,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceIndex":3,
+ "interfaceName":"r1-eth1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "3.3.3.3/32":[
+ {
+ "prefix":"3.3.3.3/32",
+ "protocol":"ospf",
+ "selected":true,
+ "distance":110,
+ "metric":10,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.3",
+ "afi":"ipv4",
+ "interfaceIndex":4,
+ "interfaceName":"r1-eth2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.1.0/24":[
+ {
+ "prefix":"10.0.1.0/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":10,
+ "nexthops":[
+ {
+ "directlyConnected":true,
+ "interfaceIndex":3,
+ "interfaceName":"r1-eth1",
+ "active":true
+ }
+ ]
+ },
+ {
+ "prefix":"10.0.1.0/24",
+ "protocol":"connected",
+ "selected":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceIndex":3,
+ "interfaceName":"r1-eth1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.2.0/24":[
+ {
+ "prefix":"10.0.2.0/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":10,
+ "nexthops":[
+ {
+ "directlyConnected":true,
+ "interfaceIndex":4,
+ "interfaceName":"r1-eth2",
+ "active":true
+ }
+ ]
+ },
+ {
+ "prefix":"10.0.2.0/24",
+ "protocol":"connected",
+ "selected":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceIndex":4,
+ "interfaceName":"r1-eth2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0/24":[
+ {
+ "prefix":"10.0.3.0/24",
+ "protocol":"ospf",
+ "selected":true,
+ "distance":110,
+ "metric":20,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceIndex":3,
+ "interfaceName":"r1-eth1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.2.3",
+ "afi":"ipv4",
+ "interfaceIndex":4,
+ "interfaceName":"r1-eth2",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-sync-ospf-topo1/r1/show_l2vpn_binding.ref b/tests/topotests/ldp-sync-ospf-topo1/r1/show_l2vpn_binding.ref
new file mode 100644
index 0000000000..b3de7e2c66
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/r1/show_l2vpn_binding.ref
@@ -0,0 +1,16 @@
+{
+ "2.2.2.2: 100":{
+ "destination":"2.2.2.2",
+ "vcId":100,
+ "localLabel":16,
+ "localControlWord":1,
+ "localVcType":"Ethernet",
+ "localGroupID":0,
+ "localIfMtu":1500,
+ "remoteLabel":16,
+ "remoteControlWord":1,
+ "remoteVcType":"Ethernet",
+ "remoteGroupID":0,
+ "remoteIfMtu":1500
+ }
+}
diff --git a/tests/topotests/ldp-sync-ospf-topo1/r1/show_l2vpn_vc.ref b/tests/topotests/ldp-sync-ospf-topo1/r1/show_l2vpn_vc.ref
new file mode 100644
index 0000000000..29e9df1089
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/r1/show_l2vpn_vc.ref
@@ -0,0 +1,8 @@
+{
+ "r1-mpw0":{
+ "peerId":"2.2.2.2",
+ "vcId":100,
+ "VpnName":"CUST_A",
+ "status":"up"
+ }
+}
diff --git a/tests/topotests/ldp-sync-ospf-topo1/r1/show_ldp_binding.ref b/tests/topotests/ldp-sync-ospf-topo1/r1/show_ldp_binding.ref
new file mode 100644
index 0000000000..b3a12ec53f
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/r1/show_ldp_binding.ref
@@ -0,0 +1,44 @@
+{
+ "bindings":[
+ {
+ "addressFamily":"ipv4",
+ "prefix":"1.1.1.1/32",
+ "neighborId":"2.2.2.2",
+ "localLabel":"imp-null",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"1.1.1.1/32",
+ "neighborId":"3.3.3.3",
+ "localLabel":"imp-null",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"2.2.2.2/32",
+ "neighborId":"2.2.2.2",
+ "remoteLabel":"imp-null",
+ "inUse":1
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"2.2.2.2/32",
+ "neighborId":"3.3.3.3",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"3.3.3.3/32",
+ "neighborId":"2.2.2.2",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"3.3.3.3/32",
+ "neighborId":"3.3.3.3",
+ "remoteLabel":"imp-null",
+ "inUse":1
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-sync-ospf-topo1/r1/show_ldp_discovery.ref b/tests/topotests/ldp-sync-ospf-topo1/r1/show_ldp_discovery.ref
new file mode 100644
index 0000000000..9301e60c67
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/r1/show_ldp_discovery.ref
@@ -0,0 +1,25 @@
+{
+ "adjacencies":[
+ {
+ "addressFamily":"ipv4",
+ "neighborId":"2.2.2.2",
+ "type":"link",
+ "interface":"r1-eth1",
+ "helloHoldtime":15
+ },
+ {
+ "addressFamily":"ipv4",
+ "neighborId":"2.2.2.2",
+ "type":"targeted",
+ "peer":"2.2.2.2",
+ "helloHoldtime":45
+ },
+ {
+ "addressFamily":"ipv4",
+ "neighborId":"3.3.3.3",
+ "type":"link",
+ "interface":"r1-eth2",
+ "helloHoldtime":15
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-sync-ospf-topo1/r1/show_ldp_igp_sync.ref b/tests/topotests/ldp-sync-ospf-topo1/r1/show_ldp_igp_sync.ref
new file mode 100644
index 0000000000..54d015fef9
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/r1/show_ldp_igp_sync.ref
@@ -0,0 +1,16 @@
+{
+ "r1-eth1":{
+ "state":"labelExchangeComplete",
+ "waitTime":10,
+ "waitTimeRemaining":0,
+ "timerRunning":false,
+ "peerLdpId":"2.2.2.2"
+ },
+ "r1-eth2":{
+ "state":"labelExchangeComplete",
+ "waitTime":10,
+ "waitTimeRemaining":0,
+ "timerRunning":false,
+ "peerLdpId":"3.3.3.3"
+ }
+}
diff --git a/tests/topotests/ldp-sync-ospf-topo1/r1/show_ldp_igp_sync_r1_eth1_shutdown.ref b/tests/topotests/ldp-sync-ospf-topo1/r1/show_ldp_igp_sync_r1_eth1_shutdown.ref
new file mode 100644
index 0000000000..2232069f68
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/r1/show_ldp_igp_sync_r1_eth1_shutdown.ref
@@ -0,0 +1,16 @@
+{
+ "r1-eth1":{
+ "state":"labelExchangeNotComplete",
+ "waitTime":10,
+ "waitTimeRemaining":0,
+ "timerRunning":false,
+ "peerLdpId":""
+ },
+ "r1-eth2":{
+ "state":"labelExchangeComplete",
+ "waitTime":10,
+ "waitTimeRemaining":0,
+ "timerRunning":false,
+ "peerLdpId":"3.3.3.3"
+ }
+}
diff --git a/tests/topotests/ldp-sync-ospf-topo1/r1/show_ldp_neighbor.ref b/tests/topotests/ldp-sync-ospf-topo1/r1/show_ldp_neighbor.ref
new file mode 100644
index 0000000000..40d8ebeb90
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/r1/show_ldp_neighbor.ref
@@ -0,0 +1,16 @@
+{
+ "neighbors":[
+ {
+ "addressFamily":"ipv4",
+ "neighborId":"2.2.2.2",
+ "state":"OPERATIONAL",
+ "transportAddress":"2.2.2.2"
+ },
+ {
+ "addressFamily":"ipv4",
+ "neighborId":"3.3.3.3",
+ "state":"OPERATIONAL",
+ "transportAddress":"3.3.3.3"
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-sync-ospf-topo1/r1/show_ospf_ldp_sync.ref b/tests/topotests/ldp-sync-ospf-topo1/r1/show_ospf_ldp_sync.ref
new file mode 100644
index 0000000000..3782071bf9
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/r1/show_ospf_ldp_sync.ref
@@ -0,0 +1,12 @@
+{
+ "r1-eth1":{
+ "ldpIgpSyncEnabled":true,
+ "holdDownTimeInSec":0,
+ "ldpIgpSyncState":"Sync achieved"
+ },
+ "r1-eth2":{
+ "ldpIgpSyncEnabled":true,
+ "holdDownTimeInSec":0,
+ "ldpIgpSyncState":"Sync achieved"
+ }
+}
diff --git a/tests/topotests/ldp-sync-ospf-topo1/r1/show_ospf_ldp_sync_r1_eth1_shutdown.ref b/tests/topotests/ldp-sync-ospf-topo1/r1/show_ospf_ldp_sync_r1_eth1_shutdown.ref
new file mode 100644
index 0000000000..c2642c6483
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/r1/show_ospf_ldp_sync_r1_eth1_shutdown.ref
@@ -0,0 +1,7 @@
+{
+ "r1-eth2":{
+ "ldpIgpSyncEnabled":true,
+ "holdDownTimeInSec":0,
+ "ldpIgpSyncState":"Sync achieved"
+ }
+}
diff --git a/tests/topotests/ldp-sync-ospf-topo1/r1/show_ospf_ldp_sync_r2_eth1_shutdown.ref b/tests/topotests/ldp-sync-ospf-topo1/r1/show_ospf_ldp_sync_r2_eth1_shutdown.ref
new file mode 100644
index 0000000000..6f180b048a
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/r1/show_ospf_ldp_sync_r2_eth1_shutdown.ref
@@ -0,0 +1,12 @@
+{
+ "r1-eth1":{
+ "ldpIgpSyncEnabled":true,
+ "holdDownTimeInSec":0,
+ "ldpIgpSyncState":"Sync not achieved"
+ },
+ "r1-eth2":{
+ "ldpIgpSyncEnabled":true,
+ "holdDownTimeInSec":0,
+ "ldpIgpSyncState":"Sync achieved"
+ }
+}
diff --git a/tests/topotests/ldp-sync-ospf-topo1/r1/zebra.conf b/tests/topotests/ldp-sync-ospf-topo1/r1/zebra.conf
new file mode 100644
index 0000000000..ea047355ad
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/r1/zebra.conf
@@ -0,0 +1,29 @@
+log file zebra.log
+!
+hostname r1
+!
+debug zebra kernel
+debug zebra rib detailed
+debug zebra dplane detailed
+debug zebra nht
+debug zebra pseudowires
+debug zebra mpls
+!
+interface lo
+ ip address 1.1.1.1/32
+!
+interface r1-eth0
+ description to s1
+!
+interface r1-eth1
+ description to s4
+ ip address 10.0.1.1/24
+!
+interface r1-eth2
+ description to s5
+ ip address 10.0.2.1/24
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/ldp-sync-ospf-topo1/r2/ldpd.conf b/tests/topotests/ldp-sync-ospf-topo1/r2/ldpd.conf
new file mode 100644
index 0000000000..52398b1b72
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/r2/ldpd.conf
@@ -0,0 +1,33 @@
+hostname r2
+log file ldpd.log
+!
+debug mpls ldp zebra
+debug mpls ldp event
+debug mpls ldp errors
+debug mpls ldp sync
+!
+mpls ldp
+ router-id 2.2.2.2
+ !
+ address-family ipv4
+ discovery transport-address 2.2.2.2
+ label local allocate host-routes
+ !
+ ttl-security disable
+ !
+ interface r2-eth1
+ !
+ interface r2-eth2
+ !
+ !
+!
+l2vpn CUST_A type vpls
+ member interface r2-eth0
+ !
+ member pseudowire r2-mpw0
+ neighbor lsr-id 1.1.1.1
+ pw-id 100
+ !
+!
+line vty
+!
diff --git a/tests/topotests/ldp-sync-ospf-topo1/r2/ospfd.conf b/tests/topotests/ldp-sync-ospf-topo1/r2/ospfd.conf
new file mode 100644
index 0000000000..f93f6aed56
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/r2/ospfd.conf
@@ -0,0 +1,19 @@
+hostname r2
+log file ospfd.log
+debug ospf zebra interface
+debug ospf ldp-sync
+!
+router ospf
+ router-id 2.2.2.2
+ network 0.0.0.0/0 area 0
+ mpls ldp-sync
+ mpls ldp-sync holddown 50
+!
+interface r2-eth1
+ ip ospf network point-to-point
+ ip ospf mpls ldp-sync holddown 300
+!
+interface r2-eth2
+ ip ospf network point-to-point
+ no ip ospf mpls ldp-sync
+!
diff --git a/tests/topotests/ldp-sync-ospf-topo1/r2/show_ip_ospf_interface.ref b/tests/topotests/ldp-sync-ospf-topo1/r2/show_ip_ospf_interface.ref
new file mode 100644
index 0000000000..82806721e7
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/r2/show_ip_ospf_interface.ref
@@ -0,0 +1,11 @@
+{
+ "interfaces":{
+ "r2-eth1":{
+ "cost":10
+ },
+ "r2-eth2":{
+ "cost":10
+ }
+ }
+}
+
diff --git a/tests/topotests/ldp-sync-ospf-topo1/r2/show_ip_ospf_interface_r1_eth1_shutdown.ref b/tests/topotests/ldp-sync-ospf-topo1/r2/show_ip_ospf_interface_r1_eth1_shutdown.ref
new file mode 100644
index 0000000000..71e8af1778
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/r2/show_ip_ospf_interface_r1_eth1_shutdown.ref
@@ -0,0 +1,11 @@
+{
+ "interfaces":{
+ "r2-eth1":{
+ "cost":65535
+ },
+ "r2-eth2":{
+ "cost":10
+ }
+ }
+}
+
diff --git a/tests/topotests/ldp-sync-ospf-topo1/r2/show_ip_ospf_interface_r2_eth1_shutdown.ref b/tests/topotests/ldp-sync-ospf-topo1/r2/show_ip_ospf_interface_r2_eth1_shutdown.ref
new file mode 100644
index 0000000000..af9a9c80e5
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/r2/show_ip_ospf_interface_r2_eth1_shutdown.ref
@@ -0,0 +1,8 @@
+{
+ "interfaces":{
+ "r2-eth2":{
+ "cost":10
+ }
+ }
+}
+
diff --git a/tests/topotests/ldp-sync-ospf-topo1/r2/show_ip_ospf_neighbor.json b/tests/topotests/ldp-sync-ospf-topo1/r2/show_ip_ospf_neighbor.json
new file mode 100644
index 0000000000..5b7a5ebbb9
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/r2/show_ip_ospf_neighbor.json
@@ -0,0 +1,26 @@
+{
+ "neighbors": {
+ "1.1.1.1": [
+ {
+ "priority":1,
+ "state":"Full/DROther",
+ "address":"10.0.1.1",
+ "ifaceName":"r2-eth1:10.0.1.2",
+ "retransmitCounter":0,
+ "requestCounter":0,
+ "dbSummaryCounter":0
+ }
+ ],
+ "3.3.3.3": [
+ {
+ "priority":1,
+ "state":"Full/DROther",
+ "address":"10.0.3.3",
+ "ifaceName":"r2-eth2:10.0.3.2",
+ "retransmitCounter":0,
+ "requestCounter":0,
+ "dbSummaryCounter":0
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/ldp-sync-ospf-topo1/r2/show_ip_route.ref b/tests/topotests/ldp-sync-ospf-topo1/r2/show_ip_route.ref
new file mode 100644
index 0000000000..7147c6a595
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/r2/show_ip_route.ref
@@ -0,0 +1,157 @@
+{
+ "1.1.1.1/32":[
+ {
+ "prefix":"1.1.1.1/32",
+ "protocol":"ospf",
+ "selected":true,
+ "distance":110,
+ "metric":10,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.1",
+ "afi":"ipv4",
+ "interfaceIndex":3,
+ "interfaceName":"r2-eth1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "2.2.2.2/32":[
+ {
+ "prefix":"2.2.2.2/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":0,
+ "nexthops":[
+ {
+ "directlyConnected":true,
+ "interfaceIndex":1,
+ "interfaceName":"lo",
+ "active":true
+ }
+ ]
+ },
+ {
+ "prefix":"2.2.2.2/32",
+ "protocol":"connected",
+ "selected":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceIndex":1,
+ "interfaceName":"lo",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "3.3.3.3/32":[
+ {
+ "prefix":"3.3.3.3/32",
+ "protocol":"ospf",
+ "selected":true,
+ "distance":110,
+ "metric":10,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.3.3",
+ "afi":"ipv4",
+ "interfaceIndex":4,
+ "interfaceName":"r2-eth2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.1.0/24":[
+ {
+ "prefix":"10.0.1.0/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":10,
+ "nexthops":[
+ {
+ "directlyConnected":true,
+ "interfaceIndex":3,
+ "interfaceName":"r2-eth1",
+ "active":true
+ }
+ ]
+ },
+ {
+ "prefix":"10.0.1.0/24",
+ "protocol":"connected",
+ "selected":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceIndex":3,
+ "interfaceName":"r2-eth1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.2.0/24":[
+ {
+ "prefix":"10.0.2.0/24",
+ "protocol":"ospf",
+ "selected":true,
+ "distance":110,
+ "metric":20,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.1",
+ "afi":"ipv4",
+ "interfaceIndex":3,
+ "interfaceName":"r2-eth1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.3",
+ "afi":"ipv4",
+ "interfaceIndex":4,
+ "interfaceName":"r2-eth2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0/24":[
+ {
+ "prefix":"10.0.3.0/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":10,
+ "nexthops":[
+ {
+ "directlyConnected":true,
+ "interfaceIndex":4,
+ "interfaceName":"r2-eth2",
+ "active":true
+ }
+ ]
+ },
+ {
+ "prefix":"10.0.3.0/24",
+ "protocol":"connected",
+ "selected":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceIndex":4,
+ "interfaceName":"r2-eth2",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-sync-ospf-topo1/r2/show_l2vpn_binding.ref b/tests/topotests/ldp-sync-ospf-topo1/r2/show_l2vpn_binding.ref
new file mode 100644
index 0000000000..42c5a1cbd9
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/r2/show_l2vpn_binding.ref
@@ -0,0 +1,16 @@
+{
+ "1.1.1.1: 100":{
+ "destination":"1.1.1.1",
+ "vcId":100,
+ "localLabel":16,
+ "localControlWord":1,
+ "localVcType":"Ethernet",
+ "localGroupID":0,
+ "localIfMtu":1500,
+ "remoteLabel":16,
+ "remoteControlWord":1,
+ "remoteVcType":"Ethernet",
+ "remoteGroupID":0,
+ "remoteIfMtu":1500
+ }
+}
diff --git a/tests/topotests/ldp-sync-ospf-topo1/r2/show_l2vpn_vc.ref b/tests/topotests/ldp-sync-ospf-topo1/r2/show_l2vpn_vc.ref
new file mode 100644
index 0000000000..942ed23a1e
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/r2/show_l2vpn_vc.ref
@@ -0,0 +1,8 @@
+{
+ "r2-mpw0":{
+ "peerId":"1.1.1.1",
+ "vcId":100,
+ "VpnName":"CUST_A",
+ "status":"up"
+ }
+}
diff --git a/tests/topotests/ldp-sync-ospf-topo1/r2/show_ldp_binding.ref b/tests/topotests/ldp-sync-ospf-topo1/r2/show_ldp_binding.ref
new file mode 100644
index 0000000000..c641fb47e6
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/r2/show_ldp_binding.ref
@@ -0,0 +1,44 @@
+{
+ "bindings":[
+ {
+ "addressFamily":"ipv4",
+ "prefix":"1.1.1.1/32",
+ "neighborId":"1.1.1.1",
+ "remoteLabel":"imp-null",
+ "inUse":1
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"1.1.1.1/32",
+ "neighborId":"3.3.3.3",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"2.2.2.2/32",
+ "neighborId":"1.1.1.1",
+ "localLabel":"imp-null",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"2.2.2.2/32",
+ "neighborId":"3.3.3.3",
+ "localLabel":"imp-null",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"3.3.3.3/32",
+ "neighborId":"1.1.1.1",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"3.3.3.3/32",
+ "neighborId":"3.3.3.3",
+ "remoteLabel":"imp-null",
+ "inUse":1
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-sync-ospf-topo1/r2/show_ldp_discovery.ref b/tests/topotests/ldp-sync-ospf-topo1/r2/show_ldp_discovery.ref
new file mode 100644
index 0000000000..26801acade
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/r2/show_ldp_discovery.ref
@@ -0,0 +1,25 @@
+{
+ "adjacencies":[
+ {
+ "addressFamily":"ipv4",
+ "neighborId":"1.1.1.1",
+ "type":"link",
+ "interface":"r2-eth1",
+ "helloHoldtime":15
+ },
+ {
+ "addressFamily":"ipv4",
+ "neighborId":"1.1.1.1",
+ "type":"targeted",
+ "peer":"1.1.1.1",
+ "helloHoldtime":45
+ },
+ {
+ "addressFamily":"ipv4",
+ "neighborId":"3.3.3.3",
+ "type":"link",
+ "interface":"r2-eth2",
+ "helloHoldtime":15
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-sync-ospf-topo1/r2/show_ldp_igp_sync.ref b/tests/topotests/ldp-sync-ospf-topo1/r2/show_ldp_igp_sync.ref
new file mode 100644
index 0000000000..f2b24d7d62
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/r2/show_ldp_igp_sync.ref
@@ -0,0 +1,16 @@
+{
+ "r2-eth1":{
+ "state":"labelExchangeComplete",
+ "waitTime":10,
+ "waitTimeRemaining":0,
+ "timerRunning":false,
+ "peerLdpId":"1.1.1.1"
+ },
+ "r2-eth2":{
+ "state":"labelExchangeComplete",
+ "waitTime":10,
+ "waitTimeRemaining":0,
+ "timerRunning":false,
+ "peerLdpId":"3.3.3.3"
+ }
+}
diff --git a/tests/topotests/ldp-sync-ospf-topo1/r2/show_ldp_igp_sync_r1_eth1_shutdown.ref b/tests/topotests/ldp-sync-ospf-topo1/r2/show_ldp_igp_sync_r1_eth1_shutdown.ref
new file mode 100644
index 0000000000..b5508dd35c
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/r2/show_ldp_igp_sync_r1_eth1_shutdown.ref
@@ -0,0 +1,16 @@
+{
+ "r2-eth1":{
+ "state":"labelExchangeNotComplete",
+ "waitTime":10,
+ "waitTimeRemaining":0,
+ "timerRunning":false,
+ "peerLdpId":""
+ },
+ "r2-eth2":{
+ "state":"labelExchangeComplete",
+ "waitTime":10,
+ "waitTimeRemaining":0,
+ "timerRunning":false,
+ "peerLdpId":"3.3.3.3"
+ }
+}
diff --git a/tests/topotests/ldp-sync-ospf-topo1/r2/show_ldp_neighbor.ref b/tests/topotests/ldp-sync-ospf-topo1/r2/show_ldp_neighbor.ref
new file mode 100644
index 0000000000..eed35289ea
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/r2/show_ldp_neighbor.ref
@@ -0,0 +1,16 @@
+{
+ "neighbors":[
+ {
+ "addressFamily":"ipv4",
+ "neighborId":"1.1.1.1",
+ "state":"OPERATIONAL",
+ "transportAddress":"1.1.1.1"
+ },
+ {
+ "addressFamily":"ipv4",
+ "neighborId":"3.3.3.3",
+ "state":"OPERATIONAL",
+ "transportAddress":"3.3.3.3"
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-sync-ospf-topo1/r2/show_ospf_ldp_sync.ref b/tests/topotests/ldp-sync-ospf-topo1/r2/show_ospf_ldp_sync.ref
new file mode 100644
index 0000000000..6c27a10427
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/r2/show_ospf_ldp_sync.ref
@@ -0,0 +1,12 @@
+{
+ "r2-eth1":{
+ "ldpIgpSyncEnabled":true,
+ "holdDownTimeInSec":300,
+ "ldpIgpSyncState":"Sync achieved"
+ },
+ "r2-eth2":{
+ "ldpIgpSyncEnabled":false,
+ "holdDownTimeInSec":50,
+ "ldpIgpSyncState":"Sync not required"
+ }
+}
diff --git a/tests/topotests/ldp-sync-ospf-topo1/r2/show_ospf_ldp_sync_r1_eth1_shutdown.ref b/tests/topotests/ldp-sync-ospf-topo1/r2/show_ospf_ldp_sync_r1_eth1_shutdown.ref
new file mode 100644
index 0000000000..889f69ed7f
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/r2/show_ospf_ldp_sync_r1_eth1_shutdown.ref
@@ -0,0 +1,12 @@
+{
+ "r2-eth1":{
+ "ldpIgpSyncEnabled":true,
+ "holdDownTimeInSec":300,
+ "ldpIgpSyncState":"Holding down until Sync"
+ },
+ "r2-eth2":{
+ "ldpIgpSyncEnabled":false,
+ "holdDownTimeInSec":50,
+ "ldpIgpSyncState":"Sync not required"
+ }
+}
diff --git a/tests/topotests/ldp-sync-ospf-topo1/r2/show_ospf_ldp_sync_r2_eth1_shutdown.ref b/tests/topotests/ldp-sync-ospf-topo1/r2/show_ospf_ldp_sync_r2_eth1_shutdown.ref
new file mode 100644
index 0000000000..d9036e124b
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/r2/show_ospf_ldp_sync_r2_eth1_shutdown.ref
@@ -0,0 +1,7 @@
+{
+ "r2-eth2":{
+ "ldpIgpSyncEnabled":false,
+ "holdDownTimeInSec":50,
+ "ldpIgpSyncState":"Sync not required"
+ }
+}
diff --git a/tests/topotests/ldp-sync-ospf-topo1/r2/zebra.conf b/tests/topotests/ldp-sync-ospf-topo1/r2/zebra.conf
new file mode 100644
index 0000000000..c244442876
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/r2/zebra.conf
@@ -0,0 +1,28 @@
+log file zebra.log
+!
+hostname r2
+!
+debug zebra rib detailed
+debug zebra dplane detailed
+debug zebra kernel
+debug zebra nht
+debug zebra pseudowires
+!
+interface lo
+ ip address 2.2.2.2/32
+!
+interface r2-eth0
+ description to s2
+!
+interface r2-eth1
+ description to s4
+ ip address 10.0.1.2/24
+!
+interface r2-eth2
+ description to s6
+ ip address 10.0.3.2/24
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/ldp-sync-ospf-topo1/r3/ldpd.conf b/tests/topotests/ldp-sync-ospf-topo1/r3/ldpd.conf
new file mode 100644
index 0000000000..2935caf13b
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/r3/ldpd.conf
@@ -0,0 +1,25 @@
+hostname r3
+log file ldpd.log
+!
+debug mpls ldp zebra
+debug mpls ldp event
+debug mpls ldp errors
+debug mpls ldp sync
+!
+mpls ldp
+ router-id 3.3.3.3
+ !
+ address-family ipv4
+ discovery transport-address 3.3.3.3
+ label local allocate host-routes
+ !
+ ttl-security disable
+ !
+ interface r3-eth1
+ !
+ interface r3-eth2
+ !
+ !
+!
+line vty
+!
diff --git a/tests/topotests/ldp-sync-ospf-topo1/r3/ospfd.conf b/tests/topotests/ldp-sync-ospf-topo1/r3/ospfd.conf
new file mode 100644
index 0000000000..09eea759ad
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/r3/ospfd.conf
@@ -0,0 +1,18 @@
+hostname r3
+log file ospfd.log
+debug ospf zebra interface
+debug ospf ldp-sync
+!
+router ospf
+ router-id 3.3.3.3
+ network 0.0.0.0/0 area 0
+ mpls ldp-sync
+ mpls ldp-sync holddown 50
+!
+interface r3-eth1
+ ip ospf network point-to-point
+ no ip ospf mpls ldp-sync
+!
+interface r3-eth2
+ ip ospf network point-to-point
+!
diff --git a/tests/topotests/ldp-sync-ospf-topo1/r3/show_ip_ospf_interface.ref b/tests/topotests/ldp-sync-ospf-topo1/r3/show_ip_ospf_interface.ref
new file mode 100644
index 0000000000..aec97b30cb
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/r3/show_ip_ospf_interface.ref
@@ -0,0 +1,11 @@
+{
+ "interfaces":{
+ "r3-eth1":{
+ "cost":10
+ },
+ "r3-eth2":{
+ "cost":10
+ }
+ }
+}
+
diff --git a/tests/topotests/ldp-sync-ospf-topo1/r3/show_ip_ospf_interface_r1_eth1_shutdown.ref b/tests/topotests/ldp-sync-ospf-topo1/r3/show_ip_ospf_interface_r1_eth1_shutdown.ref
new file mode 100644
index 0000000000..aec97b30cb
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/r3/show_ip_ospf_interface_r1_eth1_shutdown.ref
@@ -0,0 +1,11 @@
+{
+ "interfaces":{
+ "r3-eth1":{
+ "cost":10
+ },
+ "r3-eth2":{
+ "cost":10
+ }
+ }
+}
+
diff --git a/tests/topotests/ldp-sync-ospf-topo1/r3/show_ip_ospf_interface_r2_eth1_shutdown.ref b/tests/topotests/ldp-sync-ospf-topo1/r3/show_ip_ospf_interface_r2_eth1_shutdown.ref
new file mode 100644
index 0000000000..aec97b30cb
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/r3/show_ip_ospf_interface_r2_eth1_shutdown.ref
@@ -0,0 +1,11 @@
+{
+ "interfaces":{
+ "r3-eth1":{
+ "cost":10
+ },
+ "r3-eth2":{
+ "cost":10
+ }
+ }
+}
+
diff --git a/tests/topotests/ldp-sync-ospf-topo1/r3/show_ip_ospf_neighbor.json b/tests/topotests/ldp-sync-ospf-topo1/r3/show_ip_ospf_neighbor.json
new file mode 100644
index 0000000000..1b29b9f947
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/r3/show_ip_ospf_neighbor.json
@@ -0,0 +1,26 @@
+{
+ "neighbors": {
+ "1.1.1.1": [
+ {
+ "priority":1,
+ "state":"Full/DROther",
+ "address":"10.0.2.1",
+ "ifaceName":"r3-eth1:10.0.2.3",
+ "retransmitCounter":0,
+ "requestCounter":0,
+ "dbSummaryCounter":0
+ }
+ ],
+ "2.2.2.2": [
+ {
+ "priority":1,
+ "state":"Full/DROther",
+ "address":"10.0.3.2",
+ "ifaceName":"r3-eth2:10.0.3.3",
+ "retransmitCounter":0,
+ "requestCounter":0,
+ "dbSummaryCounter":0
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/ldp-sync-ospf-topo1/r3/show_ip_route.ref b/tests/topotests/ldp-sync-ospf-topo1/r3/show_ip_route.ref
new file mode 100644
index 0000000000..d77de7c9e3
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/r3/show_ip_route.ref
@@ -0,0 +1,157 @@
+{
+ "1.1.1.1/32":[
+ {
+ "prefix":"1.1.1.1/32",
+ "protocol":"ospf",
+ "selected":true,
+ "distance":110,
+ "metric":10,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.1",
+ "afi":"ipv4",
+ "interfaceIndex":3,
+ "interfaceName":"r3-eth1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "2.2.2.2/32":[
+ {
+ "prefix":"2.2.2.2/32",
+ "protocol":"ospf",
+ "selected":true,
+ "distance":110,
+ "metric":10,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceIndex":4,
+ "interfaceName":"r3-eth2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "3.3.3.3/32":[
+ {
+ "prefix":"3.3.3.3/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":0,
+ "nexthops":[
+ {
+ "directlyConnected":true,
+ "interfaceIndex":1,
+ "interfaceName":"lo",
+ "active":true
+ }
+ ]
+ },
+ {
+ "prefix":"3.3.3.3/32",
+ "protocol":"connected",
+ "selected":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceIndex":1,
+ "interfaceName":"lo",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.1.0/24":[
+ {
+ "prefix":"10.0.1.0/24",
+ "protocol":"ospf",
+ "selected":true,
+ "distance":110,
+ "metric":20,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.1",
+ "afi":"ipv4",
+ "interfaceIndex":3,
+ "interfaceName":"r3-eth1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceIndex":4,
+ "interfaceName":"r3-eth2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.2.0/24":[
+ {
+ "prefix":"10.0.2.0/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":10,
+ "nexthops":[
+ {
+ "directlyConnected":true,
+ "interfaceIndex":3,
+ "interfaceName":"r3-eth1",
+ "active":true
+ }
+ ]
+ },
+ {
+ "prefix":"10.0.2.0/24",
+ "protocol":"connected",
+ "selected":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceIndex":3,
+ "interfaceName":"r3-eth1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0/24":[
+ {
+ "prefix":"10.0.3.0/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":10,
+ "nexthops":[
+ {
+ "directlyConnected":true,
+ "interfaceIndex":4,
+ "interfaceName":"r3-eth2",
+ "active":true
+ }
+ ]
+ },
+ {
+ "prefix":"10.0.3.0/24",
+ "protocol":"connected",
+ "selected":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceIndex":4,
+ "interfaceName":"r3-eth2",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-sync-ospf-topo1/r3/show_l2vpn_binding.ref b/tests/topotests/ldp-sync-ospf-topo1/r3/show_l2vpn_binding.ref
new file mode 100644
index 0000000000..2c63c08510
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/r3/show_l2vpn_binding.ref
@@ -0,0 +1,2 @@
+{
+}
diff --git a/tests/topotests/ldp-sync-ospf-topo1/r3/show_l2vpn_vc.ref b/tests/topotests/ldp-sync-ospf-topo1/r3/show_l2vpn_vc.ref
new file mode 100644
index 0000000000..2c63c08510
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/r3/show_l2vpn_vc.ref
@@ -0,0 +1,2 @@
+{
+}
diff --git a/tests/topotests/ldp-sync-ospf-topo1/r3/show_ldp_binding.ref b/tests/topotests/ldp-sync-ospf-topo1/r3/show_ldp_binding.ref
new file mode 100644
index 0000000000..e54bd6e755
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/r3/show_ldp_binding.ref
@@ -0,0 +1,44 @@
+{
+ "bindings":[
+ {
+ "addressFamily":"ipv4",
+ "prefix":"1.1.1.1/32",
+ "neighborId":"1.1.1.1",
+ "remoteLabel":"imp-null",
+ "inUse":1
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"1.1.1.1/32",
+ "neighborId":"2.2.2.2",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"2.2.2.2/32",
+ "neighborId":"1.1.1.1",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"2.2.2.2/32",
+ "neighborId":"2.2.2.2",
+ "remoteLabel":"imp-null",
+ "inUse":1
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"3.3.3.3/32",
+ "neighborId":"1.1.1.1",
+ "localLabel":"imp-null",
+ "inUse":0
+ },
+ {
+ "addressFamily":"ipv4",
+ "prefix":"3.3.3.3/32",
+ "neighborId":"2.2.2.2",
+ "localLabel":"imp-null",
+ "inUse":0
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-sync-ospf-topo1/r3/show_ldp_discovery.ref b/tests/topotests/ldp-sync-ospf-topo1/r3/show_ldp_discovery.ref
new file mode 100644
index 0000000000..42fa98d4da
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/r3/show_ldp_discovery.ref
@@ -0,0 +1,18 @@
+{
+ "adjacencies":[
+ {
+ "addressFamily":"ipv4",
+ "neighborId":"1.1.1.1",
+ "type":"link",
+ "interface":"r3-eth1",
+ "helloHoldtime":15
+ },
+ {
+ "addressFamily":"ipv4",
+ "neighborId":"2.2.2.2",
+ "type":"link",
+ "interface":"r3-eth2",
+ "helloHoldtime":15
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-sync-ospf-topo1/r3/show_ldp_igp_sync.ref b/tests/topotests/ldp-sync-ospf-topo1/r3/show_ldp_igp_sync.ref
new file mode 100644
index 0000000000..73261830c9
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/r3/show_ldp_igp_sync.ref
@@ -0,0 +1,16 @@
+{
+ "r3-eth1":{
+ "state":"labelExchangeComplete",
+ "waitTime":10,
+ "waitTimeRemaining":0,
+ "timerRunning":false,
+ "peerLdpId":"1.1.1.1"
+ },
+ "r3-eth2":{
+ "state":"labelExchangeComplete",
+ "waitTime":10,
+ "waitTimeRemaining":0,
+ "timerRunning":false,
+ "peerLdpId":"2.2.2.2"
+ }
+}
diff --git a/tests/topotests/ldp-sync-ospf-topo1/r3/show_ldp_igp_sync_r1_eth1_shutdown.ref b/tests/topotests/ldp-sync-ospf-topo1/r3/show_ldp_igp_sync_r1_eth1_shutdown.ref
new file mode 100644
index 0000000000..73261830c9
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/r3/show_ldp_igp_sync_r1_eth1_shutdown.ref
@@ -0,0 +1,16 @@
+{
+ "r3-eth1":{
+ "state":"labelExchangeComplete",
+ "waitTime":10,
+ "waitTimeRemaining":0,
+ "timerRunning":false,
+ "peerLdpId":"1.1.1.1"
+ },
+ "r3-eth2":{
+ "state":"labelExchangeComplete",
+ "waitTime":10,
+ "waitTimeRemaining":0,
+ "timerRunning":false,
+ "peerLdpId":"2.2.2.2"
+ }
+}
diff --git a/tests/topotests/ldp-sync-ospf-topo1/r3/show_ldp_neighbor.ref b/tests/topotests/ldp-sync-ospf-topo1/r3/show_ldp_neighbor.ref
new file mode 100644
index 0000000000..5c482da697
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/r3/show_ldp_neighbor.ref
@@ -0,0 +1,16 @@
+{
+ "neighbors":[
+ {
+ "addressFamily":"ipv4",
+ "neighborId":"1.1.1.1",
+ "state":"OPERATIONAL",
+ "transportAddress":"1.1.1.1"
+ },
+ {
+ "addressFamily":"ipv4",
+ "neighborId":"2.2.2.2",
+ "state":"OPERATIONAL",
+ "transportAddress":"2.2.2.2"
+ }
+ ]
+}
diff --git a/tests/topotests/ldp-sync-ospf-topo1/r3/show_ospf_ldp_sync.ref b/tests/topotests/ldp-sync-ospf-topo1/r3/show_ospf_ldp_sync.ref
new file mode 100644
index 0000000000..b417ab040a
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/r3/show_ospf_ldp_sync.ref
@@ -0,0 +1,12 @@
+{
+ "r3-eth1":{
+ "ldpIgpSyncEnabled":false,
+ "holdDownTimeInSec":50,
+ "ldpIgpSyncState":"Sync not required"
+ },
+ "r3-eth2":{
+ "ldpIgpSyncEnabled":true,
+ "holdDownTimeInSec":50,
+ "ldpIgpSyncState":"Sync achieved"
+ }
+}
diff --git a/tests/topotests/ldp-sync-ospf-topo1/r3/show_ospf_ldp_sync_r1_eth1_shutdown.ref b/tests/topotests/ldp-sync-ospf-topo1/r3/show_ospf_ldp_sync_r1_eth1_shutdown.ref
new file mode 100644
index 0000000000..b417ab040a
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/r3/show_ospf_ldp_sync_r1_eth1_shutdown.ref
@@ -0,0 +1,12 @@
+{
+ "r3-eth1":{
+ "ldpIgpSyncEnabled":false,
+ "holdDownTimeInSec":50,
+ "ldpIgpSyncState":"Sync not required"
+ },
+ "r3-eth2":{
+ "ldpIgpSyncEnabled":true,
+ "holdDownTimeInSec":50,
+ "ldpIgpSyncState":"Sync achieved"
+ }
+}
diff --git a/tests/topotests/ldp-sync-ospf-topo1/r3/show_ospf_ldp_sync_r2_eth1_shutdown.ref b/tests/topotests/ldp-sync-ospf-topo1/r3/show_ospf_ldp_sync_r2_eth1_shutdown.ref
new file mode 100644
index 0000000000..b417ab040a
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/r3/show_ospf_ldp_sync_r2_eth1_shutdown.ref
@@ -0,0 +1,12 @@
+{
+ "r3-eth1":{
+ "ldpIgpSyncEnabled":false,
+ "holdDownTimeInSec":50,
+ "ldpIgpSyncState":"Sync not required"
+ },
+ "r3-eth2":{
+ "ldpIgpSyncEnabled":true,
+ "holdDownTimeInSec":50,
+ "ldpIgpSyncState":"Sync achieved"
+ }
+}
diff --git a/tests/topotests/ldp-sync-ospf-topo1/r3/zebra.conf b/tests/topotests/ldp-sync-ospf-topo1/r3/zebra.conf
new file mode 100644
index 0000000000..b1919bd296
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/r3/zebra.conf
@@ -0,0 +1,32 @@
+log file zebra.log
+!
+hostname r3
+!
+debug zebra rib detailed
+debug zebra dplane detailed
+debug zebra kernel
+debug zebra nht
+debug zebra pseudowires
+!
+interface lo
+ ip address 3.3.3.3/32
+!
+interface r3-eth0
+ description to s3
+!
+interface r3-eth1
+ description to s5
+ ip address 10.0.2.3/24
+!
+interface r3-eth2
+ description to s6
+ ip address 10.0.3.3/24
+!
+!!interface r3-eth3
+!! description to s4
+!! ip address 10.0.1.3/24
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/ldp-sync-ospf-topo1/test_ldp_sync_ospf_topo1.dot b/tests/topotests/ldp-sync-ospf-topo1/test_ldp_sync_ospf_topo1.dot
new file mode 100644
index 0000000000..4f1bd22f7c
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/test_ldp_sync_ospf_topo1.dot
@@ -0,0 +1,111 @@
+## Color coding:
+#########################
+## Main FRR: #f08080 red
+## Switches: #d0e0d0 gray
+## RIP: #19e3d9 Cyan
+## RIPng: #fcb314 dark yellow
+## OSPFv2: #32b835 Green
+## OSPFv3: #19e3d9 Cyan
+## ISIS IPv4 #fcb314 dark yellow
+## ISIS IPv6 #9a81ec purple
+## BGP IPv4 #eee3d3 beige
+## BGP IPv6 #fdff00 yellow
+##### Colors (see http://www.color-hex.com/)
+
+graph template {
+ label="Test Topology - LDP-VPLS 1";
+
+ # Routers
+ ce1 [
+ shape=doubleoctagon,
+ label="ce1",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ ce2 [
+ shape=doubleoctagon
+ label="ce2",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ ce3 [
+ shape=doubleoctagon
+ label="ce3",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r1 [
+ shape=doubleoctagon,
+ label="r1",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r2 [
+ shape=doubleoctagon
+ label="r2",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r3 [
+ shape=doubleoctagon
+ label="r3",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+
+
+ # Switches
+ s1 [
+ shape=oval,
+ label="VPLS\n172.16.1.0/24",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+ s2 [
+ shape=oval,
+ label="VPLS\n172.16.1.0/24",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+ s3 [
+ shape=oval,
+ label="VPLS\n172.16.1.0/24",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+ s4 [
+ shape=oval,
+ label="s4\n10.0.1.0/24",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+ s5 [
+ shape=oval,
+ label="s5\n10.0.2.0/24",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+ s6 [
+ shape=oval,
+ label="s6\n10.0.3.0/24",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+
+ # Connections
+ ce1 -- s1 [label="eth0\n.1"];
+ ce2 -- s2 [label="eth0\n.2"];
+ ce3 -- s3 [label="eth0\n.3"];
+
+ r1 -- s1 [label="eth0"];
+ r1 -- s4 [label="eth1\n.1"];
+ r1 -- s5 [label="eth2\n.1"];
+
+ r2 -- s2 [label="eth0"];
+ r2 -- s4 [label="eth1\n.2"];
+ r2 -- s6 [label="eth2\n.2"];
+
+ r3 -- s3 [label="eth0"];
+ r3 -- s5 [label="eth1\n.3"];
+ r3 -- s6 [label="eth2\n.3"];
+}
diff --git a/tests/topotests/ldp-sync-ospf-topo1/test_ldp_sync_ospf_topo1.py b/tests/topotests/ldp-sync-ospf-topo1/test_ldp_sync_ospf_topo1.py
new file mode 100644
index 0000000000..9694fa982f
--- /dev/null
+++ b/tests/topotests/ldp-sync-ospf-topo1/test_ldp_sync_ospf_topo1.py
@@ -0,0 +1,429 @@
+#!/usr/bin/env python
+
+#
+# test_ldp_ospf_topo1.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2020 by Volta Networks
+#
+# 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_ldp_vpls_topo1.py:
+
+ +---------+ +---------+
+ | | | |
+ | CE1 | | CE2 |
+ | | | |
+ +---------+ +---------+
+ce1-eth0 (172.16.1.1/24)| |ce2-eth0 (172.16.1.2/24)
+ | |
+ | |
+ rt1-eth0| |rt2-eth0
+ +---------+ 10.0.1.0/24 +---------+
+ | |rt1-eth1 | |
+ | RT1 +----------------+ RT2 |
+ | 1.1.1.1 | rt2-eth1| 2.2.2.2 |
+ | | | |
+ +---------+ +---------+
+ rt1-eth2| |rt2-eth2
+ | |
+ | |
+ 10.0.2.0/24| +---------+ |10.0.3.0/24
+ | | | |
+ | | RT3 | |
+ +--------+ 3.3.3.3 +-------+
+ rt3-eth2| |rt3-eth1
+ +---------+
+ |rt3-eth0
+ |
+ |
+ ce3-eth0 (172.16.1.3/24)|
+ +---------+
+ | |
+ | CE3 |
+ | |
+ +---------+
+"""
+
+import os
+import sys
+import pytest
+import json
+from time import sleep
+from functools import partial
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+
+# Required to instantiate the topology builder class.
+from mininet.topo import Topo
+
+
+class TemplateTopo(Topo):
+ "Test topology builder"
+
+ def build(self, *_args, **_opts):
+ "Build function"
+ tgen = get_topogen(self)
+
+ #
+ # Define FRR Routers
+ #
+ for router in ["ce1", "ce2", "ce3", "r1", "r2", "r3"]:
+ tgen.add_router(router)
+
+ #
+ # Define connections
+ #
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["ce1"])
+ switch.add_link(tgen.gears["r1"])
+
+ switch = tgen.add_switch("s2")
+ switch.add_link(tgen.gears["ce2"])
+ switch.add_link(tgen.gears["r2"])
+
+ switch = tgen.add_switch("s3")
+ switch.add_link(tgen.gears["ce3"])
+ switch.add_link(tgen.gears["r3"])
+
+ switch = tgen.add_switch("s4")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["r2"])
+
+ switch = tgen.add_switch("s5")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["r3"])
+
+ switch = tgen.add_switch("s6")
+ switch.add_link(tgen.gears["r2"])
+ switch.add_link(tgen.gears["r3"])
+
+
+def setup_module(mod):
+ "Sets up the pytest environment"
+ tgen = Topogen(TemplateTopo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ # For all registered routers, load the zebra configuration file
+ for rname, router in router_list.items():
+ router.load_config(
+ TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
+ )
+ # Don't start ospfd and ldpd in the CE nodes
+ if router.name[0] == "r":
+ router.load_config(
+ TopoRouter.RD_OSPF, os.path.join(CWD, "{}/ospfd.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_LDP, os.path.join(CWD, "{}/ldpd.conf".format(rname))
+ )
+
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ "Teardown the pytest environment"
+ tgen = get_topogen()
+
+ # This function tears down the whole topology.
+ tgen.stop_topology()
+
+
+def router_compare_json_output(rname, command, reference):
+ "Compare router JSON output"
+
+ logger.info('Comparing router "%s" "%s" output', rname, command)
+
+ tgen = get_topogen()
+ filename = "{}/{}/{}".format(CWD, rname, reference)
+ expected = json.loads(open(filename).read())
+
+ # Run test function until we get an result.
+ test_func = partial(topotest.router_json_cmp, tgen.gears[rname], command, expected)
+ _, diff = topotest.run_and_expect(test_func, None, count=320, wait=0.5)
+ assertmsg = '"{}" JSON output mismatches the expected result'.format(rname)
+ assert diff is None, assertmsg
+
+
+def test_ospf_convergence():
+ logger.info("Test: check OSPF adjacencies")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ["r1", "r2", "r3"]:
+ router_compare_json_output(
+ rname, "show ip ospf neighbor json", "show_ip_ospf_neighbor.json"
+ )
+
+
+def test_rib():
+ logger.info("Test: verify RIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ["r1", "r2", "r3"]:
+ router_compare_json_output(rname, "show ip route json", "show_ip_route.ref")
+
+
+def test_ldp_adjacencies():
+ logger.info("Test: verify LDP adjacencies")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ["r1", "r2", "r3"]:
+ router_compare_json_output(
+ rname, "show mpls ldp discovery json", "show_ldp_discovery.ref"
+ )
+
+
+def test_ldp_neighbors():
+ logger.info("Test: verify LDP neighbors")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ["r1", "r2", "r3"]:
+ router_compare_json_output(
+ rname, "show mpls ldp neighbor json", "show_ldp_neighbor.ref"
+ )
+
+
+def test_ldp_bindings():
+ logger.info("Test: verify LDP bindings")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ["r1", "r2", "r3"]:
+ router_compare_json_output(
+ rname, "show mpls ldp binding json", "show_ldp_binding.ref"
+ )
+
+
+def test_ldp_pwid_bindings():
+ logger.info("Test: verify LDP PW-ID bindings")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ["r1", "r2", "r3"]:
+ router_compare_json_output(
+ rname, "show l2vpn atom binding json", "show_l2vpn_binding.ref"
+ )
+
+
+def test_ldp_pseudowires():
+ logger.info("Test: verify LDP pseudowires")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ["r1", "r2", "r3"]:
+ router_compare_json_output(
+ rname, "show l2vpn atom vc json", "show_l2vpn_vc.ref"
+ )
+
+def test_ldp_igp_sync():
+ logger.info("Test: verify LDP igp-sync")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ["r1", "r2", "r3"]:
+ router_compare_json_output(
+ rname, "show mpls ldp igp-sync json", "show_ldp_igp_sync.ref"
+ )
+
+def test_ospf_ldp_sync():
+ logger.info("Test: verify OSPF igp-sync")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ["r1", "r2", "r3"]:
+ router_compare_json_output(
+ rname, "show ip ospf mpls ldp-sync json", "show_ospf_ldp_sync.ref"
+ )
+
+ for rname in ["r1", "r2", "r3"]:
+ router_compare_json_output(
+ rname, "show ip ospf interface json", "show_ip_ospf_interface.ref"
+ )
+
+
+def test_r1_eth1_shutdown():
+ logger.info("Test: verify behaviour after r1-eth1 is shutdown")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Shut down r1-r2 link */
+ tgen = get_topogen()
+ tgen.gears["r1"].peer_link_enable("r1-eth1", False)
+ topotest.sleep(5, "Waiting for the network to reconverge")
+
+ # check if the pseudowire is still up (using an alternate path for nexthop resolution)
+ for rname in ["r1", "r2", "r3"]:
+ router_compare_json_output(
+ rname, "show l2vpn atom vc json", "show_l2vpn_vc.ref"
+ )
+
+ for rname in ["r1", "r2", "r3"]:
+ router_compare_json_output(
+ rname, "show mpls ldp igp-sync json", "show_ldp_igp_sync_r1_eth1_shutdown.ref"
+ )
+
+ for rname in ["r1", "r2", "r3"]:
+ router_compare_json_output(
+ rname, "show ip ospf mpls ldp-sync json", "show_ospf_ldp_sync_r1_eth1_shutdown.ref"
+ )
+
+ for rname in ["r1", "r2", "r3"]:
+ router_compare_json_output(
+ rname, "show ip ospf interface json", "show_ip_ospf_interface_r1_eth1_shutdown.ref"
+ )
+
+def test_r1_eth1_no_shutdown():
+ logger.info("Test: verify behaviour after r1-eth1 is no shutdown")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Run no shutdown on r1-eth1 interface */
+ tgen = get_topogen()
+ tgen.gears["r1"].peer_link_enable("r1-eth1", True)
+ topotest.sleep(5, "Waiting for the network to reconverge")
+
+ for rname in ["r1", "r2", "r3"]:
+ router_compare_json_output(
+ rname, "show mpls ldp igp-sync json", "show_ldp_igp_sync.ref"
+ )
+
+ for rname in ["r1", "r2", "r3"]:
+ router_compare_json_output(
+ rname, "show ip ospf mpls ldp-sync json", "show_ospf_ldp_sync.ref"
+ )
+
+ for rname in ["r1", "r2", "r3"]:
+ router_compare_json_output(
+ rname, "show ip ospf interface json", "show_ip_ospf_interface.ref"
+ )
+
+def test_r2_eth1_shutdown():
+ logger.info("Test: verify behaviour after r2-eth1 is shutdown")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Shut down r1-r2 link */
+ tgen = get_topogen()
+ tgen.gears["r2"].peer_link_enable("r2-eth1", False)
+ topotest.sleep(5, "Waiting for the network to reconverge")
+
+ for rname in ["r1", "r2", "r3"]:
+ router_compare_json_output(
+ rname, "show mpls ldp igp-sync json", "show_ldp_igp_sync_r1_eth1_shutdown.ref"
+ )
+
+ for rname in ["r1", "r2", "r3"]:
+ router_compare_json_output(
+ rname, "show ip ospf mpls ldp-sync json", "show_ospf_ldp_sync_r2_eth1_shutdown.ref"
+ )
+
+ for rname in ["r1", "r2", "r3"]:
+ router_compare_json_output(
+ rname, "show ip ospf interface json", "show_ip_ospf_interface_r2_eth1_shutdown.ref"
+ )
+
+def test_r2_eth1_no_shutdown():
+ logger.info("Test: verify behaviour after r2-eth1 is no shutdown")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Run no shutdown on r2-eth1 interface */
+ tgen = get_topogen()
+ tgen.gears["r2"].peer_link_enable("r2-eth1", True)
+ topotest.sleep(5, "Waiting for the network to reconverge")
+
+ for rname in ["r1", "r2", "r3"]:
+ router_compare_json_output(
+ rname, "show mpls ldp igp-sync json", "show_ldp_igp_sync.ref"
+ )
+
+ for rname in ["r1", "r2", "r3"]:
+ router_compare_json_output(
+ rname, "show ip ospf mpls ldp-sync json", "show_ospf_ldp_sync.ref"
+ )
+
+ for rname in ["r1", "r2", "r3"]:
+ router_compare_json_output(
+ rname, "show ip ospf interface json", "show_ip_ospf_interface.ref"
+ )
+
+# Memory leak test template
+def test_memory_leak():
+ "Run the memory leak test and report results."
+ tgen = get_topogen()
+ if not tgen.is_memleak_enabled():
+ pytest.skip("Memory leak test/report is disabled")
+
+ tgen.report_memory_leaks()
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/ldp-vpls-topo1/test_ldp_vpls_topo1.py b/tests/topotests/ldp-vpls-topo1/test_ldp_vpls_topo1.py
index a1662dc411..0b8bf4de0e 100755..100644
--- a/tests/topotests/ldp-vpls-topo1/test_ldp_vpls_topo1.py
+++ b/tests/topotests/ldp-vpls-topo1/test_ldp_vpls_topo1.py
@@ -130,7 +130,7 @@ def setup_module(mod):
router_list = tgen.routers()
# For all registered routers, load the zebra configuration file
- for rname, router in router_list.iteritems():
+ for rname, router in router_list.items():
router.load_config(
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
)
diff --git a/tests/topotests/lib/bgp.py b/tests/topotests/lib/bgp.py
index e2f887bb89..a3d846edbb 100644
--- a/tests/topotests/lib/bgp.py
+++ b/tests/topotests/lib/bgp.py
@@ -367,7 +367,7 @@ def __create_bgp_unicast_neighbor(
bgp_data = input_dict["address_family"]
- for addr_type, addr_dict in bgp_data.iteritems():
+ for addr_type, addr_dict in bgp_data.items():
if not addr_dict:
continue
@@ -391,12 +391,11 @@ def __create_bgp_unicast_neighbor(
del_action = advertise_network_dict.setdefault("delete", False)
# Generating IPs for verification
- prefix = str(ipaddress.ip_network(unicode(network[0])).prefixlen)
network_list = generate_ips(network, no_of_network)
for ip in network_list:
- ip = str(ipaddress.ip_network(unicode(ip)).network_address)
+ ip = str(ipaddress.ip_network(unicode(ip)))
- cmd = "network {}/{}".format(ip, prefix)
+ cmd = "network {}".format(ip)
if del_action:
cmd = "no {}".format(cmd)
@@ -471,7 +470,7 @@ def __create_bgp_unicast_neighbor(
)
config_data.extend(neigh_data)
- for addr_type, addr_dict in bgp_data.iteritems():
+ for addr_type, addr_dict in bgp_data.items():
if not addr_dict or not check_address_types(addr_type):
continue
@@ -509,7 +508,7 @@ def __create_l2vpn_evpn_address_family(
bgp_data = input_dict["address_family"]
- for family_type, family_dict in bgp_data.iteritems():
+ for family_type, family_dict in bgp_data.items():
if family_type != "l2vpn":
continue
@@ -665,8 +664,8 @@ def __create_bgp_neighbor(topo, input_dict, router, addr_type, add_neigh=True):
bgp_data = input_dict["address_family"]
neigh_data = bgp_data[addr_type]["unicast"]["neighbor"]
- for name, peer_dict in neigh_data.iteritems():
- for dest_link, peer in peer_dict["dest_link"].iteritems():
+ for name, peer_dict in neigh_data.items():
+ for dest_link, peer in peer_dict["dest_link"].items():
nh_details = topo[name]
if "vrfs" in topo[router] or type(nh_details["bgp"]) is list:
@@ -770,8 +769,8 @@ def __create_bgp_unicast_address_family(
bgp_data = input_dict["address_family"]
neigh_data = bgp_data[addr_type]["unicast"]["neighbor"]
- for peer_name, peer_dict in deepcopy(neigh_data).iteritems():
- for dest_link, peer in peer_dict["dest_link"].iteritems():
+ for peer_name, peer_dict in deepcopy(neigh_data).items():
+ for dest_link, peer in peer_dict["dest_link"].items():
deactivate = None
activate = None
nh_details = topo[peer_name]
@@ -779,7 +778,7 @@ def __create_bgp_unicast_address_family(
deactivate_addr_family = peer.setdefault("deactivate", None)
# Loopback interface
if "source_link" in peer and peer["source_link"] == "lo":
- for destRouterLink, data in sorted(nh_details["links"].iteritems()):
+ for destRouterLink, data in sorted(nh_details["links"].items()):
if "type" in data and data["type"] == "loopback":
if dest_link == destRouterLink:
ip_addr = nh_details["links"][destRouterLink][
@@ -961,7 +960,7 @@ def modify_bgp_config_when_bgpd_down(tgen, topo, input_dict):
# Copy bgp config file to /etc/frr
for dut in input_dict.keys():
router_list = tgen.routers()
- for router, rnode in router_list.iteritems():
+ for router, rnode in router_list.items():
if router != dut:
continue
@@ -1083,7 +1082,7 @@ def verify_bgp_convergence(tgen, topo, dut=None):
"""
logger.debug("Entering lib API: verify_bgp_convergence()")
- for router, rnode in tgen.routers().iteritems():
+ for router, rnode in tgen.routers().items():
if "bgp" not in topo["routers"][router]:
continue
@@ -1462,9 +1461,9 @@ def verify_as_numbers(tgen, topo, input_dict):
bgp_neighbors = bgp_addr_type[addr_type]["unicast"]["neighbor"]
- for bgp_neighbor, peer_data in bgp_neighbors.iteritems():
+ for bgp_neighbor, peer_data in bgp_neighbors.items():
remote_as = input_dict[bgp_neighbor]["bgp"]["local_as"]
- for dest_link, peer_dict in peer_data["dest_link"].iteritems():
+ for dest_link, peer_dict in peer_data["dest_link"].items():
neighbor_ip = None
data = topo["routers"][bgp_neighbor]["links"]
@@ -1534,7 +1533,7 @@ def verify_bgp_convergence_from_running_config(tgen, dut=None):
logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
- for router, rnode in tgen.routers().iteritems():
+ for router, rnode in tgen.routers().items():
if dut is not None and dut != router:
continue
@@ -1686,8 +1685,8 @@ def clear_bgp_and_verify(tgen, topo, router):
for addr_type in bgp_addr_type:
bgp_neighbors = bgp_addr_type[addr_type]["unicast"]["neighbor"]
- for bgp_neighbor, peer_data in bgp_neighbors.iteritems():
- for dest_link, peer_dict in peer_data["dest_link"].iteritems():
+ for bgp_neighbor, peer_data in bgp_neighbors.items():
+ for dest_link, peer_dict in peer_data["dest_link"].items():
data = topo["routers"][bgp_neighbor]["links"]
if dest_link in data:
@@ -1768,8 +1767,8 @@ def clear_bgp_and_verify(tgen, topo, router):
for addr_type in bgp_addr_type:
bgp_neighbors = bgp_addr_type[addr_type]["unicast"]["neighbor"]
- for bgp_neighbor, peer_data in bgp_neighbors.iteritems():
- for dest_link, peer_dict in peer_data["dest_link"].iteritems():
+ for bgp_neighbor, peer_data in bgp_neighbors.items():
+ for dest_link, peer_dict in peer_data["dest_link"].items():
data = topo["routers"][bgp_neighbor]["links"]
if dest_link in data:
@@ -1873,8 +1872,8 @@ def verify_bgp_timers_and_functionality(tgen, topo, input_dict):
continue
bgp_neighbors = bgp_addr_type[addr_type]["unicast"]["neighbor"]
- for bgp_neighbor, peer_data in bgp_neighbors.iteritems():
- for dest_link, peer_dict in peer_data["dest_link"].iteritems():
+ for bgp_neighbor, peer_data in bgp_neighbors.items():
+ for dest_link, peer_dict in peer_data["dest_link"].items():
data = topo["routers"][bgp_neighbor]["links"]
keepalivetimer = peer_dict["keepalivetimer"]
@@ -2116,7 +2115,7 @@ def verify_bgp_attributes(
"""
logger.debug("Entering lib API: verify_bgp_attributes()")
- for router, rnode in tgen.routers().iteritems():
+ for router, rnode in tgen.routers().items():
if router != dut:
continue
@@ -2198,7 +2197,7 @@ def verify_bgp_attributes(
return True
-@retry(attempts=4, wait=2, return_is_str=True, initial_wait=2)
+@retry(attempts=5, wait=2, return_is_str=True)
def verify_best_path_as_per_bgp_attribute(
tgen, addr_type, router, input_dict, attribute
):
@@ -2330,7 +2329,7 @@ def verify_best_path_as_per_bgp_attribute(
# - rule is IGP>EGP>INCOMPLETE
_next_hop = [
key
- for (key, value) in attribute_dict.iteritems()
+ for (key, value) in attribute_dict.items()
if value == "IGP"
][0]
compare = ""
@@ -2513,7 +2512,7 @@ def verify_best_path_as_per_admin_distance(
return True
-@retry(attempts=5, wait=2, return_is_str=True, initial_wait=2)
+@retry(attempts=6, wait=2, return_is_str=True)
def verify_bgp_rib(tgen, addr_type, dut, input_dict, next_hop=None, aspath=None):
"""
This API is to verify whether bgp rib has any
@@ -2550,7 +2549,7 @@ def verify_bgp_rib(tgen, addr_type, dut, input_dict, next_hop=None, aspath=None)
list1 = []
list2 = []
for routerInput in input_dict.keys():
- for router, rnode in router_list.iteritems():
+ for router, rnode in router_list.items():
if router != dut:
continue
@@ -2773,7 +2772,7 @@ def verify_bgp_rib(tgen, addr_type, dut, input_dict, next_hop=None, aspath=None)
return True
-@retry(attempts=4, wait=2, return_is_str=True, initial_wait=2)
+@retry(attempts=5, wait=2, return_is_str=True)
def verify_graceful_restart(tgen, topo, addr_type, input_dict, dut, peer):
"""
This API is to verify verify_graceful_restart configuration of DUT and
@@ -2834,7 +2833,7 @@ def verify_graceful_restart(tgen, topo, addr_type, input_dict, dut, peer):
logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
- for router, rnode in tgen.routers().iteritems():
+ for router, rnode in tgen.routers().items():
if router != dut:
continue
@@ -3022,7 +3021,7 @@ def verify_graceful_restart(tgen, topo, addr_type, input_dict, dut, peer):
return True
-@retry(attempts=4, wait=2, return_is_str=True, initial_wait=2)
+@retry(attempts=5, wait=2, return_is_str=True)
def verify_r_bit(tgen, topo, addr_type, input_dict, dut, peer):
"""
This API is to verify r_bit in the BGP gr capability advertised
@@ -3082,7 +3081,7 @@ def verify_r_bit(tgen, topo, addr_type, input_dict, dut, peer):
logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
- for router, rnode in tgen.routers().iteritems():
+ for router, rnode in tgen.routers().items():
if router != dut:
continue
@@ -3140,7 +3139,7 @@ def verify_r_bit(tgen, topo, addr_type, input_dict, dut, peer):
return True
-@retry(attempts=4, wait=2, return_is_str=True, initial_wait=2)
+@retry(attempts=5, wait=2, return_is_str=True)
def verify_eor(tgen, topo, addr_type, input_dict, dut, peer):
"""
This API is to verify EOR
@@ -3200,7 +3199,7 @@ def verify_eor(tgen, topo, addr_type, input_dict, dut, peer):
"""
logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
- for router, rnode in tgen.routers().iteritems():
+ for router, rnode in tgen.routers().items():
if router != dut:
continue
@@ -3303,7 +3302,7 @@ def verify_eor(tgen, topo, addr_type, input_dict, dut, peer):
return True
-@retry(attempts=4, wait=2, return_is_str=True, initial_wait=2)
+@retry(attempts=5, wait=2, return_is_str=True)
def verify_f_bit(tgen, topo, addr_type, input_dict, dut, peer):
"""
This API is to verify f_bit in the BGP gr capability advertised
@@ -3365,7 +3364,7 @@ def verify_f_bit(tgen, topo, addr_type, input_dict, dut, peer):
logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
- for router, rnode in tgen.routers().iteritems():
+ for router, rnode in tgen.routers().items():
if router != dut:
continue
@@ -3443,7 +3442,7 @@ def verify_f_bit(tgen, topo, addr_type, input_dict, dut, peer):
return True
-@retry(attempts=4, wait=2, return_is_str=True, initial_wait=2)
+@retry(attempts=5, wait=2, return_is_str=True)
def verify_graceful_restart_timers(tgen, topo, addr_type, input_dict, dut, peer):
"""
This API is to verify graceful restart timers, configured and recieved
@@ -3491,7 +3490,7 @@ def verify_graceful_restart_timers(tgen, topo, addr_type, input_dict, dut, peer)
logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
- for router, rnode in tgen.routers().iteritems():
+ for router, rnode in tgen.routers().items():
if router != dut:
continue
@@ -3569,7 +3568,7 @@ def verify_graceful_restart_timers(tgen, topo, addr_type, input_dict, dut, peer)
return True
-@retry(attempts=4, wait=2, return_is_str=True, initial_wait=2)
+@retry(attempts=5, wait=2, return_is_str=True)
def verify_gr_address_family(tgen, topo, addr_type, addr_family, dut):
"""
This API is to verify gr_address_family in the BGP gr capability advertised
@@ -3595,7 +3594,7 @@ def verify_gr_address_family(tgen, topo, addr_type, addr_family, dut):
logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
- for router, rnode in tgen.routers().iteritems():
+ for router, rnode in tgen.routers().items():
if router != dut:
continue
@@ -3659,7 +3658,7 @@ def verify_gr_address_family(tgen, topo, addr_type, addr_family, dut):
logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
-@retry(attempts=5, wait=2, return_is_str=True, initial_wait=2)
+@retry(attempts=6, wait=2, return_is_str=True)
def verify_attributes_for_evpn_routes(
tgen,
topo,
@@ -4060,7 +4059,7 @@ def verify_attributes_for_evpn_routes(
return False
-@retry(attempts=5, wait=2, return_is_str=True, initial_wait=2)
+@retry(attempts=6, wait=2, return_is_str=True)
def verify_evpn_routes(
tgen, topo, dut, input_dict, routeType=5, EthTag=0, next_hop=None
):
diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py
index 1846d43138..6dd8d646f3 100644
--- a/tests/topotests/lib/common_config.py
+++ b/tests/topotests/lib/common_config.py
@@ -36,6 +36,8 @@ import ConfigParser
import traceback
import socket
import ipaddress
+import platform
+
if sys.version_info[0] > 2:
import io
@@ -46,7 +48,7 @@ else:
from lib.topolog import logger, logger_config
from lib.topogen import TopoRouter, get_topogen
-from lib.topotest import interface_set_status
+from lib.topotest import interface_set_status, version_cmp
FRRCFG_FILE = "frr_json.conf"
FRRCFG_BKUP_FILE = "frr_json_initial.conf"
@@ -256,6 +258,7 @@ def create_common_configuration(
"route_maps": "! Route Maps Config\n",
"bgp": "! BGP Config\n",
"vrf": "! VRF Config\n",
+ "ospf": "! OSPF Config\n",
}
)
@@ -352,7 +355,7 @@ def kill_mininet_routers_process(tgen):
"""
router_list = tgen.routers()
- for rname, router in router_list.iteritems():
+ for rname, router in router_list.items():
daemon_list = [
"zebra",
"ospfd",
@@ -379,7 +382,7 @@ def check_router_status(tgen):
try:
router_list = tgen.routers()
- for router, rnode in router_list.iteritems():
+ for router, rnode in router_list.items():
result = rnode.check_router_running()
if result != "":
@@ -609,7 +612,7 @@ def get_frr_ipv6_linklocal(tgen, router, intf=None, vrf=None):
"""
router_list = tgen.routers()
- for rname, rnode in router_list.iteritems():
+ for rname, rnode in router_list.items():
if rname != router:
continue
@@ -667,7 +670,7 @@ def generate_support_bundle():
test_name = sys._getframe(2).f_code.co_name
TMPDIR = os.path.join(LOGDIR, tgen.modname)
- for rname, rnode in router_list.iteritems():
+ for rname, rnode in router_list.items():
logger.info("Generating support bundle for {}".format(rname))
rnode.run("mkdir -p /var/log/frr")
bundle_log = rnode.run("python2 /usr/lib/frr/generate_support_bundle.py")
@@ -682,7 +685,7 @@ def generate_support_bundle():
return True
-def start_topology(tgen):
+def start_topology(tgen, daemon=None):
"""
Starting topology, create tmp files which are loaded to routers
to start deamons and then start routers
@@ -734,9 +737,16 @@ def start_topology(tgen):
router.load_config(
TopoRouter.RD_ZEBRA, "{}/{}/zebra.conf".format(TMPDIR, rname)
)
+
# Loading empty bgpd.conf file to router, to start the bgp deamon
router.load_config(TopoRouter.RD_BGP, "{}/{}/bgpd.conf".format(TMPDIR, rname))
+ if daemon and 'ospfd' in daemon:
+ # Loading empty ospf.conf file to router, to start the bgp deamon
+ router.load_config(
+ TopoRouter.RD_OSPF,
+ '{}/{}/ospfd.conf'.format(TMPDIR, rname)
+ )
# Starting routers
logger.info("Starting all routers once topology is created")
tgen.start_router()
@@ -809,6 +819,24 @@ def number_to_column(routerName):
return ord(routerName[0]) - 97
+def topo_daemons(tgen, topo):
+ """
+ Returns daemon list required for the suite based on topojson.
+ """
+ daemon_list = []
+
+ router_list = tgen.routers()
+ ROUTER_LIST = sorted(
+ router_list.keys(), key=lambda x: int(re_search("\d+", x).group(0))
+ )
+
+ for rtr in ROUTER_LIST:
+ if 'ospf' in topo['routers'][rtr] and 'ospfd' not in daemon_list:
+ daemon_list.append('ospfd')
+
+ return daemon_list
+
+
#############################################
# Common APIs, will be used by all protocols
#############################################
@@ -876,7 +904,7 @@ def create_vrf_cfg(tgen, topo, input_dict=None, build=False):
input_dict = deepcopy(input_dict)
try:
- for c_router, c_data in input_dict.iteritems():
+ for c_router, c_data in input_dict.items():
rnode = tgen.routers()[c_router]
if "vrfs" in c_data:
for vrf in c_data["vrfs"]:
@@ -921,7 +949,7 @@ def create_vrf_cfg(tgen, topo, input_dict=None, build=False):
if "links" in c_data:
for destRouterLink, data in sorted(
- c_data["links"].iteritems()
+ c_data["links"].items()
):
# Loopback interfaces
if "type" in data and data["type"] == "loopback":
@@ -1156,7 +1184,7 @@ def find_interface_with_greater_ip(topo, router, loopback=True, interface=True):
lo_list = []
interfaces_list = []
lo_exists = False
- for destRouterLink, data in sorted(link_data.iteritems()):
+ for destRouterLink, data in sorted(link_data.items()):
if loopback:
if "type" in data and data["type"] == "loopback":
lo_exists = True
@@ -1350,9 +1378,9 @@ def create_interfaces_cfg(tgen, topo, build=False):
topo = deepcopy(topo)
try:
- for c_router, c_data in topo.iteritems():
+ for c_router, c_data in topo.items():
interface_data = []
- for destRouterLink, data in sorted(c_data["links"].iteritems()):
+ for destRouterLink, data in sorted(c_data["links"].items()):
# Loopback interfaces
if "type" in data and data["type"] == "loopback":
interface_name = destRouterLink
@@ -1392,6 +1420,58 @@ def create_interfaces_cfg(tgen, topo, build=False):
else:
interface_data.append("ipv6 address {}\n".format(intf_addr))
+ if 'ospf' in data:
+ ospf_data = data['ospf']
+ if 'area' in ospf_data:
+ intf_ospf_area = c_data["links"][destRouterLink][
+ "ospf"]["area"]
+ if "delete" in data and data["delete"]:
+ interface_data.append("no ip ospf area")
+ else:
+ interface_data.append("ip ospf area {}".format(
+ intf_ospf_area
+ ))
+
+ if "hello_interval" in ospf_data:
+ intf_ospf_hello = c_data["links"][destRouterLink][
+ "ospf"]["hello_interval"]
+ if "delete" in data and data["delete"]:
+ interface_data.append("no ip ospf "\
+ " hello-interval")
+ else:
+ interface_data.append("ip ospf "\
+ " hello-interval {}".format(intf_ospf_hello))
+
+ if "dead_interval" in ospf_data:
+ intf_ospf_dead = c_data["links"][destRouterLink][
+ "ospf"]["dead_interval"]
+ if "delete" in data and data["delete"]:
+ interface_data.append("no ip ospf"\
+ " dead-interval")
+ else:
+ interface_data.append("ip ospf "\
+ " dead-interval {}".format(intf_ospf_dead))
+
+ if "network" in ospf_data:
+ intf_ospf_nw = c_data["links"][destRouterLink][
+ "ospf"]["network"]
+ if "delete" in data and data["delete"]:
+ interface_data.append("no ip ospf"\
+ " network {}".format(intf_ospf_nw))
+ else:
+ interface_data.append("ip ospf"\
+ " network {}".format(intf_ospf_nw))
+
+ if "priority" in ospf_data:
+ intf_ospf_nw = c_data["links"][destRouterLink][
+ "ospf"]["priority"]
+
+ if "delete" in data and data["delete"]:
+ interface_data.append("no ip ospf"\
+ " priority")
+ else:
+ interface_data.append("ip ospf"\
+ " priority {}".format(intf_ospf_nw))
result = create_common_configuration(
tgen, c_router, interface_data, "interface_config", build=build
)
@@ -1574,11 +1654,11 @@ def create_prefix_lists(tgen, input_dict, build=False):
config_data = []
prefix_lists = input_dict[router]["prefix_lists"]
- for addr_type, prefix_data in prefix_lists.iteritems():
+ for addr_type, prefix_data in prefix_lists.items():
if not check_address_types(addr_type):
continue
- for prefix_name, prefix_list in prefix_data.iteritems():
+ for prefix_name, prefix_list in prefix_data.items():
for prefix_dict in prefix_list:
if "action" not in prefix_dict or "network" not in prefix_dict:
errormsg = "'action' or network' missing in" " input_dict"
@@ -1715,7 +1795,7 @@ def create_route_maps(tgen, input_dict, build=False):
logger.debug("route_maps not present in input_dict")
continue
rmap_data = []
- for rmap_name, rmap_value in input_dict[router]["route_maps"].iteritems():
+ for rmap_name, rmap_value in input_dict[router]["route_maps"].items():
for rmap_dict in rmap_value:
del_action = rmap_dict.setdefault("delete", False)
@@ -2462,7 +2542,7 @@ def configure_interface_mac(tgen, input_dict):
#############################################
# Verification APIs
#############################################
-@retry(attempts=5, wait=2, return_is_str=True, initial_wait=2)
+@retry(attempts=6, wait=2, return_is_str=True)
def verify_rib(
tgen,
addr_type,
@@ -2527,7 +2607,7 @@ def verify_rib(
additional_nexthops_in_required_nhs = []
found_hops = []
for routerInput in input_dict.keys():
- for router, rnode in router_list.iteritems():
+ for router, rnode in router_list.items():
if router != dut:
continue
@@ -2880,7 +2960,7 @@ def verify_fib_routes(tgen, addr_type, dut, input_dict, next_hop=None):
router_list = tgen.routers()
for routerInput in input_dict.keys():
- for router, rnode in router_list.iteritems():
+ for router, rnode in router_list.items():
if router != dut:
continue
@@ -3136,7 +3216,7 @@ def verify_fib_routes(tgen, addr_type, dut, input_dict, next_hop=None):
router_list = tgen.routers()
for routerInput in input_dict.keys():
- for router, rnode in router_list.iteritems():
+ for router, rnode in router_list.items():
if router != dut:
continue
@@ -3495,7 +3575,7 @@ def verify_prefix_lists(tgen, input_dict):
return True
-@retry(attempts=2, wait=4, return_is_str=True, initial_wait=2)
+@retry(attempts=3, wait=4, return_is_str=True)
def verify_route_maps(tgen, input_dict):
"""
Running "show route-map" command and verifying given route-map
@@ -3746,7 +3826,7 @@ def verify_cli_json(tgen, input_dict):
return True
-@retry(attempts=2, wait=4, return_is_str=True, initial_wait=2)
+@retry(attempts=3, wait=4, return_is_str=True)
def verify_evpn_vni(tgen, input_dict):
"""
API to verify evpn vni details using "show evpn vni detail json"
@@ -3864,7 +3944,7 @@ def verify_evpn_vni(tgen, input_dict):
return False
-@retry(attempts=2, wait=4, return_is_str=True, initial_wait=2)
+@retry(attempts=3, wait=4, return_is_str=True)
def verify_vrf_vni(tgen, input_dict):
"""
API to verify vrf vni details using "show vrf vni json"
@@ -3973,3 +4053,30 @@ def verify_vrf_vni(tgen, input_dict):
logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
return False
+
+
+def required_linux_kernel_version(required_version):
+ """
+ This API is used to check linux version compatibility of the test suite.
+ If version mentioned in required_version is higher than the linux kernel
+ of the system, test suite will be skipped. This API returns true or errormsg.
+
+ Parameters
+ ----------
+ * `required_version` : Kernel version required for the suites to run.
+
+ Usage
+ -----
+ result = linux_kernel_version_lowerthan('4.15')
+
+ Returns
+ -------
+ errormsg(str) or True
+ """
+ system_kernel = platform.release()
+ if version_cmp(system_kernel, required_version) < 0:
+ error_msg = ('These tests will not run on kernel "{}", '
+ 'they require kernel >= {})'.format(system_kernel,
+ required_version ))
+ return error_msg
+ return True
diff --git a/tests/topotests/lib/ltemplate.py b/tests/topotests/lib/ltemplate.py
index a76d8e4b08..192c121008 100644
--- a/tests/topotests/lib/ltemplate.py
+++ b/tests/topotests/lib/ltemplate.py
@@ -82,7 +82,7 @@ class LTemplate():
router_list = tgen.routers()
# For all registred routers, load the zebra configuration file
- for rname, router in router_list.iteritems():
+ for rname, router in router_list.items():
logger.info("Setting up %s" % rname)
for rd_val in TopoRouter.RD:
config = os.path.join(self.testdir, '{}/{}.conf'.format(rname,TopoRouter.RD[rd_val]))
diff --git a/tests/topotests/lib/ospf.py b/tests/topotests/lib/ospf.py
new file mode 100644
index 0000000000..a2351bf747
--- /dev/null
+++ b/tests/topotests/lib/ospf.py
@@ -0,0 +1,1182 @@
+#
+# Copyright (c) 2020 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation, Inc.
+# ("NetDEF") in this file.
+#
+# 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 VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE 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.
+#
+
+from copy import deepcopy
+import traceback
+from time import sleep
+from lib.topolog import logger
+import ipaddr
+
+
+# Import common_config to use commomnly used APIs
+from lib.common_config import (create_common_configuration,
+ InvalidCLIError, retry,
+ generate_ips,
+ check_address_types,
+ validate_ip_address,
+ run_frr_cmd)
+
+LOGDIR = "/tmp/topotests/"
+TMPDIR = None
+
+################################
+# Configure procs
+################################
+
+def create_router_ospf(
+ tgen, topo, input_dict=None, build=False,
+ load_config=True):
+ """
+ API to configure ospf on router.
+
+ Parameters
+ ----------
+ * `tgen` : Topogen object
+ * `topo` : json file data
+ * `input_dict` : Input dict data, required when configuring from testcase
+ * `build` : Only for initial setup phase this is set as True.
+ * `load_config` : Loading the config to router this is set as True.
+
+ Usage
+ -----
+ input_dict = {
+ "r1": {
+ "ospf": {
+ "router_id": "22.22.22.22",
+ "area": [{ "id":0.0.0.0, "type": "nssa"}]
+ }
+ }
+
+ result = create_router_ospf(tgen, topo, input_dict)
+
+ Returns
+ -------
+ True or False
+ """
+ logger.debug("Entering lib API: create_router_ospf()")
+ result = False
+
+ if not input_dict:
+ input_dict = deepcopy(topo)
+ else:
+ topo = topo["routers"]
+ input_dict = deepcopy(input_dict)
+
+ for router in input_dict.keys():
+ if "ospf" not in input_dict[router]:
+ logger.debug("Router %s: 'ospf' not present in input_dict", router)
+ continue
+
+ result = __create_ospf_global(
+ tgen, input_dict, router, build, load_config)
+ if result is True:
+ ospf_data = input_dict[router]["ospf"]
+
+
+ logger.debug("Exiting lib API: create_router_ospf()")
+ return result
+
+
+def __create_ospf_global(
+ tgen, input_dict, router, build=False,
+ load_config=True):
+ """
+ Helper API to create ospf global configuration.
+
+ Parameters
+ ----------
+ * `tgen` : Topogen object
+ * `input_dict` : Input dict data, required when configuring from testcase
+ * `router` : router to be configured.
+ * `build` : Only for initial setup phase this is set as True.
+ * `load_config` : Loading the config to router this is set as True.
+
+ Returns
+ -------
+ True or False
+ """
+
+ result = False
+ logger.debug("Entering lib API: __create_ospf_global()")
+ try:
+
+ ospf_data = input_dict[router]["ospf"]
+ del_ospf_action = ospf_data.setdefault("delete", False)
+ if del_ospf_action:
+ config_data = ["no router ospf"]
+ result = create_common_configuration(tgen, router, config_data,
+ "ospf", build,
+ load_config)
+ return result
+
+ config_data = []
+ cmd = "router ospf"
+
+ config_data.append(cmd)
+
+ # router id
+ router_id = ospf_data.setdefault("router_id", None)
+ del_router_id = ospf_data.setdefault("del_router_id", False)
+ if del_router_id:
+ config_data.append("no ospf router-id")
+ if router_id:
+ config_data.append("ospf router-id {}".format(
+ router_id))
+
+ # redistribute command
+ redistribute_data = ospf_data.setdefault("redistribute", {})
+ if redistribute_data:
+ for redistribute in redistribute_data:
+ if "redist_type" not in redistribute:
+ logger.debug("Router %s: 'redist_type' not present in "
+ "input_dict", router)
+ else:
+ cmd = "redistribute {}".format(
+ redistribute["redist_type"])
+ for red_type in redistribute_data:
+ if "route_map" in red_type:
+ cmd = cmd + " route-map {}".format(red_type[
+ 'route_map'])
+ del_action = redistribute.setdefault("delete", False)
+ if del_action:
+ cmd = "no {}".format(cmd)
+ config_data.append(cmd)
+ #area information
+ area_data = ospf_data.setdefault("area", {})
+ if area_data:
+ for area in area_data:
+ if "id" not in area:
+ logger.debug("Router %s: 'area id' not present in "
+ "input_dict", router)
+ else:
+ cmd = "area {}".format(area["id"])
+
+ if "type" in area:
+ cmd = cmd + " {}".format(area["type"])
+
+ del_action = area.setdefault("delete", False)
+ if del_action:
+ cmd = "no {}".format(cmd)
+ config_data.append(cmd)
+ result = create_common_configuration(tgen, router, config_data,
+ "ospf", build, load_config)
+
+ # summary information
+ summary_data = ospf_data.setdefault("summary-address", {})
+ if summary_data:
+ for summary in summary_data:
+ if "prefix" not in summary:
+ logger.debug("Router %s: 'summary-address' not present in "
+ "input_dict", router)
+ else:
+ cmd = "summary {}/{}".format(summary["prefix"], summary[
+ "mask"])
+
+ _tag = summary.setdefault("tag", None)
+ if _tag:
+ cmd = "{} tag {}".format(cmd, _tag)
+
+ _advertise = summary.setdefault("advertise", True)
+ if not _advertise:
+ cmd = "{} no-advertise".format(cmd)
+
+ del_action = summary.setdefault("delete", False)
+ if del_action:
+ cmd = "no {}".format(cmd)
+ config_data.append(cmd)
+ result = create_common_configuration(tgen, router, config_data,
+ "ospf", build, load_config)
+
+ except InvalidCLIError:
+ # Traceback
+ errormsg = traceback.format_exc()
+ logger.error(errormsg)
+ return errormsg
+
+ logger.debug("Exiting lib API: create_ospf_global()")
+ return result
+
+
+def create_router_ospf6(
+ tgen, topo, input_dict=None, build=False,
+ load_config=True):
+ """
+ API to configure ospf on router
+
+ Parameters
+ ----------
+ * `tgen` : Topogen object
+ * `topo` : json file data
+ * `input_dict` : Input dict data, required when configuring from testcase
+ * `build` : Only for initial setup phase this is set as True.
+
+ Usage
+ -----
+ input_dict = {
+ "r1": {
+ "ospf6": {
+ "router_id": "22.22.22.22",
+ }
+ }
+
+ Returns
+ -------
+ True or False
+ """
+ logger.debug("Entering lib API: create_router_ospf()")
+ result = False
+
+ if not input_dict:
+ input_dict = deepcopy(topo)
+ else:
+ topo = topo["routers"]
+ input_dict = deepcopy(input_dict)
+ for router in input_dict.keys():
+ if "ospf" not in input_dict[router]:
+ logger.debug("Router %s: 'ospf' not present in input_dict", router)
+ continue
+
+ result = __create_ospf_global(
+ tgen, input_dict, router, build, load_config)
+
+ logger.debug("Exiting lib API: create_router_ospf()")
+ return result
+
+
+def __create_ospf6_global(
+ tgen, input_dict, router, build=False,
+ load_config=True):
+ """
+ Helper API to create ospf global configuration.
+
+ Parameters
+ ----------
+ * `tgen` : Topogen object
+ * `input_dict` : Input dict data, required when configuring from testcase
+ * `router` : router id to be configured.
+ * `build` : Only for initial setup phase this is set as True.
+
+ Returns
+ -------
+ True or False
+ """
+
+ result = False
+ logger.debug("Entering lib API: __create_ospf_global()")
+ try:
+
+ ospf_data = input_dict[router]["ospf6"]
+ del_ospf_action = ospf_data.setdefault("delete", False)
+ if del_ospf_action:
+ config_data = ["no ipv6 router ospf"]
+ result = create_common_configuration(tgen, router, config_data,
+ "ospf", build,
+ load_config)
+ return result
+
+ config_data = []
+ cmd = "router ospf"
+
+ config_data.append(cmd)
+
+ router_id = ospf_data.setdefault("router_id", None)
+ del_router_id = ospf_data.setdefault("del_router_id", False)
+ if del_router_id:
+ config_data.append("no ospf router-id")
+ if router_id:
+ config_data.append("ospf router-id {}".format(
+ router_id))
+
+ result = create_common_configuration(tgen, router, config_data,
+ "ospf", build, load_config)
+ except InvalidCLIError:
+ # Traceback
+ errormsg = traceback.format_exc()
+ logger.error(errormsg)
+ return errormsg
+
+ logger.debug("Exiting lib API: create_ospf_global()")
+ return result
+
+def config_ospf_interface (tgen, topo, input_dict=None, build=False,
+ load_config=True):
+ """
+ API to configure ospf on router.
+
+ Parameters
+ ----------
+ * `tgen` : Topogen object
+ * `topo` : json file data
+ * `input_dict` : Input dict data, required when configuring from testcase
+ * `build` : Only for initial setup phase this is set as True.
+ * `load_config` : Loading the config to router this is set as True.
+
+ Usage
+ -----
+ r1_ospf_auth = {
+ "r1": {
+ "links": {
+ "r2": {
+ "ospf": {
+ "authentication": 'message-digest',
+ "authentication-key": "ospf",
+ "message-digest-key": "10"
+ }
+ }
+ }
+ }
+ }
+ result = config_ospf_interface(tgen, topo, r1_ospf_auth)
+
+ Returns
+ -------
+ True or False
+ """
+ logger.debug("Enter lib config_ospf_interface")
+ if not input_dict:
+ input_dict = deepcopy(topo)
+ else:
+ input_dict = deepcopy(input_dict)
+ for router in input_dict.keys():
+ config_data = []
+ 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)
+ continue
+ ospf_data = input_dict[router]['links'][lnk]['ospf']
+ data_ospf_area = ospf_data.setdefault("area", None)
+ data_ospf_auth = ospf_data.setdefault("authentication", None)
+ data_ospf_dr_priority = ospf_data.setdefault("priority", None)
+ data_ospf_cost = ospf_data.setdefault("cost", None)
+
+ try:
+ intf = topo['routers'][router]['links'][lnk]['interface']
+ except KeyError:
+ intf = topo['switches'][router]['links'][lnk]['interface']
+
+ # interface
+ cmd = "interface {}".format(intf)
+
+ config_data.append(cmd)
+ # interface area config
+ if data_ospf_area:
+ cmd = "ip ospf area {}".format(data_ospf_area)
+ config_data.append(cmd)
+ # interface ospf auth
+ if data_ospf_auth:
+ if data_ospf_auth == 'null':
+ cmd = "ip ospf authentication null"
+ elif data_ospf_auth == 'message-digest':
+ cmd = "ip ospf authentication message-digest"
+ else:
+ cmd = "ip ospf authentication"
+
+ if 'del_action' in ospf_data:
+ cmd = "no {}".format(cmd)
+ config_data.append(cmd)
+
+ if "message-digest-key" in ospf_data:
+ cmd = "ip ospf message-digest-key {} md5 {}".format(
+ ospf_data["message-digest-key"],ospf_data[
+ "authentication-key"])
+ if 'del_action' in ospf_data:
+ cmd = "no {}".format(cmd)
+ config_data.append(cmd)
+
+ if "authentication-key" in ospf_data and \
+ "message-digest-key" not in ospf_data:
+ cmd = "ip ospf authentication-key {}".format(ospf_data[
+ "authentication-key"])
+ if 'del_action' in ospf_data:
+ cmd = "no {}".format(cmd)
+ config_data.append(cmd)
+
+ # interface ospf dr priority
+ if data_ospf_dr_priority in ospf_data:
+ cmd = "ip ospf priority {}".format(
+ ospf_data["priority"])
+ if 'del_action' in ospf_data:
+ cmd = "no {}".format(cmd)
+ config_data.append(cmd)
+
+ # interface ospf cost
+ if data_ospf_cost in ospf_data:
+ cmd = "ip ospf cost {}".format(
+ ospf_data["cost"])
+ if 'del_action' in ospf_data:
+ cmd = "no {}".format(cmd)
+ config_data.append(cmd)
+
+ if build:
+ return config_data
+ else:
+ result = create_common_configuration(tgen, router, config_data,
+ "interface_config",
+ build=build)
+ logger.debug("Exiting lib API: create_igmp_config()")
+ return result
+
+def clear_ospf(tgen, router):
+ """
+ This API is to clear ospf neighborship by running
+ clear ip ospf interface * command,
+
+ Parameters
+ ----------
+ * `tgen`: topogen object
+ * `router`: device under test
+
+ Usage
+ -----
+ clear_ospf(tgen, "r1")
+ """
+
+ logger.debug("Entering lib API: clear_ospf()")
+ if router not in tgen.routers():
+ return False
+
+ rnode = tgen.routers()[router]
+
+ # Clearing OSPF
+ logger.info("Clearing ospf process for router %s..", router)
+
+ run_frr_cmd(rnode, "clear ip ospf interface ")
+
+ logger.debug("Exiting lib API: clear_ospf()")
+
+
+################################
+# Verification procs
+################################
+@retry(attempts=40, wait=2, return_is_str=True)
+def verify_ospf_neighbor(tgen, topo, dut=None, input_dict=None, lan=False):
+ """
+ This API is to verify ospf neighborship by running
+ show ip ospf neighbour command,
+
+ Parameters
+ ----------
+ * `tgen` : Topogen object
+ * `topo` : json file data
+ * `dut`: device under test
+ * `input_dict` : Input dict data, required when configuring from testcase
+ * `lan` : verify neighbors in lan topology
+
+ Usage
+ -----
+ 1. To check FULL neighbors.
+ verify_ospf_neighbor(tgen, topo, dut=dut)
+
+ 2. To check neighbors with their roles.
+ input_dict = {
+ "r0": {
+ "ospf": {
+ "neighbors": {
+ "r1": {
+ "state": "Full",
+ "role": "DR"
+ },
+ "r2": {
+ "state": "Full",
+ "role": "DROther"
+ },
+ "r3": {
+ "state": "Full",
+ "role": "DROther"
+ }
+ }
+ }
+ }
+ }
+ result = verify_ospf_neighbor(tgen, topo, dut, input_dict, lan=True)
+
+ Returns
+ -------
+ True or False (Error Message)
+ """
+ logger.debug("Entering lib API: verify_ospf_neighbor()")
+ result = False
+ if input_dict:
+ for router, rnode in tgen.routers().iteritems():
+ if 'ospf' not in topo['routers'][router]:
+ continue
+
+ if dut is not None and dut != router:
+ continue
+
+ logger.info("Verifying OSPF neighborship on router %s:", router)
+ show_ospf_json = run_frr_cmd(rnode,
+ "show ip ospf neighbor all json", isjson=True)
+
+ # Verifying output dictionary show_ospf_json is empty or not
+ if not bool(show_ospf_json):
+ errormsg = "OSPF is not running"
+ return errormsg
+
+ ospf_data_list = input_dict[router]["ospf"]
+ ospf_nbr_list = ospf_data_list['neighbors']
+
+ for ospf_nbr, nbr_data in ospf_nbr_list.items():
+ data_ip = topo['routers'][ospf_nbr]['links']
+ data_rid = topo['routers'][ospf_nbr]['ospf']['router_id']
+ if ospf_nbr in data_ip:
+ nbr_details = nbr_data[ospf_nbr]
+ elif lan:
+ for switch in topo['switches']:
+ if 'ospf' in topo['switches'][switch]['links'][router]:
+ neighbor_ip = data_ip[switch]['ipv4'].split("/")[0]
+ else:
+ continue
+ else:
+ neighbor_ip = data_ip[router]['ipv4'].split("/")[0]
+
+ nh_state = None
+ neighbor_ip = neighbor_ip.lower()
+ nbr_rid = data_rid
+ try:
+ nh_state = show_ospf_json[nbr_rid][0][
+ 'state'].split('/')[0]
+ intf_state = show_ospf_json[nbr_rid][0][
+ 'state'].split('/')[1]
+ except KeyError:
+ errormsg = "[DUT: {}] OSPF peer {} missing".format(router,
+ nbr_rid)
+ return errormsg
+
+ nbr_state = nbr_data.setdefault("state",None)
+ nbr_role = nbr_data.setdefault("role",None)
+
+ if nbr_state:
+ if nbr_state == nh_state:
+ logger.info("[DUT: {}] OSPF Nbr is {}:{} State {}".format
+ (router, ospf_nbr, nbr_rid, nh_state))
+ result = True
+ else:
+ errormsg = ("[DUT: {}] OSPF is not Converged, neighbor"
+ " state is {}".format(router, nh_state))
+ return errormsg
+ if nbr_role:
+ if nbr_role == intf_state:
+ logger.info("[DUT: {}] OSPF Nbr is {}: {} Role {}".format(
+ router, ospf_nbr, nbr_rid, nbr_role))
+ else:
+ errormsg = ("[DUT: {}] OSPF is not Converged with rid"
+ "{}, role is {}".format(router, nbr_rid, intf_state))
+ return errormsg
+ continue
+ else:
+ for router, rnode in tgen.routers().iteritems():
+ if 'ospf' not in topo['routers'][router]:
+ continue
+
+ if dut is not None and dut != router:
+ continue
+
+ logger.info("Verifying OSPF neighborship on router %s:", router)
+ show_ospf_json = run_frr_cmd(rnode,
+ "show ip ospf neighbor all json", isjson=True)
+ # Verifying output dictionary show_ospf_json is empty or not
+ if not bool(show_ospf_json):
+ errormsg = "OSPF is not running"
+ return errormsg
+
+ ospf_data_list = topo["routers"][router]["ospf"]
+ ospf_neighbors = ospf_data_list['neighbors']
+ total_peer = 0
+ total_peer = len(ospf_neighbors.keys())
+ no_of_ospf_nbr = 0
+ ospf_nbr_list = ospf_data_list['neighbors']
+ no_of_peer = 0
+ for ospf_nbr, nbr_data in ospf_nbr_list.items():
+ if nbr_data:
+ data_ip = topo['routers'][nbr_data["nbr"]]['links']
+ data_rid = topo['routers'][nbr_data["nbr"]][
+ 'ospf']['router_id']
+ else:
+ data_ip = topo['routers'][ospf_nbr]['links']
+ data_rid = topo['routers'][ospf_nbr]['ospf']['router_id']
+ if ospf_nbr in data_ip:
+ nbr_details = nbr_data[ospf_nbr]
+ elif lan:
+ for switch in topo['switches']:
+ if 'ospf' in topo['switches'][switch]['links'][router]:
+ neighbor_ip = data_ip[switch]['ipv4'].split("/")[0]
+ else:
+ continue
+ else:
+ neighbor_ip = data_ip[router]['ipv4'].split("/")[0]
+
+ nh_state = None
+ neighbor_ip = neighbor_ip.lower()
+ nbr_rid = data_rid
+ try:
+ nh_state = show_ospf_json[nbr_rid][0][
+ 'state'].split('/')[0]
+ except KeyError:
+ errormsg = "[DUT: {}] OSPF peer {} missing,from "\
+ "{} ".format(router,
+ nbr_rid, ospf_nbr)
+ return errormsg
+
+ if nh_state == 'Full':
+ no_of_peer += 1
+
+ if no_of_peer == total_peer:
+ logger.info("[DUT: {}] OSPF is Converged".format(router))
+ result = True
+ else:
+ errormsg = ("[DUT: {}] OSPF is not Converged".format(router))
+ return errormsg
+
+ logger.debug("Exiting API: verify_ospf_neighbor()")
+ return result
+
+@retry(attempts=21, wait=2, return_is_str=True)
+def verify_ospf_rib(tgen, dut, input_dict, next_hop=None,
+ tag=None, metric=None, fib=None):
+ """
+ This API is to verify ospf routes by running
+ show ip ospf route command.
+
+ Parameters
+ ----------
+ * `tgen` : Topogen object
+ * `dut`: device under test
+ * `input_dict` : Input dict data, required when configuring from testcase
+ * `next_hop` : next to be verified
+ * `tag` : tag to be verified
+ * `metric` : metric to be verified
+ * `fib` : True if the route is installed in FIB.
+
+ Usage
+ -----
+ input_dict = {
+ "r1": {
+ "static_routes": [
+ {
+ "network": ip_net,
+ "no_of_ip": 1,
+ "routeType": "N"
+ }
+ ]
+ }
+ }
+
+ result = verify_ospf_rib(tgen, dut, input_dict,next_hop=nh)
+
+ Returns
+ -------
+ True or False (Error Message)
+ """
+
+ logger.info("Entering lib API: verify_ospf_rib()")
+ result = False
+ router_list = tgen.routers()
+ additional_nexthops_in_required_nhs = []
+ found_hops = []
+ for routerInput in input_dict.keys():
+ for router, rnode in router_list.iteritems():
+ if router != dut:
+ continue
+
+ logger.info("Checking router %s RIB:", router)
+
+ # Verifying RIB routes
+ command = "show ip ospf route"
+
+ found_routes = []
+ missing_routes = []
+
+ if "static_routes" in input_dict[routerInput] or \
+ "prefix" in input_dict[routerInput]:
+ if "prefix" in input_dict[routerInput]:
+ static_routes = input_dict[routerInput]["prefix"]
+ else:
+ static_routes = input_dict[routerInput]["static_routes"]
+
+
+ for static_route in static_routes:
+ cmd = "{}".format(command)
+
+ cmd = "{} json".format(cmd)
+
+ ospf_rib_json = run_frr_cmd(rnode, cmd, isjson=True)
+
+ # Verifying output dictionary ospf_rib_json is not empty
+ if bool(ospf_rib_json) is False:
+ errormsg = "[DUT: {}] No routes found in OSPF route " \
+ "table".format(router)
+ return errormsg
+
+ network = static_route["network"]
+ no_of_ip = static_route.setdefault("no_of_ip", 1)
+ _tag = static_route.setdefault("tag", None)
+ _rtype = static_route.setdefault("routeType", None)
+
+
+ # Generating IPs for verification
+ ip_list = generate_ips(network, no_of_ip)
+ st_found = False
+ nh_found = False
+
+ for st_rt in ip_list:
+ st_rt = str(ipaddr.IPNetwork(unicode(st_rt)))
+
+ _addr_type = validate_ip_address(st_rt)
+ if _addr_type != 'ipv4':
+ continue
+
+ if st_rt in ospf_rib_json:
+ st_found = True
+ found_routes.append(st_rt)
+
+ if fib and next_hop:
+ if type(next_hop) is not list:
+ next_hop = [next_hop]
+
+ for mnh in range(0, len(ospf_rib_json[st_rt])):
+ if 'fib' in ospf_rib_json[st_rt][
+ mnh]["nexthops"][0]:
+ found_hops.append([rib_r[
+ "ip"] for rib_r in ospf_rib_json[
+ st_rt][mnh]["nexthops"]])
+
+ if found_hops[0]:
+ missing_list_of_nexthops = \
+ set(found_hops[0]).difference(next_hop)
+ additional_nexthops_in_required_nhs = \
+ set(next_hop).difference(found_hops[0])
+
+ if additional_nexthops_in_required_nhs:
+ logger.info(
+ "Nexthop "
+ "%s is not active for route %s in "
+ "RIB of router %s\n",
+ additional_nexthops_in_required_nhs,
+ st_rt, dut)
+ errormsg = (
+ "Nexthop {} is not active"
+ " for route {} in RIB of router"
+ " {}\n".format(
+ additional_nexthops_in_required_nhs,
+ st_rt, dut))
+ return errormsg
+ else:
+ nh_found = True
+
+ elif next_hop and fib is None:
+ if type(next_hop) is not list:
+ next_hop = [next_hop]
+ found_hops = [rib_r["ip"] for rib_r in
+ ospf_rib_json[st_rt][
+ "nexthops"]]
+
+ if found_hops:
+ missing_list_of_nexthops = \
+ set(found_hops).difference(next_hop)
+ additional_nexthops_in_required_nhs = \
+ set(next_hop).difference(found_hops)
+
+ if additional_nexthops_in_required_nhs:
+ logger.info(
+ "Missing nexthop %s for route"\
+ " %s in RIB of router %s\n", \
+ additional_nexthops_in_required_nhs, \
+ st_rt, dut)
+ errormsg=("Nexthop {} is Missing for "\
+ "route {} in RIB of router {}\n".format(
+ additional_nexthops_in_required_nhs,
+ st_rt, dut))
+ return errormsg
+ else:
+ nh_found = True
+ if _rtype:
+ if "routeType" not in ospf_rib_json[
+ st_rt]:
+ errormsg = ("[DUT: {}]: routeType missing"
+ "for route {} in OSPF RIB \n".\
+ format(dut, st_rt))
+ return errormsg
+ elif _rtype != ospf_rib_json[st_rt][
+ "routeType"]:
+ errormsg = ("[DUT: {}]: routeType mismatch"
+ "for route {} in OSPF RIB \n".\
+ format(dut, st_rt))
+ return errormsg
+ else:
+ logger.info("DUT: {}]: Found routeType {}"
+ "for route {}".\
+ format(dut, _rtype, st_rt))
+ if tag:
+ if "tag" not in ospf_rib_json[
+ st_rt]:
+ errormsg = ("[DUT: {}]: tag is not"
+ " present for"
+ " route {} in RIB \n".\
+ format(dut, st_rt
+ ))
+ return errormsg
+
+ if _tag != ospf_rib_json[
+ st_rt]["tag"]:
+ errormsg = ("[DUT: {}]: tag value {}"
+ " is not matched for"
+ " route {} in RIB \n".\
+ format(dut, _tag, st_rt,
+ ))
+ return errormsg
+
+ if metric is not None:
+ if "type2cost" not in ospf_rib_json[
+ st_rt]:
+ errormsg = ("[DUT: {}]: metric is"
+ " not present for"
+ " route {} in RIB \n".\
+ format(dut, st_rt))
+ return errormsg
+
+ if metric != ospf_rib_json[
+ st_rt]["type2cost"]:
+ errormsg = ("[DUT: {}]: metric value "
+ "{} is not matched for "
+ "route {} in RIB \n".\
+ format(dut, metric, st_rt,
+ ))
+ return errormsg
+
+ else:
+ missing_routes.append(st_rt)
+
+ if nh_found:
+ logger.info("[DUT: {}]: Found next_hop {} for all OSPF"
+ " routes in RIB".format(router, next_hop))
+
+ if len(missing_routes) > 0:
+ errormsg = ("[DUT: {}]: Missing route in RIB, "
+ "routes: {}".\
+ format(dut, missing_routes))
+ return errormsg
+
+ if found_routes:
+ logger.info("[DUT: %s]: Verified routes in RIB, found"
+ " routes are: %s\n", dut, found_routes)
+ result = True
+
+ logger.info("Exiting lib API: verify_ospf_rib()")
+ return result
+
+
+@retry(attempts=10, wait=2, return_is_str=True)
+def verify_ospf_interface(tgen, topo, dut=None,lan=False, input_dict=None):
+ """
+ This API is to verify ospf routes by running
+ show ip ospf interface command.
+
+ Parameters
+ ----------
+ * `tgen` : Topogen object
+ * `topo` : topology descriptions
+ * `dut`: device under test
+ * `lan`: if set to true this interface belongs to LAN.
+ * `input_dict` : Input dict data, required when configuring from testcase
+
+ Usage
+ -----
+ input_dict= {
+ 'r0': {
+ 'links':{
+ 's1': {
+ 'ospf':{
+ 'priority':98,
+ 'timerDeadSecs': 4,
+ 'area': '0.0.0.3',
+ 'mcastMemberOspfDesignatedRouters': True,
+ 'mcastMemberOspfAllRouters': True,
+ 'ospfEnabled': True,
+
+ }
+ }
+ }
+ }
+ }
+ result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
+
+ Returns
+ -------
+ True or False (Error Message)
+ """
+
+ logger.debug("Entering lib API: verify_ospf_interface()")
+ result = False
+ for router, rnode in tgen.routers().iteritems():
+ if 'ospf' not in topo['routers'][router]:
+ continue
+
+ if dut is not None and dut != router:
+ continue
+
+ logger.info("Verifying OSPF interface on router %s:", router)
+ show_ospf_json = run_frr_cmd(rnode, "show ip ospf interface json",
+ isjson=True)
+
+ # Verifying output dictionary show_ospf_json is empty or not
+ if not bool(show_ospf_json):
+ errormsg = "OSPF is not running"
+ return errormsg
+
+ # To find neighbor ip type
+ ospf_intf_data = input_dict[router]["links"]
+ for ospf_intf, intf_data in ospf_intf_data.items():
+ intf = topo['routers'][router]['links'][ospf_intf]['interface']
+ if intf in show_ospf_json['interfaces']:
+ for intf_attribute in intf_data['ospf']:
+ if intf_data['ospf'][intf_attribute] == show_ospf_json[
+ 'interfaces'][intf][intf_attribute]:
+ logger.info("[DUT: %s] OSPF interface %s: %s is %s",
+ router, intf, intf_attribute, intf_data['ospf'][
+ intf_attribute])
+ else:
+ errormsg= "[DUT: {}] OSPF interface {}: {} is {}, \
+ Expected is {}".format(router, intf, intf_attribute,
+ intf_data['ospf'][intf_attribute], show_ospf_json[
+ 'interfaces'][intf][intf_attribute])
+ return errormsg
+ result = True
+ logger.debug("Exiting API: verify_ospf_interface()")
+ return result
+
+
+@retry(attempts=11, wait=2, return_is_str=True)
+def verify_ospf_database(tgen, topo, dut, input_dict):
+ """
+ This API is to verify ospf lsa's by running
+ show ip ospf database command.
+
+ Parameters
+ ----------
+ * `tgen` : Topogen object
+ * `dut`: device under test
+ * `input_dict` : Input dict data, required when configuring from testcase
+ * `topo` : next to be verified
+
+ Usage
+ -----
+ input_dict = {
+ "areas": {
+ "0.0.0.0": {
+ "Router Link States": {
+ "100.1.1.0-100.1.1.0": {
+ "LSID": "100.1.1.0",
+ "Advertised router": "100.1.1.0",
+ "LSA Age": 130,
+ "Sequence Number": "80000006",
+ "Checksum": "a703",
+ "Router links": 3
+ }
+ },
+ "Net Link States": {
+ "10.0.0.2-100.1.1.1": {
+ "LSID": "10.0.0.2",
+ "Advertised router": "100.1.1.1",
+ "LSA Age": 137,
+ "Sequence Number": "80000001",
+ "Checksum": "9583"
+ }
+ },
+ },
+ }
+ }
+ result = verify_ospf_database(tgen, topo, dut, input_dict)
+
+ Returns
+ -------
+ True or False (Error Message)
+ """
+
+ result = False
+ router = dut
+ logger.debug("Entering lib API: verify_ospf_database()")
+
+ if 'ospf' not in topo['routers'][dut]:
+ errormsg = "[DUT: {}] OSPF is not configured on the router.".format(
+ dut)
+ return errormsg
+
+ rnode = tgen.routers()[dut]
+
+ logger.info("Verifying OSPF interface on router %s:", dut)
+ show_ospf_json = run_frr_cmd(rnode, "show ip ospf database json",
+ isjson=True)
+ # Verifying output dictionary show_ospf_json is empty or not
+ if not bool(show_ospf_json):
+ errormsg = "OSPF is not running"
+ return errormsg
+
+ # for inter and inter lsa's
+ ospf_db_data = input_dict.setdefault("areas", None)
+ ospf_external_lsa = input_dict.setdefault(
+ 'AS External Link States', None)
+ if ospf_db_data:
+ for ospf_area, area_lsa in ospf_db_data.items():
+ if ospf_area in show_ospf_json['areas']:
+ if 'Router Link States' in area_lsa:
+ for lsa in area_lsa['Router Link States']:
+ if lsa in show_ospf_json['areas'][ospf_area][
+ 'Router Link States']:
+ logger.info(
+ "[DUT: %s] OSPF LSDB area %s:Router "
+ "LSA %s", router, ospf_area, lsa)
+ result = True
+ else:
+ errormsg = \
+ "[DUT: {}] OSPF LSDB area {}: expected" \
+ " Router LSA is {}".format(router, ospf_area, lsa)
+ return errormsg
+ if 'Net Link States' in area_lsa:
+ for lsa in area_lsa['Net Link States']:
+ if lsa in show_ospf_json['areas'][ospf_area][
+ 'Net Link States']:
+ logger.info(
+ "[DUT: %s] OSPF LSDB area %s:Network "
+ "LSA %s", router, ospf_area, lsa)
+ result = True
+ else:
+ errormsg = \
+ "[DUT: {}] OSPF LSDB area {}: expected" \
+ " Network LSA is {}".format(router, ospf_area, lsa)
+ return errormsg
+ if 'Summary Link States' in area_lsa:
+ for lsa in area_lsa['Summary Link States']:
+ if lsa in show_ospf_json['areas'][ospf_area][
+ 'Summary Link States']:
+ logger.info(
+ "[DUT: %s] OSPF LSDB area %s:Summary "
+ "LSA %s", router, ospf_area, lsa)
+ result = True
+ else:
+ errormsg = \
+ "[DUT: {}] OSPF LSDB area {}: expected" \
+ " Summary LSA is {}".format(router, ospf_area, lsa)
+ return errormsg
+ if 'ASBR-Summary Link States' in area_lsa:
+ for lsa in area_lsa['ASBR-Summary Link States']:
+ if lsa in show_ospf_json['areas'][ospf_area][
+ 'ASBR-Summary Link States']:
+ logger.info(
+ "[DUT: %s] OSPF LSDB area %s:ASBR Summary "
+ "LSA %s", router, ospf_area, lsa)
+ result = True
+ else:
+ errormsg = \
+ "[DUT: {}] OSPF LSDB area {}: expected" \
+ " ASBR Summary LSA is {}".format(
+ router, ospf_area, lsa)
+ return errormsg
+ if ospf_external_lsa:
+ for ospf_ext_lsa, ext_lsa_data in ospf_external_lsa.items():
+ if ospf_ext_lsa in show_ospf_json['AS External Link States']:
+ logger.info(
+ "[DUT: %s] OSPF LSDB:External LSA %s",
+ router, ospf_ext_lsa)
+ result = True
+ else:
+ errormsg = \
+ "[DUT: {}] OSPF LSDB : expected" \
+ " External LSA is {}".format(router, ospf_ext_lsa)
+ return errormsg
+
+ logger.debug("Exiting API: verify_ospf_database()")
+ return result
+
+
+
+@retry(attempts=10, wait=2, return_is_str=True)
+def verify_ospf_summary(tgen, topo, dut, input_dict):
+ """
+ This API is to verify ospf routes by running
+ show ip ospf interface command.
+
+ Parameters
+ ----------
+ * `tgen` : Topogen object
+ * `topo` : topology descriptions
+ * `dut`: device under test
+ * `input_dict` : Input dict data, required when configuring from testcase
+
+ Usage
+ -----
+ input_dict = {
+ "11.0.0.0/8": {
+ "Summary address": "11.0.0.0/8",
+ "Metric-type": "E2",
+ "Metric": 20,
+ "Tag": 0,
+ "External route count": 5
+ }
+ }
+ result = verify_ospf_summary(tgen, topo, dut, input_dict)
+
+ Returns
+ -------
+ True or False (Error Message)
+ """
+
+ logger.debug("Entering lib API: verify_ospf_summary()")
+ result = False
+ router = dut
+
+ logger.info("Verifying OSPF summary on router %s:", router)
+
+ if 'ospf' not in topo['routers'][dut]:
+ errormsg = "[DUT: {}] OSPF is not configured on the router.".format(
+ router)
+ return errormsg
+
+ rnode = tgen.routers()[dut]
+ show_ospf_json = run_frr_cmd(rnode, "show ip ospf summary detail json",
+ isjson=True)
+
+ # Verifying output dictionary show_ospf_json is empty or not
+ if not bool(show_ospf_json):
+ errormsg = "OSPF is not running"
+ return errormsg
+
+ # To find neighbor ip type
+ ospf_summary_data = input_dict
+ for ospf_summ, summ_data in ospf_summary_data.items():
+ if ospf_summ not in show_ospf_json:
+ continue
+ summary = ospf_summary_data[ospf_summ]['Summary address']
+ if summary in show_ospf_json:
+ for summ in summ_data:
+ if summ_data[summ] == show_ospf_json[summary][summ]:
+ logger.info("[DUT: %s] OSPF summary %s:%s is %s",
+ router, summary, summ, summ_data[summ])
+ result = True
+ else:
+ errormsg = ("[DUT: {}] OSPF summary {}:{} is %s, "
+ "Expected is {}".format(router,summary, summ,
+ show_ospf_json[summary][summ]))
+ return errormsg
+
+ logger.debug("Exiting API: verify_ospf_summary()")
+ return result
diff --git a/tests/topotests/lib/topogen.py b/tests/topotests/lib/topogen.py
index a6cc5280ec..b9f82877e2 100644
--- a/tests/topotests/lib/topogen.py
+++ b/tests/topotests/lib/topogen.py
@@ -254,7 +254,7 @@ class Topogen(object):
```py
tgen = get_topogen()
router_dict = tgen.get_gears(TopoRouter)
- for router_name, router in router_dict.iteritems():
+ for router_name, router in router_dict.items():
# Do stuff
```
* List iteration:
@@ -267,7 +267,7 @@ class Topogen(object):
"""
return dict(
(name, gear)
- for name, gear in self.gears.iteritems()
+ for name, gear in self.gears.items()
if isinstance(gear, geartype)
)
@@ -316,7 +316,7 @@ class Topogen(object):
"""
if router is None:
# pylint: disable=r1704
- for _, router in self.routers().iteritems():
+ for _, router in self.routers().items():
router.start()
else:
if isinstance(router, str):
@@ -430,7 +430,7 @@ class TopoGear(object):
def __str__(self):
links = ""
- for myif, dest in self.links.iteritems():
+ for myif, dest in self.links.items():
_, destif = dest
if links != "":
links += ","
@@ -684,7 +684,7 @@ class TopoRouter(TopoGear):
# Enable all daemon command logging, logging files
# and set them to the start dir.
- for daemon, enabled in nrouter.daemons.iteritems():
+ for daemon, enabled in nrouter.daemons.items():
if enabled == 0:
continue
self.vtysh_cmd(
@@ -733,7 +733,7 @@ class TopoRouter(TopoGear):
# Enable all daemon command logging, logging files
# and set them to the start dir.
- for daemon, enabled in nrouter.daemons.iteritems():
+ for daemon, enabled in nrouter.daemons.items():
for d in daemons:
if enabled == 0:
continue
diff --git a/tests/topotests/lib/topojson.py b/tests/topotests/lib/topojson.py
index 9c2baedde4..b3af09aa99 100644
--- a/tests/topotests/lib/topojson.py
+++ b/tests/topotests/lib/topojson.py
@@ -23,6 +23,9 @@ from json import dumps as json_dumps
from re import search as re_search
import ipaddress
import pytest
+import ipaddr
+from copy import deepcopy
+
# Import topogen and topotest helpers
from lib.topolog import logger
@@ -41,7 +44,7 @@ from lib.common_config import (
)
from lib.bgp import create_router_bgp
-
+from lib.ospf import create_router_ospf
ROUTER_LIST = []
@@ -58,12 +61,27 @@ def build_topo_from_json(tgen, topo):
topo["routers"].keys(), key=lambda x: int(re_search("\d+", x).group(0))
)
+ SWITCH_LIST = []
+ if "switches" in topo:
+ SWITCH_LIST = sorted(
+ topo["switches"].keys(), key=lambda x: int(re_search("\d+", x).group(0))
+ )
+
listRouters = ROUTER_LIST[:]
+ listSwitches = SWITCH_LIST[:]
+ listAllRouters = deepcopy(listRouters)
+ dictSwitches = {}
+
for routerN in ROUTER_LIST:
logger.info("Topo: Add router {}".format(routerN))
tgen.add_router(routerN)
listRouters.append(routerN)
+ for switchN in SWITCH_LIST:
+ logger.info("Topo: Add switch {}".format(switchN))
+ dictSwitches[switchN] = tgen.add_switch(switchN)
+ listSwitches.append(switchN)
+
if "ipv4base" in topo:
ipv4Next = ipaddress.IPv4Address(topo["link_ip_start"]["ipv4"])
ipv4Step = 2 ** (32 - topo["link_ip_start"]["v4mask"])
@@ -91,7 +109,7 @@ def build_topo_from_json(tgen, topo):
return int(re_search("\d+", x).group(0))
for destRouterLink, data in sorted(
- topo["routers"][curRouter]["links"].iteritems(),
+ topo["routers"][curRouter]["links"].items(),
key=lambda x: link_sort(x[0]),
):
currRouter_lo_json = topo["routers"][curRouter]["links"][destRouterLink]
@@ -191,6 +209,72 @@ def build_topo_from_json(tgen, topo):
),
)
+ switch_count = 0
+ add_switch_to_topo = []
+ while listSwitches != []:
+ curSwitch = listSwitches.pop(0)
+ # Physical Interfaces
+ if "links" in topo['switches'][curSwitch]:
+ for destRouterLink, data in sorted(
+ topo['switches'][curSwitch]['links'].iteritems()):
+
+ # Loopback interfaces
+ if "dst_node" in data:
+ destRouter = data['dst_node']
+
+ elif "-" in destRouterLink:
+ # Spliting and storing destRouterLink data in tempList
+ tempList = destRouterLink.split("-")
+ # destRouter
+ destRouter = tempList.pop(0)
+ else:
+ destRouter = destRouterLink
+
+ if destRouter in listAllRouters:
+
+ topo['routers'][destRouter]['links'][curSwitch] = \
+ deepcopy(topo['switches'][curSwitch]['links'][destRouterLink])
+
+ # Assigning name to interfaces
+ topo['routers'][destRouter]['links'][curSwitch]['interface'] = \
+ '{}-{}-eth{}'.format(destRouter, curSwitch, topo['routers'] \
+ [destRouter]['nextIfname'])
+
+ topo['switches'][curSwitch]['links'][destRouter]['interface'] = \
+ '{}-{}-eth{}'.format(curSwitch, destRouter, topo['routers'] \
+ [destRouter]['nextIfname'])
+
+ topo['routers'][destRouter]['nextIfname'] += 1
+
+ # Add links
+ dictSwitches[curSwitch].add_link(tgen.gears[destRouter], \
+ topo['switches'][curSwitch]['links'][destRouter]['interface'],
+ topo['routers'][destRouter]['links'][curSwitch]['interface'],
+ )
+
+ # IPv4
+ if 'ipv4' in topo['routers'][destRouter]['links'][curSwitch]:
+ if topo['routers'][destRouter]['links'][curSwitch]['ipv4'] == 'auto':
+ topo['routers'][destRouter]['links'][curSwitch]['ipv4'] = \
+ '{}/{}'.format(ipv4Next, topo['link_ip_start'][ \
+ 'v4mask'])
+ ipv4Next += 1
+ # IPv6
+ if 'ipv6' in topo['routers'][destRouter]['links'][curSwitch]:
+ if topo['routers'][destRouter]['links'][curSwitch]['ipv6'] == 'auto':
+ topo['routers'][destRouter]['links'][curSwitch]['ipv6'] = \
+ '{}/{}'.format(ipv6Next, topo['link_ip_start'][ \
+ 'v6mask'])
+ ipv6Next = ipaddr.IPv6Address(int(ipv6Next) + ipv6Step)
+
+ logger.debug(
+ "Generated link data for router: %s\n%s",
+ curRouter,
+ json_dumps(
+ topo["routers"][curRouter]["links"], indent=4, sort_keys=True
+ ),
+ )
+
def build_config_from_json(tgen, topo, save_bkup=True):
"""
@@ -210,6 +294,7 @@ def build_config_from_json(tgen, topo, save_bkup=True):
("bgp_community_list", create_bgp_community_lists),
("route_maps", create_route_maps),
("bgp", create_router_bgp),
+ ("ospf", create_router_ospf)
]
)
diff --git a/tests/topotests/ospf-sr-topo1/test_ospf_sr_topo1.py b/tests/topotests/ospf-sr-topo1/test_ospf_sr_topo1.py
index 6792c56b3b..86fc90e665 100755..100644
--- a/tests/topotests/ospf-sr-topo1/test_ospf_sr_topo1.py
+++ b/tests/topotests/ospf-sr-topo1/test_ospf_sr_topo1.py
@@ -93,7 +93,7 @@ def setup_module(mod):
router_list = tgen.routers()
- for rname, router in router_list.iteritems():
+ for rname, router in router_list.items():
router.load_config(
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
)
diff --git a/tests/topotests/ospf-topo1-vrf/test_ospf_topo1_vrf.py b/tests/topotests/ospf-topo1-vrf/test_ospf_topo1_vrf.py
index 130d0c85f9..4ec09b10d3 100755..100644
--- a/tests/topotests/ospf-topo1-vrf/test_ospf_topo1_vrf.py
+++ b/tests/topotests/ospf-topo1-vrf/test_ospf_topo1_vrf.py
@@ -84,7 +84,7 @@ def setup_module(mod):
router_list = tgen.routers()
# check for zebra capability
- for rname, router in router_list.iteritems():
+ for rname, router in router_list.items():
if router.check_capability(TopoRouter.RD_ZEBRA, "--vrfwnetns") == False:
return pytest.skip(
"Skipping OSPF VRF NETNS feature. VRF NETNS backend not available on FRR"
@@ -106,7 +106,7 @@ def setup_module(mod):
"ip netns exec {0}-cust1 ifconfig {0}-eth1 up",
]
- for rname, router in router_list.iteritems():
+ for rname, router in router_list.items():
# create VRF rx-cust1 and link rx-eth0 to rx-cust1
for cmd in cmds:
@@ -141,7 +141,7 @@ def teardown_module(mod):
]
router_list = tgen.routers()
- for rname, router in router_list.iteritems():
+ for rname, router in router_list.items():
for cmd in cmds:
tgen.net[rname].cmd(cmd.format(rname))
tgen.stop_topology()
@@ -169,7 +169,7 @@ def test_ospf_convergence():
if tgen.routers_have_failure():
pytest.skip("skipped because of router(s) failure")
- for rname, router in tgen.routers().iteritems():
+ for rname, router in tgen.routers().items():
logger.info('Waiting for router "%s" convergence', rname)
# Load expected results from the command
@@ -216,7 +216,7 @@ def test_ospf_json():
if tgen.routers_have_failure():
pytest.skip("skipped because of router(s) failure")
- for rname, router in tgen.routers().iteritems():
+ for rname, router in tgen.routers().items():
logger.info(
'Comparing router "%s" "show ip ospf vrf %s-cust1 json" output',
router.name,
@@ -283,7 +283,7 @@ def test_ospf_link_down():
)
# Expect convergence on all routers
- for rname, router in tgen.routers().iteritems():
+ for rname, router in tgen.routers().items():
logger.info('Waiting for router "%s" convergence after link failure', rname)
# Load expected results from the command
reffile = os.path.join(CWD, "{}/ospfroute_down.txt".format(rname))
diff --git a/tests/topotests/ospf-topo1/test_ospf_topo1.py b/tests/topotests/ospf-topo1/test_ospf_topo1.py
index d734f378e7..3af60fd48f 100755..100644
--- a/tests/topotests/ospf-topo1/test_ospf_topo1.py
+++ b/tests/topotests/ospf-topo1/test_ospf_topo1.py
@@ -95,7 +95,7 @@ def setup_module(mod):
ospf6_config = "ospf6d.conf-pre-v4"
router_list = tgen.routers()
- for rname, router in router_list.iteritems():
+ for rname, router in router_list.items():
router.load_config(
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
)
@@ -146,7 +146,7 @@ def test_ospf_convergence():
if tgen.routers_have_failure():
pytest.skip("skipped because of router(s) failure")
- for router, rnode in tgen.routers().iteritems():
+ for router, rnode in tgen.routers().items():
logger.info('Waiting for router "%s" convergence', router)
# Load expected results from the command
@@ -335,7 +335,7 @@ def test_ospf_link_down():
router3.peer_link_enable("r3-eth0", False)
# Expect convergence on all routers
- for router, rnode in tgen.routers().iteritems():
+ for router, rnode in tgen.routers().items():
logger.info('Waiting for router "%s" convergence after link failure', router)
# Load expected results from the command
reffile = os.path.join(CWD, "{}/ospfroute_down.txt".format(router))
diff --git a/tests/topotests/ospf-topo2/test_ospf_topo2.py b/tests/topotests/ospf-topo2/test_ospf_topo2.py
index a04d841214..0b6f568462 100755..100644
--- a/tests/topotests/ospf-topo2/test_ospf_topo2.py
+++ b/tests/topotests/ospf-topo2/test_ospf_topo2.py
@@ -76,7 +76,7 @@ def setup_module(mod):
tgen.start_topology()
router_list = tgen.routers()
- for rname, router in router_list.iteritems():
+ for rname, router in router_list.items():
router.load_config(
TopoRouter.RD_ZEBRA,
os.path.join(CWD, '{}/zebra.conf'.format(rname))
@@ -118,7 +118,7 @@ def test_ospf_convergence():
if tgen.routers_have_failure():
pytest.skip('skipped because of router(s) failure')
- for router, rnode in tgen.routers().iteritems():
+ for router, rnode in tgen.routers().items():
logger.info('Waiting for router "%s" convergence', router)
json_file = '{}/{}/ospf-route.json'.format(CWD, router)
diff --git a/tests/topotests/ospf6-topo1/test_ospf6_topo1.py b/tests/topotests/ospf6-topo1/test_ospf6_topo1.py
index 30c09ea606..8e3a329f10 100755..100644
--- a/tests/topotests/ospf6-topo1/test_ospf6_topo1.py
+++ b/tests/topotests/ospf6-topo1/test_ospf6_topo1.py
@@ -164,7 +164,7 @@ def setup_module(mod):
# tgen.mininet_cli()
router_list = tgen.routers()
- for rname, router in router_list.iteritems():
+ for rname, router in router_list.items():
router.load_config(
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
)
@@ -209,7 +209,7 @@ def test_ospf6_converged():
sys.stdout.flush()
# Look for any node not yet converged
- for router, rnode in tgen.routers().iteritems():
+ for router, rnode in tgen.routers().items():
resStr = rnode.vtysh_cmd("show ipv6 ospf neigh")
isConverged = False
@@ -287,7 +287,7 @@ def test_ospfv3_routingTable():
# tgen.mininet_cli()
# Verify OSPFv3 Routing Table
- for router, rnode in tgen.routers().iteritems():
+ for router, rnode in tgen.routers().items():
logger.info('Waiting for router "%s" convergence', router)
# Load expected results from the command
diff --git a/tests/topotests/ospf_basic_functionality/ospf_authentication.json b/tests/topotests/ospf_basic_functionality/ospf_authentication.json
new file mode 100644
index 0000000000..4edb9f25a8
--- /dev/null
+++ b/tests/topotests/ospf_basic_functionality/ospf_authentication.json
@@ -0,0 +1,166 @@
+{
+ "ipv4base": "10.0.0.0",
+ "ipv4mask": 24,
+ "link_ip_start": {
+ "ipv4": "10.0.0.0",
+ "v4mask": 24
+ },
+ "lo_prefix": {
+ "ipv4": "1.0.",
+ "v4mask": 32
+ },
+ "routers": {
+ "r0": {
+ "links": {
+ "r1": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r2": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r3": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ }
+ },
+ "ospf": {
+ "router_id": "100.1.1.0",
+ "neighbors": {
+ "r1": {},
+ "r2": {},
+ "r3": {}
+ },
+ "redistribute": [
+ {
+ "redist_type": "static"
+ },
+ {
+ "redist_type": "connected"
+ }
+ ]
+ }
+ },
+ "r1": {
+ "links": {
+ "r0": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r2": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r3": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ }
+ },
+ "ospf": {
+ "router_id": "100.1.1.1",
+ "neighbors": {
+ "r0": {},
+ "r2": {},
+ "r3": {}
+ }
+ }
+ },
+ "r2": {
+ "links": {
+ "r0": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r1": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r3": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ }
+ },
+ "ospf": {
+ "router_id": "100.1.1.2",
+ "neighbors": {
+ "r1": {},
+ "r0": {},
+ "r3": {}
+ }
+ }
+ },
+ "r3": {
+ "links": {
+ "r0": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r1": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r2": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ }
+ },
+ "ospf": {
+ "router_id": "100.1.1.3",
+ "neighbors": {
+ "r0": {},
+ "r1": {},
+ "r2": {}
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/topotests/ospf_basic_functionality/ospf_ecmp.json b/tests/topotests/ospf_basic_functionality/ospf_ecmp.json
new file mode 100644
index 0000000000..ea5b9a4655
--- /dev/null
+++ b/tests/topotests/ospf_basic_functionality/ospf_ecmp.json
@@ -0,0 +1,342 @@
+{
+
+ "ipv4base": "10.0.0.0",
+ "ipv4mask": 24,
+ "link_ip_start": {
+ "ipv4": "10.0.0.0",
+ "v4mask": 24
+ },
+ "lo_prefix": {
+ "ipv4": "1.0.",
+ "v4mask": 32
+ },
+ "routers": {
+ "r0": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "type": "loopback"
+ },
+ "r1": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r1-link1": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r1-link2": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r1-link3": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r1-link4": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r1-link5": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r1-link6": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r1-link7": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r2": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r3": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4,
+ "network": "point-to-point"
+ }
+ }
+ },
+ "ospf": {
+ "router_id": "100.1.1.0",
+ "neighbors": {
+ "r1": {},
+ "r1-link1": {
+ "nbr": "r1"
+ },
+ "r1-link2": {
+ "nbr": "r1"
+ },
+ "r1-link3": {
+ "nbr": "r1"
+ },
+ "r1-link4": {
+ "nbr": "r1"
+ },
+ "r1-link5": {
+ "nbr": "r1"
+ },
+ "r1-link6": {
+ "nbr": "r1"
+ },
+ "r1-link7": {
+ "nbr": "r1"
+ },
+ "r2": {},
+ "r3": {}
+ }
+ }
+ },
+ "r1": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "type": "loopback"
+ },
+ "r0": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r0-link1": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r0-link2": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r0-link3": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r0-link4": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r0-link5": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r0-link6": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r0-link7": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r2": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r3": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r3-link0": {
+ "ipv4": "auto",
+ "description": "DummyIntftoR3"
+ }
+ },
+ "ospf": {
+ "router_id": "100.1.1.1",
+ "neighbors": {
+ "r0": {},
+ "r0-link1": {
+ "nbr": "r0"
+ },
+ "r0-link2": {
+ "nbr": "r0"
+ },
+ "r0-link3": {
+ "nbr": "r0"
+ },
+ "r0-link4": {
+ "nbr": "r0"
+ },
+ "r0-link5": {
+ "nbr": "r0"
+ },
+ "r0-link6": {
+ "nbr": "r0"
+ },
+ "r0-link7": {
+ "nbr": "r0"
+ },
+ "r2": {},
+ "r3": {}
+ }
+ }
+ },
+ "r2": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "type": "loopback"
+ },
+ "r0": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r1": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r3": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ }
+ },
+ "ospf": {
+ "router_id": "100.1.1.2",
+ "neighbors": {
+ "r1": {},
+ "r0": {},
+ "r3": {}
+ }
+ }
+ },
+ "r3": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "type": "loopback"
+ },
+ "r0": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4,
+ "network": "point-to-point"
+ }
+ },
+ "r1": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r2": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r1-link0": {
+ "ipv4": "auto",
+ "description": "DummyIntftoR1",
+ "ospf": {
+ "area": "0.0.0.0"
+ }
+ }
+ },
+ "ospf": {
+ "router_id": "100.1.1.3",
+ "neighbors": {
+ "r0": {},
+ "r1": {},
+ "r2": {}
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/topotests/ospf_basic_functionality/ospf_ecmp_lan.json b/tests/topotests/ospf_basic_functionality/ospf_ecmp_lan.json
new file mode 100644
index 0000000000..ecfd35d639
--- /dev/null
+++ b/tests/topotests/ospf_basic_functionality/ospf_ecmp_lan.json
@@ -0,0 +1,234 @@
+{
+
+ "ipv4base": "10.0.0.0",
+ "ipv4mask": 24,
+ "link_ip_start": {
+ "ipv4": "10.0.0.0",
+ "v4mask": 24
+ },
+ "lo_prefix": {
+ "ipv4": "1.0.",
+ "v4mask": 32
+ },
+ "switches": {
+ "s1": {
+ "links": {
+ "r0": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.3",
+ "hello_interval": 1,
+ "dead_interval": 4,
+ "priority": 98
+ }
+ },
+ "r1": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.3",
+ "hello_interval": 1,
+ "dead_interval": 4,
+ "priority": 99
+ }
+ },
+ "r2": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.3",
+ "hello_interval": 1,
+ "dead_interval": 4,
+ "priority": 0
+ }
+ },
+ "r3": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.3",
+ "hello_interval": 1,
+ "dead_interval": 4,
+ "priority": 0
+ }
+ },
+ "r4": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.3",
+ "hello_interval": 1,
+ "dead_interval": 4,
+ "priority": 0
+ }
+ },
+ "r5": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.3",
+ "hello_interval": 1,
+ "dead_interval": 4,
+ "priority": 0
+ }
+ },
+ "r6": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.3",
+ "hello_interval": 1,
+ "dead_interval": 4,
+ "priority": 0
+ }
+ },
+ "r7": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.3",
+ "hello_interval": 1,
+ "dead_interval": 4,
+ "priority": 0
+ }
+ }
+ }
+ }
+ },
+ "routers": {
+ "r0": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "type": "loopback"
+ }
+ },
+ "ospf": {
+ "router_id": "100.1.1.0",
+ "neighbors": {
+ "r1": {},
+ "r2": {},
+ "r3": {}
+ }
+ }
+ },
+ "r1": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "type": "loopback"
+ },
+ "r3-link0": {
+ "ipv4": "auto",
+ "description": "DummyIntftoR3"
+ }
+ },
+ "ospf": {
+ "router_id": "100.1.1.1",
+ "neighbors": {
+ "r0": {},
+ "r2": {},
+ "r3": {}
+ }
+ }
+ },
+ "r2": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "type": "loopback"
+ }
+ },
+ "ospf": {
+ "router_id": "100.1.1.2",
+ "area": [{
+ "id": "0.0.0.2",
+ "type": "nssa"
+ }],
+ "neighbors": {
+ "r1": {},
+ "r0": {}
+ }
+ }
+ },
+ "r3": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "type": "loopback"
+ },
+ "r1-link0": {
+ "ipv4": "auto",
+ "description": "DummyIntftoR1",
+ "ospf": {
+ "area": "0.0.0.3"
+ }
+ }
+ },
+ "ospf": {
+ "router_id": "100.1.1.3",
+ "area": [{
+ "id": "0.0.0.2",
+ "type": "nssa"
+ }],
+ "neighbors": {
+ "r0": {},
+ "r1": {}
+ }
+ }
+ },
+ "r4": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "type": "loopback"
+ }
+ },
+ "ospf": {
+ "router_id": "100.1.1.4",
+ "neighbors": {
+ "r0": {},
+ "r1": {}
+ }
+ }
+ },
+ "r5": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "type": "loopback"
+ }
+ },
+ "ospf": {
+ "router_id": "100.1.1.5",
+ "neighbors": {
+ "r0": {},
+ "r1": {}
+ }
+ }
+ },
+ "r6": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "type": "loopback"
+ }
+ },
+ "ospf": {
+ "router_id": "100.1.1.6",
+ "neighbors": {
+ "r0": {},
+ "r1": {}
+ }
+ }
+ },
+ "r7": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "type": "loopback"
+ }
+ },
+ "ospf": {
+ "router_id": "100.1.1.7",
+ "neighbors": {
+ "r0": {},
+ "r1": {}
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/topotests/ospf_basic_functionality/ospf_lan.json b/tests/topotests/ospf_basic_functionality/ospf_lan.json
new file mode 100644
index 0000000000..126934c344
--- /dev/null
+++ b/tests/topotests/ospf_basic_functionality/ospf_lan.json
@@ -0,0 +1,138 @@
+{
+
+ "ipv4base": "10.0.0.0",
+ "ipv4mask": 24,
+ "link_ip_start": {
+ "ipv4": "10.0.0.0",
+ "v4mask": 24
+ },
+ "lo_prefix": {
+ "ipv4": "1.0.",
+ "v4mask": 32
+ },
+ "switches": {
+ "s1": {
+ "links": {
+ "r0": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.3",
+ "hello_interval": 1,
+ "dead_interval": 4,
+ "priority": 98
+ }
+ },
+ "r1": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.3",
+ "hello_interval": 1,
+ "dead_interval": 4,
+ "priority": 99
+ }
+ },
+ "r2": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.3",
+ "hello_interval": 1,
+ "dead_interval": 4,
+ "priority": 0
+ }
+ },
+ "r3": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.3",
+ "hello_interval": 1,
+ "dead_interval": 4,
+ "priority": 0
+ }
+ }
+ }
+ }
+ },
+ "routers": {
+ "r0": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "type": "loopback"
+ }
+ },
+ "ospf": {
+ "router_id": "100.1.1.0",
+ "neighbors": {
+ "r1": {},
+ "r2": {},
+ "r3": {}
+ }
+ }
+ },
+ "r1": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "type": "loopback"
+ },
+ "r3-link0": {
+ "ipv4": "auto",
+ "description": "DummyIntftoR3"
+ }
+ },
+ "ospf": {
+ "router_id": "100.1.1.1",
+ "neighbors": {
+ "r0": {},
+ "r2": {},
+ "r3": {}
+ }
+ }
+ },
+ "r2": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "type": "loopback"
+ }
+ },
+ "ospf": {
+ "router_id": "100.1.1.2",
+ "area": [{
+ "id": "0.0.0.2",
+ "type": "nssa"
+ }],
+ "neighbors": {
+ "r1": {},
+ "r0": {}
+ }
+ }
+ },
+ "r3": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "type": "loopback"
+ },
+ "r1-link0": {
+ "ipv4": "auto",
+ "description": "DummyIntftoR1",
+ "ospf": {
+ "area": "0.0.0.3"
+ }
+ }
+ },
+ "ospf": {
+ "router_id": "100.1.1.3",
+ "area": [{
+ "id": "0.0.0.2",
+ "type": "nssa"
+ }],
+ "neighbors": {
+ "r0": {},
+ "r1": {}
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/topotests/ospf_basic_functionality/ospf_nssa.json b/tests/topotests/ospf_basic_functionality/ospf_nssa.json
new file mode 100644
index 0000000000..f95a297bb3
--- /dev/null
+++ b/tests/topotests/ospf_basic_functionality/ospf_nssa.json
@@ -0,0 +1,188 @@
+{
+
+ "ipv4base": "10.0.0.0",
+ "ipv4mask": 24,
+ "link_ip_start": {
+ "ipv4": "10.0.0.0",
+ "v4mask": 24
+ },
+ "lo_prefix": {
+ "ipv4": "1.0.",
+ "v4mask": 32
+ },
+ "routers": {
+ "r0": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "type": "loopback"
+ },
+ "r1": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r2": {
+ "ipv4": "auto"
+ },
+ "r3": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4,
+ "network": "point-to-point"
+ }
+ }
+ },
+ "ospf": {
+ "router_id": "100.1.1.0",
+ "neighbors": {
+ "r1": {},
+ "r3": {}
+ }
+ }
+ },
+ "r1": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "type": "loopback"
+ },
+ "r0": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r2": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.2",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r3": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.2",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r3-link0": {
+ "ipv4": "auto",
+ "description": "DummyIntftoR3"
+ }
+ },
+ "ospf": {
+ "router_id": "100.1.1.1",
+ "area": [{
+ "id": "0.0.0.2",
+ "type": "nssa"
+ }],
+ "neighbors": {
+ "r0": {},
+ "r2": {},
+ "r3": {}
+ }
+ }
+ },
+ "r2": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "type": "loopback"
+ },
+ "r0": {
+ "ipv4": "auto"
+ },
+ "r1": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.2",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r3": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.2",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ }
+ },
+ "ospf": {
+ "router_id": "100.1.1.2",
+ "area": [{
+ "id": "0.0.0.2",
+ "type": "nssa"
+ }],
+ "neighbors": {
+ "r1": {},
+ "r3": {}
+ }
+ }
+ },
+ "r3": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "type": "loopback"
+ },
+ "r0": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4,
+ "network": "point-to-point"
+ }
+ },
+ "r1": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.2",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r2": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.2",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r1-link0": {
+ "ipv4": "auto",
+ "description": "DummyIntftoR1",
+ "ospf": {
+ "area": "0.0.0.3"
+ }
+ }
+ },
+ "ospf": {
+ "router_id": "100.1.1.3",
+ "area": [{
+ "id": "0.0.0.2",
+ "type": "nssa"
+ }],
+ "neighbors": {
+ "r0": {},
+ "r1": {},
+ "r2": {}
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/topotests/ospf_basic_functionality/ospf_routemaps.json b/tests/topotests/ospf_basic_functionality/ospf_routemaps.json
new file mode 100644
index 0000000000..60a8434d42
--- /dev/null
+++ b/tests/topotests/ospf_basic_functionality/ospf_routemaps.json
@@ -0,0 +1,159 @@
+{
+
+ "ipv4base": "10.0.0.0",
+ "ipv4mask": 24,
+ "link_ip_start": {
+ "ipv4": "10.0.0.0",
+ "v4mask": 24
+ },
+ "lo_prefix": {
+ "ipv4": "1.0.",
+ "v4mask": 32
+ },
+ "routers": {
+ "r0": {
+ "links": {
+ "r1": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r2": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r3": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ }
+ },
+ "ospf": {
+ "router_id": "100.1.1.0",
+ "neighbors": {
+ "r1": {},
+ "r2": {},
+ "r3": {}
+ }
+ }
+ },
+ "r1": {
+ "links": {
+ "r0": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r2": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r3": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ }
+ },
+ "ospf": {
+ "router_id": "100.1.1.1",
+ "neighbors": {
+ "r0": {},
+ "r2": {},
+ "r3": {}
+ }
+ }
+ },
+ "r2": {
+ "links": {
+ "r0": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r1": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r3": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ }
+ },
+ "ospf": {
+ "router_id": "100.1.1.2",
+ "neighbors": {
+ "r1": {},
+ "r0": {},
+ "r3": {}
+ }
+ }
+ },
+ "r3": {
+ "links": {
+ "r0": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r1": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r2": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ }
+ },
+ "ospf": {
+ "router_id": "100.1.1.3",
+ "neighbors": {
+ "r0": {},
+ "r1": {},
+ "r2": {}
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/topotests/ospf_basic_functionality/ospf_rte_calc.json b/tests/topotests/ospf_basic_functionality/ospf_rte_calc.json
new file mode 100644
index 0000000000..9062a09091
--- /dev/null
+++ b/tests/topotests/ospf_basic_functionality/ospf_rte_calc.json
@@ -0,0 +1,168 @@
+{
+
+ "ipv4base": "10.0.0.0",
+ "ipv4mask": 24,
+ "link_ip_start": {
+ "ipv4": "10.0.0.0",
+ "v4mask": 24
+ },
+ "lo_prefix": {
+ "ipv4": "1.0.",
+ "v4mask": 32
+ },
+ "routers": {
+ "r0": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "type": "loopback"
+ },
+ "r1": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r2": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r3": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ }
+ },
+ "ospf": {
+ "router_id": "100.1.1.0",
+ "neighbors": {
+ "r1": {},
+ "r2": {}
+ }
+ }
+ },
+ "r1": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "type": "loopback"
+ },
+ "r0": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r2": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r3": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ }
+ },
+ "ospf": {
+ "router_id": "100.1.1.1",
+ "neighbors": {
+ "r0": {},
+ "r2": {},
+ "r3": {}
+ }
+ }
+ },
+ "r2": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "type": "loopback"
+ },
+ "r0": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r1": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r3": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ }
+ },
+ "ospf": {
+ "router_id": "100.1.1.2",
+ "neighbors": {
+ "r1": {},
+ "r0": {},
+ "r3": {}
+ }
+ }
+ },
+ "r3": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "type": "loopback"
+ },
+ "r0": {
+ "ipv4": "auto"
+ },
+ "r1": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r2": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ }
+ },
+ "ospf": {
+ "router_id": "100.1.1.3",
+ "neighbors": {
+ "r1": {},
+ "r2": {}
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/topotests/ospf_basic_functionality/ospf_single_area.json b/tests/topotests/ospf_basic_functionality/ospf_single_area.json
new file mode 100644
index 0000000000..c595912887
--- /dev/null
+++ b/tests/topotests/ospf_basic_functionality/ospf_single_area.json
@@ -0,0 +1,188 @@
+{
+
+ "ipv4base": "10.0.0.0",
+ "ipv4mask": 24,
+ "link_ip_start": {
+ "ipv4": "10.0.0.0",
+ "v4mask": 24
+ },
+ "lo_prefix": {
+ "ipv4": "1.0.",
+ "v4mask": 32
+ },
+ "routers": {
+ "r0": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "type": "loopback"
+ },
+ "r1": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r2": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r3": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4,
+ "network": "point-to-point"
+ }
+ }
+ },
+ "ospf": {
+ "router_id": "100.1.1.0",
+ "neighbors": {
+ "r1": {},
+ "r2": {},
+ "r3": {}
+ }
+ }
+ },
+ "r1": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "type": "loopback"
+ },
+ "r0": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r2": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r3": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r3-link0": {
+ "ipv4": "auto",
+ "description": "DummyIntftoR3"
+ }
+ },
+ "ospf": {
+ "router_id": "100.1.1.1",
+ "neighbors": {
+ "r0": {},
+ "r2": {},
+ "r3": {}
+ }
+ }
+ },
+ "r2": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "type": "loopback"
+ },
+ "r0": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r1": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r3": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ }
+ },
+ "ospf": {
+ "router_id": "100.1.1.2",
+ "neighbors": {
+ "r1": {},
+ "r0": {},
+ "r3": {}
+ }
+ }
+ },
+ "r3": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "type": "loopback"
+ },
+ "r0": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4,
+ "network": "point-to-point"
+ }
+ },
+ "r1": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r2": {
+ "ipv4": "auto",
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r1-link0": {
+ "ipv4": "auto",
+ "description": "DummyIntftoR1",
+ "ospf": {
+ "area": "0.0.0.0"
+ }
+ }
+ },
+ "ospf": {
+ "router_id": "100.1.1.3",
+ "neighbors": {
+ "r0": {},
+ "r1": {},
+ "r2": {}
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_authentication.py b/tests/topotests/ospf_basic_functionality/test_ospf_authentication.py
new file mode 100644
index 0000000000..a2f9c03ab4
--- /dev/null
+++ b/tests/topotests/ospf_basic_functionality/test_ospf_authentication.py
@@ -0,0 +1,891 @@
+#!/usr/bin/python
+
+#
+# Copyright (c) 2020 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation, Inc.
+# ("NetDEF") in this file.
+#
+# 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 VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE 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.
+#
+
+
+"""OSPF Basic Functionality Automation."""
+import os
+import sys
+import time
+import pytest
+from time import sleep
+from copy import deepcopy
+import json
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+sys.path.append(os.path.join(CWD, "../lib/"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from mininet.topo import Topo
+from lib.topogen import Topogen, get_topogen
+
+# Import topoJson from lib, to create topology and initial configuration
+from lib.common_config import (
+ start_topology,
+ write_test_header,
+ write_test_footer,
+ reset_config_on_routers,
+ step,
+ shutdown_bringup_interface,
+ topo_daemons
+)
+from lib.topolog import logger
+from lib.topojson import build_topo_from_json, build_config_from_json
+from lib.ospf import verify_ospf_neighbor, config_ospf_interface, clear_ospf
+from ipaddress import IPv4Address
+
+# Global variables
+topo = None
+# Reading the data from JSON File for topology creation
+jsonFile = "{}/ospf_authentication.json".format(CWD)
+try:
+ with open(jsonFile, "r") as topoJson:
+ topo = json.load(topoJson)
+except IOError:
+ assert False, "Could not read file {}".format(jsonFile)
+"""
+TOPOOLOGY =
+ Please view in a fixed-width font such as Courier.
+ +---+ A1 +---+
+ +R1 +------------+R2 |
+ +-+-+- +--++
+ | -- -- |
+ | -- A0 -- |
+ A0| ---- |
+ | ---- | A2
+ | -- -- |
+ | -- -- |
+ +-+-+- +-+-+
+ +R0 +-------------+R3 |
+ +---+ A3 +---+
+
+TESTCASES =
+1. Verify ospf authentication with Simple password authentication.
+2. Verify ospf authentication with MD5 authentication.
+3. Verify ospf authentication with different authentication methods.
+
+ """
+
+
+class CreateTopo(Topo):
+ """
+ Test topology builder.
+
+ * `Topo`: Topology object
+ """
+
+ def build(self, *_args, **_opts):
+ """Build function."""
+ tgen = get_topogen(self)
+
+ # Building topology from json file
+ build_topo_from_json(tgen, topo)
+
+
+def setup_module(mod):
+ """
+ Sets up the pytest environment
+
+ * `mod`: module name
+ """
+ global topo
+ testsuite_run_time = time.asctime(time.localtime(time.time()))
+ logger.info("Testsuite start time: {}".format(testsuite_run_time))
+ logger.info("=" * 40)
+
+ logger.info("Running setup_module to create topology")
+
+ # This function initiates the topology build with Topogen...
+ tgen = Topogen(CreateTopo, mod.__name__)
+ # ... and here it calls Mininet initialization functions.
+
+ # get list of daemons needs to be started for this suite.
+ daemons = topo_daemons(tgen, topo)
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start deamons and then start routers
+ start_topology(tgen, daemons)
+
+ # Creating configuration from JSON
+ build_config_from_json(tgen, topo)
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ ospf_covergence = verify_ospf_neighbor(tgen, topo)
+ assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ logger.info("Running setup_module() done")
+
+
+def teardown_module(mod):
+ """
+ Teardown the pytest environment.
+
+ * `mod`: module name
+ """
+
+ logger.info("Running teardown_module to delete topology")
+
+ tgen = get_topogen()
+
+ # Stop toplogy and Remove tmp files
+ tgen.stop_topology()
+
+ logger.info(
+ "Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
+ )
+ logger.info("=" * 40)
+
+
+# ##################################
+# Test cases start here.
+# ##################################
+
+
+def test_ospf_authentication_simple_pass_tc28_p1(request):
+ """
+ OSPF Authentication - Verify ospf authentication with Simple
+ password authentication.
+
+ """
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+ global topo
+ step("Bring up the base config.")
+ reset_config_on_routers(tgen)
+ step(
+ "Configure ospf with on R1 and R2, enable ospf on R1 interface"
+ "connected to R2 with simple password authentication using ip ospf "
+ "authentication Simple password cmd."
+ )
+
+ r1_ospf_auth = {
+ "r1": {
+ "links": {
+ "r2": {"ospf": {"authentication": True, "authentication-key": "ospf"}}
+ }
+ }
+ }
+ result = config_ospf_interface(tgen, topo, r1_ospf_auth)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("clear ip ospf after configuring the authentication.")
+ clear_ospf(tgen, "r1")
+
+ step("Verify that the neighbour is not FULL between R1 and R2.")
+ dut = "r1"
+ ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut, expected=False)
+ assert ospf_covergence is not True, "setup_module :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ step(
+ "On R2 enable ospf on interface with simple password authentication "
+ "using ip ospf authentication Simple password cmd."
+ )
+
+ r2_ospf_auth = {
+ "r2": {
+ "links": {
+ "r1": {"ospf": {"authentication": True, "authentication-key": "ospf"}}
+ }
+ }
+ }
+ result = config_ospf_interface(tgen, topo, r2_ospf_auth)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that the neighbour is FULL between R1 and R2 "
+ "using show ip ospf neighbor cmd."
+ )
+
+ dut = "r2"
+ ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
+ assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ step(
+ "Disable simple password authentication on R2 using no ip ospf "
+ "authentication Simple password cmd."
+ )
+ r2_ospf_auth = {
+ "r2": {
+ "links": {
+ "r1": {
+ "ospf": {
+ "authentication": True,
+ "authentication-key": "ospf",
+ "del_action": True,
+ }
+ }
+ }
+ }
+ }
+ result = config_ospf_interface(tgen, topo, r2_ospf_auth)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify on R1 neighbour is deleted for R2 after dead interval expiry")
+ # wait till the dead time expiry
+ sleep(6)
+ dut = "r2"
+ ospf_covergence = verify_ospf_neighbor(
+ tgen, topo, dut=dut, expected=False, attempts=5
+ )
+ assert ospf_covergence is not True, "setup_module :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ step("Again On R2 enable ospf on interface with Simple password auth")
+ r2_ospf_auth = {
+ "r2": {
+ "links": {
+ "r1": {"ospf": {"authentication": True, "authentication-key": "ospf"}}
+ }
+ }
+ }
+ result = config_ospf_interface(tgen, topo, r2_ospf_auth)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that the neighbour is FULL between R1 and R2 using"
+ " show ip ospf neighbor cmd."
+ )
+
+ dut = "r2"
+ ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
+ assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ step("Shut no shut interface on R1")
+ dut = "r1"
+ intf = topo["routers"]["r1"]["links"]["r2"]["interface"]
+ shutdown_bringup_interface(tgen, dut, intf, False)
+
+ dut = "r2"
+ step(
+ "Verify that the neighbour is not FULL between R1 and R2 using "
+ "show ip ospf neighbor cmd."
+ )
+ ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut, expected=False)
+ assert ospf_covergence is not True, "setup_module :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ dut = "r1"
+ shutdown_bringup_interface(tgen, dut, intf, True)
+
+ step(
+ "Verify that the neighbour is FULL between R1 and R2 using "
+ "show ip ospf neighbor cmd."
+ )
+
+ dut = "r2"
+ ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
+ assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ step("Change Ip address on R1 and R2")
+
+ topo_modify_change_ip = deepcopy(topo)
+ intf_ip = topo_modify_change_ip["routers"]["r1"]["links"]["r2"]["ipv4"]
+ topo_modify_change_ip["routers"]["r1"]["links"]["r2"]["ipv4"] = str(
+ IPv4Address(unicode(intf_ip.split("/")[0])) + 3
+ ) + "/{}".format(intf_ip.split("/")[1])
+
+ build_config_from_json(tgen, topo_modify_change_ip, save_bkup=False)
+
+ reset_config_on_routers(tgen, routerName="r1")
+ dut = "r1"
+ intf = topo["routers"]["r1"]["links"]["r2"]["interface"]
+ shutdown_bringup_interface(tgen, dut, intf, False)
+ shutdown_bringup_interface(tgen, dut, intf, True)
+
+ # clear ip ospf after configuring the authentication.
+ clear_ospf(tgen, "r1")
+
+ r1_ospf_auth = {
+ "r1": {
+ "links": {
+ "r2": {"ospf": {"authentication": True, "authentication-key": "ospf"}}
+ }
+ }
+ }
+ result = config_ospf_interface(tgen, topo, r1_ospf_auth)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that the neighbour is FULL between R1 and R2 with new "
+ "ip address using show ip ospf "
+ )
+
+ dut = "r1"
+ ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
+ assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_ospf_authentication_md5_tc29_p1(request):
+ """
+ OSPF Authentication - Verify ospf authentication with MD5 authentication.
+
+ """
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+ global topo
+ step("Bring up the base config.")
+ reset_config_on_routers(tgen)
+ step(
+ "Configure ospf with on R1 and R2, enable ospf on R1 interface "
+ "connected to R2 with message-digest authentication using ip "
+ "ospf authentication message-digest cmd."
+ )
+
+ r1_ospf_auth = {
+ "r1": {
+ "links": {
+ "r2": {
+ "ospf": {
+ "authentication": "message-digest",
+ "authentication-key": "ospf",
+ "message-digest-key": "10",
+ }
+ }
+ }
+ }
+ }
+ result = config_ospf_interface(tgen, topo, r1_ospf_auth)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify that the neighbour is not FULL between R1 and R2.")
+ # wait for dead time expiry.
+ sleep(6)
+ dut = "r1"
+ ospf_covergence = verify_ospf_neighbor(
+ tgen, topo, dut=dut, expected=False, attempts=3
+ )
+ assert ospf_covergence is not True, "setup_module :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ step(
+ "On R2 enable ospf on interface with message-digest authentication"
+ " using ip ospf authentication message-digest password cmd."
+ )
+
+ r2_ospf_auth = {
+ "r2": {
+ "links": {
+ "r1": {
+ "ospf": {
+ "authentication": "message-digest",
+ "authentication-key": "ospf",
+ "message-digest-key": "10",
+ }
+ }
+ }
+ }
+ }
+ result = config_ospf_interface(tgen, topo, r2_ospf_auth)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that the neighbour is FULL between R1 and R2 "
+ "using show ip ospf neighbor cmd."
+ )
+
+ dut = "r2"
+ ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
+ assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ step(
+ "Disable message-digest authentication on R2 using no ip ospf "
+ "authentication message-digest password cmd."
+ )
+
+ r2_ospf_auth = {
+ "r2": {
+ "links": {
+ "r1": {
+ "ospf": {
+ "authentication": "message-digest",
+ "authentication-key": "ospf",
+ "message-digest-key": "10",
+ "del_action": True,
+ }
+ }
+ }
+ }
+ }
+ result = config_ospf_interface(tgen, topo, r2_ospf_auth)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify on R1 ,nbr is deleted for R2 after dead interval expiry")
+ # wait till the dead timer expiry
+ sleep(6)
+ dut = "r2"
+ ospf_covergence = verify_ospf_neighbor(
+ tgen, topo, dut=dut, expected=False, attempts=5
+ )
+ assert ospf_covergence is not True, "setup_module :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ step("Again On R2 enable ospf on interface with message-digest auth")
+ r2_ospf_auth = {
+ "r2": {
+ "links": {
+ "r1": {
+ "ospf": {
+ "authentication": "message-digest",
+ "authentication-key": "ospf",
+ "message-digest-key": "10",
+ }
+ }
+ }
+ }
+ }
+ result = config_ospf_interface(tgen, topo, r2_ospf_auth)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that the neighbour is FULL between R1 and R2 using"
+ " show ip ospf neighbor cmd."
+ )
+
+ dut = "r2"
+ ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
+ assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ step("Shut no shut interface on R1")
+ dut = "r1"
+ intf = topo["routers"]["r1"]["links"]["r2"]["interface"]
+ shutdown_bringup_interface(tgen, dut, intf, False)
+
+ dut = "r2"
+ step(
+ "Verify that the neighbour is not FULL between R1 and R2 using "
+ "show ip ospf neighbor cmd."
+ )
+ ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut, expected=False)
+ assert ospf_covergence is not True, "setup_module :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ dut = "r1"
+ shutdown_bringup_interface(tgen, dut, intf, True)
+
+ step(
+ "Verify that the neighbour is FULL between R1 and R2 using "
+ "show ip ospf neighbor cmd."
+ )
+
+ dut = "r2"
+ ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
+ assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ step("Change Ip address on R1 and R2")
+
+ topo_modify_change_ip = deepcopy(topo)
+
+ intf_ip = topo_modify_change_ip["routers"]["r1"]["links"]["r2"]["ipv4"]
+
+ topo_modify_change_ip["routers"]["r1"]["links"]["r2"]["ipv4"] = str(
+ IPv4Address(unicode(intf_ip.split("/")[0])) + 3
+ ) + "/{}".format(intf_ip.split("/")[1])
+
+ build_config_from_json(tgen, topo_modify_change_ip, save_bkup=False)
+
+ reset_config_on_routers(tgen, routerName="r1")
+ dut = "r1"
+ intf = topo["routers"]["r1"]["links"]["r2"]["interface"]
+ shutdown_bringup_interface(tgen, dut, intf, False)
+ shutdown_bringup_interface(tgen, dut, intf, True)
+ clear_ospf(tgen, "r1")
+ r1_ospf_auth = {
+ "r1": {
+ "links": {
+ "r2": {
+ "ospf": {
+ "authentication": "message-digest",
+ "authentication-key": "ospf",
+ "message-digest-key": "10",
+ }
+ }
+ }
+ }
+ }
+ result = config_ospf_interface(tgen, topo, r1_ospf_auth)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that the neighbour is FULL between R1 and R2 with new "
+ "ip address using show ip ospf "
+ )
+
+ dut = "r1"
+ ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
+ assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_ospf_authentication_different_auths_tc30_p1(request):
+ """
+ OSPF Authentication - Verify ospf authentication with different
+ authentication methods.
+
+ """
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+ global topo
+ step("Bring up the base config.")
+ reset_config_on_routers(tgen)
+ step(
+ "Configure ospf with on R1 and R2, enable ospf on R1 interface "
+ "connected to R2 with message-digest authentication using ip "
+ "ospf authentication message-digest cmd."
+ )
+
+ r1_ospf_auth = {
+ "r1": {
+ "links": {
+ "r2": {
+ "ospf": {
+ "authentication": "message-digest",
+ "authentication-key": "ospf",
+ "message-digest-key": "10",
+ }
+ }
+ }
+ }
+ }
+ result = config_ospf_interface(tgen, topo, r1_ospf_auth)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ # wait for dead timer expiry
+ sleep(6)
+ step("Verify that the neighbour is not FULL between R1 and R2.")
+ dut = "r1"
+ ospf_covergence = verify_ospf_neighbor(
+ tgen, topo, dut=dut, expected=False, attempts=5
+ )
+ assert ospf_covergence is not True, "setup_module :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ step(
+ "On R2 enable ospf on interface with message-digest authentication"
+ " using ip ospf authentication message-digest password cmd."
+ )
+
+ r2_ospf_auth = {
+ "r2": {
+ "links": {
+ "r1": {
+ "ospf": {
+ "authentication": "message-digest",
+ "authentication-key": "ospf",
+ "message-digest-key": "10",
+ }
+ }
+ }
+ }
+ }
+ result = config_ospf_interface(tgen, topo, r2_ospf_auth)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that the neighbour is FULL between R1 and R2 "
+ "using show ip ospf neighbor cmd."
+ )
+
+ dut = "r2"
+ ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
+ assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ step(" Delete the configured password on both the routers.")
+
+ r2_ospf_auth = {
+ "r2": {
+ "links": {
+ "r1": {
+ "ospf": {
+ "authentication": "message-digest",
+ "authentication-key": "ospf",
+ "message-digest-key": "10",
+ "del_action": True,
+ }
+ }
+ }
+ }
+ }
+ result = config_ospf_interface(tgen, topo, r2_ospf_auth)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ r1_ospf_auth = {
+ "r1": {
+ "links": {
+ "r2": {
+ "ospf": {
+ "authentication": "message-digest",
+ "authentication-key": "ospf",
+ "message-digest-key": "10",
+ "del_action": True,
+ }
+ }
+ }
+ }
+ }
+ result = config_ospf_interface(tgen, topo, r1_ospf_auth)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that the deletion is successful and neighbour is FULL"
+ " between R1 and R2 using show ip ospf neighbor cmd."
+ )
+
+ dut = "r2"
+ ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
+ assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ step("Change the authentication type to simple password.")
+ r1_ospf_auth = {
+ "r1": {
+ "links": {
+ "r2": {"ospf": {"authentication": True, "authentication-key": "ospf"}}
+ }
+ }
+ }
+ result = config_ospf_interface(tgen, topo, r1_ospf_auth)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ r2_ospf_auth = {
+ "r2": {
+ "links": {
+ "r1": {"ospf": {"authentication": True, "authentication-key": "ospf"}}
+ }
+ }
+ }
+ result = config_ospf_interface(tgen, topo, r2_ospf_auth)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that the deletion is successful and neighbour is"
+ " FULL between R1 and R2 using show ip "
+ )
+
+ dut = "r2"
+ ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
+ assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ step("Change the password in simple password.")
+
+ r1_ospf_auth = {
+ "r1": {
+ "links": {
+ "r2": {"ospf": {"authentication": True, "authentication-key": "OSPFv4"}}
+ }
+ }
+ }
+ result = config_ospf_interface(tgen, topo, r1_ospf_auth)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ r2_ospf_auth = {
+ "r2": {
+ "links": {
+ "r1": {"ospf": {"authentication": True, "authentication-key": "OSPFv4"}}
+ }
+ }
+ }
+ result = config_ospf_interface(tgen, topo, r2_ospf_auth)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that the deletion is successful and neighbour is"
+ " FULL between R1 and R2 using show ip "
+ )
+
+ dut = "r2"
+ ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
+ assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ step("Delete the password authentication on the interface ")
+
+ r1_ospf_auth = {
+ "r1": {
+ "links": {
+ "r2": {
+ "ospf": {
+ "authentication": True,
+ "authentication-key": "OSPFv4",
+ "del_action": True,
+ }
+ }
+ }
+ }
+ }
+ result = config_ospf_interface(tgen, topo, r1_ospf_auth)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ r2_ospf_auth = {
+ "r2": {
+ "links": {
+ "r1": {
+ "ospf": {
+ "authentication": True,
+ "authentication-key": "OSPFv4",
+ "del_action": True,
+ }
+ }
+ }
+ }
+ }
+ result = config_ospf_interface(tgen, topo, r2_ospf_auth)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that the deletion is successful and neighbour is"
+ " FULL between R1 and R2 using show ip "
+ )
+
+ dut = "r2"
+ ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
+ assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ step("Enable Md5 authentication on the interface")
+
+ r1_ospf_auth = {
+ "r1": {
+ "links": {
+ "r2": {
+ "ospf": {
+ "authentication": "message-digest",
+ "authentication-key": "ospf",
+ "message-digest-key": "10",
+ }
+ }
+ }
+ }
+ }
+ result = config_ospf_interface(tgen, topo, r1_ospf_auth)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ r2_ospf_auth = {
+ "r2": {
+ "links": {
+ "r1": {
+ "ospf": {
+ "authentication": "message-digest",
+ "authentication-key": "ospf",
+ "message-digest-key": "10",
+ }
+ }
+ }
+ }
+ }
+ result = config_ospf_interface(tgen, topo, r2_ospf_auth)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that the neighbour is FULL between R1 and R2 using"
+ " show ip ospf neighbor cmd."
+ )
+
+ dut = "r2"
+ ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
+ assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ step("Change the MD5 authentication password")
+
+ r1_ospf_auth = {
+ "r1": {
+ "links": {
+ "r2": {
+ "ospf": {
+ "authentication": "message-digest",
+ "authentication-key": "OSPFv4",
+ "message-digest-key": "10",
+ }
+ }
+ }
+ }
+ }
+ result = config_ospf_interface(tgen, topo, r1_ospf_auth)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ r2_ospf_auth = {
+ "r2": {
+ "links": {
+ "r1": {
+ "ospf": {
+ "authentication": "message-digest",
+ "authentication-key": "OSPFv4",
+ "message-digest-key": "10",
+ }
+ }
+ }
+ }
+ }
+ result = config_ospf_interface(tgen, topo, r2_ospf_auth)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py b/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py
new file mode 100644
index 0000000000..399fa02230
--- /dev/null
+++ b/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py
@@ -0,0 +1,495 @@
+#!/usr/bin/python
+
+#
+# Copyright (c) 2020 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation, Inc.
+# ("NetDEF") in this file.
+#
+# 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 VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE 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.
+#
+
+
+"""OSPF Basic Functionality Automation."""
+import os
+import sys
+import time
+import pytest
+import json
+from time import sleep
+from copy import deepcopy
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+sys.path.append(os.path.join(CWD, "../lib/"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from mininet.topo import Topo
+from lib.topogen import Topogen, get_topogen
+from ipaddress import IPv4Address
+
+# Import topoJson from lib, to create topology and initial configuration
+from lib.common_config import (
+ start_topology,
+ write_test_header,
+ write_test_footer,
+ reset_config_on_routers,
+ verify_rib,
+ create_static_routes,
+ step,
+ create_route_maps,
+ shutdown_bringup_interface,
+ create_interfaces_cfg,
+ topo_daemons
+)
+from lib.topolog import logger
+
+from lib.topojson import build_topo_from_json, build_config_from_json
+from lib.ospf import (
+ verify_ospf_neighbor,
+ config_ospf_interface,
+ clear_ospf,
+ verify_ospf_rib,
+ create_router_ospf,
+ verify_ospf_interface,
+)
+
+topo = None
+
+# Reading the data from JSON File for topology creation
+jsonFile = "{}/ospf_ecmp.json".format(CWD)
+
+try:
+ with open(jsonFile, "r") as topoJson:
+ topo = json.load(topoJson)
+except IOError:
+ assert False, "Could not read file {}".format(jsonFile)
+
+# Global variables
+NETWORK = {
+ "ipv4": [
+ "11.0.20.1/32",
+ "11.0.20.2/32",
+ "11.0.20.3/32",
+ "11.0.20.4/32",
+ "11.0.20.5/32",
+ ]
+}
+"""
+TOPOLOGY :
+ Please view in a fixed-width font such as Courier.
+ +---+ A1 +---+
+ +R1 +------------+R2 |
+ +-+-+- +--++
+ | -- -- |
+ | -- A0 -- |
+ A0| ---- |
+ | ---- | A2
+ | -- -- |
+ | -- -- |
+ +-+-+- +-+-+
+ +R0 +-------------+R3 |
+ +---+ A3 +---+
+
+TESTCASES :
+1. Verify OSPF ECMP with max path configured as 8 (ECMPconfigured at FRR level)
+2. Verify OSPF ECMP with max path configured as 2 (Edge having 2 uplink ports)
+ """
+
+
+class CreateTopo(Topo):
+ """
+ Test topology builder.
+
+ * `Topo`: Topology object
+ """
+
+ def build(self, *_args, **_opts):
+ """Build function."""
+ tgen = get_topogen(self)
+
+ # Building topology from json file
+ build_topo_from_json(tgen, topo)
+
+
+def setup_module(mod):
+ """
+ Sets up the pytest environment
+
+ * `mod`: module name
+ """
+ global topo
+ testsuite_run_time = time.asctime(time.localtime(time.time()))
+ logger.info("Testsuite start time: {}".format(testsuite_run_time))
+ logger.info("=" * 40)
+
+ logger.info("Running setup_module to create topology")
+
+ # This function initiates the topology build with Topogen...
+ tgen = Topogen(CreateTopo, mod.__name__)
+ # ... and here it calls Mininet initialization functions.
+
+ # get list of daemons needs to be started for this suite.
+ daemons = topo_daemons(tgen, topo)
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start deamons and then start routers
+ start_topology(tgen, daemons)
+
+ # Creating configuration from JSON
+ build_config_from_json(tgen, topo)
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ # Api call verify whether OSPF is converged
+ ospf_covergence = verify_ospf_neighbor(tgen, topo)
+ assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ logger.info("Running setup_module() done")
+
+
+def teardown_module(mod):
+ """
+ Teardown the pytest environment.
+
+ * `mod`: module name
+ """
+
+ logger.info("Running teardown_module to delete topology")
+
+ tgen = get_topogen()
+
+ # Stop toplogy and Remove tmp files
+ tgen.stop_topology()
+
+ logger.info(
+ "Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
+ )
+ logger.info("=" * 40)
+
+
+def red_static(dut, config=True):
+ """Local def for Redstribute static routes inside ospf."""
+ global topo
+ tgen = get_topogen()
+ if config:
+ ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "static"}]}}}
+ else:
+ ospf_red = {
+ dut: {"ospf": {"redistribute": [{"redist_type": "static", "delete": True}]}}
+ }
+ result = create_router_ospf(tgen, topo, ospf_red)
+ assert result is True, "Testcase : Failed \n Error: {}".format(result)
+
+
+def red_connected(dut, config=True):
+ """Local def for Redstribute connected routes inside ospf."""
+ global topo
+ tgen = get_topogen()
+ if config:
+ ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "connected"}]}}}
+ else:
+ ospf_red = {
+ dut: {
+ "ospf": {
+ "redistribute": [{"redist_type": "connected", "del_action": True}]
+ }
+ }
+ }
+ result = create_router_ospf(tgen, topo, ospf_red)
+ assert result is True, "Testcase: Failed \n Error: {}".format(result)
+
+
+# ##################################
+# Test cases start here.
+# ##################################
+
+
+def test_ospf_ecmp_tc16_p0(request):
+ """
+ Verify OSPF ECMP.
+
+ Verify OSPF ECMP with max path configured as 8 (ECMP
+ configured at FRR level)
+ """
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ global topo
+ step("Bring up the base config as per the topology")
+ step("Configure 8 interfaces between R1 and R2 and enable ospf in area 0.")
+ reset_config_on_routers(tgen)
+ step("Verify that OSPF is up with 8 neighborship sessions.")
+ dut = "r1"
+ ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
+ assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ step("Configure a static route in R0 and redistribute in OSPF.")
+
+ input_dict = {
+ "r0": {
+ "static_routes": [
+ {"network": NETWORK["ipv4"][0], "no_of_ip": 5, "next_hop": "Null0",}
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ dut = "r0"
+ red_static(dut)
+
+ step("Verify that route in R2 in stalled with 8 next hops.")
+ nh = []
+ for item in range(1, 7):
+ nh.append(topo["routers"]["r0"]["links"]["r1-link1"]["ipv4"].split("/")[0])
+
+ nh2 = topo["routers"]["r0"]["links"]["r1"]["ipv4"].split("/")[0]
+
+ nh.append(nh2)
+
+ dut = "r1"
+ result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ protocol = "ospf"
+ result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, next_hop=nh)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("shut no shut all the interfaces on the remote router - R2")
+ dut = "r1"
+ for intfr in range(1, 7):
+ intf = topo["routers"]["r1"]["links"]["r0-link{}".format(intfr)]["interface"]
+ shutdown_bringup_interface(tgen, dut, intf, False)
+
+ result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh, expected=False)
+ assert result is not True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ protocol = "ospf"
+ result = verify_rib(
+ tgen, "ipv4", dut, input_dict, protocol=protocol, next_hop=nh, expected=False
+ )
+ assert result is not True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for intfr in range(1, 7):
+ intf = topo["routers"]["r1"]["links"]["r0-link{}".format(intfr)]["interface"]
+ shutdown_bringup_interface(tgen, dut, intf, True)
+
+ result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ protocol = "ospf"
+ result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, next_hop=nh)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("shut no shut on all the interfaces on DUT (r1)")
+ for intfr in range(1, 7):
+ intf = topo["routers"]["r1"]["links"]["r0-link{}".format(intfr)]["interface"]
+ shutdown_bringup_interface(tgen, dut, intf, False)
+
+ for intfr in range(1, 7):
+ intf = topo["routers"]["r1"]["links"]["r0-link{}".format(intfr)]["interface"]
+ shutdown_bringup_interface(tgen, dut, intf, True)
+
+ step(
+ "Verify that all the neighbours are up and routes are installed"
+ " with 8 next hop in ospf and ip route tables on R1."
+ )
+
+ step("Verify that OSPF is up with 8 neighborship sessions.")
+ dut = "r1"
+ ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
+ assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ dut = "r1"
+ result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ protocol = "ospf"
+ result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, next_hop=nh)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(" Un configure static route on R0")
+
+ dut = "r0"
+ red_static(dut, config=False)
+
+ # Wait for R0 to flush external LSAs.
+ sleep(10)
+
+ step("Verify that route is withdrawn from R2.")
+ dut = "r1"
+ result = verify_ospf_rib(
+ tgen, dut, input_dict, next_hop=nh, attempts=5, expected=False
+ )
+ assert result is not True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ protocol = "ospf"
+ result = verify_rib(
+ tgen,
+ "ipv4",
+ dut,
+ input_dict,
+ protocol=protocol,
+ next_hop=nh,
+ attempts=5,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Re configure the static route in R0.")
+ dut = "r0"
+ red_static(dut)
+
+ dut = "r1"
+ result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ protocol = "ospf"
+ result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, next_hop=nh)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_ospf_ecmp_tc17_p0(request):
+ """
+ Verify OSPF ECMP.
+
+ Verify OSPF ECMP with max path configured as 2 (Edge having 2 uplink ports)
+ """
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ global topo
+ step("Bring up the base config as per the topology")
+ step("Configure 2 interfaces between R1 and R2 & enable ospf in area 0.")
+ reset_config_on_routers(tgen)
+ step("Verify that OSPF is up with 2 neighborship sessions.")
+ dut = "r1"
+ ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
+ assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ step("Configure a static route in R0 and redistribute in OSPF.")
+
+ input_dict = {
+ "r0": {
+ "static_routes": [
+ {"network": NETWORK["ipv4"][0], "no_of_ip": 5, "next_hop": "Null0",}
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ dut = "r0"
+ red_static(dut)
+
+ step("Verify that route in R2 in stalled with 2 next hops.")
+
+ nh1 = topo["routers"]["r0"]["links"]["r1-link1"]["ipv4"].split("/")[0]
+ nh2 = topo["routers"]["r0"]["links"]["r1"]["ipv4"].split("/")[0]
+ nh = [nh1, nh2]
+
+ dut = "r1"
+ result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ protocol = "ospf"
+ result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, next_hop=nh)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(" Un configure static route on R0")
+
+ dut = "r0"
+ red_static(dut, config=False)
+ # sleep till the route gets withdrawn
+ sleep(10)
+
+ step("Verify that route is withdrawn from R2.")
+ dut = "r1"
+ result = verify_ospf_rib(
+ tgen, dut, input_dict, next_hop=nh, attempts=5, expected=False
+ )
+ assert result is not True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ protocol = "ospf"
+ result = verify_rib(
+ tgen,
+ "ipv4",
+ dut,
+ input_dict,
+ protocol=protocol,
+ next_hop=nh,
+ attempts=5,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Reconfigure the static route in R0.Change ECMP value to 2.")
+ dut = "r0"
+ red_static(dut)
+
+ step("Configure cost on R0 as 100")
+ r0_ospf_cost = {"r0": {"links": {"r1": {"ospf": {"cost": 100}}}}}
+ result = config_ospf_interface(tgen, topo, r0_ospf_cost)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ dut = "r1"
+ result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ protocol = "ospf"
+ result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, next_hop=nh)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_ecmp_lan.py b/tests/topotests/ospf_basic_functionality/test_ospf_ecmp_lan.py
new file mode 100644
index 0000000000..17a3676e2e
--- /dev/null
+++ b/tests/topotests/ospf_basic_functionality/test_ospf_ecmp_lan.py
@@ -0,0 +1,369 @@
+#!/usr/bin/python
+
+#
+# Copyright (c) 2020 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation, Inc.
+# ("NetDEF") in this file.
+#
+# 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 VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE 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.
+#
+
+
+"""OSPF Basic Functionality Automation."""
+import os
+import sys
+import time
+import pytest
+import json
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+sys.path.append(os.path.join(CWD, "../lib/"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from mininet.topo import Topo
+from lib.topogen import Topogen, get_topogen
+
+# Import topoJson from lib, to create topology and initial configuration
+from lib.common_config import (
+ start_topology,
+ write_test_header,
+ create_interfaces_cfg,
+ write_test_footer,
+ reset_config_on_routers,
+ verify_rib,
+ create_static_routes,
+ check_address_types,
+ step,
+ create_route_maps,
+ shutdown_bringup_interface,
+ stop_router,
+ start_router,
+ topo_daemons
+)
+from lib.bgp import verify_bgp_convergence, create_router_bgp
+from lib.topolog import logger
+from lib.topojson import build_topo_from_json, build_config_from_json
+
+from lib.ospf import (
+ verify_ospf_neighbor,
+ config_ospf_interface,
+ clear_ospf,
+ verify_ospf_rib,
+ create_router_ospf,
+ verify_ospf_interface,
+)
+from ipaddress import IPv4Address
+
+# Global variables
+topo = None
+# Reading the data from JSON File for topology creation
+
+jsonFile = "{}/ospf_ecmp_lan.json".format(CWD)
+try:
+ with open(jsonFile, "r") as topoJson:
+ topo = json.load(topoJson)
+except IOError:
+ assert False, "Could not read file {}".format(jsonFile)
+
+NETWORK = {
+ "ipv4": [
+ "11.0.20.1/32",
+ "11.0.20.2/32",
+ "11.0.20.3/32",
+ "11.0.20.4/32",
+ "11.0.20.5/32",
+ ],
+ "ipv6": ["1::1/128", "1::2/128", "1::3/128", "1::4/128", "1::5/128"],
+}
+MASK = {"ipv4": "32", "ipv6": "128"}
+NEXT_HOP = {
+ "ipv4": ["10.0.0.1", "10.0.1.1", "10.0.2.1", "10.0.3.1", "10.0.4.1"],
+ "ipv6": ["Null0", "Null0", "Null0", "Null0", "Null0"],
+}
+"""
+TOPOOLOGY =
+ Please view in a fixed-width font such as Courier.
+ Topo : Broadcast Networks
+ +---+ +---+ +---+ +---+
+ |R0 + +R1 + +R2 + +R3 |
+ +-+-+ +-+-+ +-+-+ +-+-+
+ | | | |
+ | | | |
+ --+-----------+--------------+---------------+-----
+ Ethernet Segment
+
+TESTCASES =
+1. Verify OSPF ECMP with max path configured as 8
+ (Edge having 1 uplink port as broadcast network,
+ connect to 8 TORs - LAN case)
+
+ """
+
+
+class CreateTopo(Topo):
+ """
+ Test topology builder.
+
+ * `Topo`: Topology object
+ """
+
+ def build(self, *_args, **_opts):
+ """Build function."""
+ tgen = get_topogen(self)
+
+ # Building topology from json file
+ build_topo_from_json(tgen, topo)
+
+
+def setup_module(mod):
+ """
+ Sets up the pytest environment
+
+ * `mod`: module name
+ """
+ global topo
+ testsuite_run_time = time.asctime(time.localtime(time.time()))
+ logger.info("Testsuite start time: {}".format(testsuite_run_time))
+ logger.info("=" * 40)
+
+ logger.info("Running setup_module to create topology")
+
+ # This function initiates the topology build with Topogen...
+ tgen = Topogen(CreateTopo, mod.__name__)
+ # ... and here it calls Mininet initialization functions.
+
+ # get list of daemons needs to be started for this suite.
+ daemons = topo_daemons(tgen, topo)
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start deamons and then start routers
+ start_topology(tgen, daemons)
+
+ # Creating configuration from JSON
+ build_config_from_json(tgen, topo)
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ # Api call verify whether OSPF is converged
+ ospf_covergence = verify_ospf_neighbor(tgen, topo, lan=True)
+ assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ logger.info("Running setup_module() done")
+
+
+def teardown_module():
+ """Teardown the pytest environment"""
+
+ logger.info("Running teardown_module to delete topology")
+
+ tgen = get_topogen()
+
+ try:
+ # Stop toplogy and Remove tmp files
+ tgen.stop_topology()
+
+ except OSError:
+ # OSError exception is raised when mininet tries to stop switch
+ # though switch is stopped once but mininet tries to stop same
+ # switch again, where it ended up with exception
+ pass
+
+
+def red_static(dut, config=True):
+ """Local def for Redstribute static routes inside ospf."""
+ global topo
+ tgen = get_topogen()
+ if config:
+ ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "static"}]}}}
+ else:
+ ospf_red = {
+ dut: {
+ "ospf": {
+ "redistribute": [{"redist_type": "static", "del_action": True}]
+ }
+ }
+ }
+ result = create_router_ospf(tgen, topo, ospf_red)
+ assert result is True, "Testcase : Failed \n Error: {}".format(result)
+
+
+def red_connected(dut, config=True):
+ """Local def for Redstribute connected routes inside ospf."""
+ global topo
+ tgen = get_topogen()
+ if config:
+ ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "connected"}]}}}
+ else:
+ ospf_red = {
+ dut: {
+ "ospf": {
+ "redistribute": [{"redist_type": "connected", "del_action": True}]
+ }
+ }
+ }
+ result = create_router_ospf(tgen, topo, ospf_red)
+ assert result is True, "Testcase: Failed \n Error: {}".format(result)
+
+
+# ##################################
+# Test cases start here.
+# ##################################
+
+
+def test_ospf_lan_ecmp_tc18_p0(request):
+ """
+ OSPF ECMP.
+
+ Verify OSPF ECMP with max path configured as 8
+ (Edge having 1 uplink port as broadcast network,
+ connect to 8 TORs - LAN case)
+
+ """
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ global topo
+ step("Bring up the base config as per the topology")
+ step(". Configure ospf in all the routers on LAN interface.")
+ reset_config_on_routers(tgen)
+ step("Verify that OSPF is up with 8 neighborship sessions.")
+
+ ospf_covergence = verify_ospf_neighbor(tgen, topo, lan=True)
+ assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ step(
+ "Configure a static route in all the routes and "
+ "redistribute static/connected in OSPF."
+ )
+
+ for rtr in topo["routers"]:
+ input_dict = {
+ rtr: {
+ "static_routes": [
+ {"network": NETWORK["ipv4"][0], "no_of_ip": 5, "next_hop": "Null0"}
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ dut = rtr
+ red_static(dut)
+
+ step(
+ "Verify that route in R0 in stalled with 8 hops. "
+ "Verify ospf route table and ip route table."
+ )
+
+ nh = []
+ for rtr in topo["routers"]:
+ nh.append(topo["routers"][rtr]["links"]["s1"]["ipv4"].split("/")[0])
+ nh.remove(topo["routers"]["r1"]["links"]["s1"]["ipv4"].split("/")[0])
+ dut = "r1"
+ result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ protocol = "ospf"
+ result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, next_hop=nh)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(" clear ip ospf interface on DUT(r0)")
+ clear_ospf(tgen, "r0")
+
+ step(
+ "Verify that after clearing the ospf interface all the "
+ "neighbours are up and routes are installed with 8 next hop "
+ "in ospf and ip route tables on R0"
+ )
+
+ dut = "r0"
+ ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut, lan=True)
+ assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ step(" clear ip ospf interface on R2")
+ clear_ospf(tgen, "r2")
+
+ dut = "r2"
+ ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut, lan=True)
+ assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ step("Delete static/connected cmd in ospf in all the routes one by one.")
+ for rtr in topo["routers"]:
+ input_dict = {
+ rtr: {
+ "static_routes": [
+ {
+ "network": NETWORK["ipv4"][0],
+ "no_of_ip": 5,
+ "next_hop": "Null0",
+ "delete": True,
+ }
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Verify that all the routes are withdrawn from R0")
+ dut = "r1"
+ result = verify_ospf_rib(
+ tgen, dut, input_dict, next_hop=nh, attempts=5, expected=False
+ )
+ assert result is not True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ protocol = "ospf"
+ result = verify_rib(
+ tgen,
+ "ipv4",
+ dut,
+ input_dict,
+ protocol=protocol,
+ next_hop=nh,
+ attempts=5,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_lan.py b/tests/topotests/ospf_basic_functionality/test_ospf_lan.py
new file mode 100644
index 0000000000..f261104206
--- /dev/null
+++ b/tests/topotests/ospf_basic_functionality/test_ospf_lan.py
@@ -0,0 +1,724 @@
+#!/usr/bin/python
+
+#
+# Copyright (c) 2020 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation, Inc.
+# ("NetDEF") in this file.
+#
+# 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 VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE 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.
+#
+
+
+"""OSPF Basic Functionality Automation."""
+import os
+import sys
+import time
+import pytest
+import json
+from copy import deepcopy
+import ipaddress
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+sys.path.append(os.path.join(CWD, "../lib/"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from mininet.topo import Topo
+from lib.topogen import Topogen, get_topogen
+
+# Import topoJson from lib, to create topology and initial configuration
+from lib.common_config import (
+ start_topology,
+ write_test_header,
+ create_interfaces_cfg,
+ write_test_footer,
+ reset_config_on_routers,
+ verify_rib,
+ create_static_routes,
+ check_address_types,
+ step,
+ create_route_maps,
+ shutdown_bringup_interface,
+ stop_router,
+ start_router,
+ topo_daemons
+)
+from lib.bgp import verify_bgp_convergence, create_router_bgp
+from lib.topolog import logger
+from lib.topojson import build_topo_from_json, build_config_from_json
+from lib.ospf import (
+ verify_ospf_neighbor,
+ config_ospf_interface,
+ clear_ospf,
+ verify_ospf_rib,
+ create_router_ospf,
+ verify_ospf_interface,
+)
+from ipaddress import IPv4Address
+
+# Global variables
+topo = None
+# Reading the data from JSON File for topology creation
+jsonFile = "{}/ospf_lan.json".format(CWD)
+try:
+ with open(jsonFile, "r") as topoJson:
+ topo = json.load(topoJson)
+except IOError:
+ assert False, "Could not read file {}".format(jsonFile)
+
+NETWORK = {
+ "ipv4": [
+ "11.0.20.1/32",
+ "11.0.20.2/32",
+ "11.0.20.3/32",
+ "11.0.20.4/32",
+ "11.0.20.5/32",
+ ]
+}
+
+"""
+Topology:
+
+ Please view in a fixed-width font such as Courier.
+ Topo : Broadcast Networks
+ +---+ +---+ +---+ +---+
+ |R0 + +R1 + +R2 + +R3 |
+ +-+-+ +-+-+ +-+-+ +-+-+
+ | | | |
+ | | | |
+ --+-----------+--------------+---------------+-----
+ Ethernet Segment
+
+Testcases:
+1. OSPF Hello protocol - Verify DR BDR Elections
+2. OSPF IFSM -Verify state change events on DR / BDR / DR Other
+
+ """
+
+
+class CreateTopo(Topo):
+ """
+ Test topology builder.
+
+ * `Topo`: Topology object
+ """
+
+ def build(self, *_args, **_opts):
+ """Build function."""
+ tgen = get_topogen(self)
+
+ # Building topology from json file
+ build_topo_from_json(tgen, topo)
+
+
+def setup_module(mod):
+ """
+ Sets up the pytest environment
+
+ * `mod`: module name
+ """
+ global topo
+ testsuite_run_time = time.asctime(time.localtime(time.time()))
+ logger.info("Testsuite start time: {}".format(testsuite_run_time))
+ logger.info("=" * 40)
+
+ logger.info("Running setup_module to create topology")
+
+ # This function initiates the topology build with Topogen...
+ tgen = Topogen(CreateTopo, mod.__name__)
+ # ... and here it calls Mininet initialization functions.
+
+ # get list of daemons needs to be started for this suite.
+ daemons = topo_daemons(tgen, topo)
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start deamons and then start routers
+ start_topology(tgen, daemons)
+
+ # Creating configuration from JSON
+ build_config_from_json(tgen, topo)
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ # Api call verify whether OSPF is converged
+ ospf_covergence = verify_ospf_neighbor(tgen, topo, lan=True)
+ assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ logger.info("Running setup_module() done")
+
+
+def teardown_module():
+ """Teardown the pytest environment"""
+
+ logger.info("Running teardown_module to delete topology")
+
+ tgen = get_topogen()
+
+ try:
+ # Stop toplogy and Remove tmp files
+ tgen.stop_topology
+
+ except OSError:
+ # OSError exception is raised when mininet tries to stop switch
+ # though switch is stopped once but mininet tries to stop same
+ # switch again, where it ended up with exception
+ pass
+
+
+def red_static(dut, config=True):
+ """Local def for Redstribute static routes inside ospf."""
+ global topo
+ tgen = get_topogen()
+ if config:
+ ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "static"}]}}}
+ else:
+ ospf_red = {
+ dut: {
+ "ospf": {
+ "redistribute": [{"redist_type": "static", "del_action": True}]
+ }
+ }
+ }
+ result = create_router_ospf(tgen, topo, ospf_red)
+ assert result is True, "Testcase : Failed \n Error: {}".format(result)
+
+
+def red_connected(dut, config=True):
+ """Local def for Redstribute connected routes inside ospf."""
+ global topo
+ tgen = get_topogen()
+ if config:
+ ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "connected"}]}}}
+ else:
+ ospf_red = {
+ dut: {
+ "ospf": {
+ "redistribute": [{"redist_type": "connected", "del_action": True}]
+ }
+ }
+ }
+ result = create_router_ospf(tgen, topo, ospf_red)
+ assert result is True, "Testcase: Failed \n Error: {}".format(result)
+
+
+# ##################################
+# Test cases start here.
+# ##################################
+
+
+def test_ospf_lan_tc1_p0(request):
+ """
+ OSPF Hello protocol - Verify DR BDR Elections
+
+ """
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ global topo
+ step("Bring up the base config as per the topology")
+ reset_config_on_routers(tgen)
+ step("Verify that DR BDR DRother are elected in the LAN.")
+ input_dict = {
+ "r0": {
+ "ospf": {
+ "neighbors": {
+ "r1": {"state": "Full", "role": "DR"},
+ "r2": {"state": "Full", "role": "DROther"},
+ "r3": {"state": "Full", "role": "DROther"},
+ }
+ }
+ }
+ }
+ dut = "r0"
+ result = verify_ospf_neighbor(tgen, topo, dut, input_dict, lan=True)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that all the routers are in FULL state with DR and BDR "
+ "in the topology"
+ )
+
+ input_dict = {
+ "r1": {
+ "ospf": {
+ "neighbors": {
+ "r0": {"state": "Full", "role": "Backup"},
+ "r2": {"state": "Full", "role": "DROther"},
+ "r3": {"state": "Full", "role": "DROther"},
+ }
+ }
+ }
+ }
+ dut = "r1"
+ result = verify_ospf_neighbor(tgen, topo, dut, input_dict, lan=True)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Configure DR pririty 100 on R0 and clear ospf neighbors " "on all the routers."
+ )
+
+ input_dict = {
+ "r0": {
+ "links": {
+ "s1": {
+ "interface": topo["routers"]["r0"]["links"]["s1"]["interface"],
+ "ospf": {"priority": 100},
+ }
+ }
+ }
+ }
+
+ result = create_interfaces_cfg(tgen, input_dict)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("Clear ospf neighbours in all routers")
+ for rtr in ["r0", "r1", "r2", "r3"]:
+ clear_ospf(tgen, rtr)
+
+ step("Verify that DR election is triggered and R0 is elected as DR")
+ input_dict = {
+ "r0": {
+ "ospf": {
+ "neighbors": {
+ "r1": {"state": "Full", "role": "Backup"},
+ "r2": {"state": "Full", "role": "DROther"},
+ "r3": {"state": "Full", "role": "DROther"},
+ }
+ }
+ }
+ }
+ dut = "r0"
+ result = verify_ospf_neighbor(tgen, topo, dut, input_dict, lan=True)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Configure DR pririty 150 on R0 and clear ospf neighbors " "on all the routers."
+ )
+
+ input_dict = {
+ "r0": {
+ "links": {
+ "s1": {
+ "interface": topo["routers"]["r0"]["links"]["s1"]["interface"],
+ "ospf": {"priority": 150},
+ }
+ }
+ }
+ }
+
+ result = create_interfaces_cfg(tgen, input_dict)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("Clear ospf neighbours in all routers")
+ for rtr in ["r0", "r1"]:
+ clear_ospf(tgen, rtr)
+
+ step("Verify that DR election is triggered and R0 is elected as DR")
+ input_dict = {
+ "r0": {
+ "ospf": {
+ "neighbors": {
+ "r1": {"state": "Full", "role": "Backup"},
+ "r2": {"state": "Full", "role": "DROther"},
+ "r3": {"state": "Full", "role": "DROther"},
+ }
+ }
+ }
+ }
+ dut = "r0"
+ result = verify_ospf_neighbor(tgen, topo, dut, input_dict, lan=True)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Configure DR priority 0 on R0 & Clear ospf nbrs on all the routers")
+
+ input_dict = {
+ "r0": {
+ "links": {
+ "s1": {
+ "interface": topo["routers"]["r0"]["links"]["s1"]["interface"],
+ "ospf": {"priority": 0},
+ }
+ }
+ }
+ }
+
+ result = create_interfaces_cfg(tgen, input_dict)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("Clear ospf neighbours in all routers")
+ for rtr in ["r1"]:
+ clear_ospf(tgen, rtr)
+
+ step("Verify that DR election is triggered and R0 is elected as DRother")
+ input_dict = {
+ "r0": {
+ "ospf": {
+ "neighbors": {
+ "r1": {"state": "Full", "role": "DR"},
+ "r2": {"state": "2-Way", "role": "DROther"},
+ "r3": {"state": "2-Way", "role": "DROther"},
+ }
+ }
+ }
+ }
+ dut = "r0"
+ result = verify_ospf_neighbor(tgen, topo, dut, input_dict, lan=True)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Configure DR priority to default on R0 and Clear ospf neighbors"
+ " on all the routers"
+ )
+
+ input_dict = {
+ "r0": {
+ "links": {
+ "s1": {
+ "interface": topo["routers"]["r0"]["links"]["s1"]["interface"],
+ "ospf": {"priority": 100},
+ }
+ }
+ }
+ }
+
+ result = create_interfaces_cfg(tgen, input_dict)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("Clear ospf neighbours in all routers")
+ for rtr in ["r0", "r1"]:
+ clear_ospf(tgen, rtr)
+
+ step("Verify that DR election is triggered and R0 is elected as DR")
+ input_dict = {
+ "r0": {
+ "ospf": {
+ "neighbors": {
+ "r1": {"state": "Full", "role": "Backup"},
+ "r2": {"state": "Full", "role": "DROther"},
+ "r3": {"state": "Full", "role": "DROther"},
+ }
+ }
+ }
+ }
+ dut = "r0"
+ result = verify_ospf_neighbor(tgen, topo, dut, input_dict, lan=True)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Shut interface on R0")
+ dut = "r0"
+ intf = topo["routers"]["r0"]["links"]["s1"]["interface"]
+ shutdown_bringup_interface(tgen, dut, intf, False)
+
+ result = verify_ospf_neighbor(tgen, topo, dut, lan=True, expected=False)
+ assert result is not True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("No Shut interface on R0")
+ dut = "r0"
+ intf = topo["routers"]["r0"]["links"]["s1"]["interface"]
+ shutdown_bringup_interface(tgen, dut, intf, True)
+
+ input_dict = {
+ "r0": {
+ "ospf": {
+ "neighbors": {
+ "r1": {"state": "Full", "role": "DR"},
+ "r2": {"state": "Full", "role": "DROther"},
+ "r3": {"state": "Full", "role": "DROther"},
+ }
+ }
+ }
+ }
+ step("Verify that after no shut ospf neighbours are full on R0.")
+ result = verify_ospf_neighbor(tgen, topo, dut, input_dict, lan=True)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Clear ospf on DR router in the topology.")
+ clear_ospf(tgen, "r0")
+
+ step("Verify that BDR is getting promoted to DR after clear.")
+ step("Verify that all the nbrs are in FULL state with the elected DR.")
+ result = verify_ospf_neighbor(tgen, topo, dut, input_dict, lan=True)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Change the ip on LAN intf on R0 to other ip from the same subnet.")
+ topo_modify_change_ip = deepcopy(topo)
+ intf_ip = topo_modify_change_ip["routers"]["r0"]["links"]["s1"]["ipv4"]
+ topo_modify_change_ip["routers"]["r0"]["links"]["s1"]["ipv4"] = str(
+ IPv4Address(unicode(intf_ip.split("/")[0])) + 3
+ ) + "/{}".format(intf_ip.split("/")[1])
+
+ build_config_from_json(tgen, topo_modify_change_ip, save_bkup=False)
+
+ step(
+ "Verify that OSPF is in FULL state with other routers with "
+ "newly configured IP."
+ )
+ result = verify_ospf_neighbor(tgen, topo, dut, input_dict, lan=True)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Change the ospf router id on the R0 and clear ip ospf interface.")
+ change_rid = {"r0": {"ospf": {"router_id": "100.1.1.100"}}}
+
+ result = create_router_ospf(tgen, topo, change_rid)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+ topo["routers"]["r0"]["ospf"]["router_id"] = "100.1.1.100"
+ step("Reload the FRR router")
+
+ stop_router(tgen, "r0")
+ start_router(tgen, "r0")
+
+ step(
+ "Verify that OSPF is in FULL state with other routers with"
+ " newly configured router id."
+ )
+ input_dict = {
+ "r1": {
+ "ospf": {
+ "neighbors": {
+ "r0": {"state": "Full", "role": "Backup"},
+ "r2": {"state": "Full", "role": "DROther"},
+ "r3": {"state": "Full", "role": "DROther"},
+ }
+ }
+ }
+ }
+ dut = "r1"
+ result = verify_ospf_neighbor(tgen, topo, dut, input_dict, lan=True)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Reconfigure the original router id and clear ip ospf interface.")
+ change_rid = {"r0": {"ospf": {"router_id": "100.1.1.0"}}}
+ result = create_router_ospf(tgen, topo, change_rid)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+ topo["routers"]["r0"]["ospf"]["router_id"] = "100.1.1.0"
+ step("Reload the FRR router")
+ # stop/start -> restart FRR router and verify
+ stop_router(tgen, "r0")
+ start_router(tgen, "r0")
+
+ step("Verify that OSPF is enabled with router id previously configured.")
+ input_dict = {
+ "r1": {
+ "ospf": {
+ "neighbors": {
+ "r0": {"state": "Full", "role": "Backup"},
+ "r2": {"state": "Full", "role": "DROther"},
+ "r3": {"state": "Full", "role": "DROther"},
+ }
+ }
+ }
+ }
+ dut = "r1"
+ result = verify_ospf_neighbor(tgen, topo, dut, input_dict, lan=True)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_ospf_lan_tc2_p0(request):
+ """
+ OSPF IFSM -Verify state change events on DR / BDR / DR Other
+
+ """
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ global topo
+ step("Bring up the base config as per the topology")
+ reset_config_on_routers(tgen)
+ step(
+ "Verify that OSPF is subscribed to multi cast services "
+ "(All SPF, all DR Routers)."
+ )
+ step("Verify that interface is enabled in ospf.")
+ dut = "r0"
+ input_dict = {
+ "r0": {
+ "links": {
+ "s1": {
+ "ospf": {
+ "priority": 98,
+ "timerDeadSecs": 4,
+ "area": "0.0.0.3",
+ "mcastMemberOspfDesignatedRouters": True,
+ "mcastMemberOspfAllRouters": True,
+ "ospfEnabled": True,
+ }
+ }
+ }
+ }
+ }
+ result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Delete the ip address")
+ topo1 = {
+ "r0": {
+ "links": {
+ "r3": {
+ "ipv4": topo["routers"]["r0"]["links"]["s1"]["ipv4"],
+ "interface": topo["routers"]["r0"]["links"]["s1"]["interface"],
+ "delete": True,
+ }
+ }
+ }
+ }
+
+ result = create_interfaces_cfg(tgen, topo1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Change the ip on the R0 interface")
+
+ topo_modify_change_ip = deepcopy(topo)
+ intf_ip = topo_modify_change_ip["routers"]["r0"]["links"]["s1"]["ipv4"]
+ topo_modify_change_ip["routers"]["r0"]["links"]["s1"]["ipv4"] = str(
+ IPv4Address(unicode(intf_ip.split("/")[0])) + 3
+ ) + "/{}".format(intf_ip.split("/")[1])
+
+ build_config_from_json(tgen, topo_modify_change_ip, save_bkup=False)
+ step("Verify that interface is enabled in ospf.")
+ dut = "r0"
+ input_dict = {
+ "r0": {
+ "links": {
+ "s1": {
+ "ospf": {
+ "ipAddress": topo_modify_change_ip["routers"]["r0"]["links"][
+ "s1"
+ ]["ipv4"].split("/")[0],
+ "ipAddressPrefixlen": int(
+ topo_modify_change_ip["routers"]["r0"]["links"]["s1"][
+ "ipv4"
+ ].split("/")[1]
+ ),
+ }
+ }
+ }
+ }
+ }
+ result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Modify the mask on the R0 interface")
+ ip_addr = topo_modify_change_ip["routers"]["r0"]["links"]["s1"]["ipv4"]
+ mask = topo_modify_change_ip["routers"]["r0"]["links"]["s1"]["ipv4"]
+ step("Delete the ip address")
+ topo1 = {
+ "r0": {
+ "links": {
+ "r3": {
+ "ipv4": ip_addr,
+ "interface": topo["routers"]["r0"]["links"]["s1"]["interface"],
+ "delete": True,
+ }
+ }
+ }
+ }
+
+ result = create_interfaces_cfg(tgen, topo1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Change the ip on the R0 interface")
+
+ topo_modify_change_ip = deepcopy(topo)
+ intf_ip = topo_modify_change_ip["routers"]["r0"]["links"]["s1"]["ipv4"]
+ topo_modify_change_ip["routers"]["r0"]["links"]["s1"]["ipv4"] = str(
+ IPv4Address(unicode(intf_ip.split("/")[0])) + 3
+ ) + "/{}".format(int(intf_ip.split("/")[1]) + 1)
+
+ build_config_from_json(tgen, topo_modify_change_ip, save_bkup=False)
+ step("Verify that interface is enabled in ospf.")
+ dut = "r0"
+ input_dict = {
+ "r0": {
+ "links": {
+ "s1": {
+ "ospf": {
+ "ipAddress": topo_modify_change_ip["routers"]["r0"]["links"][
+ "s1"
+ ]["ipv4"].split("/")[0],
+ "ipAddressPrefixlen": int(
+ topo_modify_change_ip["routers"]["r0"]["links"]["s1"][
+ "ipv4"
+ ].split("/")[1]
+ ),
+ }
+ }
+ }
+ }
+ }
+ result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Change the area id on the interface")
+ input_dict = {
+ "r0": {
+ "links": {
+ "s1": {
+ "interface": topo["routers"]["r0"]["links"]["s1"]["interface"],
+ "ospf": {"area": "0.0.0.3"},
+ "delete": True,
+ }
+ }
+ }
+ }
+
+ result = create_interfaces_cfg(tgen, input_dict)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ input_dict = {
+ "r0": {
+ "links": {
+ "s1": {
+ "interface": topo["routers"]["r0"]["links"]["s1"]["interface"],
+ "ospf": {"area": "0.0.0.2"},
+ }
+ }
+ }
+ }
+
+ result = create_interfaces_cfg(tgen, input_dict)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+ step("Verify that interface is enabled in ospf.")
+ dut = "r0"
+ input_dict = {
+ "r0": {"links": {"s1": {"ospf": {"area": "0.0.0.2", "ospfEnabled": True}}}}
+ }
+ result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_nssa.py b/tests/topotests/ospf_basic_functionality/test_ospf_nssa.py
new file mode 100644
index 0000000000..ff4399f19e
--- /dev/null
+++ b/tests/topotests/ospf_basic_functionality/test_ospf_nssa.py
@@ -0,0 +1,336 @@
+#!/usr/bin/python
+
+#
+# Copyright (c) 2020 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation, Inc.
+# ("NetDEF") in this file.
+#
+# 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 VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE 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.
+#
+
+
+"""OSPF Basic Functionality Automation."""
+import ipaddress
+from lib.ospf import (
+ verify_ospf_neighbor,
+ config_ospf_interface,
+ clear_ospf,
+ verify_ospf_rib,
+ create_router_ospf,
+ verify_ospf_interface,
+)
+from lib.topojson import build_topo_from_json, build_config_from_json
+from lib.topolog import logger
+from lib.common_config import (
+ start_topology,
+ write_test_header,
+ write_test_footer,
+ reset_config_on_routers,
+ verify_rib,
+ create_static_routes,
+ step,
+ create_route_maps,
+ shutdown_bringup_interface,
+ create_interfaces_cfg,
+ topo_daemons
+)
+from ipaddress import IPv4Address
+from lib.topogen import Topogen, get_topogen
+from mininet.topo import Topo
+import os
+import sys
+import time
+import pytest
+import json
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+sys.path.append(os.path.join(CWD, "../lib/"))
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+
+# Global variables
+topo = None
+# Reading the data from JSON File for topology creation
+jsonFile = "{}/ospf_nssa.json".format(CWD)
+try:
+ with open(jsonFile, "r") as topoJson:
+ topo = json.load(topoJson)
+except IOError:
+ assert False, "Could not read file {}".format(jsonFile)
+NETWORK = {
+ "ipv4": [
+ "11.0.20.1/32",
+ "11.0.20.2/32",
+ "11.0.20.3/32",
+ "11.0.20.4/32",
+ "11.0.20.5/32",
+ ]
+}
+"""
+TOPOOLOGY =
+ Please view in a fixed-width font such as Courier.
+ +---+ A1 +---+
+ +R1 +------------+R2 |
+ +-+-+- +--++
+ | -- -- |
+ | -- A0 -- |
+ A0| ---- |
+ | ---- | A2
+ | -- -- |
+ | -- -- |
+ +-+-+- +-+-+
+ +R0 +-------------+R3 |
+ +---+ A3 +---+
+
+
+
+TESTCASES =
+1. OSPF Learning - Verify OSPF can learn different types of LSA and
+ processes them.[Edge learning different types of LSAs]
+2. Verify that ospf non back bone area can be configured as NSSA area
+3. Verify that ospf NSSA area DUT is capable receiving & processing
+ Type7 N2 route.
+"""
+
+
+class CreateTopo(Topo):
+ """
+ Test topology builder.
+
+ * `Topo`: Topology object
+ """
+
+ def build(self, *_args, **_opts):
+ """Build function."""
+ tgen = get_topogen(self)
+
+ # Building topology from json file
+ build_topo_from_json(tgen, topo)
+
+
+def setup_module(mod):
+ """
+ Sets up the pytest environment
+
+ * `mod`: module name
+ """
+ global topo
+ testsuite_run_time = time.asctime(time.localtime(time.time()))
+ logger.info("Testsuite start time: {}".format(testsuite_run_time))
+ logger.info("=" * 40)
+
+ logger.info("Running setup_module to create topology")
+
+ # This function initiates the topology build with Topogen...
+ tgen = Topogen(CreateTopo, mod.__name__)
+ # ... and here it calls Mininet initialization functions.
+
+ # get list of daemons needs to be started for this suite.
+ daemons = topo_daemons(tgen, topo)
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start deamons and then start routers
+ start_topology(tgen, daemons)
+
+ # Creating configuration from JSON
+ build_config_from_json(tgen, topo)
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ # Api call verify whether OSPF is converged
+ ospf_covergence = verify_ospf_neighbor(tgen, topo)
+ assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ logger.info("Running setup_module() done")
+
+
+def teardown_module(mod):
+ """
+ Teardown the pytest environment.
+
+ * `mod`: module name
+ """
+
+ logger.info("Running teardown_module to delete topology")
+
+ tgen = get_topogen()
+
+ # Stop toplogy and Remove tmp files
+ tgen.stop_topology()
+
+ logger.info(
+ "Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
+ )
+ logger.info("=" * 40)
+
+
+def red_static(dut, config=True):
+ """Local def for Redstribute static routes inside ospf."""
+ global topo
+ tgen = get_topogen()
+ if config:
+ ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "static"}]}}}
+ else:
+ ospf_red = {
+ dut: {"ospf": {"redistribute": [{"redist_type": "static", "delete": True}]}}
+ }
+ result = create_router_ospf(tgen, topo, ospf_red)
+ assert result is True, "Testcase : Failed \n Error: {}".format(result)
+
+
+def red_connected(dut, config=True):
+ """Local def for Redstribute connected routes inside ospf."""
+ global topo
+ tgen = get_topogen()
+ if config:
+ ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "connected"}]}}}
+ else:
+ ospf_red = {
+ dut: {
+ "ospf": {
+ "redistribute": [{"redist_type": "connected", "del_action": True}]
+ }
+ }
+ }
+ result = create_router_ospf(tgen, topo, ospf_red)
+ assert result is True, "Testcase: Failed \n Error: {}".format(result)
+
+
+# ##################################
+# Test cases start here.
+# ##################################
+
+
+def test_ospf_learning_tc15_p0(request):
+ """Verify OSPF can learn different types of LSA and processes them.
+
+ OSPF Learning : Edge learning different types of LSAs.
+ """
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ global topo
+ step("Bring up the base config as per the topology")
+ step("Configure area 1 as NSSA Area")
+
+ reset_config_on_routers(tgen)
+
+ step("Verify that Type 3 summary LSA is originated for the same Area 0")
+ ip = topo["routers"]["r1"]["links"]["r3-link0"]["ipv4"]
+ ip_net = str(ipaddress.ip_interface(u"{}".format(ip)).network)
+
+ dut = "r0"
+ input_dict = {
+ "r1": {
+ "static_routes": [{"network": ip_net, "no_of_ip": 1, "routeType": "N IA"}]
+ }
+ }
+
+ dut = "r0"
+ result = verify_ospf_rib(tgen, dut, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ protocol = "ospf"
+ result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ input_dict = {
+ "r2": {
+ "static_routes": [
+ {"network": NETWORK["ipv4"][0], "no_of_ip": 5, "next_hop": "Null0"}
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Redistribute static route in R2 ospf.")
+ dut = "r2"
+ red_static(dut)
+
+ step("Verify that Type 5 LSA is originated by R2.")
+ dut = "r0"
+ protocol = "ospf"
+ result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify that R0 receives Type 4 summary LSA.")
+ dut = "r0"
+ input_dict = {
+ "r1": {
+ "static_routes": [
+ {"network": NETWORK["ipv4"][0], "no_of_ip": 1, "routeType": "N E2"}
+ ]
+ }
+ }
+
+ dut = "r1"
+ result = verify_ospf_rib(tgen, dut, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ ospf_covergence = verify_ospf_neighbor(tgen, topo)
+ assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ step("Change area 1 as non nssa area (on the fly changing area" " type on DUT).")
+
+ for rtr in ["r1", "r2", "r3"]:
+ input_dict = {
+ rtr: {"ospf": {"area": [{"id": "0.0.0.2", "type": "nssa", "delete": True}]}}
+ }
+ result = create_router_ospf(tgen, topo, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Verify that OSPF neighbours are reset after changing area type.")
+ step("Verify that ABR R2 originates type 5 LSA in area 1.")
+ step("Verify that route is calculated and installed in R1.")
+
+ input_dict = {
+ "r1": {
+ "static_routes": [
+ {"network": NETWORK["ipv4"][0], "no_of_ip": 1, "routeType": "N E2"}
+ ]
+ }
+ }
+
+ dut = "r1"
+ result = verify_ospf_rib(tgen, dut, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py b/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py
new file mode 100644
index 0000000000..6ebc74a013
--- /dev/null
+++ b/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py
@@ -0,0 +1,540 @@
+#!/usr/bin/python
+
+#
+# Copyright (c) 2020 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation, Inc.
+# ("NetDEF") in this file.
+#
+# 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 VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE 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.
+#
+
+
+"""OSPF Basic Functionality Automation."""
+import os
+import sys
+import time
+import pytest
+import json
+from copy import deepcopy
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+sys.path.append(os.path.join(CWD, "../lib/"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from mininet.topo import Topo
+from lib.topogen import Topogen, get_topogen
+
+# Import topoJson from lib, to create topology and initial configuration
+from lib.common_config import (
+ start_topology,
+ write_test_header,
+ write_test_footer,
+ reset_config_on_routers,
+ create_prefix_lists,
+ verify_rib,
+ create_static_routes,
+ check_address_types,
+ step,
+ create_route_maps,
+ verify_prefix_lists,
+ topo_daemons
+)
+from lib.topolog import logger
+from lib.topojson import build_topo_from_json, build_config_from_json
+from lib.ospf import (
+ verify_ospf_neighbor,
+ clear_ospf,
+ verify_ospf_rib,
+ create_router_ospf,
+ verify_ospf_database,
+)
+
+# Global variables
+topo = None
+# Reading the data from JSON File for topology creation
+jsonFile = "{}/ospf_routemaps.json".format(CWD)
+try:
+ with open(jsonFile, "r") as topoJson:
+ topo = json.load(topoJson)
+except IOError:
+ assert False, "Could not read file {}".format(jsonFile)
+
+NETWORK = {
+ "ipv4": [
+ "11.0.20.1/32",
+ "11.0.20.2/32",
+ "11.0.20.3/32",
+ "11.0.20.4/32",
+ "11.0.20.5/32",
+ ]
+}
+routerids = ["100.1.1.0", "100.1.1.1", "100.1.1.2", "100.1.1.3"]
+
+"""
+TOPOOLOGY =
+ Please view in a fixed-width font such as Courier.
+ +---+ A1 +---+
+ +R1 +------------+R2 |
+ +-+-+- +--++
+ | -- -- |
+ | -- A0 -- |
+ A0| ---- |
+ | ---- | A2
+ | -- -- |
+ | -- -- |
+ +-+-+- +-+-+
+ +R0 +-------------+R3 |
+ +---+ A3 +---+
+
+TESTCASES =
+1. OSPF Route map - Verify OSPF route map support functionality.
+2. Verify OSPF route map support functionality when route map is not
+ configured at system level but configured in OSPF
+3. Verify OSPF route map support functionality with set/match clauses
+ /call/continue/goto in a route-map to see if it takes immediate effect.
+4. Verify OSPF route map support functionality
+ when route map actions are toggled.
+5. Verify OSPF route map support functionality with multiple sequence
+ numbers in a single route-map for different match/set clauses.
+6. Verify OSPF route map support functionality when we add/remove route-maps
+ with multiple set clauses and without any match statement.(Set only)
+7. Verify OSPF route map support functionality when we
+ add/remove route-maps with multiple match clauses and without
+ any set statement.(Match only)
+ """
+
+
+class CreateTopo(Topo):
+ """
+ Test topology builder.
+
+ * `Topo`: Topology object
+ """
+
+ def build(self, *_args, **_opts):
+ """Build function."""
+ tgen = get_topogen(self)
+
+ # Building topology from json file
+ build_topo_from_json(tgen, topo)
+
+
+def setup_module(mod):
+ """
+ Sets up the pytest environment
+
+ * `mod`: module name
+ """
+ global topo
+ testsuite_run_time = time.asctime(time.localtime(time.time()))
+ logger.info("Testsuite start time: {}".format(testsuite_run_time))
+ logger.info("=" * 40)
+
+ logger.info("Running setup_module to create topology")
+
+ # This function initiates the topology build with Topogen...
+ tgen = Topogen(CreateTopo, mod.__name__)
+ # ... and here it calls Mininet initialization functions.
+
+ # get list of daemons needs to be started for this suite.
+ daemons = topo_daemons(tgen, topo)
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start deamons and then start routers
+ start_topology(tgen, daemons)
+
+ # Creating configuration from JSON
+ build_config_from_json(tgen, topo)
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ # Api call verify whether OSPF is converged
+ ospf_covergence = verify_ospf_neighbor(tgen, topo)
+ assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ logger.info("Running setup_module() done")
+
+
+def teardown_module(mod):
+ """
+ Teardown the pytest environment.
+
+ * `mod`: module name
+ """
+
+ logger.info("Running teardown_module to delete topology")
+
+ tgen = get_topogen()
+
+ # Stop toplogy and Remove tmp files
+ tgen.stop_topology()
+
+ logger.info(
+ "Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
+ )
+ logger.info("=" * 40)
+
+
+# ##################################
+# Test cases start here.
+# ##################################
+
+
+def test_ospf_routemaps_functionality_tc20_p0(request):
+ """
+ OSPF route map support functionality.
+
+ Verify OSPF route map support functionality when route map is not
+ configured at system level but configured in OSPF
+
+ """
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+ global topo
+ step("Bring up the base config as per the topology")
+ reset_config_on_routers(tgen)
+
+ step("Create static routes(10.0.20.1/32 and 10.0.20.2/32) in R0")
+ # Create Static routes
+ input_dict = {
+ "r0": {
+ "static_routes": [
+ {"network": NETWORK["ipv4"][0], "no_of_ip": 5, "next_hop": "Null0",}
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Redistribute to ospf using route map ( non existent route map)")
+ ospf_red_r1 = {
+ "r0": {
+ "ospf": {
+ "redistribute": [{"redist_type": "static", "route_map": "rmap_ipv4"}]
+ }
+ }
+ }
+ result = create_router_ospf(tgen, topo, ospf_red_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that routes are not allowed in OSPF even tough no "
+ "matching routing map is configured."
+ )
+
+ dut = "r1"
+ protocol = "ospf"
+ result = verify_ospf_rib(tgen, dut, input_dict, attempts=2, expected=False)
+ assert result is not True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(
+ tgen, "ipv4", dut, input_dict, protocol=protocol, attempts=2, expected=False
+ )
+ assert result is not True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "configure the route map with the same name that is used "
+ "in the ospf with deny rule."
+ )
+
+ # Create route map
+ routemaps = {"r0": {"route_maps": {"rmap_ipv4": [{"action": "deny"}]}}}
+ result = create_route_maps(tgen, routemaps)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("verify that now route map is activated & routes are denied in OSPF.")
+ dut = "r1"
+ protocol = "ospf"
+ result = verify_ospf_rib(tgen, dut, input_dict, expected=False)
+ assert result is not True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(
+ tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False
+ )
+ assert result is not True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ # Create route map
+ routemaps = {"r0": {"route_maps": {"rmap_ipv4": [{"action": "deny"}]}}}
+ result = create_route_maps(tgen, routemaps)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("verify that now route map is activated & routes are denied in OSPF.")
+ dut = "r1"
+ protocol = "ospf"
+ result = verify_ospf_rib(tgen, dut, input_dict, expected=False)
+ assert result is not True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(
+ tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False
+ )
+ assert result is not True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Delete the route map.")
+ # Create route map
+ routemaps = {
+ "r0": {"route_maps": {"rmap_ipv4": [{"action": "deny", "delete": True}]}}
+ }
+ result = create_route_maps(tgen, routemaps)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that routes are allowed in OSPF even tough "
+ "no matching routing map is configured."
+ )
+ dut = "r1"
+ protocol = "ospf"
+ result = verify_ospf_rib(tgen, dut, input_dict, expected=False)
+ assert result is not True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(
+ tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False
+ )
+ assert result is not True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_ospf_routemaps_functionality_tc24_p0(request):
+ """
+ OSPF Route map - Multiple set clauses.
+
+ Verify OSPF route map support functionality when we
+ add/remove route-maps with multiple match clauses and without
+ any set statement.(Match only)
+
+ """
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+ global topo
+ step("Bring up the base config as per the topology")
+ reset_config_on_routers(tgen)
+
+ step(
+ "Create static routes(10.0.20.1/32) in R1 and redistribute to "
+ "OSPF using route map."
+ )
+ # Create Static routes
+ input_dict = {
+ "r0": {
+ "static_routes": [
+ {"network": NETWORK["ipv4"][0], "no_of_ip": 1, "next_hop": "Null0",}
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ ospf_red_r0 = {
+ "r0": {
+ "ospf": {
+ "redistribute": [{"redist_type": "static", "route_map": "rmap_ipv4"}]
+ }
+ }
+ }
+ result = create_router_ospf(tgen, topo, ospf_red_r0)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ # Create ip prefix list
+ pfx_list = {
+ "r0": {
+ "prefix_lists": {
+ "ipv4": {
+ "pf_list_1_ipv4": [
+ {"seqid": 10, "network": "any", "action": "permit"}
+ ]
+ }
+ }
+ }
+ }
+ result = create_prefix_lists(tgen, pfx_list)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("verify that prefix-list is created in R0.")
+ result = verify_prefix_lists(tgen, pfx_list)
+ assert result is not True, (
+ "Testcase {} : Failed \n Prefix list not "
+ "present. Error: {}".format(tc_name, result)
+ )
+
+ # Create route map
+ routemaps = {
+ "r0": {
+ "route_maps": {
+ "rmap_ipv4": [
+ {
+ "action": "permit",
+ "match": {"ipv4": {"prefix_lists": "pf_list_1_ipv4"}},
+ }
+ ]
+ }
+ }
+ }
+ result = create_route_maps(tgen, routemaps)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify that metric falls back to original metric for ospf routes.")
+ dut = "r1"
+ protocol = "ospf"
+
+ result = verify_ospf_rib(tgen, dut, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Create static routes(10.0.20.1/32) in R1 and redistribute to "
+ "OSPF using route map."
+ )
+ # Create Static routes
+ input_dict = {
+ "r0": {
+ "static_routes": [
+ {
+ "network": NETWORK["ipv4"][1],
+ "no_of_ip": 1,
+ "next_hop": "Null0",
+ "tag": 1000,
+ }
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ # Create ip prefix list
+ pfx_list = {
+ "r0": {
+ "prefix_lists": {
+ "ipv4": {
+ "pf_list_1_ipv4": [
+ {"seqid": 10, "network": "any", "action": "permit"}
+ ]
+ }
+ }
+ }
+ }
+ result = create_prefix_lists(tgen, pfx_list)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("verify that prefix-list is created in R0.")
+ result = verify_prefix_lists(tgen, pfx_list)
+ assert result is not True, (
+ "Testcase {} : Failed \n Prefix list not "
+ "present. Error: {}".format(tc_name, result)
+ )
+
+ # Create route map
+ routemaps = {
+ "r0": {
+ "route_maps": {
+ "rmap_ipv4": [{"action": "permit", "match": {"ipv4": {"tag": "1000"}}}]
+ }
+ }
+ }
+ result = create_route_maps(tgen, routemaps)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify that metric falls back to original metric for ospf routes.")
+ dut = "r1"
+ protocol = "ospf"
+
+ result = verify_ospf_rib(tgen, dut, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Delete the match clause with tag in route map")
+ # Create route map
+ routemaps = {
+ "r0": {
+ "route_maps": {
+ "rmap_ipv4": [
+ {
+ "action": "permit",
+ "match": {"ipv4": {"tag": "1000", "delete": True}},
+ }
+ ]
+ }
+ }
+ }
+ result = create_route_maps(tgen, routemaps)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify that metric falls back to original metric for ospf routes.")
+ dut = "r1"
+ protocol = "ospf"
+
+ result = verify_ospf_rib(tgen, dut, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Delete the match clause with metric in route map.")
+
+ # Create route map
+ routemaps = {
+ "r0": {
+ "route_maps": {
+ "rmap_ipv4": [
+ {
+ "action": "permit",
+ "match": {"ipv4": {"prefix_lists": "pf_list_1_ipv4"}},
+ }
+ ]
+ }
+ }
+ }
+ result = create_route_maps(tgen, routemaps)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ result = verify_ospf_rib(tgen, dut, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py b/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py
new file mode 100644
index 0000000000..2c6bcf0162
--- /dev/null
+++ b/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py
@@ -0,0 +1,612 @@
+#!/usr/bin/python
+
+#
+# Copyright (c) 2020 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation, Inc.
+# ("NetDEF") in this file.
+#
+# 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 VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE 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.
+#
+
+
+"""OSPF Basic Functionality Automation."""
+import os
+import sys
+import time
+import pytest
+import ipaddress
+import json
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+sys.path.append(os.path.join(CWD, "../lib/"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from mininet.topo import Topo
+from lib.topogen import Topogen, get_topogen
+
+# Import topoJson from lib, to create topology and initial configuration
+from lib.common_config import (
+ start_topology,
+ write_test_header,
+ create_interfaces_cfg,
+ write_test_footer,
+ reset_config_on_routers,
+ verify_rib,
+ create_static_routes,
+ step,
+ shutdown_bringup_interface,
+ topo_daemons
+)
+from lib.bgp import verify_bgp_convergence, create_router_bgp
+from lib.topolog import logger
+from lib.topojson import build_topo_from_json, build_config_from_json
+
+from lib.ospf import (
+ verify_ospf_neighbor,
+ clear_ospf,
+ verify_ospf_rib,
+ create_router_ospf,
+)
+
+# Global variables
+topo = None
+
+# number of retries.
+nretry = 5
+
+# Reading the data from JSON File for topology creation
+jsonFile = "{}/ospf_rte_calc.json".format(CWD)
+try:
+ with open(jsonFile, "r") as topoJson:
+ topo = json.load(topoJson)
+except IOError:
+ assert False, "Could not read file {}".format(jsonFile)
+
+NETWORK = {
+ "ipv4": [
+ "11.0.20.1/32",
+ "11.0.20.2/32",
+ "11.0.20.3/32",
+ "11.0.20.4/32",
+ "11.0.20.5/32",
+ ]
+}
+TOPOOLOGY = """
+ Please view in a fixed-width font such as Courier.
+ +---+ A1 +---+
+ +R1 +------------+R2 |
+ +-+-+- +--++
+ | -- -- |
+ | -- A0 -- |
+ A0| ---- |
+ | ---- | A2
+ | -- -- |
+ | -- -- |
+ +-+-+- +-+-+
+ +R0 +-------------+R3 |
+ +---+ A3 +---+
+"""
+
+TESTCASES = """
+1. Test OSPF intra area route calculations.
+2. Test OSPF inter area route calculations.
+3. Test OSPF redistribution of connected routes.
+"""
+
+
+class CreateTopo(Topo):
+ """
+ Test topology builder.
+
+ * `Topo`: Topology object
+ """
+
+ def build(self, *_args, **_opts):
+ """Build function."""
+ tgen = get_topogen(self)
+
+ # Building topology from json file
+ build_topo_from_json(tgen, topo)
+
+
+def setup_module(mod):
+ """
+ Sets up the pytest environment
+
+ * `mod`: module name
+ """
+ global topo
+ testsuite_run_time = time.asctime(time.localtime(time.time()))
+ logger.info("Testsuite start time: {}".format(testsuite_run_time))
+ logger.info("=" * 40)
+
+ logger.info("Running setup_module to create topology")
+
+ # This function initiates the topology build with Topogen...
+ tgen = Topogen(CreateTopo, mod.__name__)
+ # ... and here it calls Mininet initialization functions.
+
+ # get list of daemons needs to be started for this suite.
+ daemons = topo_daemons(tgen, topo)
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start deamons and then start routers
+ start_topology(tgen, daemons)
+
+ # Creating configuration from JSON
+ build_config_from_json(tgen, topo)
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ # Api call verify whether OSPF is converged
+ ospf_covergence = verify_ospf_neighbor(tgen, topo)
+ assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ logger.info("Running setup_module() done")
+
+
+def teardown_module(mod):
+ """
+ Teardown the pytest environment.
+
+ * `mod`: module name
+ """
+
+ logger.info("Running teardown_module to delete topology")
+
+ tgen = get_topogen()
+
+ # Stop toplogy and Remove tmp files
+ tgen.stop_topology()
+
+ logger.info(
+ "Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
+ )
+ logger.info("=" * 40)
+
+
+def red_static(dut, config=True):
+ """Local def for Redstribute static routes inside ospf."""
+ global topo
+ tgen = get_topogen()
+ if config:
+ ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "static"}]}}}
+ else:
+ ospf_red = {
+ dut: {
+ "ospf": {
+ "redistribute": [{"redist_type": "static", "del_action": True}]
+ }
+ }
+ }
+ result = create_router_ospf(tgen, topo, ospf_red)
+ assert result is True, "Testcase : Failed \n Error: {}".format(result)
+
+
+def red_connected(dut, config=True):
+ """Local def for Redstribute connected routes inside ospf."""
+ global topo
+ tgen = get_topogen()
+ if config:
+ ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "connected"}]}}}
+ else:
+ ospf_red = {
+ dut: {
+ "ospf": {
+ "redistribute": [{"redist_type": "connected", "del_action": True}]
+ }
+ }
+ }
+ result = create_router_ospf(tgen, topo, ospf_red)
+ assert result is True, "Testcase: Failed \n Error: {}".format(result)
+
+
+# ##################################
+# Test cases start here.
+# ##################################
+
+
+def test_ospf_redistribution_tc5_p0(request):
+ """Test OSPF intra area route calculations."""
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ global topo
+ step("Bring up the base config.")
+ reset_config_on_routers(tgen)
+
+ step("Verify that OSPF neighbors are FULL.")
+ ospf_covergence = verify_ospf_neighbor(tgen, topo)
+ assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ step("verify intra area route is calculated for r0-r3 interface ip in R1")
+ ip = topo["routers"]["r0"]["links"]["r3"]["ipv4"]
+ ip_net = str(ipaddress.ip_interface(u"{}".format(ip)).network)
+ nh = topo["routers"]["r0"]["links"]["r1"]["ipv4"].split("/")[0]
+ input_dict = {
+ "r1": {"static_routes": [{"network": ip_net, "no_of_ip": 1, "routeType": "N"}]}
+ }
+
+ dut = "r1"
+ result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ protocol = "ospf"
+ result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, next_hop=nh)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Delete the ip address on newly configured interface of R0")
+ topo1 = {
+ "r0": {
+ "links": {
+ "r3": {
+ "ipv4": topo["routers"]["r0"]["links"]["r3"]["ipv4"],
+ "interface": topo["routers"]["r0"]["links"]["r3"]["interface"],
+ "delete": True,
+ }
+ }
+ }
+ }
+
+ result = create_interfaces_cfg(tgen, topo1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ dut = "r1"
+ for num in range(0, nretry):
+ result = verify_ospf_rib(
+ tgen, dut, input_dict, next_hop=nh, expected=False)
+ if result is not True:
+ break
+
+ assert result is not True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ protocol = "ospf"
+ result = verify_rib(
+ tgen,
+ "ipv4",
+ dut,
+ input_dict,
+ protocol=protocol,
+ next_hop=nh,
+ attempts=5,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Add back the deleted ip address on newly configured interface of R0")
+ topo1 = {
+ "r0": {
+ "links": {
+ "r3": {
+ "ipv4": topo["routers"]["r0"]["links"]["r3"]["ipv4"],
+ "interface": topo["routers"]["r0"]["links"]["r3"]["interface"],
+ }
+ }
+ }
+ }
+
+ result = create_interfaces_cfg(tgen, topo1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ dut = "r1"
+ result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ protocol = "ospf"
+ result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, next_hop=nh)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Shut no shut interface on R0")
+ dut = "r0"
+ intf = topo["routers"]["r0"]["links"]["r3"]["interface"]
+ shutdown_bringup_interface(tgen, dut, intf, False)
+
+ step("un shut the OSPF interface on R0")
+ dut = "r0"
+ shutdown_bringup_interface(tgen, dut, intf, True)
+
+ dut = "r1"
+ result = verify_ospf_rib(tgen, dut, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ protocol = "ospf"
+ result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, next_hop=nh)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_ospf_redistribution_tc6_p0(request):
+ """Test OSPF inter area route calculations."""
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ global topo
+ step("Bring up the base config.")
+ reset_config_on_routers(tgen)
+
+ step("Verify that OSPF neighbors are FULL.")
+ ospf_covergence = verify_ospf_neighbor(tgen, topo)
+ assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ step("verify intra area route is calculated for r0-r3 interface ip in R1")
+ ip = topo["routers"]["r0"]["links"]["r3"]["ipv4"]
+ ip_net = str(ipaddress.ip_interface(u"{}".format(ip)).network)
+ nh = topo["routers"]["r0"]["links"]["r1"]["ipv4"].split("/")[0]
+ input_dict = {
+ "r1": {"static_routes": [{"network": ip_net, "no_of_ip": 1, "routeType": "N"}]}
+ }
+
+ dut = "r1"
+ result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ protocol = "ospf"
+ result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, next_hop=nh)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Delete the ip address on newly configured loopback of R0")
+ topo1 = {
+ "r0": {
+ "links": {
+ "r3": {
+ "ipv4": topo["routers"]["r0"]["links"]["r3"]["ipv4"],
+ "interface": topo["routers"]["r0"]["links"]["r3"]["interface"],
+ "delete": True,
+ }
+ }
+ }
+ }
+
+ result = create_interfaces_cfg(tgen, topo1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ dut = "r1"
+ for num in range(0, nretry):
+ result = verify_ospf_rib(
+ tgen, dut, input_dict, next_hop=nh, expected=False)
+ if result is not True:
+ break
+ assert result is not True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ protocol = "ospf"
+ result = verify_rib(
+ tgen,
+ "ipv4",
+ dut,
+ input_dict,
+ protocol=protocol,
+ next_hop=nh,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Add back the deleted ip address on newly configured interface of R0")
+ topo1 = {
+ "r0": {
+ "links": {
+ "r3": {
+ "ipv4": topo["routers"]["r0"]["links"]["r3"]["ipv4"],
+ "interface": topo["routers"]["r0"]["links"]["r3"]["interface"],
+ }
+ }
+ }
+ }
+
+ result = create_interfaces_cfg(tgen, topo1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ dut = "r1"
+ result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ protocol = "ospf"
+ result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, next_hop=nh)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Shut no shut interface on R0")
+ dut = "r0"
+ intf = topo["routers"]["r0"]["links"]["r3"]["interface"]
+ shutdown_bringup_interface(tgen, dut, intf, False)
+
+ step("un shut the OSPF interface on R0")
+ dut = "r0"
+ shutdown_bringup_interface(tgen, dut, intf, True)
+
+ dut = "r1"
+ result = verify_ospf_rib(tgen, dut, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ protocol = "ospf"
+ result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, next_hop=nh)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_ospf_redistribution_tc8_p1(request):
+ """
+ Test OSPF redistribution of connected routes.
+
+ Verify OSPF redistribution of connected routes when bgp multi hop
+ neighbor is configured using ospf routes
+
+ """
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+ global topo
+ step("Bring up the base config.")
+ step(
+ "Configure loopback interface on all routers, and redistribut"
+ "e connected routes into ospf"
+ )
+ reset_config_on_routers(tgen)
+
+ step(
+ "verify that connected routes -loopback is found in all routers"
+ "advertised/exchaged via ospf"
+ )
+ for rtr in topo["routers"]:
+ red_static(rtr)
+ red_connected(rtr)
+ for node in topo["routers"]:
+ input_dict = {
+ "r0": {
+ "static_routes": [
+ {
+ "network": topo["routers"][node]["links"]["lo"]["ipv4"],
+ "no_of_ip": 1,
+ }
+ ]
+ }
+ }
+ for rtr in topo["routers"]:
+ result = verify_rib(tgen, "ipv4", rtr, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure E BGP multi hop using the loopback addresses.")
+ as_num = 100
+ for node in topo["routers"]:
+ as_num += 1
+ topo["routers"][node].update(
+ {
+ "bgp": {
+ "local_as": as_num,
+ "address_family": {"ipv4": {"unicast": {"neighbor": {}}}},
+ }
+ }
+ )
+ for node in topo["routers"]:
+ for rtr in topo["routers"]:
+ if node is not rtr:
+ topo["routers"][node]["bgp"]["address_family"]["ipv4"]["unicast"][
+ "neighbor"
+ ].update(
+ {
+ rtr: {
+ "dest_link": {
+ "lo": {"source_link": "lo", "ebgp_multihop": 2}
+ }
+ }
+ }
+ )
+
+ result = create_router_bgp(tgen, topo, topo["routers"])
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify that BGP neighbor is ESTABLISHED")
+ result = verify_bgp_convergence(tgen, topo)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+ step(
+ "Configure couple of static routes in R0 and "
+ "Redistribute static routes in R1 bgp."
+ )
+
+ for rtr in topo["routers"]:
+ ospf_red = {
+ rtr: {"ospf": {"redistribute": [{"redist_type": "static", "delete": True}]}}
+ }
+ result = create_router_ospf(tgen, topo, ospf_red)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ input_dict = {
+ "r0": {
+ "static_routes": [
+ {"network": NETWORK["ipv4"][0], "no_of_ip": 5, "next_hop": "Null0",}
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ configure_bgp_on_r0 = {
+ "r0": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {"unicast": {"redistribute": [{"redist_type": "static"}]}}
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, configure_bgp_on_r0)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+ protocol = "bgp"
+ for rtr in ["r1", "r2", "r3"]:
+ result = verify_rib(tgen, "ipv4", rtr, input_dict, protocol=protocol)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Clear ospf neighbours in R0")
+ for rtr in topo["routers"]:
+ clear_ospf(tgen, rtr)
+
+ step("Verify that OSPF neighbours are reset and forms new adjacencies.")
+ # Api call verify whether OSPF is converged
+ ospf_covergence = verify_ospf_neighbor(tgen, topo)
+ assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ step("Verify that BGP neighbours are reset and forms new adjacencies.")
+ result = verify_bgp_convergence(tgen, topo)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ protocol = "bgp"
+ for rtr in ["r1", "r2", "r3"]:
+ result = verify_rib(tgen, "ipv4", rtr, input_dict, protocol=protocol)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_single_area.py b/tests/topotests/ospf_basic_functionality/test_ospf_single_area.py
new file mode 100644
index 0000000000..5a141224f1
--- /dev/null
+++ b/tests/topotests/ospf_basic_functionality/test_ospf_single_area.py
@@ -0,0 +1,781 @@
+#!/usr/bin/python
+
+#
+# Copyright (c) 2020 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation, Inc.
+# ("NetDEF") in this file.
+#
+# 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 VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE 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.
+#
+
+
+"""OSPF Basic Functionality Automation."""
+import os
+import sys
+import time
+import pytest
+import json
+from copy import deepcopy
+from ipaddress import IPv4Address
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+sys.path.append(os.path.join(CWD, "../lib/"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from mininet.topo import Topo
+from lib.topogen import Topogen, get_topogen
+import ipaddress
+
+# Import topoJson from lib, to create topology and initial configuration
+from lib.common_config import (
+ start_topology,
+ write_test_header,
+ write_test_footer,
+ reset_config_on_routers,
+ verify_rib,
+ create_static_routes,
+ step,
+ create_route_maps,
+ shutdown_bringup_interface,
+ create_interfaces_cfg,
+ topo_daemons
+)
+from lib.topolog import logger
+from lib.topojson import build_topo_from_json, build_config_from_json
+
+from lib.ospf import (
+ verify_ospf_neighbor,
+ config_ospf_interface,
+ clear_ospf,
+ verify_ospf_rib,
+ create_router_ospf,
+ verify_ospf_interface,
+ verify_ospf_database,
+)
+
+# Global variables
+topo = None
+
+# Reading the data from JSON File for topology creation
+jsonFile = "{}/ospf_single_area.json".format(CWD)
+try:
+ with open(jsonFile, "r") as topoJson:
+ topo = json.load(topoJson)
+except IOError:
+ assert False, "Could not read file {}".format(jsonFile)
+
+"""
+TOPOOLOGY =
+ Please view in a fixed-width font such as Courier.
+ +---+ A1 +---+
+ +R1 +------------+R2 |
+ +-+-+- +--++
+ | -- -- |
+ | -- A0 -- |
+ A0| ---- |
+ | ---- | A2
+ | -- -- |
+ | -- -- |
+ +-+-+- +-+-+
+ +R0 +-------------+R3 |
+ +---+ A3 +---+
+
+TESTCASES =
+1. OSPF IFSM -Verify state change events on p2p network.
+2. OSPF Timers - Verify OSPF interface timer hello interval functionality
+3. OSPF Timers - Verify OSPF interface timer dead interval functionality
+4. Verify ospf show commands with json output.
+ """
+
+
+class CreateTopo(Topo):
+ """
+ Test topology builder.
+
+ * `Topo`: Topology object
+ """
+
+ def build(self, *_args, **_opts):
+ """Build function."""
+ tgen = get_topogen(self)
+
+ # Building topology from json file
+ build_topo_from_json(tgen, topo)
+
+
+def setup_module(mod):
+ """
+ Sets up the pytest environment
+
+ * `mod`: module name
+ """
+ global topo
+ testsuite_run_time = time.asctime(time.localtime(time.time()))
+ logger.info("Testsuite start time: {}".format(testsuite_run_time))
+ logger.info("=" * 40)
+
+ logger.info("Running setup_module to create topology")
+
+ # This function initiates the topology build with Topogen...
+ tgen = Topogen(CreateTopo, mod.__name__)
+ # ... and here it calls Mininet initialization functions.
+
+ # get list of daemons needs to be started for this suite.
+ daemons = topo_daemons(tgen, topo)
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start deamons and then start routers
+ start_topology(tgen, daemons)
+
+ # Creating configuration from JSON
+ build_config_from_json(tgen, topo)
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ ospf_covergence = verify_ospf_neighbor(tgen, topo)
+ assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ logger.info("Running setup_module() done")
+
+
+def teardown_module(mod):
+ """
+ Teardown the pytest environment.
+
+ * `mod`: module name
+ """
+
+ logger.info("Running teardown_module to delete topology")
+
+ tgen = get_topogen()
+
+ # Stop toplogy and Remove tmp files
+ tgen.stop_topology()
+
+ logger.info(
+ "Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
+ )
+ logger.info("=" * 40)
+
+
+# ##################################
+# Test cases start here.
+# ##################################
+
+
+def test_ospf_p2p_tc3_p0(request):
+ """OSPF IFSM -Verify state change events on p2p network."""
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ global topo
+ step("Bring up the base config as per the topology")
+ reset_config_on_routers(tgen)
+ step(
+ "Verify that OSPF is subscribed to multi cast services "
+ "(All SPF, all DR Routers)."
+ )
+ step("Verify that interface is enabled in ospf.")
+ step("Verify that config is successful.")
+ dut = "r0"
+ input_dict = {
+ "r0": {
+ "links": {
+ "r3": {"ospf": {"mcastMemberOspfAllRouters": True, "ospfEnabled": True}}
+ }
+ }
+ }
+ result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Delete the ip address")
+ topo1 = {
+ "r0": {
+ "links": {
+ "r3": {
+ "ipv4": topo["routers"]["r0"]["links"]["r3"]["ipv4"],
+ "interface": topo["routers"]["r0"]["links"]["r3"]["interface"],
+ "delete": True,
+ }
+ }
+ }
+ }
+
+ result = create_interfaces_cfg(tgen, topo1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Change the ip on the R0 interface")
+
+ topo_modify_change_ip = deepcopy(topo)
+ intf_ip = topo_modify_change_ip["routers"]["r0"]["links"]["r3"]["ipv4"]
+ topo_modify_change_ip["routers"]["r0"]["links"]["r3"]["ipv4"] = str(
+ IPv4Address(unicode(intf_ip.split("/")[0])) + 3
+ ) + "/{}".format(intf_ip.split("/")[1])
+
+ build_config_from_json(tgen, topo_modify_change_ip, save_bkup=False)
+ step("Verify that interface is enabled in ospf.")
+ dut = "r0"
+ input_dict = {
+ "r0": {
+ "links": {
+ "r3": {
+ "ospf": {
+ "ipAddress": topo_modify_change_ip["routers"]["r0"]["links"][
+ "r3"
+ ]["ipv4"].split("/")[0],
+ "ipAddressPrefixlen": int(
+ topo_modify_change_ip["routers"]["r0"]["links"]["r3"][
+ "ipv4"
+ ].split("/")[1]
+ ),
+ }
+ }
+ }
+ }
+ }
+ result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Modify the mask on the R0 interface")
+ ip_addr = topo_modify_change_ip["routers"]["r0"]["links"]["r3"]["ipv4"]
+ mask = topo_modify_change_ip["routers"]["r0"]["links"]["r3"]["ipv4"]
+ step("Delete the ip address")
+ topo1 = {
+ "r0": {
+ "links": {
+ "r3": {
+ "ipv4": ip_addr,
+ "interface": topo["routers"]["r0"]["links"]["r3"]["interface"],
+ "delete": True,
+ }
+ }
+ }
+ }
+
+ result = create_interfaces_cfg(tgen, topo1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Change the ip on the R0 interface")
+
+ topo_modify_change_ip = deepcopy(topo)
+ intf_ip = topo_modify_change_ip["routers"]["r0"]["links"]["r3"]["ipv4"]
+ topo_modify_change_ip["routers"]["r0"]["links"]["r3"]["ipv4"] = str(
+ IPv4Address(unicode(intf_ip.split("/")[0])) + 3
+ ) + "/{}".format(int(intf_ip.split("/")[1]) + 1)
+
+ build_config_from_json(tgen, topo_modify_change_ip, save_bkup=False)
+ step("Verify that interface is enabled in ospf.")
+ dut = "r0"
+ input_dict = {
+ "r0": {
+ "links": {
+ "r3": {
+ "ospf": {
+ "ipAddress": topo_modify_change_ip["routers"]["r0"]["links"][
+ "r3"
+ ]["ipv4"].split("/")[0],
+ "ipAddressPrefixlen": int(
+ topo_modify_change_ip["routers"]["r0"]["links"]["r3"][
+ "ipv4"
+ ].split("/")[1]
+ ),
+ }
+ }
+ }
+ }
+ }
+ result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ topo1 = {
+ "r0": {
+ "links": {
+ "r3": {
+ "ipv4": topo_modify_change_ip["routers"]["r0"]["links"]["r3"][
+ "ipv4"
+ ],
+ "interface": topo_modify_change_ip["routers"]["r0"]["links"]["r3"][
+ "interface"
+ ],
+ "delete": True,
+ }
+ }
+ }
+ }
+
+ result = create_interfaces_cfg(tgen, topo1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ build_config_from_json(tgen, topo, save_bkup=False)
+
+ step("Change the area id on the interface")
+ input_dict = {
+ "r0": {
+ "links": {
+ "r3": {
+ "interface": topo["routers"]["r0"]["links"]["r3"]["interface"],
+ "ospf": {"area": "0.0.0.0"},
+ "delete": True,
+ }
+ }
+ }
+ }
+
+ result = create_interfaces_cfg(tgen, input_dict)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ input_dict = {
+ "r0": {
+ "links": {
+ "r3": {
+ "interface": topo["routers"]["r0"]["links"]["r3"]["interface"],
+ "ospf": {"area": "0.0.0.1"},
+ }
+ }
+ }
+ }
+
+ result = create_interfaces_cfg(tgen, input_dict)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+ step("Verify that interface is enabled in ospf.")
+ dut = "r0"
+ input_dict = {
+ "r0": {"links": {"r3": {"ospf": {"area": "0.0.0.1", "ospfEnabled": True}}}}
+ }
+ result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ input_dict = {
+ "r0": {
+ "links": {
+ "r3": {
+ "interface": topo["routers"]["r0"]["links"]["r3"]["interface"],
+ "ospf": {"area": "0.0.0.1"},
+ "delete": True,
+ }
+ }
+ }
+ }
+
+ result = create_interfaces_cfg(tgen, input_dict)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ input_dict = {
+ "r0": {
+ "links": {
+ "r3": {
+ "interface": topo["routers"]["r0"]["links"]["r3"]["interface"],
+ "ospf": {"area": "0.0.0.0"},
+ }
+ }
+ }
+ }
+
+ result = create_interfaces_cfg(tgen, input_dict)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ # Api call verify whether BGP is converged
+ ospf_covergence = verify_ospf_neighbor(tgen, topo)
+ assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_ospf_hello_tc10_p0(request):
+ """
+ OSPF timers.
+
+ Verify OSPF interface timer hello interval functionality
+ """
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ global topo
+ step("Bring up the base config as per the topology")
+ reset_config_on_routers(tgen)
+
+ step("modify hello timer from default value to some other value on r1")
+
+ topo1 = {
+ "r1": {
+ "links": {
+ "r0": {
+ "interface": topo["routers"]["r1"]["links"]["r0"]["interface"],
+ "ospf": {"hello_interval": 11, "dead_interval": 12},
+ }
+ }
+ }
+ }
+
+ result = create_interfaces_cfg(tgen, topo1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "verify that new timer value is configured and applied using "
+ "the show ip ospf interface command."
+ )
+ dut = "r1"
+ input_dict = {
+ "r1": {
+ "links": {"r0": {"ospf": {"timerMsecs": 11 * 1000, "timerDeadSecs": 12}}}
+ }
+ }
+ result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("modify hello timer from default value to r1 hello timer on r2")
+
+ topo1 = {
+ "r0": {
+ "links": {
+ "r1": {
+ "interface": topo["routers"]["r0"]["links"]["r1"]["interface"],
+ "ospf": {"hello_interval": 11, "dead_interval": 12},
+ }
+ }
+ }
+ }
+
+ result = create_interfaces_cfg(tgen, topo1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("verify that new timer value is configured.")
+ input_dict = {
+ "r0": {
+ "links": {"r1": {"ospf": {"timerMsecs": 11 * 1000, "timerDeadSecs": 12}}}
+ }
+ }
+ dut = "r0"
+ result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("verify that ospf neighbours are full")
+ ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
+ assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ step("reconfigure the default hello timer value to default on r1 and r2")
+
+ topo1 = {
+ "r0": {
+ "links": {
+ "r1": {
+ "interface": topo["routers"]["r0"]["links"]["r1"]["interface"],
+ "ospf": {"hello_interval": 10, "dead_interval": 40},
+ }
+ }
+ }
+ }
+
+ result = create_interfaces_cfg(tgen, topo1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ topo1 = {
+ "r1": {
+ "links": {
+ "r0": {
+ "interface": topo["routers"]["r1"]["links"]["r0"]["interface"],
+ "ospf": {"hello_interval": 10, "dead_interval": 40},
+ }
+ }
+ }
+ }
+
+ result = create_interfaces_cfg(tgen, topo1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("verify that new timer value is configured.")
+ input_dict = {
+ "r0": {
+ "links": {"r1": {"ospf": {"timerMsecs": 10 * 1000, "timerDeadSecs": 40}}}
+ }
+ }
+ dut = "r0"
+ result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("verify that ospf neighbours are full")
+ ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
+ assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ step("reconfigure the default hello timer value to default on r1 and r2")
+
+ topo1 = {
+ "r0": {
+ "links": {
+ "r1": {
+ "interface": topo["routers"]["r0"]["links"]["r1"]["interface"],
+ "ospf": {"hello_interval": 10, "dead_interval": 40},
+ }
+ }
+ }
+ }
+
+ result = create_interfaces_cfg(tgen, topo1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ topo1 = {
+ "r1": {
+ "links": {
+ "r0": {
+ "interface": topo["routers"]["r1"]["links"]["r0"]["interface"],
+ "ospf": {"hello_interval": 10, "dead_interval": 40},
+ }
+ }
+ }
+ }
+
+ result = create_interfaces_cfg(tgen, topo1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("verify that new timer value is configured.")
+ input_dict = {
+ "r0": {
+ "links": {"r1": {"ospf": {"timerMsecs": 10 * 1000, "timerDeadSecs": 40}}}
+ }
+ }
+ dut = "r0"
+ result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("verify that ospf neighbours are full")
+ ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
+ assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ step("configure hello timer = 1 on r1 and r2")
+ topo1 = {
+ "r0": {
+ "links": {
+ "r1": {
+ "interface": topo["routers"]["r0"]["links"]["r1"]["interface"],
+ "ospf": {"hello_interval": 1, "dead_interval": 4},
+ }
+ }
+ }
+ }
+
+ result = create_interfaces_cfg(tgen, topo1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ topo1 = {
+ "r1": {
+ "links": {
+ "r0": {
+ "interface": topo["routers"]["r1"]["links"]["r0"]["interface"],
+ "ospf": {"hello_interval": 1, "dead_interval": 4},
+ }
+ }
+ }
+ }
+
+ result = create_interfaces_cfg(tgen, topo1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("verify that new timer value is configured.")
+ input_dict = {
+ "r0": {"links": {"r1": {"ospf": {"timerMsecs": 1 * 1000, "timerDeadSecs": 4}}}}
+ }
+ dut = "r0"
+ result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("verify that ospf neighbours are full")
+ ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
+ assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ step(" Configure hello timer = 65535")
+ topo1 = {
+ "r0": {
+ "links": {
+ "r1": {
+ "interface": topo["routers"]["r0"]["links"]["r1"]["interface"],
+ "ospf": {"hello_interval": 65535, "dead_interval": 4},
+ }
+ }
+ }
+ }
+
+ result = create_interfaces_cfg(tgen, topo1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ topo1 = {
+ "r1": {
+ "links": {
+ "r0": {
+ "interface": topo["routers"]["r1"]["links"]["r0"]["interface"],
+ "ospf": {"hello_interval": 65535, "dead_interval": 4},
+ }
+ }
+ }
+ }
+
+ result = create_interfaces_cfg(tgen, topo1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("verify that new timer value is configured.")
+ input_dict = {
+ "r0": {
+ "links": {"r1": {"ospf": {"timerMsecs": 65535 * 1000, "timerDeadSecs": 4}}}
+ }
+ }
+ dut = "r0"
+ result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("verify that ospf neighbours are full")
+ ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
+ assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ step(" Try configuring timer values outside range for example 65536")
+ topo1 = {
+ "r0": {
+ "links": {
+ "r1": {
+ "interface": topo["routers"]["r0"]["links"]["r1"]["interface"],
+ "ospf": {"hello_interval": 65536, "dead_interval": 4},
+ }
+ }
+ }
+ }
+
+ result = create_interfaces_cfg(tgen, topo1)
+ assert result is not True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Unconfigure the hello timer from the interface from r1 and r2.")
+
+ topo1 = {
+ "r1": {
+ "links": {
+ "r0": {
+ "interface": topo["routers"]["r1"]["links"]["r0"]["interface"],
+ "ospf": {"hello_interval": 65535},
+ "delete": True,
+ }
+ }
+ }
+ }
+
+ result = create_interfaces_cfg(tgen, topo1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that timer value is deleted from intf & " "set to default value 40 sec."
+ )
+ input_dict = {"r1": {"links": {"r0": {"ospf": {"timerMsecs": 10 * 1000}}}}}
+ dut = "r1"
+ result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_ospf_show_p1(request):
+ """Verify ospf show commands with json output."""
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ global topo
+ step(" Bring up the base config as per the topology")
+ reset_config_on_routers(tgen)
+
+ ospf_covergence = verify_ospf_neighbor(tgen, topo)
+ assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+ dut = "r1"
+ input_dict = {
+ "r1": {
+ "links": {
+ "r0": {
+ "ospf": {
+ "ifUp": True,
+ "ifFlags": "<UP,BROADCAST,RUNNING,MULTICAST>",
+ "ospfEnabled": True,
+ "ipAddressPrefixlen": 24,
+ "ospfIfType": "Broadcast",
+ "area": "0.0.0.0",
+ "networkType": "BROADCAST",
+ "cost": 10,
+ "transmitDelaySecs": 1,
+ "state": "DR",
+ "priority": 1,
+ "mcastMemberOspfAllRouters": True,
+ "timerMsecs": 1000,
+ "timerDeadSecs": 4,
+ "timerWaitSecs": 4,
+ "timerRetransmitSecs": 5,
+ "nbrCount": 1,
+ "nbrAdjacentCount": 1,
+ }
+ }
+ }
+ }
+ }
+ result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ # show ip ospf route
+ ip = topo["routers"]["r0"]["links"]["r3"]["ipv4"]
+ ip_net = str(ipaddress.ip_interface(u"{}".format(ip)).network)
+ nh = topo["routers"]["r0"]["links"]["r1"]["ipv4"].split("/")[0]
+ input_dict = {
+ "r1": {"static_routes": [{"network": ip_net, "no_of_ip": 1, "routeType": "N"}]}
+ }
+
+ dut = "r1"
+ result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/pbr-topo1/test_pbr_topo1.py b/tests/topotests/pbr-topo1/test_pbr_topo1.py
index ffac8e2889..9ae4cce360 100755..100644
--- a/tests/topotests/pbr-topo1/test_pbr_topo1.py
+++ b/tests/topotests/pbr-topo1/test_pbr_topo1.py
@@ -92,7 +92,7 @@ def setup_module(module):
pytest.skip(tgen.errors)
router_list = tgen.routers()
- for rname, router in router_list.iteritems():
+ for rname, router in router_list.items():
# Install vrf into the kernel and slave eth3
router.run("ip link add vrf-chiyoda type vrf table 1000")
router.run("ip link set dev {}-eth3 master vrf-chiyoda".format(rname))
diff --git a/tests/topotests/pim-basic/r1/bgpd.conf b/tests/topotests/pim-basic/r1/bgpd.conf
index 1ca643f758..84d9598bc6 100644
--- a/tests/topotests/pim-basic/r1/bgpd.conf
+++ b/tests/topotests/pim-basic/r1/bgpd.conf
@@ -1,4 +1,5 @@
router bgp 65001
no bgp ebgp-requires-policy
neighbor 10.0.30.3 remote-as external
+ neighbor 10.0.30.3 timers 3 10
redistribute connected
diff --git a/tests/topotests/pim-basic/rp/bgpd.conf b/tests/topotests/pim-basic/rp/bgpd.conf
index 451799288a..1bfae6059b 100644
--- a/tests/topotests/pim-basic/rp/bgpd.conf
+++ b/tests/topotests/pim-basic/rp/bgpd.conf
@@ -1,4 +1,5 @@
router bgp 65003
no bgp ebgp-requires-policy
neighbor 10.0.30.1 remote-as external
+ neighbor 10.0.30.1 timers 3 10
redistribute connected
diff --git a/tests/topotests/pim-basic/test_pim.py b/tests/topotests/pim-basic/test_pim.py
index 2abee39176..e8a9f72b48 100644
--- a/tests/topotests/pim-basic/test_pim.py
+++ b/tests/topotests/pim-basic/test_pim.py
@@ -87,7 +87,7 @@ def setup_module(mod):
tgen.start_topology()
# For all registered routers, load the zebra configuration file
- for rname, router in tgen.routers().iteritems():
+ for rname, router in tgen.routers().items():
router.load_config(
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
)
diff --git a/tests/topotests/route-scale/test_route_scale.py b/tests/topotests/route-scale/test_route_scale.py
index 508d1746b3..0bfae3b830 100755..100644
--- a/tests/topotests/route-scale/test_route_scale.py
+++ b/tests/topotests/route-scale/test_route_scale.py
@@ -86,7 +86,7 @@ def setup_module(module):
tgen.start_topology()
router_list = tgen.routers()
- for rname, router in router_list.iteritems():
+ for rname, router in router_list.items():
router.load_config(
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
)
diff --git a/tests/topotests/zebra_netlink/test_zebra_netlink.py b/tests/topotests/zebra_netlink/test_zebra_netlink.py
index 7b692c75ab..3b3c74d502 100755..100644
--- a/tests/topotests/zebra_netlink/test_zebra_netlink.py
+++ b/tests/topotests/zebra_netlink/test_zebra_netlink.py
@@ -81,7 +81,7 @@ def setup_module(mod):
tgen.start_topology()
router_list = tgen.routers()
- for rname, router in router_list.iteritems():
+ for rname, router in router_list.items():
router.load_config(
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
)
diff --git a/tests/topotests/zebra_rib/test_zebra_rib.py b/tests/topotests/zebra_rib/test_zebra_rib.py
index 17eb736cab..13965c63ae 100755..100644
--- a/tests/topotests/zebra_rib/test_zebra_rib.py
+++ b/tests/topotests/zebra_rib/test_zebra_rib.py
@@ -73,7 +73,7 @@ def setup_module(mod):
tgen.start_topology()
router_list = tgen.routers()
- for rname, router in router_list.iteritems():
+ for rname, router in router_list.items():
router.load_config(
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
)
diff --git a/tools/frr-reload.py b/tools/frr-reload.py
index 8ffc313c04..88873da904 100755
--- a/tools/frr-reload.py
+++ b/tools/frr-reload.py
@@ -128,17 +128,13 @@ class Vtysh(object):
% (child.returncode))
def mark_file(self, filename, stdin=None):
- kwargs = {}
- if stdin is not None:
- kwargs['stdin'] = stdin
-
child = self._call(['-m', '-f', filename],
- stdout=subprocess.PIPE, **kwargs)
+ stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE)
try:
stdout, stderr = child.communicate()
except subprocess.TimeoutExpired:
child.kill()
- stdout, stderr = proc.communicate()
+ stdout, stderr = child.communicate()
raise VtyshException('vtysh call timed out!')
if child.wait() != 0:
@@ -1313,8 +1309,12 @@ if __name__ == '__main__':
# Create a Config object from the config generated by newconf
newconf = Config(vtysh)
- newconf.load_from_file(args.filename)
- reload_ok = True
+ try:
+ newconf.load_from_file(args.filename)
+ reload_ok = True
+ except VtyshException as ve:
+ log.error("vtysh failed to process new configuration: {}".format(ve))
+ reload_ok = False
if args.test:
diff --git a/yang/frr-interface.yang b/yang/frr-interface.yang
index dade9f97fe..46c03a1d1f 100644
--- a/yang/frr-interface.yang
+++ b/yang/frr-interface.yang
@@ -300,11 +300,7 @@ module frr-interface {
}
leaf vrf {
- type string {
- length "1..16";
- }
- /* yang version 0.16 having issue accessing leafref. */
- /* type frr-vrf:vrf-ref;*/
+ type frr-vrf:vrf-ref;
description
"VRF this interface is associated with.";
}
diff --git a/yang/frr-isisd.yang b/yang/frr-isisd.yang
index 00296516ef..cc959bd9fe 100644
--- a/yang/frr-isisd.yang
+++ b/yang/frr-isisd.yang
@@ -612,6 +612,26 @@ module frr-isisd {
"IPv6 destination-source topology.";
}
}
+
+ container mpls {
+ description
+ "Configuration of MPLS parameters";
+ leaf ldp-sync {
+ type boolean;
+ default "true";
+ description
+ "Enable MPLS LDP-Sync functionality on this circuit.";
+ }
+ leaf holddown {
+ type uint16 {
+ range "0..10000";
+ }
+ units "seconds";
+ description
+ "Time to wait for LDP-Sync to occur before restoring interface metric.";
+ }
+ }
+
}
grouping adjacency-state {
@@ -1324,6 +1344,26 @@ module frr-isisd {
}
}
}
+
+ container mpls {
+ description
+ "Configuration of MPLS parameters";
+ container ldp-sync {
+ presence "Present if MPLS LDP-Sync is enabled.";
+ description
+ "Enable MPLS LDP-Sync functionality.";
+ leaf holddown {
+ type uint16 {
+ range "0..10000";
+ }
+ units "seconds";
+ default "0";
+ description
+ "Time to wait for LDP-Sync to occur before restoring interface metric.";
+ }
+ }
+ }
+
}
}
diff --git a/yang/frr-ripd.yang b/yang/frr-ripd.yang
index 4e5795b8f7..f5775ab968 100644
--- a/yang/frr-ripd.yang
+++ b/yang/frr-ripd.yang
@@ -143,7 +143,7 @@ module frr-ripd {
"Enable RIP on the specified IP network.";
}
leaf-list interface {
- type string;
+ type frr-interface:interface-ref;
description
"Enable RIP on the specified interface.";
}
@@ -204,14 +204,14 @@ module frr-ripd {
}
leaf-list passive-interface {
when "../passive-default = 'false'";
- type string;
+ type frr-interface:interface-ref;
description
"A list of interfaces where the sending of RIP packets
is disabled.";
}
leaf-list non-passive-interface {
when "../passive-default = 'true'";
- type string;
+ type frr-interface:interface-ref;
description
"A list of interfaces where the sending of RIP packets
is enabled.";
diff --git a/yang/frr-ripngd.yang b/yang/frr-ripngd.yang
index 47ae67b238..52e208b2c9 100644
--- a/yang/frr-ripngd.yang
+++ b/yang/frr-ripngd.yang
@@ -101,7 +101,7 @@ module frr-ripngd {
"Enable RIPng on the specified IPv6 network.";
}
leaf-list interface {
- type string;
+ type frr-interface:interface-ref;
description
"Enable RIPng on the specified interface.";
}
diff --git a/yang/frr-route-map.yang b/yang/frr-route-map.yang
index 70a6f4470c..b22a96a740 100644
--- a/yang/frr-route-map.yang
+++ b/yang/frr-route-map.yang
@@ -249,7 +249,7 @@ module frr-route-map {
case interface {
when "./condition = 'interface'";
leaf interface {
- type string;
+ type frr-interface:interface-ref;
}
}
diff --git a/yang/frr-zebra.yang b/yang/frr-zebra.yang
index 7762c75d68..2efc45c146 100644
--- a/yang/frr-zebra.yang
+++ b/yang/frr-zebra.yang
@@ -393,9 +393,7 @@ module frr-zebra {
}
leaf vrf {
- type string {
- length "1..36";
- }
+ type frr-vrf:vrf-ref;
description
"The tenant VRF.";
}
@@ -715,9 +713,7 @@ module frr-zebra {
choice vrf-choice {
case single {
leaf vrf {
- type string {
- length "1..36";
- }
+ type frr-vrf:vrf-ref;
description
"Retrieve routes in a non-default vrf.";
}
@@ -815,9 +811,7 @@ module frr-zebra {
choice vrf-choice {
case single {
leaf vrf {
- type string {
- length "1..36";
- }
+ type frr-vrf:vrf-ref;
description
"Retrieve routes in a non-default vrf.";
}
@@ -853,9 +847,7 @@ module frr-zebra {
output {
list vrf-list {
leaf name {
- type string {
- length "1..36";
- }
+ type frr-vrf:vrf-ref;
description
"The VRF name";
}
@@ -910,9 +902,7 @@ module frr-zebra {
output {
list vrf-vni-list {
leaf vrf-name {
- type string {
- length "1..36";
- }
+ type frr-vrf:vrf-ref;
description
"The VRF name.";
}
diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c
index 5cd3e69299..90a08bbd6c 100644
--- a/zebra/if_netlink.c
+++ b/zebra/if_netlink.c
@@ -798,8 +798,10 @@ static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup)
if (tb[IFLA_LINK])
link_ifindex = *(ifindex_t *)RTA_DATA(tb[IFLA_LINK]);
- if (tb[IFLA_LINK_NETNSID])
+ if (tb[IFLA_LINK_NETNSID]) {
link_nsid = *(ns_id_t *)RTA_DATA(tb[IFLA_LINK_NETNSID]);
+ link_nsid = ns_id_get_absolute(ns_id, link_nsid);
+ }
/* Add interface.
* We add by index first because in some cases such as the master
@@ -848,7 +850,7 @@ static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup)
netlink_interface_update_l2info(ifp, linkinfo[IFLA_INFO_DATA],
1, link_nsid);
if (IS_ZEBRA_IF_BRIDGE_SLAVE(ifp))
- zebra_l2if_update_bridge_slave(ifp, bridge_ifindex);
+ zebra_l2if_update_bridge_slave(ifp, bridge_ifindex, ns_id);
else if (IS_ZEBRA_IF_BOND_SLAVE(ifp))
zebra_l2if_update_bond_slave(ifp, bond_ifindex);
@@ -1349,9 +1351,10 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
if (tb[IFLA_LINK])
link_ifindex = *(ifindex_t *)RTA_DATA(tb[IFLA_LINK]);
- if (tb[IFLA_LINK_NETNSID])
+ if (tb[IFLA_LINK_NETNSID]) {
link_nsid = *(ns_id_t *)RTA_DATA(tb[IFLA_LINK_NETNSID]);
-
+ link_nsid = ns_id_get_absolute(ns_id, link_nsid);
+ }
if (tb[IFLA_IFALIAS]) {
desc = (char *)RTA_DATA(tb[IFLA_IFALIAS]);
}
@@ -1439,7 +1442,8 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
1, link_nsid);
if (IS_ZEBRA_IF_BRIDGE_SLAVE(ifp))
zebra_l2if_update_bridge_slave(ifp,
- bridge_ifindex);
+ bridge_ifindex,
+ ns_id);
else if (IS_ZEBRA_IF_BOND_SLAVE(ifp))
zebra_l2if_update_bond_slave(ifp, bond_ifindex);
} else if (ifp->vrf_id != vrf_id) {
@@ -1540,7 +1544,8 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
0, link_nsid);
if (IS_ZEBRA_IF_BRIDGE_SLAVE(ifp) || was_bridge_slave)
zebra_l2if_update_bridge_slave(ifp,
- bridge_ifindex);
+ bridge_ifindex,
+ ns_id);
else if (IS_ZEBRA_IF_BOND_SLAVE(ifp) || was_bond_slave)
zebra_l2if_update_bond_slave(ifp, bond_ifindex);
}
diff --git a/zebra/interface.c b/zebra/interface.c
index b824e313ec..d29f61450e 100644
--- a/zebra/interface.c
+++ b/zebra/interface.c
@@ -1242,6 +1242,23 @@ static void nbr_connected_dump_vty(struct vty *vty,
vty_out(vty, "\n");
}
+static const char *zebra_zifslavetype_2str(zebra_slave_iftype_t zif_slave_type)
+{
+ switch (zif_slave_type) {
+ case ZEBRA_IF_SLAVE_BRIDGE:
+ return "Bridge";
+ case ZEBRA_IF_SLAVE_VRF:
+ return "Vrf";
+ case ZEBRA_IF_SLAVE_BOND:
+ return "Bond";
+ case ZEBRA_IF_SLAVE_OTHER:
+ return "Other";
+ case ZEBRA_IF_SLAVE_NONE:
+ return "None";
+ }
+ return "None";
+}
+
static const char *zebra_ziftype_2str(zebra_iftype_t zif_type)
{
switch (zif_type) {
@@ -1469,6 +1486,9 @@ static void if_dump_vty(struct vty *vty, struct interface *ifp)
vty_out(vty, " Interface Type %s\n",
zebra_ziftype_2str(zebra_if->zif_type));
+ vty_out(vty, " Interface Slave Type %s\n",
+ zebra_zifslavetype_2str(zebra_if->zif_slave_type));
+
if (IS_ZEBRA_IF_BRIDGE(ifp)) {
struct zebra_l2info_bridge *bridge_info;
diff --git a/zebra/main.c b/zebra/main.c
index cfc45567d7..2afef46bb2 100644
--- a/zebra/main.c
+++ b/zebra/main.c
@@ -183,7 +183,7 @@ static void sigint(void)
vrf_terminate();
rtadv_terminate();
- ns_walk_func(zebra_ns_early_shutdown);
+ ns_walk_func(zebra_ns_early_shutdown, NULL, NULL);
zebra_ns_notify_close();
access_list_reset();
@@ -214,7 +214,7 @@ int zebra_finalize(struct thread *dummy)
zlog_info("Zebra final shutdown");
/* Final shutdown of ns resources */
- ns_walk_func(zebra_ns_final_shutdown);
+ ns_walk_func(zebra_ns_final_shutdown, NULL, NULL);
/* Stop dplane thread and finish any cleanup */
zebra_dplane_shutdown();
diff --git a/zebra/rule_netlink.c b/zebra/rule_netlink.c
index 3a3baab4ca..d6a34327a6 100644
--- a/zebra/rule_netlink.c
+++ b/zebra/rule_netlink.c
@@ -74,7 +74,7 @@ netlink_rule_msg_encode(int cmd, const struct zebra_dplane_ctx *ctx,
char buf[];
} *req = buf;
- const char *ifname = dplane_ctx_get_ifname(ctx);
+ const char *ifname = dplane_ctx_rule_get_ifname(ctx);
char buf1[PREFIX_STRLEN];
char buf2[PREFIX_STRLEN];
@@ -141,9 +141,9 @@ netlink_rule_msg_encode(int cmd, const struct zebra_dplane_ctx *ctx,
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug(
- "Tx %s family %s IF %s(%u) Pref %u Fwmark %u Src %s Dst %s Table %u",
+ "Tx %s family %s IF %s Pref %u Fwmark %u Src %s Dst %s Table %u",
nl_msg_type_to_str(cmd), nl_family_to_str(family),
- ifname, dplane_ctx_get_ifindex(ctx), priority, fwmark,
+ ifname, priority, fwmark,
prefix2str(src_ip, buf1, sizeof(buf1)),
prefix2str(dst_ip, buf2, sizeof(buf2)), table);
@@ -324,13 +324,13 @@ int netlink_rule_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
ret = dplane_pbr_rule_delete(&rule);
zlog_debug(
- "%s: %s leftover rule: family %s IF %s(%u) Pref %u Src %s Dst %s Table %u",
+ "%s: %s leftover rule: family %s IF %s Pref %u Src %s Dst %s Table %u",
__func__,
((ret == ZEBRA_DPLANE_REQUEST_FAILURE)
? "Failed to remove"
: "Removed"),
nl_family_to_str(frh->family), rule.ifname,
- rule.rule.ifindex, rule.rule.priority,
+ rule.rule.priority,
prefix2str(&rule.rule.filter.src_ip, buf1,
sizeof(buf1)),
prefix2str(&rule.rule.filter.dst_ip, buf2,
@@ -350,10 +350,10 @@ int netlink_rule_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug(
- "Rx %s family %s IF %s(%u) Pref %u Src %s Dst %s Table %u",
+ "Rx %s family %s IF %s Pref %u Src %s Dst %s Table %u",
nl_msg_type_to_str(h->nlmsg_type),
nl_family_to_str(frh->family), rule.ifname,
- rule.rule.ifindex, rule.rule.priority,
+ rule.rule.priority,
prefix2str(&rule.rule.filter.src_ip, buf1,
sizeof(buf1)),
prefix2str(&rule.rule.filter.dst_ip, buf2,
diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c
index 4b31b46bce..e436e5a288 100644
--- a/zebra/zapi_msg.c
+++ b/zebra/zapi_msg.c
@@ -815,7 +815,7 @@ void zsend_rule_notify_owner(const struct zebra_dplane_ctx *ctx,
stream_putl(s, dplane_ctx_rule_get_seq(ctx));
stream_putl(s, dplane_ctx_rule_get_priority(ctx));
stream_putl(s, dplane_ctx_rule_get_unique(ctx));
- stream_putl(s, dplane_ctx_get_ifindex(ctx));
+ stream_put(s, dplane_ctx_rule_get_ifname(ctx), INTERFACE_NAMSIZ);
stream_putw_at(s, 0, stream_get_endp(s));
@@ -1349,6 +1349,20 @@ static void zread_interface_add(ZAPI_HANDLER_ARGS)
struct vrf *vrf;
struct interface *ifp;
+ vrf_id_t vrf_id = zvrf_id(zvrf);
+ if (vrf_id != VRF_DEFAULT && vrf_id != VRF_UNKNOWN) {
+ FOR_ALL_INTERFACES (zvrf->vrf, ifp) {
+ /* Skip pseudo interface. */
+ if (!CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE))
+ continue;
+
+ zsend_interface_add(client, ifp);
+ zsend_interface_link_params(client, ifp);
+ zsend_interface_addresses(client, ifp);
+ }
+ return;
+ }
+
RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
FOR_ALL_INTERFACES (vrf, ifp) {
/* Skip pseudo interface. */
@@ -2737,6 +2751,7 @@ static inline void zread_rule(ZAPI_HANDLER_ARGS)
struct zebra_pbr_rule zpr;
struct stream *s;
uint32_t total, i;
+ char ifname[INTERFACE_NAMSIZ + 1] = {};
s = msg;
STREAM_GETL(s, total);
@@ -2762,21 +2777,10 @@ static inline void zread_rule(ZAPI_HANDLER_ARGS)
STREAM_GETC(s, zpr.rule.filter.dsfield);
STREAM_GETL(s, zpr.rule.filter.fwmark);
STREAM_GETL(s, zpr.rule.action.table);
- STREAM_GETL(s, zpr.rule.ifindex);
-
- if (zpr.rule.ifindex) {
- struct interface *ifp;
+ STREAM_GET(ifname, s, INTERFACE_NAMSIZ);
- ifp = if_lookup_by_index_per_ns(zvrf->zns,
- zpr.rule.ifindex);
- if (!ifp) {
- zlog_debug("Failed to lookup ifindex: %u",
- zpr.rule.ifindex);
- return;
- }
-
- strlcpy(zpr.ifname, ifp->name, sizeof(zpr.ifname));
- }
+ strlcpy(zpr.ifname, ifname, sizeof(zpr.ifname));
+ strlcpy(zpr.rule.ifname, ifname, sizeof(zpr.rule.ifname));
if (!is_default_prefix(&zpr.rule.filter.src_ip))
zpr.rule.filter.filter_bm |= PBR_FILTER_SRC_IP;
diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c
index 9771235717..abd0adb64e 100644
--- a/zebra/zebra_dplane.c
+++ b/zebra/zebra_dplane.c
@@ -210,6 +210,7 @@ struct dplane_ctx_rule {
uint8_t dsfield;
struct prefix src_ip;
struct prefix dst_ip;
+ char ifname[INTERFACE_NAMSIZ + 1];
};
struct dplane_rule_info {
@@ -1632,6 +1633,13 @@ int dplane_ctx_rule_get_sock(const struct zebra_dplane_ctx *ctx)
return ctx->u.rule.sock;
}
+const char *dplane_ctx_rule_get_ifname(const struct zebra_dplane_ctx *ctx)
+{
+ DPLANE_CTX_VALID(ctx);
+
+ return ctx->u.rule.new.ifname;
+}
+
int dplane_ctx_rule_get_unique(const struct zebra_dplane_ctx *ctx)
{
DPLANE_CTX_VALID(ctx);
@@ -2191,6 +2199,7 @@ static void dplane_ctx_rule_init_single(struct dplane_ctx_rule *dplane_rule,
dplane_rule->dsfield = rule->rule.filter.dsfield;
prefix_copy(&(dplane_rule->dst_ip), &rule->rule.filter.dst_ip);
prefix_copy(&(dplane_rule->src_ip), &rule->rule.filter.src_ip);
+ strlcpy(dplane_rule->ifname, rule->ifname, INTERFACE_NAMSIZ);
}
/**
@@ -2212,10 +2221,9 @@ static int dplane_ctx_rule_init(struct zebra_dplane_ctx *ctx,
char buf2[PREFIX_STRLEN];
zlog_debug(
- "init dplane ctx %s: IF %s(%u) Prio %u Fwmark %u Src %s Dst %s Table %u",
+ "init dplane ctx %s: IF %s Prio %u Fwmark %u Src %s Dst %s Table %u",
dplane_op2str(op), new_rule->ifname,
- new_rule->rule.ifindex, new_rule->rule.priority,
- new_rule->rule.filter.fwmark,
+ new_rule->rule.priority, new_rule->rule.filter.fwmark,
prefix2str(&new_rule->rule.filter.src_ip, buf1,
sizeof(buf1)),
prefix2str(&new_rule->rule.filter.dst_ip, buf2,
@@ -2232,7 +2240,6 @@ static int dplane_ctx_rule_init(struct zebra_dplane_ctx *ctx,
ctx->zd_vrf_id = new_rule->vrf_id;
memcpy(ctx->zd_ifname, new_rule->ifname, sizeof(new_rule->ifname));
- ctx->zd_ifindex = new_rule->rule.ifindex;
ctx->u.rule.sock = new_rule->sock;
ctx->u.rule.unique = new_rule->rule.unique;
diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h
index 5dd789a851..1d852b1bac 100644
--- a/zebra/zebra_dplane.h
+++ b/zebra/zebra_dplane.h
@@ -423,6 +423,7 @@ uint32_t dplane_ctx_neigh_get_update_flags(const struct zebra_dplane_ctx *ctx);
int dplane_ctx_rule_get_sock(const struct zebra_dplane_ctx *ctx);
int dplane_ctx_rule_get_unique(const struct zebra_dplane_ctx *ctx);
int dplane_ctx_rule_get_seq(const struct zebra_dplane_ctx *ctx);
+const char *dplane_ctx_rule_get_ifname(const struct zebra_dplane_ctx *ctx);
uint32_t dplane_ctx_rule_get_priority(const struct zebra_dplane_ctx *ctx);
uint32_t dplane_ctx_rule_get_old_priority(const struct zebra_dplane_ctx *ctx);
uint32_t dplane_ctx_rule_get_table(const struct zebra_dplane_ctx *ctx);
diff --git a/zebra/zebra_evpn.c b/zebra/zebra_evpn.c
index 73df93258e..56699c4e83 100644
--- a/zebra/zebra_evpn.c
+++ b/zebra/zebra_evpn.c
@@ -622,6 +622,60 @@ void zebra_evpn_svi_macip_del_for_evpn_hash(struct hash_bucket *bucket,
return;
}
+static int zebra_evpn_map_vlan_ns(struct ns *ns,
+ void *_in_param,
+ void **_p_zevpn)
+{
+ struct zebra_ns *zns = ns->info;
+ struct route_node *rn;
+ struct interface *br_if;
+ zebra_evpn_t **p_zevpn = (zebra_evpn_t **)_p_zevpn;
+ zebra_evpn_t *zevpn;
+ struct interface *tmp_if = NULL;
+ struct zebra_if *zif;
+ struct zebra_l2info_vxlan *vxl = NULL;
+ struct zebra_from_svi_param *in_param =
+ (struct zebra_from_svi_param *)_in_param;
+ int found = 0;
+
+ if (!in_param)
+ return NS_WALK_STOP;
+ br_if = in_param->br_if;
+ zif = in_param->zif;
+ assert(zif);
+ assert(br_if);
+
+ /* See if this interface (or interface plus VLAN Id) maps to a VxLAN */
+ /* TODO: Optimize with a hash. */
+ for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
+ tmp_if = (struct interface *)rn->info;
+ if (!tmp_if)
+ continue;
+ zif = tmp_if->info;
+ if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
+ continue;
+ if (!if_is_operative(tmp_if))
+ continue;
+ vxl = &zif->l2info.vxl;
+
+ if (zif->brslave_info.br_if != br_if)
+ continue;
+
+ if (!in_param->bridge_vlan_aware
+ || vxl->access_vlan == in_param->vid) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found)
+ return NS_WALK_CONTINUE;
+
+ zevpn = zebra_evpn_lookup(vxl->vni);
+ if (p_zevpn)
+ *p_zevpn = zevpn;
+ return NS_WALK_STOP;
+}
+
/*
* Map port or (port, VLAN) to an EVPN. This is invoked upon getting MAC
* notifications, to see if they are of interest.
@@ -629,25 +683,51 @@ void zebra_evpn_svi_macip_del_for_evpn_hash(struct hash_bucket *bucket,
zebra_evpn_t *zebra_evpn_map_vlan(struct interface *ifp,
struct interface *br_if, vlanid_t vid)
{
- struct zebra_ns *zns;
- struct route_node *rn;
- struct interface *tmp_if = NULL;
struct zebra_if *zif;
struct zebra_l2info_bridge *br;
- struct zebra_l2info_vxlan *vxl = NULL;
- uint8_t bridge_vlan_aware;
- zebra_evpn_t *zevpn;
- int found = 0;
+ zebra_evpn_t **p_zevpn;
+ zebra_evpn_t *zevpn = NULL;
+ struct zebra_from_svi_param in_param;
/* Determine if bridge is VLAN-aware or not */
zif = br_if->info;
assert(zif);
br = &zif->l2info.br;
- bridge_vlan_aware = br->vlan_aware;
+ in_param.bridge_vlan_aware = br->vlan_aware;
+ in_param.vid = vid;
+ in_param.br_if = br_if;
+ in_param.zif = zif;
+ p_zevpn = &zevpn;
+
+ ns_walk_func(zebra_evpn_map_vlan_ns,
+ (void *)&in_param,
+ (void **)p_zevpn);
+ return zevpn;
+}
+
+static int zebra_evpn_from_svi_ns(struct ns *ns,
+ void *_in_param,
+ void **_p_zevpn)
+{
+ struct zebra_ns *zns = ns->info;
+ struct route_node *rn;
+ struct interface *br_if;
+ zebra_evpn_t **p_zevpn = (zebra_evpn_t **)_p_zevpn;
+ zebra_evpn_t *zevpn;
+ struct interface *tmp_if = NULL;
+ struct zebra_if *zif;
+ struct zebra_l2info_vxlan *vxl = NULL;
+ struct zebra_from_svi_param *in_param =
+ (struct zebra_from_svi_param *)_in_param;
+ int found = 0;
+
+ if (!in_param)
+ return NS_WALK_STOP;
+ br_if = in_param->br_if;
+ zif = in_param->zif;
+ assert(zif);
- /* See if this interface (or interface plus VLAN Id) maps to a VxLAN */
/* TODO: Optimize with a hash. */
- zns = zebra_ns_lookup(NS_DEFAULT);
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
tmp_if = (struct interface *)rn->info;
if (!tmp_if)
@@ -662,17 +742,20 @@ zebra_evpn_t *zebra_evpn_map_vlan(struct interface *ifp,
if (zif->brslave_info.br_if != br_if)
continue;
- if (!bridge_vlan_aware || vxl->access_vlan == vid) {
+ if (!in_param->bridge_vlan_aware
+ || vxl->access_vlan == in_param->vid) {
found = 1;
break;
}
}
if (!found)
- return NULL;
+ return NS_WALK_CONTINUE;
zevpn = zebra_evpn_lookup(vxl->vni);
- return zevpn;
+ if (p_zevpn)
+ *p_zevpn = zevpn;
+ return NS_WALK_STOP;
}
/*
@@ -682,16 +765,11 @@ zebra_evpn_t *zebra_evpn_map_vlan(struct interface *ifp,
zebra_evpn_t *zebra_evpn_from_svi(struct interface *ifp,
struct interface *br_if)
{
- struct zebra_ns *zns;
- struct route_node *rn;
- struct interface *tmp_if = NULL;
- struct zebra_if *zif;
struct zebra_l2info_bridge *br;
- struct zebra_l2info_vxlan *vxl = NULL;
- uint8_t bridge_vlan_aware;
- vlanid_t vid = 0;
- zebra_evpn_t *zevpn;
- int found = 0;
+ zebra_evpn_t *zevpn = NULL;
+ zebra_evpn_t **p_zevpn;
+ struct zebra_if *zif;
+ struct zebra_from_svi_param in_param;
if (!br_if)
return NULL;
@@ -704,8 +782,10 @@ zebra_evpn_t *zebra_evpn_from_svi(struct interface *ifp,
zif = br_if->info;
assert(zif);
br = &zif->l2info.br;
- bridge_vlan_aware = br->vlan_aware;
- if (bridge_vlan_aware) {
+ in_param.bridge_vlan_aware = br->vlan_aware;
+ in_param.vid = 0;
+
+ if (in_param.bridge_vlan_aware) {
struct zebra_l2info_vlan *vl;
if (!IS_ZEBRA_IF_VLAN(ifp))
@@ -714,37 +794,52 @@ zebra_evpn_t *zebra_evpn_from_svi(struct interface *ifp,
zif = ifp->info;
assert(zif);
vl = &zif->l2info.vl;
- vid = vl->vid;
+ in_param.vid = vl->vid;
}
+ in_param.br_if = br_if;
+ in_param.zif = zif;
+ p_zevpn = &zevpn;
/* See if this interface (or interface plus VLAN Id) maps to a VxLAN */
- /* TODO: Optimize with a hash. */
- zns = zebra_ns_lookup(NS_DEFAULT);
+ ns_walk_func(zebra_evpn_from_svi_ns, (void *)&in_param,
+ (void **)p_zevpn);
+ return zevpn;
+}
+
+static int zvni_map_to_macvlan_ns(struct ns *ns,
+ void *_in_param,
+ void **_p_ifp)
+{
+ struct zebra_ns *zns = ns->info;
+ struct zebra_from_svi_param *in_param =
+ (struct zebra_from_svi_param *)_in_param;
+ struct interface **p_ifp = (struct interface **)_p_ifp;
+ struct route_node *rn;
+ struct interface *tmp_if = NULL;
+ struct zebra_if *zif;
+
+ if (!in_param)
+ return NS_WALK_STOP;
+
+ /* Identify corresponding VLAN interface. */
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
tmp_if = (struct interface *)rn->info;
- if (!tmp_if)
+ /* Check oper status of the SVI. */
+ if (!tmp_if || !if_is_operative(tmp_if))
continue;
zif = tmp_if->info;
- if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
- continue;
- if (!if_is_operative(tmp_if))
- continue;
- vxl = &zif->l2info.vxl;
- if (zif->brslave_info.br_if != br_if)
+ if (!zif || zif->zif_type != ZEBRA_IF_MACVLAN)
continue;
- if (!bridge_vlan_aware || vxl->access_vlan == vid) {
- found = 1;
- break;
+ if (zif->link == in_param->svi_if) {
+ if (p_ifp)
+ *p_ifp = tmp_if;
+ return NS_WALK_STOP;
}
}
- if (!found)
- return NULL;
-
- zevpn = zebra_evpn_lookup(vxl->vni);
- return zevpn;
+ return NS_WALK_CONTINUE;
}
/* Map to MAC-VLAN interface corresponding to specified SVI interface.
@@ -752,11 +847,10 @@ zebra_evpn_t *zebra_evpn_from_svi(struct interface *ifp,
struct interface *zebra_evpn_map_to_macvlan(struct interface *br_if,
struct interface *svi_if)
{
- struct zebra_ns *zns;
- struct route_node *rn;
struct interface *tmp_if = NULL;
struct zebra_if *zif;
- int found = 0;
+ struct interface **p_ifp;
+ struct zebra_from_svi_param in_param;
/* Defensive check, caller expected to invoke only with valid bridge. */
if (!br_if)
@@ -771,25 +865,17 @@ struct interface *zebra_evpn_map_to_macvlan(struct interface *br_if,
zif = br_if->info;
assert(zif);
- /* Identify corresponding VLAN interface. */
- zns = zebra_ns_lookup(NS_DEFAULT);
- for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
- tmp_if = (struct interface *)rn->info;
- /* Check oper status of the SVI. */
- if (!tmp_if || !if_is_operative(tmp_if))
- continue;
- zif = tmp_if->info;
-
- if (!zif || zif->zif_type != ZEBRA_IF_MACVLAN)
- continue;
+ in_param.vid = 0;
+ in_param.br_if = br_if;
+ in_param.zif = NULL;
+ in_param.svi_if = svi_if;
+ p_ifp = &tmp_if;
- if (zif->link == svi_if) {
- found = 1;
- break;
- }
- }
-
- return found ? tmp_if : NULL;
+ /* Identify corresponding VLAN interface. */
+ ns_walk_func(zvni_map_to_macvlan_ns,
+ (void *)&in_param,
+ (void **)p_ifp);
+ return tmp_if;
}
/*
@@ -812,6 +898,7 @@ void zebra_evpn_install_mac_hash(struct hash_bucket *bucket, void *ctxt)
void zebra_evpn_read_mac_neigh(zebra_evpn_t *zevpn, struct interface *ifp)
{
struct zebra_ns *zns;
+ struct zebra_vrf *zvrf;
struct zebra_if *zif;
struct interface *vlan_if;
struct zebra_l2info_vxlan *vxl;
@@ -819,7 +906,10 @@ void zebra_evpn_read_mac_neigh(zebra_evpn_t *zevpn, struct interface *ifp)
zif = ifp->info;
vxl = &zif->l2info.vxl;
- zns = zebra_ns_lookup(NS_DEFAULT);
+ zvrf = zebra_vrf_lookup_by_id(zevpn->vrf_id);
+ if (!zvrf || !zvrf->zns)
+ return;
+ zns = zvrf->zns;
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
@@ -921,7 +1011,7 @@ zebra_evpn_t *zebra_evpn_add(vni_t vni)
zevpn = hash_get(zvrf->evpn_table, &tmp_zevpn, zebra_evpn_alloc);
assert(zevpn);
- zebra_evpn_evpn_es_init(zevpn);
+ zebra_evpn_es_evi_init(zevpn);
/* Create hash table for MAC */
zevpn->mac_table = zebra_mac_db_create("Zebra EVPN MAC Table");
@@ -951,7 +1041,7 @@ int zebra_evpn_del(zebra_evpn_t *zevpn)
hash_free(zevpn->mac_table);
zevpn->mac_table = NULL;
- zebra_evpn_evpn_es_cleanup(zevpn);
+ zebra_evpn_es_evi_cleanup(zevpn);
/* Free the EVPN hash entry and allocated memory. */
tmp_zevpn = hash_release(zvrf->evpn_table, zevpn);
@@ -1315,7 +1405,7 @@ void process_remote_macip_add(vni_t vni, struct ethaddr *macaddr,
}
}
- zvrf = vrf_info_lookup(zevpn->vxlan_if->vrf_id);
+ zvrf = zebra_vrf_get_evpn();
if (!zvrf)
return;
diff --git a/zebra/zebra_evpn.h b/zebra/zebra_evpn.h
index 3b6a5b21e8..27392ec85c 100644
--- a/zebra/zebra_evpn.h
+++ b/zebra/zebra_evpn.h
@@ -123,6 +123,15 @@ struct zebra_evpn_t_ {
struct list *local_es_evi_list;
};
+/* for parsing evpn and vni contexts */
+struct zebra_from_svi_param {
+ struct interface *br_if;
+ struct interface *svi_if;
+ struct zebra_if *zif;
+ uint8_t bridge_vlan_aware;
+ vlanid_t vid;
+};
+
struct interface *zvni_map_to_svi(vlanid_t vid, struct interface *br_if);
static inline struct interface *zevpn_map_to_svi(zebra_evpn_t *zevpn)
diff --git a/zebra/zebra_evpn_mac.c b/zebra/zebra_evpn_mac.c
index b9cc02a276..75031ddba6 100644
--- a/zebra/zebra_evpn_mac.c
+++ b/zebra/zebra_evpn_mac.c
@@ -249,7 +249,7 @@ static void zebra_evpn_mac_get_access_info(zebra_mac_t *mac,
struct zebra_ns *zns;
*vid = mac->fwd_info.local.vid;
- zns = zebra_ns_lookup(NS_DEFAULT);
+ zns = zebra_ns_lookup(mac->fwd_info.local.ns_id);
*ifpP = if_lookup_by_index_per_ns(zns,
mac->fwd_info.local.ifindex);
}
@@ -1610,6 +1610,12 @@ static bool zebra_evpn_local_mac_update_fwd_info(zebra_mac_t *mac,
{
struct zebra_if *zif = ifp->info;
bool es_change;
+ ns_id_t local_ns_id = NS_DEFAULT;
+ struct zebra_vrf *zvrf;
+
+ zvrf = zebra_vrf_lookup_by_id(ifp->vrf_id);
+ if (zvrf && zvrf->zns)
+ local_ns_id = zvrf->zns->ns_id;
memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
@@ -1618,6 +1624,7 @@ static bool zebra_evpn_local_mac_update_fwd_info(zebra_mac_t *mac,
if (!mac->es) {
/* if es is set fwd_info is not-relevant/taped-out */
mac->fwd_info.local.ifindex = ifp->ifindex;
+ mac->fwd_info.local.ns_id = local_ns_id;
mac->fwd_info.local.vid = vid;
}
@@ -2060,6 +2067,7 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, zebra_evpn_t *zevpn,
if (is_dup_detect) {
inform_client = false;
upd_neigh = false;
+ es_change = false;
}
}
}
@@ -2092,7 +2100,8 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, zebra_evpn_t *zevpn,
mac->es ? mac->es->esi_str : "", mac->loc_seq,
mac->flags,
local_inactive ? " local-inactive" : "");
- inform_client = true;
+ if (!is_dup_detect)
+ inform_client = true;
}
if (es_change) {
@@ -2204,6 +2213,12 @@ int zebra_evpn_mac_gw_macip_add(struct interface *ifp, zebra_evpn_t *zevpn,
{
char buf[ETHER_ADDR_STRLEN];
zebra_mac_t *mac;
+ ns_id_t local_ns_id = NS_DEFAULT;
+ struct zebra_vrf *zvrf;
+
+ zvrf = zebra_vrf_lookup_by_id(ifp->vrf_id);
+ if (zvrf && zvrf->zns)
+ local_ns_id = zvrf->zns->ns_id;
mac = zebra_evpn_mac_lookup(zevpn, macaddr);
if (!mac) {
@@ -2223,6 +2238,7 @@ int zebra_evpn_mac_gw_macip_add(struct interface *ifp, zebra_evpn_t *zevpn,
SET_FLAG(mac->flags, ZEBRA_MAC_DEF_GW);
memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
mac->fwd_info.local.ifindex = ifp->ifindex;
+ mac->fwd_info.local.ns_id = local_ns_id;
mac->fwd_info.local.vid = vlan_id;
*macp = mac;
diff --git a/zebra/zebra_evpn_mac.h b/zebra/zebra_evpn_mac.h
index 39aaf1fb30..f9ca81445f 100644
--- a/zebra/zebra_evpn_mac.h
+++ b/zebra/zebra_evpn_mac.h
@@ -91,6 +91,7 @@ struct zebra_mac_t_ {
union {
struct {
ifindex_t ifindex;
+ ns_id_t ns_id;
vlanid_t vid;
} local;
diff --git a/zebra/zebra_evpn_mh.c b/zebra/zebra_evpn_mh.c
index 3c99ce29c3..2567171c5e 100644
--- a/zebra/zebra_evpn_mh.c
+++ b/zebra/zebra_evpn_mh.c
@@ -363,7 +363,7 @@ void zebra_evpn_es_evi_show_vni(struct vty *vty, bool uj, vni_t vni, int detail)
}
/* Initialize the ES tables maintained per-L2_VNI */
-void zebra_evpn_evpn_es_init(zebra_evpn_t *zevpn)
+void zebra_evpn_es_evi_init(zebra_evpn_t *zevpn)
{
/* Initialize the ES-EVI RB tree */
RB_INIT(zebra_es_evi_rb_head, &zevpn->es_evi_rb_tree);
@@ -376,7 +376,7 @@ void zebra_evpn_evpn_es_init(zebra_evpn_t *zevpn)
}
/* Cleanup the ES info maintained per- EVPN */
-void zebra_evpn_evpn_es_cleanup(zebra_evpn_t *zevpn)
+void zebra_evpn_es_evi_cleanup(zebra_evpn_t *zevpn)
{
struct zebra_evpn_es_evi *es_evi;
struct zebra_evpn_es_evi *es_evi_next;
diff --git a/zebra/zebra_evpn_mh.h b/zebra/zebra_evpn_mh.h
index ed62677e3b..72b7f9b675 100644
--- a/zebra/zebra_evpn_mh.h
+++ b/zebra/zebra_evpn_mh.h
@@ -198,8 +198,8 @@ extern void zebra_evpn_mh_terminate(void);
extern bool zebra_evpn_is_if_es_capable(struct zebra_if *zif);
extern void zebra_evpn_if_init(struct zebra_if *zif);
extern void zebra_evpn_if_cleanup(struct zebra_if *zif);
-extern void zebra_evpn_evpn_es_init(zebra_evpn_t *zevpn);
-extern void zebra_evpn_evpn_es_cleanup(zebra_evpn_t *zevpn);
+extern void zebra_evpn_es_evi_init(zebra_evpn_t *zevpn);
+extern void zebra_evpn_es_evi_cleanup(zebra_evpn_t *zevpn);
extern void zebra_evpn_vxl_evpn_set(struct zebra_if *zif, zebra_evpn_t *zevpn,
bool set);
extern void zebra_evpn_es_set_base_evpn(zebra_evpn_t *zevpn);
diff --git a/zebra/zebra_evpn_neigh.c b/zebra/zebra_evpn_neigh.c
index 492052b1b2..661d1c7f81 100644
--- a/zebra/zebra_evpn_neigh.c
+++ b/zebra/zebra_evpn_neigh.c
@@ -2184,9 +2184,10 @@ void process_neigh_remote_macip_add(zebra_evpn_t *zevpn, struct zebra_vrf *zvrf,
seq, n->flags);
zebra_evpn_neigh_clear_sync_info(n);
if (IS_ZEBRA_NEIGH_ACTIVE(n))
- zebra_evpn_mac_send_del_to_client(
- zevpn->vni, &mac->macaddr,
- mac->flags, false /*force*/);
+ zebra_evpn_neigh_send_del_to_client(
+ zevpn->vni, &n->ip, &n->emac,
+ n->flags, n->state,
+ false /*force*/);
}
if (memcmp(&n->emac, &mac->macaddr,
sizeof(struct ethaddr))
diff --git a/zebra/zebra_l2.c b/zebra/zebra_l2.c
index 1758c8f96a..417056ecb0 100644
--- a/zebra/zebra_l2.c
+++ b/zebra/zebra_l2.c
@@ -54,7 +54,13 @@ static void map_slaves_to_bridge(struct interface *br_if, int link)
{
struct vrf *vrf;
struct interface *ifp;
+ struct zebra_vrf *zvrf;
+ struct zebra_ns *zns;
+ zvrf = zebra_vrf_lookup_by_id(br_if->vrf_id);
+ assert(zvrf);
+ zns = zvrf->zns;
+ assert(zns);
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
FOR_ALL_INTERFACES (vrf, ifp) {
struct zebra_if *zif;
@@ -73,7 +79,8 @@ static void map_slaves_to_bridge(struct interface *br_if, int link)
br_slave = &zif->brslave_info;
if (link) {
- if (br_slave->bridge_ifindex == br_if->ifindex)
+ if (br_slave->bridge_ifindex == br_if->ifindex &&
+ br_slave->ns_id == zns->ns_id)
br_slave->br_if = br_if;
} else {
if (br_slave->br_if == br_if)
@@ -84,12 +91,14 @@ static void map_slaves_to_bridge(struct interface *br_if, int link)
}
/* Public functions */
-void zebra_l2_map_slave_to_bridge(struct zebra_l2info_brslave *br_slave)
+void zebra_l2_map_slave_to_bridge(struct zebra_l2info_brslave *br_slave,
+ struct zebra_ns *zns)
{
struct interface *br_if;
/* TODO: Handle change of master */
- br_if = if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT),
+ assert(zns);
+ br_if = if_lookup_by_index_per_ns(zebra_ns_lookup(zns->ns_id),
br_slave->bridge_ifindex);
if (br_if)
br_slave->br_if = br_if;
@@ -248,23 +257,32 @@ void zebra_l2_vxlanif_del(struct interface *ifp)
* from a bridge before it can be mapped to another bridge.
*/
void zebra_l2if_update_bridge_slave(struct interface *ifp,
- ifindex_t bridge_ifindex)
+ ifindex_t bridge_ifindex,
+ ns_id_t ns_id)
{
struct zebra_if *zif;
ifindex_t old_bridge_ifindex;
+ ns_id_t old_ns_id;
+ struct zebra_vrf *zvrf;
zif = ifp->info;
assert(zif);
+ zvrf = zebra_vrf_lookup_by_id(ifp->vrf_id);
+ if (!zvrf)
+ return;
+
old_bridge_ifindex = zif->brslave_info.bridge_ifindex;
- if (old_bridge_ifindex == bridge_ifindex)
+ old_ns_id = zif->brslave_info.ns_id;
+ if (old_bridge_ifindex == bridge_ifindex &&
+ old_ns_id == zif->brslave_info.ns_id)
return;
+ zif->brslave_info.ns_id = ns_id;
zif->brslave_info.bridge_ifindex = bridge_ifindex;
-
/* Set up or remove link with master */
if (bridge_ifindex != IFINDEX_INTERNAL) {
- zebra_l2_map_slave_to_bridge(&zif->brslave_info);
+ zebra_l2_map_slave_to_bridge(&zif->brslave_info, zvrf->zns);
/* In the case of VxLAN, invoke the handler for EVPN. */
if (zif->zif_type == ZEBRA_IF_VXLAN)
zebra_vxlan_if_update(ifp, ZEBRA_VXLIF_MASTER_CHANGE);
diff --git a/zebra/zebra_l2.h b/zebra/zebra_l2.h
index 2735d915ec..f3b15c7770 100644
--- a/zebra/zebra_l2.h
+++ b/zebra/zebra_l2.h
@@ -37,6 +37,7 @@ extern "C" {
struct zebra_l2info_brslave {
ifindex_t bridge_ifindex; /* Bridge Master */
struct interface *br_if; /* Pointer to master */
+ ns_id_t ns_id; /* network namespace where bridge is */
};
/* zebra L2 interface information - bridge interface */
@@ -81,7 +82,8 @@ union zebra_l2if_info {
#define IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(zif) ((zif)->l2info.br.vlan_aware == 1)
-extern void zebra_l2_map_slave_to_bridge(struct zebra_l2info_brslave *br_slave);
+extern void zebra_l2_map_slave_to_bridge(struct zebra_l2info_brslave *br_slave,
+ struct zebra_ns *zns);
extern void
zebra_l2_unmap_slave_from_bridge(struct zebra_l2info_brslave *br_slave);
extern void
@@ -101,7 +103,8 @@ extern void zebra_l2_vxlanif_update_access_vlan(struct interface *ifp,
vlanid_t access_vlan);
extern void zebra_l2_vxlanif_del(struct interface *ifp);
extern void zebra_l2if_update_bridge_slave(struct interface *ifp,
- ifindex_t bridge_ifindex);
+ ifindex_t bridge_ifindex,
+ ns_id_t ns_id);
extern void zebra_l2if_update_bond_slave(struct interface *ifp,
ifindex_t bond_ifindex);
diff --git a/zebra/zebra_netns_id.c b/zebra/zebra_netns_id.c
index 8de4daf439..79121bb086 100644
--- a/zebra/zebra_netns_id.c
+++ b/zebra/zebra_netns_id.c
@@ -159,27 +159,34 @@ static ns_id_t extract_nsid(struct nlmsghdr *nlh, char *buf)
return ns_id;
}
-ns_id_t zebra_ns_id_get(const char *netnspath)
+/* fd_param = -1 is ignored.
+ * netnspath set to null is ignored.
+ * one of the 2 params is mandatory. netnspath is looked in priority
+ */
+ns_id_t zebra_ns_id_get(const char *netnspath, int fd_param)
{
int ns_id = -1;
struct sockaddr_nl snl;
- int fd, sock, ret;
+ int fd = -1, sock, ret;
unsigned int seq;
ns_id_t return_nsid = NS_UNKNOWN;
/* netns path check */
- if (!netnspath)
- return NS_UNKNOWN;
- fd = open(netnspath, O_RDONLY);
- if (fd == -1)
+ if (!netnspath && fd_param == -1)
return NS_UNKNOWN;
-
+ if (netnspath) {
+ fd = open(netnspath, O_RDONLY);
+ if (fd == -1)
+ return NS_UNKNOWN;
+ } else if (fd_param != -1)
+ fd = fd_param;
/* netlink socket */
sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (sock < 0) {
flog_err_sys(EC_LIB_SOCKET, "netlink( %u) socket() error: %s",
sock, safe_strerror(errno));
- close(fd);
+ if (fd_param == -1)
+ close(fd);
return NS_UNKNOWN;
}
memset(&snl, 0, sizeof(snl));
@@ -192,7 +199,8 @@ ns_id_t zebra_ns_id_get(const char *netnspath)
"netlink( %u) socket() bind error: %s", sock,
safe_strerror(errno));
close(sock);
- close(fd);
+ if (fd_param == -1)
+ close(fd);
return NS_UNKNOWN;
}
@@ -214,7 +222,8 @@ ns_id_t zebra_ns_id_get(const char *netnspath)
ret = send_receive(sock, nlh, seq, buf);
if (ret < 0) {
close(sock);
- close(fd);
+ if (fd_param == -1)
+ close(fd);
return NS_UNKNOWN;
}
nlh = (struct nlmsghdr *)buf;
@@ -258,7 +267,8 @@ ns_id_t zebra_ns_id_get(const char *netnspath)
"netlink( %u) recvfrom() error 2 when reading: %s",
fd, safe_strerror(errno));
close(sock);
- close(fd);
+ if (fd_param == -1)
+ close(fd);
if (errno == ENOTSUP) {
zlog_debug("NEWNSID locally generated");
return zebra_ns_id_get_fallback(netnspath);
@@ -279,7 +289,8 @@ ns_id_t zebra_ns_id_get(const char *netnspath)
ret = send_receive(sock, nlh, seq, buf);
if (ret < 0) {
close(sock);
- close(fd);
+ if (fd_param == -1)
+ close(fd);
return NS_UNKNOWN;
}
nlh = (struct nlmsghdr *)buf;
@@ -310,16 +321,18 @@ ns_id_t zebra_ns_id_get(const char *netnspath)
} while (len != 0 && ret == 0);
}
- close(fd);
+ if (fd_param == -1)
+ close(fd);
close(sock);
return return_nsid;
}
#else
-ns_id_t zebra_ns_id_get(const char *netnspath)
+ns_id_t zebra_ns_id_get(const char *netnspath, int fd __attribute__ ((unused)))
{
return zebra_ns_id_get_fallback(netnspath);
}
+
#endif /* ! defined(HAVE_NETLINK) */
#ifdef HAVE_NETNS
@@ -355,7 +368,7 @@ ns_id_t zebra_ns_id_get_default(void)
return NS_DEFAULT_INTERNAL;
}
close(fd);
- return zebra_ns_id_get((char *)NS_DEFAULT_NAME);
+ return zebra_ns_id_get((char *)NS_DEFAULT_NAME, -1);
#else /* HAVE_NETNS */
return NS_DEFAULT_INTERNAL;
#endif /* !HAVE_NETNS */
diff --git a/zebra/zebra_netns_id.h b/zebra/zebra_netns_id.h
index 7a5f6851f4..dd9eab18e0 100644
--- a/zebra/zebra_netns_id.h
+++ b/zebra/zebra_netns_id.h
@@ -24,7 +24,7 @@
extern "C" {
#endif
-extern ns_id_t zebra_ns_id_get(const char *netnspath);
+extern ns_id_t zebra_ns_id_get(const char *netnspath, int fd);
extern ns_id_t zebra_ns_id_get_default(void);
#ifdef __cplusplus
diff --git a/zebra/zebra_netns_notify.c b/zebra/zebra_netns_notify.c
index ec7681bf23..995fa6fb5a 100644
--- a/zebra/zebra_netns_notify.c
+++ b/zebra/zebra_netns_notify.c
@@ -72,13 +72,14 @@ static void zebra_ns_notify_create_context_from_entry_name(const char *name)
char *netnspath = ns_netns_pathname(NULL, name);
struct vrf *vrf;
int ret;
- ns_id_t ns_id, ns_id_external;
+ ns_id_t ns_id, ns_id_external, ns_id_relative = NS_UNKNOWN;
+ struct ns *default_ns;
if (netnspath == NULL)
return;
frr_with_privs(&zserv_privs) {
- ns_id = zebra_ns_id_get(netnspath);
+ ns_id = zebra_ns_id_get(netnspath, -1);
}
if (ns_id == NS_UNKNOWN)
return;
@@ -97,9 +98,21 @@ static void zebra_ns_notify_create_context_from_entry_name(const char *name)
ns_map_nsid_with_external(ns_id, false);
return;
}
+
+ default_ns = ns_get_default();
+
+ /* force kernel ns_id creation in that new vrf */
+ frr_with_privs(&zserv_privs) {
+ ns_switch_to_netns(netnspath);
+ ns_id_relative = zebra_ns_id_get(NULL, default_ns->fd);
+ ns_switchback_to_initial();
+ }
+
frr_with_privs(&zserv_privs) {
ret = vrf_netns_handler_create(NULL, vrf, netnspath,
- ns_id_external, ns_id);
+ ns_id_external,
+ ns_id,
+ ns_id_relative);
}
if (ret != CMD_SUCCESS) {
flog_warn(EC_ZEBRA_NS_VRF_CREATION_FAILED,
diff --git a/zebra/zebra_ns.c b/zebra/zebra_ns.c
index 4e51437337..6462daf687 100644
--- a/zebra/zebra_ns.c
+++ b/zebra/zebra_ns.c
@@ -153,20 +153,25 @@ static int zebra_ns_disable_internal(struct zebra_ns *zns, bool complete)
/* During zebra shutdown, do partial cleanup while the async dataplane
* is still running.
*/
-int zebra_ns_early_shutdown(struct ns *ns)
+int zebra_ns_early_shutdown(struct ns *ns,
+ void *param_in __attribute__((unused)),
+ void **param_out __attribute__((unused)))
{
struct zebra_ns *zns = ns->info;
if (zns == NULL)
return 0;
- return zebra_ns_disable_internal(zns, false);
+ zebra_ns_disable_internal(zns, false);
+ return NS_WALK_CONTINUE;
}
/* During zebra shutdown, do final cleanup
* after all dataplane work is complete.
*/
-int zebra_ns_final_shutdown(struct ns *ns)
+int zebra_ns_final_shutdown(struct ns *ns,
+ void *param_in __attribute__((unused)),
+ void **param_out __attribute__((unused)))
{
struct zebra_ns *zns = ns->info;
@@ -175,7 +180,7 @@ int zebra_ns_final_shutdown(struct ns *ns)
kernel_terminate(zns, true);
- return 0;
+ return NS_WALK_CONTINUE;
}
int zebra_ns_init(const char *optional_default_name)
@@ -183,12 +188,16 @@ int zebra_ns_init(const char *optional_default_name)
struct ns *default_ns;
ns_id_t ns_id;
ns_id_t ns_id_external;
+ struct ns *ns;
frr_with_privs(&zserv_privs) {
ns_id = zebra_ns_id_get_default();
}
ns_id_external = ns_map_nsid_with_external(ns_id, true);
ns_init_management(ns_id_external, ns_id);
+ ns = ns_get_default();
+ if (ns)
+ ns->relative_default_ns = ns_id;
default_ns = ns_lookup(ns_get_default_id());
if (!default_ns) {
diff --git a/zebra/zebra_ns.h b/zebra/zebra_ns.h
index dc79a83db0..f7d1f40782 100644
--- a/zebra/zebra_ns.h
+++ b/zebra/zebra_ns.h
@@ -67,9 +67,12 @@ struct zebra_ns *zebra_ns_lookup(ns_id_t ns_id);
int zebra_ns_init(const char *optional_default_name);
int zebra_ns_enable(ns_id_t ns_id, void **info);
int zebra_ns_disabled(struct ns *ns);
-int zebra_ns_early_shutdown(struct ns *ns);
-int zebra_ns_final_shutdown(struct ns *ns);
-
+int zebra_ns_early_shutdown(struct ns *ns,
+ void *param_in __attribute__((unused)),
+ void **param_out __attribute__((unused)));
+int zebra_ns_final_shutdown(struct ns *ns,
+ void *param_in __attribute__((unused)),
+ void **param_out __attribute__((unused)));
int zebra_ns_config_write(struct vty *vty, struct ns *ns);
#ifdef __cplusplus
diff --git a/zebra/zebra_pbr.c b/zebra/zebra_pbr.c
index 95d241c59f..c244d2a955 100644
--- a/zebra/zebra_pbr.c
+++ b/zebra/zebra_pbr.c
@@ -167,10 +167,11 @@ uint32_t zebra_pbr_rules_hash_key(const void *arg)
prefix_hash_key(&rule->rule.filter.src_ip));
if (rule->rule.filter.fwmark)
- key = jhash_3words(rule->rule.filter.fwmark, rule->vrf_id,
- rule->rule.ifindex, key);
+ key = jhash_2words(rule->rule.filter.fwmark, rule->vrf_id, key);
else
- key = jhash_2words(rule->vrf_id, rule->rule.ifindex, key);
+ key = jhash_1word(rule->vrf_id, key);
+
+ key = jhash(rule->ifname, strlen(rule->ifname), key);
return jhash_3words(rule->rule.filter.src_port,
rule->rule.filter.dst_port,
@@ -212,7 +213,7 @@ bool zebra_pbr_rules_hash_equal(const void *arg1, const void *arg2)
if (!prefix_same(&r1->rule.filter.dst_ip, &r2->rule.filter.dst_ip))
return false;
- if (r1->rule.ifindex != r2->rule.ifindex)
+ if (strcmp(r1->rule.ifname, r2->rule.ifname) != 0)
return false;
if (r1->vrf_id != r2->vrf_id)
@@ -224,7 +225,7 @@ bool zebra_pbr_rules_hash_equal(const void *arg1, const void *arg2)
struct pbr_rule_unique_lookup {
struct zebra_pbr_rule *rule;
uint32_t unique;
- ifindex_t ifindex;
+ char ifname[INTERFACE_NAMSIZ + 1];
vrf_id_t vrf_id;
};
@@ -234,7 +235,7 @@ static int pbr_rule_lookup_unique_walker(struct hash_bucket *b, void *data)
struct zebra_pbr_rule *rule = b->data;
if (pul->unique == rule->rule.unique
- && pul->ifindex == rule->rule.ifindex
+ && strncmp(pul->ifname, rule->rule.ifname, INTERFACE_NAMSIZ) == 0
&& pul->vrf_id == rule->vrf_id) {
pul->rule = rule;
return HASHWALK_ABORT;
@@ -249,7 +250,7 @@ pbr_rule_lookup_unique(struct zebra_pbr_rule *zrule)
struct pbr_rule_unique_lookup pul;
pul.unique = zrule->rule.unique;
- pul.ifindex = zrule->rule.ifindex;
+ strlcpy(pul.ifname, zrule->rule.ifname, INTERFACE_NAMSIZ);
pul.rule = NULL;
pul.vrf_id = zrule->vrf_id;
hash_walk(zrouter.rules_hash, &pbr_rule_lookup_unique_walker, &pul);
diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c
index 13a58bc34a..61498973e9 100644
--- a/zebra/zebra_vxlan.c
+++ b/zebra/zebra_vxlan.c
@@ -782,6 +782,43 @@ static void zl3vni_print_hash_detail(struct hash_bucket *bucket, void *data)
vty_out(vty, "\n");
}
+static int zvni_map_to_svi_ns(struct ns *ns,
+ void *_in_param,
+ void **_p_ifp)
+{
+ struct zebra_ns *zns = ns->info;
+ struct route_node *rn;
+ struct zebra_from_svi_param *in_param =
+ (struct zebra_from_svi_param *)_in_param;
+ struct zebra_l2info_vlan *vl;
+ struct interface *tmp_if = NULL;
+ struct interface **p_ifp = (struct interface **)_p_ifp;
+ struct zebra_if *zif;
+
+ if (!in_param)
+ return NS_WALK_STOP;
+
+ /* TODO: Optimize with a hash. */
+ for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
+ tmp_if = (struct interface *)rn->info;
+ /* Check oper status of the SVI. */
+ if (!tmp_if || !if_is_operative(tmp_if))
+ continue;
+ zif = tmp_if->info;
+ if (!zif || zif->zif_type != ZEBRA_IF_VLAN
+ || zif->link != in_param->br_if)
+ continue;
+ vl = (struct zebra_l2info_vlan *)&zif->l2info.vl;
+
+ if (vl->vid == in_param->vid) {
+ if (p_ifp)
+ *p_ifp = tmp_if;
+ return NS_WALK_STOP;
+ }
+ }
+ return NS_WALK_CONTINUE;
+}
+
/* Map to SVI on bridge corresponding to specified VLAN. This can be one
* of two cases:
* (a) In the case of a VLAN-aware bridge, the SVI is a L3 VLAN interface
@@ -791,15 +828,11 @@ static void zl3vni_print_hash_detail(struct hash_bucket *bucket, void *data)
*/
struct interface *zvni_map_to_svi(vlanid_t vid, struct interface *br_if)
{
- struct zebra_ns *zns;
- struct route_node *rn;
struct interface *tmp_if = NULL;
struct zebra_if *zif;
struct zebra_l2info_bridge *br;
- struct zebra_l2info_vlan *vl;
- uint8_t bridge_vlan_aware;
- int found = 0;
-
+ struct zebra_from_svi_param in_param;
+ struct interface **p_ifp;
/* Defensive check, caller expected to invoke only with valid bridge. */
if (!br_if)
return NULL;
@@ -808,33 +841,19 @@ struct interface *zvni_map_to_svi(vlanid_t vid, struct interface *br_if)
zif = br_if->info;
assert(zif);
br = &zif->l2info.br;
- bridge_vlan_aware = br->vlan_aware;
-
+ in_param.bridge_vlan_aware = br->vlan_aware;
/* Check oper status of the SVI. */
- if (!bridge_vlan_aware)
+ if (!in_param.bridge_vlan_aware)
return if_is_operative(br_if) ? br_if : NULL;
+ in_param.vid = vid;
+ in_param.br_if = br_if;
+ in_param.zif = NULL;
+ p_ifp = &tmp_if;
/* Identify corresponding VLAN interface. */
- /* TODO: Optimize with a hash. */
- zns = zebra_ns_lookup(NS_DEFAULT);
- for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
- tmp_if = (struct interface *)rn->info;
- /* Check oper status of the SVI. */
- if (!tmp_if || !if_is_operative(tmp_if))
- continue;
- zif = tmp_if->info;
- if (!zif || zif->zif_type != ZEBRA_IF_VLAN
- || zif->link != br_if)
- continue;
- vl = &zif->l2info.vl;
-
- if (vl->vid == vid) {
- found = 1;
- break;
- }
- }
-
- return found ? tmp_if : NULL;
+ ns_walk_func(zvni_map_to_svi_ns, (void *)&in_param,
+ (void **)p_ifp);
+ return tmp_if;
}
static int zebra_evpn_vxlan_del(zebra_evpn_t *zevpn)
@@ -846,18 +865,22 @@ static int zebra_evpn_vxlan_del(zebra_evpn_t *zevpn)
return zebra_evpn_del(zevpn);
}
-/*
- * Build the VNI hash table by going over the VxLAN interfaces. This
- * is called when EVPN (advertise-all-vni) is enabled.
- */
-static void zevpn_build_hash_table(void)
+
+static int zevpn_build_hash_table_zns(struct ns *ns,
+ void *param_in __attribute__((unused)),
+ void **param_out __attribute__((unused)))
{
- struct zebra_ns *zns;
+ struct zebra_ns *zns = ns->info;
struct route_node *rn;
struct interface *ifp;
+ struct zebra_vrf *zvrf;
+
+ zvrf = zebra_vrf_get_evpn();
+
+ if (!zvrf)
+ return NS_WALK_STOP;
/* Walk VxLAN interfaces and create EVPN hash. */
- zns = zebra_ns_lookup(NS_DEFAULT);
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
vni_t vni;
zebra_evpn_t *zevpn = NULL;
@@ -874,7 +897,15 @@ static void zevpn_build_hash_table(void)
vxl = &zif->l2info.vxl;
vni = vxl->vni;
-
+ /* link of VXLAN interface should be in zebra_evpn_vrf */
+ if (zvrf->zns->ns_id != vxl->link_nsid) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "Intf %s(%u) VNI %u, link not in same "
+ "namespace than BGP EVPN core instance ",
+ ifp->name, ifp->ifindex, vni);
+ continue;
+ }
/* L3-VNI and L2-VNI are handled seperately */
zl3vni = zl3vni_lookup(vni);
if (zl3vni) {
@@ -943,7 +974,7 @@ static void zevpn_build_hash_table(void)
zlog_debug(
"Failed to add EVPN hash, IF %s(%u) L2-VNI %u",
ifp->name, ifp->ifindex, vni);
- return;
+ return NS_WALK_CONTINUE;
}
if (zevpn->local_vtep_ip.s_addr !=
@@ -985,6 +1016,19 @@ static void zevpn_build_hash_table(void)
}
}
}
+ return NS_WALK_CONTINUE;
+}
+
+/*
+ * Build the VNI hash table by going over the VxLAN interfaces. This
+ * is called when EVPN (advertise-all-vni) is enabled.
+ */
+
+static void zevpn_build_hash_table(void)
+{
+ ns_walk_func(zevpn_build_hash_table_zns,
+ (void *)NULL,
+ (void **)NULL);
}
/*
@@ -1617,14 +1661,22 @@ static int zl3vni_del(zebra_l3vni_t *zl3vni)
return 0;
}
-struct interface *zl3vni_map_to_vxlan_if(zebra_l3vni_t *zl3vni)
+static int zl3vni_map_to_vxlan_if_ns(struct ns *ns,
+ void *_zl3vni,
+ void **_pifp)
{
- struct zebra_ns *zns = NULL;
+ struct zebra_ns *zns = ns->info;
+ zebra_l3vni_t *zl3vni = (zebra_l3vni_t *)_zl3vni;
struct route_node *rn = NULL;
struct interface *ifp = NULL;
+ struct zebra_vrf *zvrf;
+
+ zvrf = zebra_vrf_get_evpn();
+
+ if (!zvrf)
+ return NS_WALK_STOP;
/* loop through all vxlan-interface */
- zns = zebra_ns_lookup(NS_DEFAULT);
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
struct zebra_if *zif = NULL;
@@ -1639,13 +1691,39 @@ struct interface *zl3vni_map_to_vxlan_if(zebra_l3vni_t *zl3vni)
continue;
vxl = &zif->l2info.vxl;
- if (vxl->vni == zl3vni->vni) {
- zl3vni->local_vtep_ip = vxl->vtep_ip;
- return ifp;
+ if (vxl->vni != zl3vni->vni)
+ continue;
+
+ /* link of VXLAN interface should be in zebra_evpn_vrf */
+ if (zvrf->zns->ns_id != vxl->link_nsid) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "Intf %s(%u) VNI %u, link not in same "
+ "namespace than BGP EVPN core instance ",
+ ifp->name, ifp->ifindex, vxl->vni);
+ continue;
}
+
+
+ zl3vni->local_vtep_ip = vxl->vtep_ip;
+ if (_pifp)
+ *_pifp = (void *)ifp;
+ return NS_WALK_STOP;
}
- return NULL;
+ return NS_WALK_CONTINUE;
+}
+
+struct interface *zl3vni_map_to_vxlan_if(zebra_l3vni_t *zl3vni)
+{
+ struct interface **p_ifp;
+ struct interface *ifp = NULL;
+
+ p_ifp = &ifp;
+
+ ns_walk_func(zl3vni_map_to_vxlan_if_ns,
+ (void *)zl3vni, (void **)p_ifp);
+ return ifp;
}
struct interface *zl3vni_map_to_svi_if(zebra_l3vni_t *zl3vni)
@@ -3987,11 +4065,10 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp,
return -1;
}
- zvrf = vrf_info_lookup(zevpn->vxlan_if->vrf_id);
+ zvrf = zebra_vrf_get_evpn();
if (!zvrf) {
if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(" No Vrf found for vrf_id: %d",
- zevpn->vxlan_if->vrf_id);
+ zlog_debug(" No Evpn Global Vrf found");
return -1;
}
@@ -5447,6 +5524,25 @@ stream_failure:
return;
}
+static int macfdb_read_ns(struct ns *ns,
+ void *_in_param __attribute__((unused)),
+ void **out_param __attribute__((unused)))
+{
+ struct zebra_ns *zns = ns->info;
+
+ macfdb_read(zns);
+ return NS_WALK_CONTINUE;
+}
+
+static int neigh_read_ns(struct ns *ns,
+ void *_in_param __attribute__((unused)),
+ void **out_param __attribute__((unused)))
+{
+ struct zebra_ns *zns = ns->info;
+
+ neigh_read(zns);
+ return NS_WALK_CONTINUE;
+}
/*
* Handle message from client to learn (or stop learning) about VNIs and MACs.
@@ -5499,10 +5595,10 @@ void zebra_vxlan_advertise_all_vni(ZAPI_HANDLER_ARGS)
zebra_evpn_gw_macip_add_for_evpn_hash, NULL);
/* Read the MAC FDB */
- macfdb_read(zvrf->zns);
+ ns_walk_func(macfdb_read_ns, NULL, NULL);
/* Read neighbors */
- neigh_read(zvrf->zns);
+ ns_walk_func(neigh_read_ns, NULL, NULL);
} else {
/* Cleanup VTEPs for all EVPNs - uninstall from
* kernel and free entries.