]> git.proxmox.com Git - mirror_frr.git/commitdiff
Merge pull request #8731 from mjstapp/fix_pw_backups
authorStephen Worley <sworley@nvidia.com>
Thu, 24 Jun 2021 16:46:31 +0000 (12:46 -0400)
committerGitHub <noreply@github.com>
Thu, 24 Jun 2021 16:46:31 +0000 (12:46 -0400)
zebra: Fix pseudowires with backup nexthops

331 files changed:
babeld/babeld.c
bgpd/bgp_advertise.c
bgpd/bgp_aspath.c
bgpd/bgp_attr_evpn.c
bgpd/bgp_attr_evpn.h
bgpd/bgp_bfd.c
bgpd/bgp_bmp.c
bgpd/bgp_conditional_adv.c
bgpd/bgp_damp.c
bgpd/bgp_damp.h
bgpd/bgp_debug.c
bgpd/bgp_debug.h
bgpd/bgp_evpn.c
bgpd/bgp_evpn.h
bgpd/bgp_evpn_mh.c
bgpd/bgp_evpn_private.h
bgpd/bgp_evpn_vty.c
bgpd/bgp_evpn_vty.h
bgpd/bgp_flowspec_util.c
bgpd/bgp_fsm.c
bgpd/bgp_label.c
bgpd/bgp_mac.c
bgpd/bgp_memory.c
bgpd/bgp_memory.h
bgpd/bgp_nb_config.c
bgpd/bgp_network.c
bgpd/bgp_nexthop.c
bgpd/bgp_nexthop.h
bgpd/bgp_nht.c
bgpd/bgp_nht.h
bgpd/bgp_packet.c
bgpd/bgp_route.c
bgpd/bgp_route.h
bgpd/bgp_routemap.c
bgpd/bgp_routemap_nb.c
bgpd/bgp_routemap_nb.h
bgpd/bgp_routemap_nb_config.c
bgpd/bgp_snmp.c
bgpd/bgp_table.h
bgpd/bgp_updgrp.c
bgpd/bgp_updgrp_adv.c
bgpd/bgp_updgrp_packet.c
bgpd/bgp_vty.c
bgpd/bgp_vty.h
bgpd/bgp_zebra.c
bgpd/bgpd.c
bgpd/bgpd.h
bgpd/rfapi/rfapi.c
bgpd/rfapi/rfapi_import.c
doc/developer/conf.py
doc/developer/topotests.rst
doc/requirements.txt [new file with mode: 0644]
doc/user/basic.rst
doc/user/bgp.rst
doc/user/conf.py
doc/user/ospf6d.rst
doc/user/ospf_fundamentals.rst
doc/user/ospfd.rst
docker/alpine/Dockerfile
docker/alpine/docker-start
docker/centos-7/Dockerfile
docker/centos-7/docker-start
docker/centos-8/Dockerfile
docker/centos-8/docker-start
docker/debian/Dockerfile
docker/debian/docker-start
docker/ubuntu20-ci/Dockerfile
eigrpd/eigrp_cli.c
isisd/isis_adjacency.c
isisd/isis_circuit.c
isisd/isis_dynhn.c
isisd/isis_dynhn.h
isisd/isis_lsp.c
isisd/isis_misc.c
isisd/isis_nb_notifications.c
isisd/isis_snmp.c
isisd/isis_vty_fabricd.c
isisd/isisd.c
isisd/isisd.h
lib/bitfield.h
lib/command.c
lib/compiler.h
lib/if.c
lib/link_state.c
lib/log_filter.c
lib/log_vty.c
lib/log_vty.h
lib/memory.c
lib/northbound.c
lib/northbound_grpc.cpp
lib/routemap.h
lib/routemap_cli.c
lib/routing_nb.h
lib/srv6.c
lib/table.h
lib/vrf.c
lib/vty.c
lib/vty.h
lib/zclient.c
lib/zebra.h
lib/zlog.c
lib/zlog.h
lib/zlog_targets.c
nhrpd/nhrp_main.c
nhrpd/nhrp_vty.c
ospf6d/ospf6_abr.c
ospf6d/ospf6_abr.h
ospf6d/ospf6_area.c
ospf6d/ospf6_area.h
ospf6d/ospf6_asbr.c
ospf6d/ospf6_asbr.h
ospf6d/ospf6_flood.c
ospf6d/ospf6_flood.h
ospf6d/ospf6_interface.c
ospf6d/ospf6_interface.h
ospf6d/ospf6_intra.c
ospf6d/ospf6_lsa.c
ospf6d/ospf6_lsa.h
ospf6d/ospf6_lsdb.c
ospf6d/ospf6_message.c
ospf6d/ospf6_message.h
ospf6d/ospf6_neighbor.c
ospf6d/ospf6_neighbor.h
ospf6d/ospf6_network.c
ospf6d/ospf6_network.h
ospf6d/ospf6_nssa.c [new file with mode: 0644]
ospf6d/ospf6_nssa.h [new file with mode: 0644]
ospf6d/ospf6_proto.h
ospf6d/ospf6_route.c
ospf6d/ospf6_snmp.c
ospf6d/ospf6_spf.c
ospf6d/ospf6_spf.h
ospf6d/ospf6_top.c
ospf6d/ospf6_top.h
ospf6d/ospf6d.c
ospf6d/subdir.am
ospfd/ospf_asbr.c
ospfd/ospf_flood.c
ospfd/ospf_gr_helper.c
ospfd/ospf_gr_helper.h
ospfd/ospf_lsa.c
ospfd/ospf_main.c
ospfd/ospf_neighbor.c
ospfd/ospf_opaque.c
ospfd/ospf_packet.c
ospfd/ospf_routemap.c
ospfd/ospf_spf.c
ospfd/ospf_vty.c
ospfd/ospfd.c
pathd/path_errors.c
pathd/path_errors.h
pathd/path_nb_config.c
pathd/path_pcep.c
pathd/path_pcep.h
pathd/path_pcep_config.c
pathd/path_pcep_config.h
pathd/path_pcep_controller.c
pathd/path_pcep_controller.h
pathd/path_pcep_debug.c
pathd/path_pcep_lib.c
pathd/path_pcep_lib.h
pathd/path_pcep_pcc.c
pathd/path_pcep_pcc.h
pathd/pathd.c
pathd/pathd.h
pbrd/pbr_main.c
pbrd/pbr_vty.c
pceplib/pcep_msg_objects.h
pceplib/pcep_msg_objects_encoding.c
pceplib/pcep_msg_tlvs.h
pceplib/pcep_msg_tlvs_encoding.c
pceplib/test/pcep_msg_tools_test.c
pimd/pim_cmd.c
pimd/pim_msdp.c
pimd/pim_msdp.h
pimd/pim_nb.c
pimd/pim_nb.h
pimd/pim_nb_config.c
ripd/ripd.c
ripngd/ripngd.c
staticd/static_debug.h
staticd/static_nb.h
staticd/static_nht.h
staticd/static_routes.h
staticd/static_vrf.h
staticd/static_vty.h
staticd/static_zebra.c
staticd/static_zebra.h
tests/isisd/test_common.c
tests/isisd/test_isis_spf.c
tests/lib/test_grpc.cpp [new file with mode: 0644]
tests/lib/test_grpc.py [new file with mode: 0644]
tests/subdir.am
tests/topotests/all_protocol_startup/test_all_protocol_startup.py
tests/topotests/bfd_topo2/r4/ipv6_routes.json
tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vni_routes_base.json [new file with mode: 0644]
tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vni_routes_no_rt2.json [new file with mode: 0644]
tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vni_routes_no_rt5.json [new file with mode: 0644]
tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vrf_ipv4_base.json [new file with mode: 0644]
tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vrf_ipv4_no_rt2.json [new file with mode: 0644]
tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vrf_ipv4_no_rt5.json [new file with mode: 0644]
tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vrf_ipv6_base.json [new file with mode: 0644]
tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vrf_ipv6_no_rt2.json [new file with mode: 0644]
tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vrf_ipv6_no_rt5.json [new file with mode: 0644]
tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp-evpn-overlay-index-gateway/PE1/zebra.conf [new file with mode: 0644]
tests/topotests/bgp-evpn-overlay-index-gateway/PE1/zebra_vrf_ipv4_base.json [new file with mode: 0644]
tests/topotests/bgp-evpn-overlay-index-gateway/PE1/zebra_vrf_ipv4_no_rt2.json [new file with mode: 0644]
tests/topotests/bgp-evpn-overlay-index-gateway/PE1/zebra_vrf_ipv4_no_rt5.json [new file with mode: 0644]
tests/topotests/bgp-evpn-overlay-index-gateway/PE1/zebra_vrf_ipv6_base.json [new file with mode: 0644]
tests/topotests/bgp-evpn-overlay-index-gateway/PE1/zebra_vrf_ipv6_no_rt2.json [new file with mode: 0644]
tests/topotests/bgp-evpn-overlay-index-gateway/PE1/zebra_vrf_ipv6_no_rt5.json [new file with mode: 0644]
tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vni_routes_base.json [new file with mode: 0644]
tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vni_routes_no_rt2.json [new file with mode: 0644]
tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vni_routes_no_rt5.json [new file with mode: 0644]
tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vrf_ipv4_base.json [new file with mode: 0644]
tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vrf_ipv4_no_rt2.json [new file with mode: 0644]
tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vrf_ipv4_no_rt5.json [new file with mode: 0644]
tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vrf_ipv6_base.json [new file with mode: 0644]
tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vrf_ipv6_no_rt2.json [new file with mode: 0644]
tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vrf_ipv6_no_rt5.json [new file with mode: 0644]
tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp-evpn-overlay-index-gateway/PE2/zebra.conf [new file with mode: 0644]
tests/topotests/bgp-evpn-overlay-index-gateway/PE2/zebra_vrf_ipv4_base.json [new file with mode: 0644]
tests/topotests/bgp-evpn-overlay-index-gateway/PE2/zebra_vrf_ipv4_no_rt2.json [new file with mode: 0644]
tests/topotests/bgp-evpn-overlay-index-gateway/PE2/zebra_vrf_ipv4_no_rt5.json [new file with mode: 0644]
tests/topotests/bgp-evpn-overlay-index-gateway/PE2/zebra_vrf_ipv6_base.json [new file with mode: 0644]
tests/topotests/bgp-evpn-overlay-index-gateway/PE2/zebra_vrf_ipv6_no_rt2.json [new file with mode: 0644]
tests/topotests/bgp-evpn-overlay-index-gateway/PE2/zebra_vrf_ipv6_no_rt5.json [new file with mode: 0644]
tests/topotests/bgp-evpn-overlay-index-gateway/__init__.py [new file with mode: 0644]
tests/topotests/bgp-evpn-overlay-index-gateway/host1/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp-evpn-overlay-index-gateway/host1/zebra.conf [new file with mode: 0644]
tests/topotests/bgp-evpn-overlay-index-gateway/host2/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp-evpn-overlay-index-gateway/host2/zebra.conf [new file with mode: 0644]
tests/topotests/bgp-evpn-overlay-index-gateway/test_bgp_evpn_overlay_index_gateway.py [new file with mode: 0755]
tests/topotests/bgp_default_route_route_map_match2/__init__.py [new file with mode: 0644]
tests/topotests/bgp_default_route_route_map_match2/r1/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_default_route_route_map_match2/r1/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_default_route_route_map_match2/r2/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_default_route_route_map_match2/r2/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_default_route_route_map_match2/test_bgp_default-originate_route-map_match2.py [new file with mode: 0644]
tests/topotests/bgp_default_route_route_map_match_set/r1/bgpd.conf
tests/topotests/bgp_default_route_route_map_match_set/test_bgp_default-originate_route-map_match_set.py
tests/topotests/bgp_default_route_route_map_set/r1/bgpd.conf
tests/topotests/bgp_default_route_route_map_set/test_bgp_default-originate_route-map_set.py
tests/topotests/config_timing/r1/staticd.conf [new file with mode: 0644]
tests/topotests/config_timing/r1/zebra.conf [new file with mode: 0644]
tests/topotests/config_timing/test_config_timing.py [new file with mode: 0644]
tests/topotests/conftest.py
tests/topotests/lib/bgp.py
tests/topotests/lib/common_config.py
tests/topotests/lib/mcast-tester.py [new file with mode: 0755]
tests/topotests/lib/ospf.py
tests/topotests/lib/pim.py
tests/topotests/lib/topogen.py
tests/topotests/lib/topotest.py
tests/topotests/msdp_mesh_topo1/__init__.py [new file with mode: 0644]
tests/topotests/msdp_mesh_topo1/r1/bgpd.conf [new file with mode: 0644]
tests/topotests/msdp_mesh_topo1/r1/ospfd.conf [new file with mode: 0644]
tests/topotests/msdp_mesh_topo1/r1/pimd.conf [new file with mode: 0644]
tests/topotests/msdp_mesh_topo1/r1/zebra.conf [new file with mode: 0644]
tests/topotests/msdp_mesh_topo1/r2/bgpd.conf [new file with mode: 0644]
tests/topotests/msdp_mesh_topo1/r2/ospfd.conf [new file with mode: 0644]
tests/topotests/msdp_mesh_topo1/r2/pimd.conf [new file with mode: 0644]
tests/topotests/msdp_mesh_topo1/r2/zebra.conf [new file with mode: 0644]
tests/topotests/msdp_mesh_topo1/r3/bgpd.conf [new file with mode: 0644]
tests/topotests/msdp_mesh_topo1/r3/ospfd.conf [new file with mode: 0644]
tests/topotests/msdp_mesh_topo1/r3/pimd.conf [new file with mode: 0644]
tests/topotests/msdp_mesh_topo1/r3/zebra.conf [new file with mode: 0644]
tests/topotests/msdp_mesh_topo1/test_msdp_mesh_topo1.dot [new file with mode: 0644]
tests/topotests/msdp_mesh_topo1/test_msdp_mesh_topo1.png [new file with mode: 0644]
tests/topotests/msdp_mesh_topo1/test_msdp_mesh_topo1.py [new file with mode: 0644]
tests/topotests/ospf6_topo1/r1/show_ipv6_route.ref
tests/topotests/ospf6_topo1/r2/show_ipv6_route.ref
tests/topotests/ospf6_topo1/r3/show_ipv6_route.ref
tests/topotests/ospf6_topo1/r4/show_ipv6_route.ref
tests/topotests/ospf6_topo1/test_ospf6_topo1.py
tests/topotests/ospf6_topo1_vrf/README.md
tests/topotests/ospf6_topo1_vrf/r1/ospf6d.conf
tests/topotests/ospf6_topo1_vrf/r1/show_ipv6_vrf_route.ref
tests/topotests/ospf6_topo1_vrf/r2/ospf6d.conf
tests/topotests/ospf6_topo1_vrf/r2/show_ipv6_vrf_route.ref
tests/topotests/ospf6_topo1_vrf/r3/ospf6d.conf
tests/topotests/ospf6_topo1_vrf/r3/show_ipv6_vrf_route.ref
tests/topotests/ospf6_topo1_vrf/r4/ospf6d.conf
tests/topotests/ospf6_topo1_vrf/r4/show_ipv6_vrf_route.ref
tests/topotests/ospf6_topo1_vrf/test_ospf6_topo1_vrf.py
tests/topotests/ospf6_topo2/r2/ospf6d.conf
tests/topotests/ospf6_topo2/r2/zebra.conf
tests/topotests/ospf6_topo2/r4/ospf6d.conf [new file with mode: 0644]
tests/topotests/ospf6_topo2/r4/zebra.conf [new file with mode: 0644]
tests/topotests/ospf6_topo2/test_ospf6_topo2.dot
tests/topotests/ospf6_topo2/test_ospf6_topo2.png
tests/topotests/ospf6_topo2/test_ospf6_topo2.py
tests/topotests/ospf_basic_functionality/ospf_asbr_summary_topo1.json [new file with mode: 0644]
tests/topotests/ospf_basic_functionality/test_ospf_asbr_summary_topo1.py [new file with mode: 0644]
tests/topotests/ospf_topo1/r1/ospf6route.txt
tests/topotests/ospf_topo1/r1/ospf6route_down.txt
tests/topotests/ospf_topo1/r1/ospf6route_ecmp.txt
tests/topotests/ospf_topo1/r2/ospf6route.txt
tests/topotests/ospf_topo1/r2/ospf6route_down.txt
tests/topotests/ospf_topo1/r2/ospf6route_ecmp.txt
tests/topotests/ospf_topo1/r3/ospf6route.txt
tests/topotests/ospf_topo1/r3/ospf6route_down.txt
tests/topotests/ospf_topo1/r3/ospf6route_ecmp.txt
tests/topotests/ospf_topo1/r4/ospf6route.txt
tests/topotests/ospf_topo1/r4/ospf6route_down.txt
tests/topotests/ospf_topo1/r4/ospf6route_ecmp.txt
tests/topotests/ospfv3_basic_functionality/ospfv3_rte_calc.json [new file with mode: 0644]
tests/topotests/ospfv3_basic_functionality/ospfv3_single_area.json [new file with mode: 0644]
tests/topotests/ospfv3_basic_functionality/test_ospfv3_rte_calc.py [new file with mode: 0644]
tests/topotests/ospfv3_basic_functionality/test_ospfv3_single_area.py [new file with mode: 0644]
tools/etc/frr/support_bundle_commands.conf
tools/frr-reload.py
vrrpd/vrrp_vty.c
vtysh/vtysh.c
vtysh/vtysh.h
yang/frr-bgp-route-map.yang
yang/frr-pim.yang
zebra/zapi_msg.c
zebra/zebra_evpn.c
zebra/zebra_evpn.h
zebra/zebra_fpm_netlink.c
zebra/zebra_gr.c
zebra/zebra_mlag.c
zebra/zebra_rnh.c
zebra/zebra_srte.c
zebra/zebra_srv6.c
zebra/zebra_vxlan.c
zebra/zebra_vxlan_private.h
zebra/zserv.c

index 4d4dd2e19490f651681ccd37eb8b9b5092ca26a1..b9623b64b5fa56dd97f8c21e8028dbc77f70a3af 100644 (file)
@@ -819,6 +819,8 @@ babeld_quagga_init(void)
     install_element(BABEL_NODE, &babel_ipv6_distribute_list_cmd);
     install_element(BABEL_NODE, &babel_no_ipv6_distribute_list_cmd);
 
+    vrf_cmd_init(NULL, &babeld_privs);
+
     babel_if_init();
 
     /* Access list install. */
index 1ebe4e5b53b158f7e8329aaf86e40316e2f0c606..9da97d110fb4f6631d831b63b5f5134bcf7fd15b 100644 (file)
@@ -205,6 +205,7 @@ void bgp_adj_in_remove(struct bgp_dest *dest, struct bgp_adj_in *bai)
 {
        bgp_attr_unintern(&bai->attr);
        BGP_ADJ_IN_DEL(dest, bai);
+       bgp_dest_unlock_node(dest);
        peer_unlock(bai->peer); /* adj_in peer reference */
        XFREE(MTYPE_BGP_ADJ_IN, bai);
 }
@@ -223,10 +224,8 @@ bool bgp_adj_in_unset(struct bgp_dest *dest, struct peer *peer,
        while (adj) {
                adj_next = adj->next;
 
-               if (adj->peer == peer && adj->addpath_rx_id == addpath_id) {
+               if (adj->peer == peer && adj->addpath_rx_id == addpath_id)
                        bgp_adj_in_remove(dest, adj);
-                       bgp_dest_unlock_node(dest);
-               }
 
                adj = adj_next;
        }
index 5cf3c60fa2cd97d5467ec180698455a62f153f25..25109e030b8d705ecb3cc4ae46c86672ae03a97a 100644 (file)
@@ -910,77 +910,70 @@ size_t aspath_put(struct stream *s, struct aspath *as, int use32bit)
        if (!seg || seg->length == 0)
                return 0;
 
-       if (seg) {
-               /*
-                * Hey, what do we do when we have > STREAM_WRITABLE(s) here?
-                * At the moment, we would write out a partial aspath, and our
-                * peer
-                * will complain and drop the session :-/
-                *
-                * The general assumption here is that many things tested will
-                * never happen.  And, in real live, up to now, they have not.
-                */
-               while (seg && (ASSEGMENT_LEN(seg, use32bit)
-                              <= STREAM_WRITEABLE(s))) {
-                       struct assegment *next = seg->next;
-                       int written = 0;
-                       int asns_packed = 0;
-                       size_t lenp;
-
-                       /* Overlength segments have to be split up */
-                       while ((seg->length - written) > AS_SEGMENT_MAX) {
-                               assegment_header_put(s, seg->type,
-                                                    AS_SEGMENT_MAX);
-                               assegment_data_put(s, (seg->as + written), AS_SEGMENT_MAX,
-                                                  use32bit);
-                               written += AS_SEGMENT_MAX;
-                               bytes += ASSEGMENT_SIZE(AS_SEGMENT_MAX,
-                                                       use32bit);
-                       }
-
-                       /* write the final segment, probably is also the first
-                        */
-                       lenp = assegment_header_put(s, seg->type,
-                                                   seg->length - written);
+       /*
+        * Hey, what do we do when we have > STREAM_WRITABLE(s) here?
+        * At the moment, we would write out a partial aspath, and our
+        * peer
+        * will complain and drop the session :-/
+        *
+        * The general assumption here is that many things tested will
+        * never happen.  And, in real live, up to now, they have not.
+        */
+       while (seg && (ASSEGMENT_LEN(seg, use32bit) <= STREAM_WRITEABLE(s))) {
+               struct assegment *next = seg->next;
+               int written = 0;
+               int asns_packed = 0;
+               size_t lenp;
+
+               /* Overlength segments have to be split up */
+               while ((seg->length - written) > AS_SEGMENT_MAX) {
+                       assegment_header_put(s, seg->type, AS_SEGMENT_MAX);
                        assegment_data_put(s, (seg->as + written),
-                                          seg->length - written, use32bit);
+                                          AS_SEGMENT_MAX, use32bit);
+                       written += AS_SEGMENT_MAX;
+                       bytes += ASSEGMENT_SIZE(AS_SEGMENT_MAX, use32bit);
+               }
 
-                       /* Sequence-type segments can be 'packed' together
-                        * Case of a segment which was overlength and split up
-                        * will be missed here, but that doesn't matter.
+               /* write the final segment, probably is also the first
+                */
+               lenp = assegment_header_put(s, seg->type,
+                                           seg->length - written);
+               assegment_data_put(s, (seg->as + written),
+                                  seg->length - written, use32bit);
+
+               /* Sequence-type segments can be 'packed' together
+                * Case of a segment which was overlength and split up
+                * will be missed here, but that doesn't matter.
+                */
+               while (next && ASSEGMENTS_PACKABLE(seg, next)) {
+                       /* NB: We should never normally get here given
+                        * we
+                        * normalise aspath data when parse them.
+                        * However, better
+                        * safe than sorry. We potentially could call
+                        * assegment_normalise here instead, but it's
+                        * cheaper and
+                        * easier to do it on the fly here rather than
+                        * go through
+                        * the segment list twice every time we write
+                        * out
+                        * aspath's.
                         */
-                       while (next && ASSEGMENTS_PACKABLE(seg, next)) {
-                               /* NB: We should never normally get here given
-                                * we
-                                * normalise aspath data when parse them.
-                                * However, better
-                                * safe than sorry. We potentially could call
-                                * assegment_normalise here instead, but it's
-                                * cheaper and
-                                * easier to do it on the fly here rather than
-                                * go through
-                                * the segment list twice every time we write
-                                * out
-                                * aspath's.
-                                */
-
-                               /* Next segment's data can fit in this one */
-                               assegment_data_put(s, next->as, next->length,
-                                                  use32bit);
-
-                               /* update the length of the segment header */
-                               stream_putc_at(s, lenp,
-                                              seg->length - written
-                                                      + next->length);
-                               asns_packed += next->length;
-
-                               next = next->next;
-                       }
 
-                       bytes += ASSEGMENT_SIZE(
-                               seg->length - written + asns_packed, use32bit);
-                       seg = next;
+                       /* Next segment's data can fit in this one */
+                       assegment_data_put(s, next->as, next->length, use32bit);
+
+                       /* update the length of the segment header */
+                       stream_putc_at(s, lenp,
+                                      seg->length - written + next->length);
+                       asns_packed += next->length;
+
+                       next = next->next;
                }
+
+               bytes += ASSEGMENT_SIZE(seg->length - written + asns_packed,
+                                       use32bit);
+               seg = next;
        }
        return bytes;
 }
index 1df646c34652622e6f1388e55dcb5c0fb9c704a2..0e341a8c6b121c2ebca6b6a032b792cadaf27644 100644 (file)
@@ -315,3 +315,4 @@ extern bool is_zero_gw_ip(const union gw_addr *gw_ip, const afi_t afi)
 
        return false;
 }
+
index 6fdf73fd1e32583fed6aa4883dcace75131c8e5e..102509fdd712e5323b134c0a9d5df0cd56714893 100644 (file)
@@ -30,7 +30,21 @@ union gw_addr {
        struct in6_addr ipv6;
 };
 
+enum overlay_index_type {
+       OVERLAY_INDEX_TYPE_NONE,
+       OVERLAY_INDEX_GATEWAY_IP,
+       OVERLAY_INDEX_ESI,
+       OVERLAY_INDEX_MAC,
+};
+
+/*
+ * Structure to store ovrelay index for EVPN type-5 route
+ * This structure stores ESI and Gateway IP overlay index.
+ * MAC overlay index is stored in the RMAC attribute.
+ */
 struct bgp_route_evpn {
+       enum overlay_index_type type;
+       esi_t eth_s_id;
        union gw_addr gw_ip;
 };
 
index 6004070e68b4224726c43b60b460d026da7598c4..f6f2f5f6e427e3670a56f2e687e596fcb9f01b9c 100644 (file)
@@ -72,7 +72,7 @@ static void bfd_session_status_update(struct bfd_session_params *bsp,
        }
 
        if (bss->state == BSS_UP && bss->previous_state != BSS_UP
-           && peer->status != Established) {
+           && !peer_established(peer)) {
                if (!BGP_PEER_START_SUPPRESSED(peer)) {
                        bgp_fsm_nht_update(peer, true);
                        BGP_EVENT_ADD(peer, BGP_Start);
index abe97571c568c43b565a83c9b5df2a0346180af7..dbc35de80bd1ccbed6d8a08412cec8ac9ddf3ddb 100644 (file)
@@ -365,7 +365,7 @@ static struct stream *bmp_peerstate(struct peer *peer, bool down)
 #define BGP_BMP_MAX_PACKET_SIZE        1024
        s = stream_new(BGP_MAX_PACKET_SIZE);
 
-       if (peer->status == Established && !down) {
+       if (peer_established(peer) && !down) {
                struct bmp_bgp_peer *bbpeer;
 
                bmp_common_hdr(s, BMP_VERSION_3,
@@ -1146,7 +1146,7 @@ static bool bmp_wrqueue(struct bmp *bmp, struct pullwr *pullwr)
                zlog_info("bmp: skipping queued item for deleted peer");
                goto out;
        }
-       if (peer->status != Established)
+       if (!peer_established(peer))
                goto out;
 
        bn = bgp_node_lookup(bmp->targets->bgp->rib[afi][safi], &bqe->p);
@@ -1323,7 +1323,7 @@ static int bmp_stats(struct thread *thread)
        for (ALL_LIST_ELEMENTS_RO(bt->bgp->peer, node, peer)) {
                size_t count = 0, count_pos, len;
 
-               if (peer->status != Established)
+               if (!peer_established(peer))
                        continue;
 
                s = stream_new(BGP_MAX_PACKET_SIZE);
index 6e80765f8671ce734bd53e1f6c9a1e82978e3b0a..49bc38be662f28ce7ebcc2c2a57a69b5ecccb50b 100644 (file)
@@ -195,7 +195,7 @@ static int bgp_conditional_adv_timer(struct thread *t)
                if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE))
                        continue;
 
-               if (peer->status != Established)
+               if (!peer_established(peer))
                        continue;
 
                FOREACH_AFI_SAFI (afi, safi) {
index 3db142b8cfe02b95b412452807a6b66504bb579d..2a372c0ba4b528f02a99606c4cef3a19d94dcf20 100644 (file)
@@ -245,7 +245,6 @@ static int bgp_reuse_timer(struct thread *t)
         * list head entry. */
        assert(bdc->reuse_offset < bdc->reuse_list_size);
        plist = bdc->reuse_list[bdc->reuse_offset];
-       node = SLIST_FIRST(&plist);
        SLIST_INIT(&bdc->reuse_list[bdc->reuse_offset]);
 
        /* 2.  set offset = modulo reuse-list-size ( offset + 1 ), thereby
@@ -788,7 +787,7 @@ const char *bgp_damp_reuse_time_vty(struct vty *vty, struct bgp_path_info *path,
 
        /* If dampening is not enabled or there is no dampening information,
           return immediately.  */
-       if (!bdc || !bdi)
+       if (!bdi)
                return NULL;
 
        /* Calculate new penalty.  */
@@ -822,7 +821,7 @@ static int bgp_print_dampening_parameters(struct bgp *bgp, struct vty *vty,
 }
 
 int bgp_show_dampening_parameters(struct vty *vty, afi_t afi, safi_t safi,
-                                 uint8_t show_flags)
+                                 uint16_t show_flags)
 {
        struct bgp *bgp;
 
index 3c8f138d6a805c680d2d1d1073ed7d3f76ac023d..c03a0cc5c972a58eee1e3a34802caba416acc5b8 100644 (file)
@@ -166,7 +166,7 @@ extern const char *bgp_damp_reuse_time_vty(struct vty *vty,
                                           safi_t safi, bool use_json,
                                           json_object *json);
 extern int bgp_show_dampening_parameters(struct vty *vty, afi_t, safi_t,
-                                        uint8_t);
+                                        uint16_t);
 extern void bgp_peer_damp_enable(struct peer *peer, afi_t afi, safi_t safi,
                                 time_t half, unsigned int reuse,
                                 unsigned int suppress, time_t max);
index 8f286e66df0a24ada8a915239d5427233b317c16..856afb05f84b90d8920762c1b40af308b56b3a72 100644 (file)
@@ -2680,10 +2680,14 @@ const char *bgp_debug_rdpfxpath2str(afi_t afi, safi_t safi,
                                    union prefixconstptr pu,
                                    mpls_label_t *label, uint32_t num_labels,
                                    int addpath_valid, uint32_t addpath_id,
+                                   struct bgp_route_evpn *overlay_index,
                                    char *str, int size)
 {
        char rd_buf[RD_ADDRSTRLEN];
        char tag_buf[30];
+       char overlay_index_buf[INET6_ADDRSTRLEN + 14];
+       const struct prefix_evpn *evp;
+
        /* ' with addpath ID '          17
         * max strlen of uint32       + 10
         * +/- (just in case)         +  1
@@ -2701,6 +2705,23 @@ const char *bgp_debug_rdpfxpath2str(afi_t afi, safi_t safi,
                snprintf(pathid_buf, sizeof(pathid_buf), " with addpath ID %u",
                         addpath_id);
 
+       overlay_index_buf[0] = '\0';
+       if (overlay_index && overlay_index->type == OVERLAY_INDEX_GATEWAY_IP) {
+               char obuf[INET6_ADDRSTRLEN];
+
+               obuf[0] = '\0';
+               evp = pu.evp;
+               if (is_evpn_prefix_ipaddr_v4(evp))
+                       inet_ntop(AF_INET, &overlay_index->gw_ip, obuf,
+                                 sizeof(obuf));
+               else if (is_evpn_prefix_ipaddr_v6(evp))
+                       inet_ntop(AF_INET6, &overlay_index->gw_ip, obuf,
+                                 sizeof(obuf));
+
+               snprintf(overlay_index_buf, sizeof(overlay_index_buf),
+                        " gateway IP %s", obuf);
+       }
+
        tag_buf[0] = '\0';
        if (bgp_labeled_safi(safi) && num_labels) {
 
@@ -2720,9 +2741,10 @@ const char *bgp_debug_rdpfxpath2str(afi_t afi, safi_t safi,
        }
 
        if (prd)
-               snprintfrr(str, size, "RD %s %pFX%s%s %s %s",
+               snprintfrr(str, size, "RD %s %pFX%s%s%s %s %s",
                           prefix_rd2str(prd, rd_buf, sizeof(rd_buf)), pu.p,
-                          tag_buf, pathid_buf, afi2str(afi), safi2str(safi));
+                          overlay_index_buf, tag_buf, pathid_buf, afi2str(afi),
+                          safi2str(safi));
        else if (safi == SAFI_FLOWSPEC) {
                char return_string[BGP_FLOWSPEC_NLRI_STRING_MAX];
                const struct prefix_fs *fs = pu.fs;
index fa8da1c345b66cf367482da920865ccd938fc89d..d847fb84e7a8257ac43061d4f4f9abff4a2082fc 100644 (file)
@@ -37,7 +37,8 @@
 #define DUMP_DETAIL   32
 
 /* RD + Prefix + Path-Id */
-#define BGP_PRD_PATH_STRLEN (PREFIX_STRLEN + RD_ADDRSTRLEN + 20)
+#define BGP_PRD_PATH_STRLEN                                                    \
+       (PREFIX_STRLEN + RD_ADDRSTRLEN + INET6_ADDRSTRLEN + 34)
 
 extern int dump_open;
 extern int dump_update;
@@ -179,11 +180,11 @@ extern bool bgp_debug_update(struct peer *peer, const struct prefix *p,
 extern bool bgp_debug_bestpath(struct bgp_dest *dest);
 extern bool bgp_debug_zebra(const struct prefix *p);
 
-extern const char *
-bgp_debug_rdpfxpath2str(afi_t afi, safi_t safi, const struct prefix_rd *prd,
-                       union prefixconstptr pu, mpls_label_t *label,
-                       uint32_t num_labels, int addpath_valid,
-                       uint32_t addpath_id, char *str, int size);
+extern const char *bgp_debug_rdpfxpath2str(
+       afi_t afi, safi_t safi, const struct prefix_rd *prd,
+       union prefixconstptr pu, mpls_label_t *label, uint32_t num_labels,
+       int addpath_valid, uint32_t addpath_id,
+       struct bgp_route_evpn *overlay_index, char *str, int size);
 const char *bgp_notify_admin_message(char *buf, size_t bufsz, uint8_t *data,
                                     size_t datalen);
 
index d8e57419ee01c079036e869d0ee1c92ea176eeef..5ef593b9c023caefeb8ad8992336197d2a86083d 100644 (file)
@@ -53,6 +53,7 @@
 #include "bgpd/bgp_addpath.h"
 #include "bgpd/bgp_mac.h"
 #include "bgpd/bgp_vty.h"
+#include "bgpd/bgp_nht.h"
 
 /*
  * Definitions and external declarations.
@@ -65,6 +66,28 @@ DEFINE_QOBJ_TYPE(bgp_evpn_es);
  * Static function declarations
  */
 static int delete_all_vni_routes(struct bgp *bgp, struct bgpevpn *vpn);
+static void bgp_evpn_remote_ip_hash_init(struct bgpevpn *evpn);
+static void bgp_evpn_remote_ip_hash_destroy(struct bgpevpn *evpn);
+static void bgp_evpn_remote_ip_hash_add(struct bgpevpn *vpn,
+                                       struct bgp_path_info *pi);
+static void bgp_evpn_remote_ip_hash_del(struct bgpevpn *vpn,
+                                       struct bgp_path_info *pi);
+static void bgp_evpn_remote_ip_hash_iterate(struct bgpevpn *vpn,
+                                           void (*func)(struct hash_bucket *,
+                                                        void *),
+                                           void *arg);
+static void bgp_evpn_link_to_vni_svi_hash(struct bgp *bgp, struct bgpevpn *vpn);
+static void bgp_evpn_unlink_from_vni_svi_hash(struct bgp *bgp,
+                                             struct bgpevpn *vpn);
+static unsigned int vni_svi_hash_key_make(const void *p);
+static bool vni_svi_hash_cmp(const void *p1, const void *p2);
+static void bgp_evpn_remote_ip_process_nexthops(struct bgpevpn *vpn,
+                                               struct ipaddr *addr,
+                                               bool resolve);
+static void bgp_evpn_remote_ip_hash_link_nexthop(struct hash_bucket *bucket,
+                                                void *args);
+static void bgp_evpn_remote_ip_hash_unlink_nexthop(struct hash_bucket *bucket,
+                                                  void *args);
 static struct in_addr zero_vtep_ip;
 
 /*
@@ -1261,7 +1284,8 @@ static int update_evpn_type5_route_entry(struct bgp *bgp_evpn,
 
 /* update evpn type-5 route entry */
 static int update_evpn_type5_route(struct bgp *bgp_vrf, struct prefix_evpn *evp,
-                                  struct attr *src_attr)
+                                  struct attr *src_attr, afi_t src_afi,
+                                  safi_t src_safi)
 {
        afi_t afi = AFI_L2VPN;
        safi_t safi = SAFI_EVPN;
@@ -1315,6 +1339,26 @@ static int update_evpn_type5_route(struct bgp *bgp_vrf, struct prefix_evpn *evp,
 
        attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
 
+       if (src_afi == AFI_IP6 &&
+           CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+                      BGP_L2VPN_EVPN_ADV_IPV6_UNICAST_GW_IP)) {
+               if (src_attr &&
+                   !IN6_IS_ADDR_UNSPECIFIED(&src_attr->mp_nexthop_global)) {
+                       attr.evpn_overlay.type = OVERLAY_INDEX_GATEWAY_IP;
+                       memcpy(&attr.evpn_overlay.gw_ip.ipv6,
+                              &src_attr->mp_nexthop_global,
+                              sizeof(struct in6_addr));
+               }
+       } else if (src_afi == AFI_IP &&
+                  CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+                             BGP_L2VPN_EVPN_ADV_IPV4_UNICAST_GW_IP)) {
+               if (src_attr && src_attr->nexthop.s_addr != 0) {
+                       attr.evpn_overlay.type = OVERLAY_INDEX_GATEWAY_IP;
+                       memcpy(&attr.evpn_overlay.gw_ip.ipv4,
+                              &src_attr->nexthop, sizeof(struct in_addr));
+               }
+       }
+
        /* Setup RT and encap extended community */
        build_evpn_type5_route_extcomm(bgp_vrf, &attr);
 
@@ -2198,6 +2242,7 @@ static int delete_all_vni_routes(struct bgp *bgp, struct bgpevpn *vpn)
             dest = bgp_route_next(dest)) {
                for (pi = bgp_dest_get_bgp_path_info(dest);
                     (pi != NULL) && (nextpi = pi->next, 1); pi = nextpi) {
+                       bgp_evpn_remote_ip_hash_del(vpn, pi);
                        bgp_path_info_delete(dest, pi);
                        bgp_path_info_reap(dest, pi);
                }
@@ -2381,6 +2426,7 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
        bool new_pi = false;
        bool use_l3nhg = false;
        bool is_l3nhg_active = false;
+       char buf1[INET6_ADDRSTRLEN];
 
        memset(pp, 0, sizeof(struct prefix));
        ip_prefix_from_evpn_prefix(evp, pp);
@@ -2411,10 +2457,36 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
         * make sure to set the flag for next hop attribute.
         */
        attr = *parent_pi->attr;
-       if (afi == AFI_IP6)
-               evpn_convert_nexthop_to_ipv6(&attr);
-       else
-               attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
+       if (attr.evpn_overlay.type != OVERLAY_INDEX_GATEWAY_IP) {
+               if (afi == AFI_IP6)
+                       evpn_convert_nexthop_to_ipv6(&attr);
+               else
+                       attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
+       } else {
+
+               /*
+                * If gateway IP overlay index is specified in the NLRI of
+                * EVPN RT-5, this gateway IP should be used as the nexthop
+                * for the prefix in the VRF
+                */
+               if (bgp_debug_zebra(NULL)) {
+                       zlog_debug(
+                               "Install gateway IP %s as nexthop for prefix %pFX in vrf %s",
+                               inet_ntop(pp->family, &attr.evpn_overlay.gw_ip,
+                                         buf1, sizeof(buf1)), pp,
+                                         vrf_id_to_name(bgp_vrf->vrf_id));
+               }
+
+               if (afi == AFI_IP6) {
+                       memcpy(&attr.mp_nexthop_global,
+                              &attr.evpn_overlay.gw_ip.ipv6,
+                              sizeof(struct in6_addr));
+                       attr.mp_nexthop_len = IPV6_MAX_BYTELEN;
+               } else {
+                       attr.nexthop = attr.evpn_overlay.gw_ip.ipv4;
+                       attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
+               }
+       }
 
        bgp_evpn_es_vrf_use_nhg(bgp_vrf, &parent_pi->attr->esi, &use_l3nhg,
                                &is_l3nhg_active, NULL);
@@ -2460,8 +2532,27 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
                pi->attr = attr_new;
                pi->uptime = bgp_clock();
        }
-       /* as it is an importation, change nexthop */
-       bgp_path_info_set_flag(dest, pi, BGP_PATH_ANNC_NH_SELF);
+
+       /* Gateway IP nexthop should be resolved */
+       if (attr.evpn_overlay.type == OVERLAY_INDEX_GATEWAY_IP) {
+               if (bgp_find_or_add_nexthop(bgp_vrf, bgp_vrf, afi, safi, pi,
+                                           NULL, 0))
+                       bgp_path_info_set_flag(dest, pi, BGP_PATH_VALID);
+               else {
+                       if (BGP_DEBUG(nht, NHT)) {
+                               inet_ntop(pp->family,
+                                         &attr.evpn_overlay.gw_ip,
+                                         buf1, sizeof(buf1));
+                               zlog_debug("%s: gateway IP NH unresolved",
+                                          buf1);
+                       }
+                       bgp_path_info_unset_flag(dest, pi, BGP_PATH_VALID);
+               }
+       } else {
+
+               /* as it is an importation, change nexthop */
+               bgp_path_info_set_flag(dest, pi, BGP_PATH_ANNC_NH_SELF);
+       }
 
        /* Link path to evpn nexthop */
        bgp_evpn_path_nh_add(bgp_vrf, pi);
@@ -2565,6 +2656,9 @@ static int install_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
                pi->uptime = bgp_clock();
        }
 
+       /* Add this route to remote IP hashtable */
+       bgp_evpn_remote_ip_hash_add(vpn, pi);
+
        /* Perform route selection and update zebra, if required. */
        ret = evpn_route_select_install(bgp, vpn, dest);
 
@@ -2628,8 +2722,10 @@ static int uninstall_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
                    && (struct bgp_path_info *)pi->extra->parent == parent_pi)
                        break;
 
-       if (!pi)
+       if (!pi) {
+               bgp_dest_unlock_node(dest);
                return 0;
+       }
 
        if (bgp_debug_zebra(NULL))
                zlog_debug("... delete dest %p (l %d) pi %p (l %d, f 0x%x)",
@@ -2690,8 +2786,12 @@ static int uninstall_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
                    && (struct bgp_path_info *)pi->extra->parent == parent_pi)
                        break;
 
-       if (!pi)
+       if (!pi) {
+               bgp_dest_unlock_node(dest);
                return 0;
+       }
+
+       bgp_evpn_remote_ip_hash_del(vpn, pi);
 
        /* Mark entry for deletion */
        bgp_path_info_delete(dest, pi);
@@ -3951,7 +4051,7 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi,
        mpls_label_t label; /* holds the VNI as in the packet */
        int ret;
        afi_t gw_afi;
-       bool is_valid_update = false;
+       bool is_valid_update = true;
 
        /* Type-5 route should be 34 or 58 bytes:
         * RD (8), ESI (10), Eth Tag (4), IP len (1), IP (4 or 16),
@@ -3980,9 +4080,9 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi,
        /* Additional information outside of prefix - ESI and GW IP */
        memset(&evpn, 0, sizeof(evpn));
 
-       /* Fetch ESI */
+       /* Fetch ESI overlay index */
        if (attr)
-               memcpy(&attr->esi, pfx, sizeof(esi_t));
+               memcpy(&evpn.eth_s_id, pfx, sizeof(esi_t));
        pfx += ESI_BYTES;
 
        /* Fetch Ethernet Tag. */
@@ -4031,25 +4131,53 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi,
         * field
         */
 
+       /*
+        * An update containing a non-zero gateway IP and a non-zero ESI
+        * at the same time is should be treated as withdraw
+        */
+       if (bgp_evpn_is_esi_valid(&evpn.eth_s_id)
+           && !is_zero_gw_ip(&evpn.gw_ip, gw_afi)) {
+               flog_err(EC_BGP_EVPN_ROUTE_INVALID,
+                        "%s - Rx EVPN Type-5 ESI and gateway-IP both non-zero.",
+                        peer->host);
+               is_valid_update = false;
+       } else if (bgp_evpn_is_esi_valid(&evpn.eth_s_id))
+               evpn.type = OVERLAY_INDEX_ESI;
+       else if (!is_zero_gw_ip(&evpn.gw_ip, gw_afi))
+               evpn.type = OVERLAY_INDEX_GATEWAY_IP;
        if (attr) {
-               is_valid_update = true;
-               if (is_zero_mac(&attr->rmac) &&
-                   is_zero_gw_ip(&evpn.gw_ip, gw_afi))
+               if (is_zero_mac(&attr->rmac)
+                   && !bgp_evpn_is_esi_valid(&evpn.eth_s_id)
+                   && is_zero_gw_ip(&evpn.gw_ip, gw_afi) && label == 0) {
+                       flog_err(EC_BGP_EVPN_ROUTE_INVALID,
+                                "%s - Rx EVPN Type-5 ESI, gateway-IP, RMAC and label all zero",
+                                peer->host);
                        is_valid_update = false;
+               }
 
                if (is_mcast_mac(&attr->rmac) || is_bcast_mac(&attr->rmac))
                        is_valid_update = false;
        }
 
        /* Process the route. */
-       if (is_valid_update)
+       if (attr && is_valid_update)
                ret = bgp_update(peer, (struct prefix *)&p, addpath_id, attr,
                                 afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
                                 &prd, &label, 1, 0, &evpn);
-       else
+       else {
+               if (!is_valid_update) {
+                       char attr_str[BUFSIZ] = {0};
+
+                       bgp_dump_attr(attr, attr_str, BUFSIZ);
+                       zlog_warn(
+                               "Invalid update from peer %s vrf %u prefix %pFX attr %s - treat as withdraw",
+                               peer->hostname, peer->bgp->vrf_id, &p,
+                               attr_str);
+               }
                ret = bgp_withdraw(peer, (struct prefix *)&p, addpath_id, attr,
                                   afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
                                   &prd, &label, 1, &evpn);
+       }
 
        return ret;
 }
@@ -4078,7 +4206,7 @@ static void evpn_mpattr_encode_type5(struct stream *s, const struct prefix *p,
        /* Prefix contains RD, ESI, EthTag, IP length, IP, GWIP and VNI */
        stream_putc(s, 8 + 10 + 4 + 1 + len + 3);
        stream_put(s, prd->val, 8);
-       if (attr)
+       if (attr && attr->evpn_overlay.type == OVERLAY_INDEX_ESI)
                stream_put(s, &attr->esi, sizeof(esi_t));
        else
                stream_put(s, 0, sizeof(esi_t));
@@ -4088,7 +4216,7 @@ static void evpn_mpattr_encode_type5(struct stream *s, const struct prefix *p,
                stream_put_ipv4(s, p_evpn_p->prefix_addr.ip.ipaddr_v4.s_addr);
        else
                stream_put(s, &p_evpn_p->prefix_addr.ip.ipaddr_v6, 16);
-       if (attr) {
+       if (attr && attr->evpn_overlay.type == OVERLAY_INDEX_GATEWAY_IP) {
                const struct bgp_route_evpn *evpn_overlay =
                        bgp_attr_get_evpn_overlay(attr);
 
@@ -4301,7 +4429,7 @@ void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf, const struct prefix *p,
        struct prefix_evpn evp;
 
        build_type5_prefix_from_ip_prefix(&evp, p);
-       ret = update_evpn_type5_route(bgp_vrf, &evp, src_attr);
+       ret = update_evpn_type5_route(bgp_vrf, &evp, src_attr, afi, safi);
        if (ret)
                flog_err(EC_BGP_EVPN_ROUTE_CREATE,
                         "%u: Failed to create type-5 route for prefix %pFX",
@@ -5134,7 +5262,8 @@ struct bgpevpn *bgp_evpn_lookup_vni(struct bgp *bgp, vni_t vni)
 struct bgpevpn *bgp_evpn_new(struct bgp *bgp, vni_t vni,
                struct in_addr originator_ip,
                vrf_id_t tenant_vrf_id,
-               struct in_addr mcast_grp)
+               struct in_addr mcast_grp,
+               ifindex_t svi_ifindex)
 {
        struct bgpevpn *vpn;
 
@@ -5148,6 +5277,7 @@ struct bgpevpn *bgp_evpn_new(struct bgp *bgp, vni_t vni,
        vpn->originator_ip = originator_ip;
        vpn->tenant_vrf_id = tenant_vrf_id;
        vpn->mcast_grp = mcast_grp;
+       vpn->svi_ifindex = svi_ifindex;
 
        /* Initialize route-target import and export lists */
        vpn->import_rtl = list_new();
@@ -5168,6 +5298,9 @@ struct bgpevpn *bgp_evpn_new(struct bgp *bgp, vni_t vni,
                return NULL;
        }
 
+       bgp_evpn_remote_ip_hash_init(vpn);
+       bgp_evpn_link_to_vni_svi_hash(bgp, vpn);
+
        /* add to l2vni list on corresponding vrf */
        bgpevpn_link_to_l3vni(vpn);
 
@@ -5185,6 +5318,7 @@ struct bgpevpn *bgp_evpn_new(struct bgp *bgp, vni_t vni,
  */
 void bgp_evpn_free(struct bgp *bgp, struct bgpevpn *vpn)
 {
+       bgp_evpn_remote_ip_hash_destroy(vpn);
        bgp_evpn_vni_es_cleanup(vpn);
        bgpevpn_unlink_from_l3vni(vpn);
        bgp_table_unlock(vpn->route_table);
@@ -5192,6 +5326,7 @@ void bgp_evpn_free(struct bgp *bgp, struct bgpevpn *vpn)
        list_delete(&vpn->import_rtl);
        list_delete(&vpn->export_rtl);
        bf_release_index(bm->rd_idspace, vpn->rd_id);
+       hash_release(bgp->vni_svi_hash, vpn);
        hash_release(bgp->vnihash, vpn);
        QOBJ_UNREG(vpn);
        XFREE(MTYPE_BGP_EVPN, vpn);
@@ -5308,8 +5443,10 @@ int bgp_evpn_local_macip_del(struct bgp *bgp, vni_t vni, struct ethaddr *mac,
        } else {
                /* Re-instate the current remote best path if any */
                dest = bgp_node_lookup(vpn->route_table, (struct prefix *)&p);
-               if (dest)
+               if (dest) {
                        evpn_zebra_reinstall_best_route(bgp, vpn, dest);
+                       bgp_dest_unlock_node(dest);
+               }
        }
 
        return 0;
@@ -5603,6 +5740,9 @@ int bgp_evpn_local_vni_del(struct bgp *bgp, vni_t vni)
         */
        delete_routes_for_vni(bgp, vpn);
 
+       bgp_evpn_unlink_from_vni_svi_hash(bgp, vpn);
+
+       vpn->svi_ifindex = 0;
        /*
         * tunnel is no longer active, del tunnel ip address from tip_hash
         */
@@ -5623,8 +5763,8 @@ int bgp_evpn_local_vni_del(struct bgp *bgp, vni_t vni)
 int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni,
                           struct in_addr originator_ip,
                           vrf_id_t tenant_vrf_id,
-                          struct in_addr mcast_grp)
-
+                          struct in_addr mcast_grp,
+                          ifindex_t svi_ifindex)
 {
        struct bgpevpn *vpn;
        struct prefix_evpn p;
@@ -5636,18 +5776,65 @@ int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni,
                if (is_vni_live(vpn)
                    && IPV4_ADDR_SAME(&vpn->originator_ip, &originator_ip)
                    && IPV4_ADDR_SAME(&vpn->mcast_grp, &mcast_grp)
-                   && vpn->tenant_vrf_id == tenant_vrf_id)
+                   && vpn->tenant_vrf_id == tenant_vrf_id
+                   && vpn->svi_ifindex == svi_ifindex)
                        /* Probably some other param has changed that we don't
                         * care about. */
                        return 0;
 
                bgp_evpn_mcast_grp_change(bgp, vpn, mcast_grp);
 
+               if (vpn->svi_ifindex != svi_ifindex) {
+
+                       /*
+                        * Unresolve all the gateway IP nexthops for this VNI
+                        * for old SVI
+                        */
+                       bgp_evpn_remote_ip_hash_iterate(
+                               vpn,
+                               (void (*)(struct hash_bucket *, void *))
+                                       bgp_evpn_remote_ip_hash_unlink_nexthop,
+                               vpn);
+                       bgp_evpn_unlink_from_vni_svi_hash(bgp, vpn);
+                       vpn->svi_ifindex = svi_ifindex;
+                       bgp_evpn_link_to_vni_svi_hash(bgp, vpn);
+
+                       /*
+                        * Resolve all the gateway IP nexthops for this VNI
+                        * for new SVI
+                        */
+                       bgp_evpn_remote_ip_hash_iterate(
+                               vpn,
+                               (void (*)(struct hash_bucket *, void *))
+                                       bgp_evpn_remote_ip_hash_link_nexthop,
+                               vpn);
+               }
+
                /* Update tenant_vrf_id if it has changed. */
                if (vpn->tenant_vrf_id != tenant_vrf_id) {
+
+                       /*
+                        * Unresolve all the gateway IP nexthops for this VNI
+                        * in old tenant vrf
+                        */
+                       bgp_evpn_remote_ip_hash_iterate(
+                               vpn,
+                               (void (*)(struct hash_bucket *, void *))
+                                       bgp_evpn_remote_ip_hash_unlink_nexthop,
+                               vpn);
                        bgpevpn_unlink_from_l3vni(vpn);
                        vpn->tenant_vrf_id = tenant_vrf_id;
                        bgpevpn_link_to_l3vni(vpn);
+
+                       /*
+                        * Resolve all the gateway IP nexthops for this VNI
+                        * in new tenant vrf
+                        */
+                       bgp_evpn_remote_ip_hash_iterate(
+                               vpn,
+                               (void (*)(struct hash_bucket *, void *))
+                                       bgp_evpn_remote_ip_hash_link_nexthop,
+                               vpn);
                }
 
                /* If tunnel endpoint IP has changed, update (and delete prior
@@ -5666,7 +5853,7 @@ int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni,
        /* Create or update as appropriate. */
        if (!vpn) {
                vpn = bgp_evpn_new(bgp, vni, originator_ip, tenant_vrf_id,
-                               mcast_grp);
+                               mcast_grp, svi_ifindex);
                if (!vpn) {
                        flog_err(
                                EC_BGP_VNI,
@@ -5768,6 +5955,8 @@ void bgp_evpn_cleanup(struct bgp *bgp)
        hash_free(bgp->vrf_import_rt_hash);
        bgp->vrf_import_rt_hash = NULL;
 
+       hash_free(bgp->vni_svi_hash);
+       bgp->vni_svi_hash = NULL;
        hash_free(bgp->vnihash);
        bgp->vnihash = NULL;
 
@@ -5786,6 +5975,9 @@ void bgp_evpn_init(struct bgp *bgp)
 {
        bgp->vnihash =
                hash_create(vni_hash_key_make, vni_hash_cmp, "BGP VNI Hash");
+       bgp->vni_svi_hash =
+               hash_create(vni_svi_hash_key_make, vni_svi_hash_cmp,
+                           "BGP VNI hash based on SVI ifindex");
        bgp->import_rt_hash =
                hash_create(import_rt_hash_key_make, import_rt_hash_cmp,
                            "BGP Import RT Hash");
@@ -5878,3 +6070,408 @@ bool bgp_evpn_is_prefix_nht_supported(const struct prefix *pfx)
 
        return false;
 }
+
+static void *bgp_evpn_remote_ip_hash_alloc(void *p)
+{
+       const struct evpn_remote_ip *key = (const struct evpn_remote_ip *)p;
+       struct evpn_remote_ip *ip;
+
+       ip = XMALLOC(MTYPE_EVPN_REMOTE_IP, sizeof(struct evpn_remote_ip));
+       *ip = *key;
+       ip->macip_path_list = list_new();
+
+       return ip;
+}
+
+static unsigned int bgp_evpn_remote_ip_hash_key_make(const void *p)
+{
+       const struct evpn_remote_ip *ip = p;
+       const struct ipaddr *addr = &ip->addr;
+
+       if (IS_IPADDR_V4(addr))
+               return jhash_1word(addr->ipaddr_v4.s_addr, 0);
+
+       return jhash2(addr->ipaddr_v6.s6_addr32,
+                     array_size(addr->ipaddr_v6.s6_addr32), 0);
+}
+
+static bool bgp_evpn_remote_ip_hash_cmp(const void *p1, const void *p2)
+{
+       const struct evpn_remote_ip *ip1 = p1;
+       const struct evpn_remote_ip *ip2 = p2;
+
+       return (memcmp(&ip1->addr, &ip2->addr, sizeof(struct ipaddr)) == 0);
+}
+
+static void bgp_evpn_remote_ip_hash_init(struct bgpevpn *vpn)
+{
+       if (!evpn_resolve_overlay_index())
+               return;
+
+       vpn->remote_ip_hash = hash_create(bgp_evpn_remote_ip_hash_key_make,
+                                         bgp_evpn_remote_ip_hash_cmp,
+                                         "BGP EVPN remote IP hash");
+}
+
+static void bgp_evpn_remote_ip_hash_free(struct hash_bucket *bucket, void *args)
+{
+       struct evpn_remote_ip *ip = (struct evpn_remote_ip *)bucket->data;
+       struct bgpevpn *vpn = (struct bgpevpn *)args;
+
+       bgp_evpn_remote_ip_process_nexthops(vpn, &ip->addr, false);
+
+       list_delete(&ip->macip_path_list);
+
+       hash_release(vpn->remote_ip_hash, ip);
+       XFREE(MTYPE_EVPN_REMOTE_IP, ip);
+}
+
+static void bgp_evpn_remote_ip_hash_destroy(struct bgpevpn *vpn)
+{
+       if (!evpn_resolve_overlay_index() || vpn->remote_ip_hash == NULL)
+               return;
+
+       hash_iterate(vpn->remote_ip_hash,
+       (void (*)(struct hash_bucket *, void *))bgp_evpn_remote_ip_hash_free,
+       vpn);
+
+       hash_free(vpn->remote_ip_hash);
+       vpn->remote_ip_hash = NULL;
+}
+
+/* Add a remote MAC/IP route to hash table */
+static void bgp_evpn_remote_ip_hash_add(struct bgpevpn *vpn,
+                                       struct bgp_path_info *pi)
+{
+       struct evpn_remote_ip tmp;
+       struct evpn_remote_ip *ip;
+       struct prefix_evpn *evp;
+
+       if (!evpn_resolve_overlay_index())
+               return;
+
+       if (pi->type != ZEBRA_ROUTE_BGP || pi->sub_type != BGP_ROUTE_IMPORTED
+           || !CHECK_FLAG(pi->flags, BGP_PATH_VALID))
+               return;
+
+       evp = (struct prefix_evpn *)&pi->net->p;
+
+       if (evp->family != AF_EVPN
+           || evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE
+           || is_evpn_prefix_ipaddr_none(evp))
+               return;
+
+       tmp.addr = evp->prefix.macip_addr.ip;
+       ip = hash_lookup(vpn->remote_ip_hash, &tmp);
+       if (ip) {
+               if (listnode_lookup(ip->macip_path_list, pi) != NULL)
+                       return;
+               (void)listnode_add(ip->macip_path_list, pi);
+               return;
+       }
+
+       ip = hash_get(vpn->remote_ip_hash, &tmp, bgp_evpn_remote_ip_hash_alloc);
+       if (!ip)
+               return;
+
+       (void)listnode_add(ip->macip_path_list, pi);
+
+       bgp_evpn_remote_ip_process_nexthops(vpn, &ip->addr, true);
+}
+
+/* Delete a remote MAC/IP route from hash table */
+static void bgp_evpn_remote_ip_hash_del(struct bgpevpn *vpn,
+                                       struct bgp_path_info *pi)
+{
+       struct evpn_remote_ip tmp;
+       struct evpn_remote_ip *ip;
+       struct prefix_evpn *evp;
+
+       if (!evpn_resolve_overlay_index())
+               return;
+
+       evp = (struct prefix_evpn *)&pi->net->p;
+
+       if (evp->family != AF_EVPN
+           || evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE
+           || is_evpn_prefix_ipaddr_none(evp))
+               return;
+
+       tmp.addr = evp->prefix.macip_addr.ip;
+       ip = hash_lookup(vpn->remote_ip_hash, &tmp);
+       if (ip == NULL)
+               return;
+
+       listnode_delete(ip->macip_path_list, pi);
+
+       if (ip->macip_path_list->count == 0) {
+               bgp_evpn_remote_ip_process_nexthops(vpn, &ip->addr, false);
+               hash_release(vpn->remote_ip_hash, ip);
+               XFREE(MTYPE_EVPN_REMOTE_IP, ip);
+       }
+}
+
+static void bgp_evpn_remote_ip_hash_iterate(struct bgpevpn *vpn,
+                                           void (*func)(struct hash_bucket *,
+                                                        void *),
+                                           void *arg)
+{
+       if (!evpn_resolve_overlay_index())
+               return;
+
+       hash_iterate(vpn->remote_ip_hash, func, arg);
+}
+
+static void show_remote_ip_entry(struct hash_bucket *bucket, void *args)
+{
+       char buf[INET6_ADDRSTRLEN];
+       char buf2[EVPN_ROUTE_STRLEN];
+       struct prefix_evpn *evp;
+
+       struct listnode *node = NULL;
+       struct bgp_path_info *pi = NULL;
+       struct vty *vty = (struct vty *)args;
+       struct evpn_remote_ip *ip = (struct evpn_remote_ip *)bucket->data;
+
+       vty_out(vty, "  Remote IP: %s\n",
+               ipaddr2str(&ip->addr, buf, sizeof(buf)));
+       vty_out(vty, "      Linked MAC/IP routes:\n");
+       for (ALL_LIST_ELEMENTS_RO(ip->macip_path_list, node, pi)) {
+               evp = (struct prefix_evpn *)&pi->net->p;
+               prefix2str(evp, buf2, sizeof(buf2));
+               vty_out(vty, "        %s\n", buf2);
+       }
+}
+
+void bgp_evpn_show_remote_ip_hash(struct hash_bucket *bucket, void *args)
+{
+       struct bgpevpn *vpn = (struct bgpevpn *)bucket->data;
+       struct vty *vty = (struct vty *)args;
+
+       vty_out(vty, "VNI: %u\n", vpn->vni);
+       bgp_evpn_remote_ip_hash_iterate(
+               vpn,
+               (void (*)(struct hash_bucket *, void *))show_remote_ip_entry,
+               vty);
+       vty_out(vty, "\n");
+}
+
+static void bgp_evpn_remote_ip_hash_link_nexthop(struct hash_bucket *bucket,
+                                                void *args)
+{
+       struct evpn_remote_ip *ip = (struct evpn_remote_ip *)bucket->data;
+       struct bgpevpn *vpn = (struct bgpevpn *)args;
+
+       bgp_evpn_remote_ip_process_nexthops(vpn, &ip->addr, true);
+}
+
+static void bgp_evpn_remote_ip_hash_unlink_nexthop(struct hash_bucket *bucket,
+                                                  void *args)
+{
+       struct evpn_remote_ip *ip = (struct evpn_remote_ip *)bucket->data;
+       struct bgpevpn *vpn = (struct bgpevpn *)args;
+
+       bgp_evpn_remote_ip_process_nexthops(vpn, &ip->addr, false);
+}
+
+static unsigned int vni_svi_hash_key_make(const void *p)
+{
+       const struct bgpevpn *vpn = p;
+
+       return jhash_1word(vpn->svi_ifindex, 0);
+}
+
+static bool vni_svi_hash_cmp(const void *p1, const void *p2)
+{
+       const struct bgpevpn *vpn1 = p1;
+       const struct bgpevpn *vpn2 = p2;
+
+       return (vpn1->svi_ifindex == vpn2->svi_ifindex);
+}
+
+static struct bgpevpn *bgp_evpn_vni_svi_hash_lookup(struct bgp *bgp,
+                                                   ifindex_t svi)
+{
+       struct bgpevpn *vpn;
+       struct bgpevpn tmp;
+
+       memset(&tmp, 0, sizeof(struct bgpevpn));
+       tmp.svi_ifindex = svi;
+       vpn = hash_lookup(bgp->vni_svi_hash, &tmp);
+       return vpn;
+}
+
+static void bgp_evpn_link_to_vni_svi_hash(struct bgp *bgp, struct bgpevpn *vpn)
+{
+       if (vpn->svi_ifindex == 0)
+               return;
+
+       hash_get(bgp->vni_svi_hash, vpn, hash_alloc_intern);
+}
+
+static void bgp_evpn_unlink_from_vni_svi_hash(struct bgp *bgp,
+                                             struct bgpevpn *vpn)
+{
+       if (vpn->svi_ifindex == 0)
+               return;
+
+       hash_release(bgp->vni_svi_hash, vpn);
+}
+
+void bgp_evpn_show_vni_svi_hash(struct hash_bucket *bucket, void *args)
+{
+       struct bgpevpn *evpn = (struct bgpevpn *)bucket->data;
+       struct vty *vty = (struct vty *)args;
+
+       vty_out(vty, "SVI: %u VNI: %u\n", evpn->svi_ifindex, evpn->vni);
+}
+
+/*
+ * This function is called for a bgp_nexthop_cache entry when the nexthop is
+ * gateway IP overlay index.
+ * This function returns true if there is a remote MAC/IP route for the gateway
+ * IP in the EVI of the nexthop SVI.
+ */
+bool bgp_evpn_is_gateway_ip_resolved(struct bgp_nexthop_cache *bnc)
+{
+       struct bgp *bgp_evpn = NULL;
+       struct bgpevpn *vpn = NULL;
+       struct evpn_remote_ip tmp;
+       struct prefix *p;
+
+       if (!evpn_resolve_overlay_index())
+               return false;
+
+       if (!bnc->nexthop || bnc->nexthop->ifindex == 0)
+               return false;
+
+       bgp_evpn = bgp_get_evpn();
+       if (!bgp_evpn)
+               return false;
+
+       /*
+        * Gateway IP is resolved by nht over SVI interface.
+        * Use this SVI to find corresponding EVI(L2 context)
+        */
+       vpn = bgp_evpn_vni_svi_hash_lookup(bgp_evpn, bnc->nexthop->ifindex);
+       if (!vpn)
+               return false;
+
+       if (vpn->bgp_vrf != bnc->bgp)
+               return false;
+
+       /*
+        * Check if the gateway IP is present in the EVI remote_ip_hash table
+        * which stores all the remote IP addresses received via MAC/IP routes
+        * in this EVI
+        */
+       memset(&tmp, 0, sizeof(struct evpn_remote_ip));
+
+       p = &bnc->prefix;
+       if (p->family == AF_INET) {
+               tmp.addr.ipa_type = IPADDR_V4;
+               memcpy(&(tmp.addr.ipaddr_v4), &(p->u.prefix4),
+                      sizeof(struct in_addr));
+       } else if (p->family == AF_INET6) {
+               tmp.addr.ipa_type = IPADDR_V6;
+               memcpy(&(tmp.addr.ipaddr_v6), &(p->u.prefix6),
+                      sizeof(struct in6_addr));
+       } else
+               return false;
+
+       if (hash_lookup(vpn->remote_ip_hash, &tmp) == NULL)
+               return false;
+
+       return true;
+}
+
+/* Resolve/Unresolve nexthops when a MAC/IP route is added/deleted */
+static void bgp_evpn_remote_ip_process_nexthops(struct bgpevpn *vpn,
+                                               struct ipaddr *addr,
+                                               bool resolve)
+{
+       afi_t afi;
+       struct prefix p;
+       struct bgp_nexthop_cache *bnc;
+       struct bgp_nexthop_cache_head *tree = NULL;
+
+       if (!vpn->bgp_vrf || vpn->svi_ifindex == 0)
+               return;
+
+       memset(&p, 0, sizeof(struct prefix));
+
+       if (addr->ipa_type == IPADDR_V4) {
+               afi = AFI_IP;
+               p.family = AF_INET;
+               memcpy(&(p.u.prefix4), &(addr->ipaddr_v4),
+                      sizeof(struct in_addr));
+               p.prefixlen = IPV4_MAX_BITLEN;
+       } else if (addr->ipa_type == IPADDR_V6) {
+               afi = AFI_IP6;
+               p.family = AF_INET6;
+               memcpy(&(p.u.prefix6), &(addr->ipaddr_v6),
+                      sizeof(struct in6_addr));
+               p.prefixlen = IPV6_MAX_BITLEN;
+       } else
+               return;
+
+       tree = &vpn->bgp_vrf->nexthop_cache_table[afi];
+       bnc = bnc_find(tree, &p, 0);
+
+       if (!bnc || !bnc->is_evpn_gwip_nexthop)
+               return;
+
+       if (!bnc->nexthop || bnc->nexthop->ifindex != vpn->svi_ifindex)
+               return;
+
+       if (BGP_DEBUG(nht, NHT)) {
+               char buf[PREFIX2STR_BUFFER];
+
+               prefix2str(&bnc->prefix, buf, sizeof(buf));
+               zlog_debug("%s(%u): vni %u mac/ip %s for NH %s",
+                          vpn->bgp_vrf->name_pretty, vpn->tenant_vrf_id,
+                          vpn->vni, (resolve ? "add" : "delete"), buf);
+       }
+
+       /*
+        * MAC/IP route or SVI or tenant vrf being added to EVI.
+        * Set nexthop as valid only if it is already L3 reachable
+        */
+       if (resolve && bnc->flags & BGP_NEXTHOP_EVPN_INCOMPLETE) {
+               bnc->flags &= ~BGP_NEXTHOP_EVPN_INCOMPLETE;
+               bnc->flags |= BGP_NEXTHOP_VALID;
+               bnc->change_flags |= BGP_NEXTHOP_MACIP_CHANGED;
+               evaluate_paths(bnc);
+       }
+
+        /* MAC/IP route or SVI or tenant vrf being deleted from EVI */
+       if (!resolve &&  bnc->flags & BGP_NEXTHOP_VALID) {
+               bnc->flags &= ~BGP_NEXTHOP_VALID;
+               bnc->flags |= BGP_NEXTHOP_EVPN_INCOMPLETE;
+               bnc->change_flags |= BGP_NEXTHOP_MACIP_CHANGED;
+               evaluate_paths(bnc);
+       }
+}
+
+void bgp_evpn_handle_resolve_overlay_index_set(struct hash_bucket *bucket,
+                                              void *arg)
+{
+       struct bgpevpn *vpn = (struct bgpevpn *)bucket->data;
+       struct bgp_dest *dest;
+       struct bgp_path_info *pi;
+
+       bgp_evpn_remote_ip_hash_init(vpn);
+
+       for (dest = bgp_table_top(vpn->route_table); dest;
+            dest = bgp_route_next(dest))
+               for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next)
+                       bgp_evpn_remote_ip_hash_add(vpn, pi);
+}
+
+void bgp_evpn_handle_resolve_overlay_index_unset(struct hash_bucket *bucket,
+                                                void *arg)
+{
+       struct bgpevpn *vpn = (struct bgpevpn *)bucket->data;
+
+       bgp_evpn_remote_ip_hash_destroy(vpn);
+}
index 83a6dd84c82676a224d218f1269763acc3f3375c..eec746e3bedfc2c6ca19c6ab7e11559743125ffc 100644 (file)
@@ -63,14 +63,18 @@ static inline int advertise_type5_routes(struct bgp *bgp_vrf,
        if (!bgp_vrf->l3vni)
                return 0;
 
-       if (afi == AFI_IP &&
-           CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
-                      BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST))
+       if ((afi == AFI_IP)
+           && ((CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+                           BGP_L2VPN_EVPN_ADV_IPV4_UNICAST))
+               || (CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+                              BGP_L2VPN_EVPN_ADV_IPV4_UNICAST_GW_IP))))
                return 1;
 
-       if (afi == AFI_IP6 &&
-           CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
-                      BGP_L2VPN_EVPN_ADVERTISE_IPV6_UNICAST))
+       if ((afi == AFI_IP6)
+           && ((CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+                           BGP_L2VPN_EVPN_ADV_IPV6_UNICAST))
+               || (CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+                              BGP_L2VPN_EVPN_ADV_IPV6_UNICAST_GW_IP))))
                return 1;
 
        return 0;
@@ -152,6 +156,14 @@ static inline bool is_route_injectable_into_evpn(struct bgp_path_info *pi)
        return true;
 }
 
+static inline bool evpn_resolve_overlay_index(void)
+{
+       struct bgp *bgp = NULL;
+
+       bgp = bgp_get_evpn();
+       return bgp ? bgp->resolve_overlay_index : false;
+}
+
 extern void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf,
                                           const struct prefix *p,
                                           struct attr *src_attr, afi_t afi,
@@ -198,7 +210,8 @@ extern int bgp_evpn_local_vni_del(struct bgp *bgp, vni_t vni);
 extern int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni,
                                  struct in_addr originator_ip,
                                  vrf_id_t tenant_vrf_id,
-                                 struct in_addr mcast_grp);
+                                 struct in_addr mcast_grp,
+                                 ifindex_t svi_ifindex);
 extern void bgp_evpn_flood_control_change(struct bgp *bgp);
 extern void bgp_evpn_cleanup_on_disable(struct bgp *bgp);
 extern void bgp_evpn_cleanup(struct bgp *bgp);
@@ -206,4 +219,15 @@ extern void bgp_evpn_init(struct bgp *bgp);
 extern int bgp_evpn_get_type5_prefixlen(const struct prefix *pfx);
 extern bool bgp_evpn_is_prefix_nht_supported(const struct prefix *pfx);
 extern void update_advertise_vrf_routes(struct bgp *bgp_vrf);
+extern void bgp_evpn_show_remote_ip_hash(struct hash_bucket *bucket,
+                                        void *args);
+extern void bgp_evpn_show_vni_svi_hash(struct hash_bucket *bucket, void *args);
+extern bool bgp_evpn_is_gateway_ip_resolved(struct bgp_nexthop_cache *bnc);
+extern void
+bgp_evpn_handle_resolve_overlay_index_set(struct hash_bucket *bucket,
+                                         void *arg);
+extern void
+bgp_evpn_handle_resolve_overlay_index_unset(struct hash_bucket *bucket,
+                                           void *arg);
+
 #endif /* _QUAGGA_BGP_EVPN_H */
index 59bced6f93a177f6094ed7fa0269c32d2f3fb4a3..4b90937f627ceaa7eb573d132e0325d092f85a20 100644 (file)
@@ -269,8 +269,10 @@ static int bgp_evpn_es_route_uninstall(struct bgp *bgp, struct bgp_evpn_es *es,
                                parent_pi)
                        break;
 
-       if (!pi)
+       if (!pi) {
+               bgp_dest_unlock_node(dest);
                return 0;
+       }
 
        /* Mark entry for deletion */
        bgp_path_info_delete(dest, pi);
@@ -2070,9 +2072,8 @@ int bgp_evpn_local_es_del(struct bgp *bgp, esi_t *esi)
        /* Lookup ESI hash - should exist. */
        es = bgp_evpn_es_find(esi);
        if (!es) {
-               flog_warn(EC_BGP_EVPN_ESI,
-                         "%u: ES %s missing at local ES DEL",
-                         bgp->vrf_id, es->esi_str);
+               flog_warn(EC_BGP_EVPN_ESI, "%u: ES missing at local ES DEL",
+                         bgp->vrf_id);
                return -1;
        }
 
@@ -3317,9 +3318,6 @@ bgp_evpn_es_evi_local_info_clear(struct bgp_evpn_es_evi *es_evi)
 {
        struct bgpevpn *vpn = es_evi->vpn;
 
-       if (!CHECK_FLAG(es_evi->flags, BGP_EVPNES_EVI_LOCAL))
-               return es_evi;
-
        UNSET_FLAG(es_evi->flags, BGP_EVPNES_EVI_LOCAL);
        list_delete_node(vpn->local_es_evi_list, &es_evi->l2vni_listnode);
 
index debed9f68be51cc9b4d4c788bfca483e1ff5011e..c46f34bf742a5674f467356bf99715abbcf0809b 100644 (file)
@@ -62,6 +62,7 @@ RB_PROTOTYPE(bgp_es_evi_rb_head, bgp_evpn_es_evi, rb_node,
 struct bgpevpn {
        vni_t vni;
        vrf_id_t tenant_vrf_id;
+       ifindex_t svi_ifindex;
        uint32_t flags;
 #define VNI_FLAG_CFGD              0x1  /* VNI is user configured */
 #define VNI_FLAG_LIVE              0x2  /* VNI is "live" */
@@ -102,6 +103,15 @@ struct bgpevpn {
        struct list *import_rtl;
        struct list *export_rtl;
 
+       /*
+        * EVPN route that uses gateway IP overlay index as its nexthop
+        * needs to do a recursive lookup.
+        * A remote MAC/IP entry should be present for the gateway IP.
+        * Maintain a hash of the addresses received via remote MAC/IP routes
+        * for efficient gateway IP recursive lookup in this EVI
+        */
+       struct hash *remote_ip_hash;
+
        /* Route table for EVPN routes for
         * this VNI. */
        struct bgp_table *route_table;
@@ -178,6 +188,12 @@ struct bgp_evpn_info {
        bool is_anycast_mac;
 };
 
+/* This structure defines an entry in remote_ip_hash */
+struct evpn_remote_ip {
+       struct ipaddr addr;
+       struct list *macip_path_list;
+};
+
 static inline int is_vrf_rd_configured(struct bgp *bgp_vrf)
 {
        return (CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_RD_CFGD));
@@ -612,7 +628,8 @@ extern struct bgpevpn *bgp_evpn_lookup_vni(struct bgp *bgp, vni_t vni);
 extern struct bgpevpn *bgp_evpn_new(struct bgp *bgp, vni_t vni,
                struct in_addr originator_ip,
                vrf_id_t tenant_vrf_id,
-               struct in_addr mcast_grp);
+               struct in_addr mcast_grp,
+               ifindex_t svi_ifindex);
 extern void bgp_evpn_free(struct bgp *bgp, struct bgpevpn *vpn);
 extern bool bgp_evpn_lookup_l3vni_l2vni_table(vni_t vni);
 extern int update_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn);
index fb3ba2c0ec85c1089f66dc58c867dc56907b647f..190323859f323c7d593cd5f7e781d30af1da6aa9 100644 (file)
@@ -59,6 +59,17 @@ struct vni_walk_ctx {
        int detail;
 };
 
+int argv_find_and_parse_oly_idx(struct cmd_token **argv, int argc, int *oly_idx,
+                               enum overlay_index_type *oly)
+{
+       *oly = OVERLAY_INDEX_TYPE_NONE;
+       if (argv_find(argv, argc, "gateway-ip", oly_idx)) {
+               if (oly)
+                       *oly = OVERLAY_INDEX_GATEWAY_IP;
+       }
+       return 1;
+}
+
 static void display_vrf_import_rt(struct vty *vty, struct vrf_irt_node *irt,
                                  json_object *json)
 {
@@ -520,6 +531,9 @@ static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json)
                else
                        json_object_string_add(json, "advertiseSviMacIp",
                                               "Disabled");
+               json_object_string_add(
+                       json, "sviInterface",
+                       ifindex2ifname(vpn->svi_ifindex, vpn->tenant_vrf_id));
        } else {
                vty_out(vty, "VNI: %d", vpn->vni);
                if (is_vni_live(vpn))
@@ -553,6 +567,8 @@ static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json)
                else
                        vty_out(vty, "  Advertise-svi-macip : %s\n",
                                "Disabled");
+               vty_out(vty, "  SVI interface : %s\n",
+                       ifindex2ifname(vpn->svi_ifindex, vpn->tenant_vrf_id));
        }
 
        if (!json)
@@ -768,13 +784,13 @@ static void bgp_evpn_show_routes_mac_ip_es(struct vty *vty, esi_t *esi,
 static void bgp_evpn_show_routes_mac_ip_evi_es(struct vty *vty, esi_t *esi,
                                               json_object *json, int detail)
 {
-       return bgp_evpn_show_routes_mac_ip_es(vty, esi, json, detail, false);
+       bgp_evpn_show_routes_mac_ip_es(vty, esi, json, detail, false);
 }
 
 static void bgp_evpn_show_routes_mac_ip_global_es(struct vty *vty, esi_t *esi,
                                                  json_object *json, int detail)
 {
-       return bgp_evpn_show_routes_mac_ip_es(vty, esi, json, detail, true);
+       bgp_evpn_show_routes_mac_ip_es(vty, esi, json, detail, true);
 }
 
 static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, int type,
@@ -2279,7 +2295,7 @@ static struct bgpevpn *evpn_create_update_vni(struct bgp *bgp, vni_t vni)
                /* tenant vrf will be updated when we get local_vni_add from
                 * zebra
                 */
-               vpn = bgp_evpn_new(bgp, vni, bgp->router_id, 0, mcast_grp);
+               vpn = bgp_evpn_new(bgp, vni, bgp->router_id, 0, mcast_grp, 0);
                if (!vpn) {
                        flog_err(
                                EC_BGP_VNI,
@@ -2418,6 +2434,10 @@ static void evpn_show_route_vni_multicast(struct vty *vty, struct bgp *bgp,
        if (!dest || !bgp_dest_has_bgp_path_info_data(dest)) {
                if (!json)
                        vty_out(vty, "%% Network not in table\n");
+
+               if (dest)
+                       bgp_dest_unlock_node(dest);
+
                return;
        }
 
@@ -2452,6 +2472,8 @@ static void evpn_show_route_vni_multicast(struct vty *vty, struct bgp *bgp,
                vty_out(vty, "\nDisplayed %u paths for requested prefix\n",
                        path_cnt);
        }
+
+       bgp_dest_unlock_node(dest);
 }
 
 /*
@@ -2488,6 +2510,10 @@ static void evpn_show_route_vni_macip(struct vty *vty, struct bgp *bgp,
        if (!dest || !bgp_dest_has_bgp_path_info_data(dest)) {
                if (!json)
                        vty_out(vty, "%% Network not in table\n");
+
+               if (dest)
+                       bgp_dest_unlock_node(dest);
+
                return;
        }
 
@@ -2522,6 +2548,8 @@ static void evpn_show_route_vni_macip(struct vty *vty, struct bgp *bgp,
                vty_out(vty, "\nDisplayed %u paths for requested prefix\n",
                        path_cnt);
        }
+
+       bgp_dest_unlock_node(dest);
 }
 
 /* Disaplay EVPN routes for a ESI - VTY handler */
@@ -2592,6 +2620,10 @@ static void evpn_show_route_rd_macip(struct vty *vty, struct bgp *bgp,
        if (!dest || !bgp_dest_has_bgp_path_info_data(dest)) {
                if (!json)
                        vty_out(vty, "%% Network not in table\n");
+
+               if (dest)
+                       bgp_dest_unlock_node(dest);
+
                return;
        }
 
@@ -2627,6 +2659,8 @@ static void evpn_show_route_rd_macip(struct vty *vty, struct bgp *bgp,
                vty_out(vty, "\nDisplayed %u paths for requested prefix\n",
                        path_cnt);
        }
+
+       bgp_dest_unlock_node(dest);
 }
 
 /*
@@ -2660,14 +2694,18 @@ static void evpn_show_route_rd(struct vty *vty, struct bgp *bgp,
                return;
 
        table = bgp_dest_get_bgp_table_info(rd_dest);
-       if (table == NULL)
+       if (table == NULL) {
+               bgp_dest_unlock_node(rd_dest);
                return;
+       }
 
        if (json) {
                json_rd = json_object_new_object();
                json_object_string_add(json_rd, "rd", rd_str);
        }
 
+       bgp_dest_unlock_node(rd_dest);
+
        /* Display all prefixes with this RD. */
        for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) {
                const struct prefix_evpn *evp =
@@ -2878,6 +2916,8 @@ static void evpn_show_route_rd_all_macip(struct vty *vty, struct bgp *bgp,
                                json_rd = NULL;
                        }
                }
+
+               bgp_dest_unlock_node(dest);
        }
 
        if (json) {
@@ -3286,6 +3326,28 @@ static void evpn_unset_advertise_all_vni(struct bgp *bgp)
        bgp_evpn_cleanup_on_disable(bgp);
 }
 
+/* Set resolve overlay index flag */
+static void bgp_evpn_set_unset_resolve_overlay_index(struct bgp *bgp, bool set)
+{
+       if (set == bgp->resolve_overlay_index)
+               return;
+
+       if (set) {
+               bgp->resolve_overlay_index = true;
+               hash_iterate(bgp->vnihash,
+                            (void (*)(struct hash_bucket *, void *))
+                                    bgp_evpn_handle_resolve_overlay_index_set,
+                            NULL);
+       } else {
+               hash_iterate(
+                       bgp->vnihash,
+                       (void (*)(struct hash_bucket *, void *))
+                               bgp_evpn_handle_resolve_overlay_index_unset,
+                       NULL);
+               bgp->resolve_overlay_index = false;
+       }
+}
+
 /*
  * EVPN - use RFC8365 to auto-derive RT
  */
@@ -3784,10 +3846,11 @@ DEFUN_HIDDEN (no_bgp_evpn_advertise_vni_subnet,
 
 DEFUN (bgp_evpn_advertise_type5,
        bgp_evpn_advertise_type5_cmd,
-       "advertise " BGP_AFI_CMD_STR "" BGP_SAFI_CMD_STR " [route-map WORD]",
+       "advertise " BGP_AFI_CMD_STR "" BGP_SAFI_CMD_STR " [gateway-ip] [route-map WORD]",
        "Advertise prefix routes\n"
        BGP_AFI_HELP_STR
        BGP_SAFI_HELP_STR
+       "advertise gateway IP overlay index\n"
        "route-map for filtering specific routes\n"
        "Name of the route map\n")
 {
@@ -3799,9 +3862,14 @@ DEFUN (bgp_evpn_advertise_type5,
        safi_t safi = 0;
        int ret = 0;
        int rmap_changed = 0;
+       enum overlay_index_type oly = OVERLAY_INDEX_TYPE_NONE;
+       int idx_oly = 0;
+       bool adv_flag_changed = false;
 
        argv_find_and_parse_afi(argv, argc, &idx_afi, &afi);
        argv_find_and_parse_safi(argv, argc, &idx_safi, &safi);
+       argv_find_and_parse_oly_idx(argv, argc, &idx_oly, &oly);
+
        ret = argv_find(argv, argc, "route-map", &idx_rmap);
        if (ret) {
                if (!bgp_vrf->adv_cmd_rmap[afi][safi].name)
@@ -3826,39 +3894,149 @@ DEFUN (bgp_evpn_advertise_type5,
                return CMD_WARNING;
        }
 
+       if ((oly != OVERLAY_INDEX_TYPE_NONE)
+           && (oly != OVERLAY_INDEX_GATEWAY_IP)) {
+               vty_out(vty, "%%Unknown overlay-index type specified");
+               return CMD_WARNING;
+       }
+
        if (afi == AFI_IP) {
+               if ((!CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+                                BGP_L2VPN_EVPN_ADV_IPV4_UNICAST))
+                   && (!CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+                                   BGP_L2VPN_EVPN_ADV_IPV4_UNICAST_GW_IP))) {
+
+                       /*
+                        * this is the case for first time ever configuration
+                        * adv ipv4 unicast is enabled for the first time.
+                        * So no need to reset any flag
+                        */
+                       if (oly == OVERLAY_INDEX_TYPE_NONE)
+                               SET_FLAG(
+                                       bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+                                       BGP_L2VPN_EVPN_ADV_IPV4_UNICAST);
+                       else if (oly == OVERLAY_INDEX_GATEWAY_IP)
+                               SET_FLAG(
+                                       bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+                                       BGP_L2VPN_EVPN_ADV_IPV4_UNICAST_GW_IP);
+               } else if ((oly == OVERLAY_INDEX_TYPE_NONE)
+                          && (!CHECK_FLAG(
+                                     bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+                                     BGP_L2VPN_EVPN_ADV_IPV4_UNICAST))) {
+
+                       /*
+                        * This is modify case from gateway-ip
+                        * to no overlay index
+                        */
+                       adv_flag_changed = true;
+                       UNSET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+                                  BGP_L2VPN_EVPN_ADV_IPV4_UNICAST_GW_IP);
+                       SET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+                                BGP_L2VPN_EVPN_ADV_IPV4_UNICAST);
+               } else if ((oly == OVERLAY_INDEX_GATEWAY_IP)
+                          && (!CHECK_FLAG(
+                                     bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+                                     BGP_L2VPN_EVPN_ADV_IPV4_UNICAST_GW_IP))) {
+
+                       /*
+                        * This is modify case from no overlay index
+                        * to gateway-ip
+                        */
+                       adv_flag_changed = true;
+                       UNSET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+                                  BGP_L2VPN_EVPN_ADV_IPV4_UNICAST);
+                       SET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+                                BGP_L2VPN_EVPN_ADV_IPV4_UNICAST_GW_IP);
+               } else {
 
-               /* if we are already advertising ipv4 prefix as type-5
-                * nothing to do
-                */
-               if (!rmap_changed &&
-                   CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
-                              BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST))
-                       return CMD_WARNING;
-               SET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
-                        BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST);
+                       /*
+                        * Command is issued with the same option
+                        * (no overlay index or gateway-ip) which was
+                        * already configured. So nothing to do.
+                        * However, route-map may have been modified.
+                        * check if route-map has been modified.
+                        * If not, return an error
+                        */
+                       if (!rmap_changed)
+                               return CMD_WARNING;
+               }
        } else {
+               if ((!CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+                                BGP_L2VPN_EVPN_ADV_IPV6_UNICAST))
+                   && (!CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+                                   BGP_L2VPN_EVPN_ADV_IPV6_UNICAST_GW_IP))) {
+
+                       /*
+                        * this is the case for first time ever configuration
+                        * adv ipv6 unicast is enabled for the first time.
+                        * So no need to reset any flag
+                        */
+                       if (oly == OVERLAY_INDEX_TYPE_NONE)
+                               SET_FLAG(
+                                       bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+                                       BGP_L2VPN_EVPN_ADV_IPV6_UNICAST);
+                       else if (oly == OVERLAY_INDEX_GATEWAY_IP)
+                               SET_FLAG(
+                                       bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+                                       BGP_L2VPN_EVPN_ADV_IPV6_UNICAST_GW_IP);
+               } else if ((oly == OVERLAY_INDEX_TYPE_NONE)
+                          && (!CHECK_FLAG(
+                                     bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+                                     BGP_L2VPN_EVPN_ADV_IPV6_UNICAST))) {
+
+                       /*
+                        * This is modify case from gateway-ip
+                        * to no overlay index
+                        */
+                       adv_flag_changed = true;
+                       UNSET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+                                  BGP_L2VPN_EVPN_ADV_IPV6_UNICAST_GW_IP);
+                       SET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+                                BGP_L2VPN_EVPN_ADV_IPV6_UNICAST);
+               } else if ((oly == OVERLAY_INDEX_GATEWAY_IP)
+                          && (!CHECK_FLAG(
+                                     bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+                                     BGP_L2VPN_EVPN_ADV_IPV6_UNICAST_GW_IP))) {
+
+                       /*
+                        * This is modify case from no overlay index
+                        * to gateway-ip
+                        */
+                       adv_flag_changed = true;
+                       UNSET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+                                  BGP_L2VPN_EVPN_ADV_IPV6_UNICAST);
+                       SET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+                                BGP_L2VPN_EVPN_ADV_IPV6_UNICAST_GW_IP);
+               } else {
 
-               /* if we are already advertising ipv6 prefix as type-5
-                * nothing to do
-                */
-               if (!rmap_changed &&
-                   CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
-                              BGP_L2VPN_EVPN_ADVERTISE_IPV6_UNICAST))
-                       return CMD_WARNING;
-               SET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
-                        BGP_L2VPN_EVPN_ADVERTISE_IPV6_UNICAST);
+                       /*
+                        * Command is issued with the same option
+                        * (no overlay index or gateway-ip) which was
+                        * already configured. So nothing to do.
+                        * However, route-map may have been modified.
+                        * check if route-map has been modified.
+                        * If not, return an error
+                        */
+                       if (!rmap_changed)
+                               return CMD_WARNING;
+               }
        }
 
-       if (rmap_changed) {
+       if ((rmap_changed) || (adv_flag_changed)) {
+
+               /* If either of these are changed, then FRR needs to
+                * withdraw already advertised type5 routes.
+                */
                bgp_evpn_withdraw_type5_routes(bgp_vrf, afi, safi);
-               if (bgp_vrf->adv_cmd_rmap[afi][safi].name) {
-                       XFREE(MTYPE_ROUTE_MAP_NAME,
-                             bgp_vrf->adv_cmd_rmap[afi][safi].name);
-                       route_map_counter_decrement(
+               if (rmap_changed) {
+                       if (bgp_vrf->adv_cmd_rmap[afi][safi].name) {
+                               XFREE(MTYPE_ROUTE_MAP_NAME,
+                                     bgp_vrf->adv_cmd_rmap[afi][safi].name);
+                               route_map_counter_decrement(
                                        bgp_vrf->adv_cmd_rmap[afi][safi].map);
-                       bgp_vrf->adv_cmd_rmap[afi][safi].name = NULL;
-                       bgp_vrf->adv_cmd_rmap[afi][safi].map = NULL;
+                               bgp_vrf->adv_cmd_rmap[afi][safi].name = NULL;
+                               bgp_vrf->adv_cmd_rmap[afi][safi].map = NULL;
+                       }
                }
        }
 
@@ -3912,22 +4090,30 @@ DEFUN (no_bgp_evpn_advertise_type5,
                /* if we are not advertising ipv4 prefix as type-5
                 * nothing to do
                 */
-               if (CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
-                              BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST)) {
+               if ((CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+                               BGP_L2VPN_EVPN_ADV_IPV4_UNICAST)) ||
+                   (CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+                               BGP_L2VPN_EVPN_ADV_IPV4_UNICAST_GW_IP))) {
                        bgp_evpn_withdraw_type5_routes(bgp_vrf, afi, safi);
                        UNSET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
-                                  BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST);
+                                  BGP_L2VPN_EVPN_ADV_IPV4_UNICAST);
+                       UNSET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+                                  BGP_L2VPN_EVPN_ADV_IPV4_UNICAST_GW_IP);
                }
        } else {
 
                /* if we are not advertising ipv6 prefix as type-5
                 * nothing to do
                 */
-               if (CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
-                              BGP_L2VPN_EVPN_ADVERTISE_IPV6_UNICAST)) {
+               if ((CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+                               BGP_L2VPN_EVPN_ADV_IPV6_UNICAST)) ||
+                   (CHECK_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+                               BGP_L2VPN_EVPN_ADV_IPV6_UNICAST_GW_IP))){
                        bgp_evpn_withdraw_type5_routes(bgp_vrf, afi, safi);
                        UNSET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
-                                  BGP_L2VPN_EVPN_ADVERTISE_IPV6_UNICAST);
+                                  BGP_L2VPN_EVPN_ADV_IPV6_UNICAST);
+                       UNSET_FLAG(bgp_vrf->af_flags[AFI_L2VPN][SAFI_EVPN],
+                                  BGP_L2VPN_EVPN_ADV_IPV6_UNICAST_GW_IP);
                }
        }
 
@@ -3977,6 +4163,23 @@ DEFPY (bgp_evpn_ead_evi_tx_disable,
        return CMD_SUCCESS;
 }
 
+DEFPY (bgp_evpn_enable_resolve_overlay_index,
+       bgp_evpn_enable_resolve_overlay_index_cmd,
+       "[no$no] enable-resolve-overlay-index",
+       NO_STR
+       "Enable Recursive Resolution of type-5 route overlay index\n")
+{
+       struct bgp *bgp = VTY_GET_CONTEXT(bgp);
+
+       if (bgp != bgp_get_evpn()) {
+               vty_out(vty, "This command is only supported under EVPN VRF\n");
+               return CMD_WARNING;
+       }
+
+       bgp_evpn_set_unset_resolve_overlay_index(bgp, no ? false : true);
+       return CMD_SUCCESS;
+}
+
 DEFPY (bgp_evpn_advertise_pip_ip_mac,
        bgp_evpn_advertise_pip_ip_mac_cmd,
        "[no$no] advertise-pip [ip <A.B.C.D> [mac <X:X:X:X:X:X|X:X:X:X:X:X/M>]]",
@@ -4220,6 +4423,61 @@ DEFUN(show_bgp_l2vpn_evpn_vni,
        return CMD_SUCCESS;
 }
 
+DEFUN_HIDDEN(show_bgp_l2vpn_evpn_vni_remote_ip_hash,
+            show_bgp_l2vpn_evpn_vni_remote_ip_hash_cmd,
+            "show bgp l2vpn evpn vni remote-ip-hash",
+            SHOW_STR
+            BGP_STR
+            L2VPN_HELP_STR
+            EVPN_HELP_STR
+            "Show VNI\n"
+            "Remote IP hash\n")
+{
+       struct bgp *bgp_evpn;
+       int idx = 0;
+
+       bgp_evpn = bgp_get_evpn();
+       if (!bgp_evpn)
+               return CMD_WARNING;
+
+       if (!argv_find(argv, argc, "evpn", &idx))
+               return CMD_WARNING;
+
+       hash_iterate(bgp_evpn->vnihash,
+                    (void (*)(struct hash_bucket *,
+                              void *))bgp_evpn_show_remote_ip_hash,
+                    vty);
+
+       return CMD_SUCCESS;
+}
+
+DEFUN_HIDDEN(show_bgp_l2vpn_evpn_vni_svi_hash,
+            show_bgp_l2vpn_evpn_vni_svi_hash_cmd,
+            "show bgp l2vpn evpn vni-svi-hash",
+            SHOW_STR
+            BGP_STR
+            L2VPN_HELP_STR
+            EVPN_HELP_STR
+            "Show vni-svi-hash\n")
+{
+       struct bgp *bgp_evpn;
+       int idx = 0;
+
+       bgp_evpn = bgp_get_evpn();
+       if (!bgp_evpn)
+               return CMD_WARNING;
+
+       if (!argv_find(argv, argc, "evpn", &idx))
+               return CMD_WARNING;
+
+       hash_iterate(bgp_evpn->vni_svi_hash,
+                    (void (*)(struct hash_bucket *,
+                              void *))bgp_evpn_show_vni_svi_hash,
+                    vty);
+
+       return CMD_SUCCESS;
+}
+
 DEFPY(show_bgp_l2vpn_evpn_es_evi,
       show_bgp_l2vpn_evpn_es_evi_cmd,
       "show bgp l2vpn evpn es-evi [vni (1-16777215)$vni] [json$uj] [detail$detail]",
@@ -4310,7 +4568,7 @@ DEFPY(show_bgp_l2vpn_evpn_nh,
  * Display EVPN neighbor summary.
  */
 DEFUN(show_bgp_l2vpn_evpn_summary, show_bgp_l2vpn_evpn_summary_cmd,
-      "show bgp [vrf VRFNAME] l2vpn evpn summary [established|failed] [<neighbor <A.B.C.D|X:X::X:X|WORD>|remote-as <(1-4294967295)|internal|external>>] [wide] [json]",
+      "show bgp [vrf VRFNAME] l2vpn evpn summary [established|failed] [<neighbor <A.B.C.D|X:X::X:X|WORD>|remote-as <(1-4294967295)|internal|external>>] [terse] [wide] [json]",
       SHOW_STR BGP_STR
       "bgp vrf\n"
       "vrf name\n" L2VPN_HELP_STR EVPN_HELP_STR
@@ -4325,6 +4583,7 @@ DEFUN(show_bgp_l2vpn_evpn_summary, show_bgp_l2vpn_evpn_summary_cmd,
       "AS number\n"
       "Internal (iBGP) AS sessions\n"
       "External (eBGP) AS sessions\n"
+      "Shorten the information on BGP instances\n"
       "Increase table width for longer output\n" JSON_STR)
 {
        int idx_vrf = 0;
@@ -4333,7 +4592,7 @@ DEFUN(show_bgp_l2vpn_evpn_summary, show_bgp_l2vpn_evpn_summary_cmd,
        char *neighbor = NULL;
        as_t as = 0; /* 0 means AS filter not set */
        int as_type = AS_UNSPECIFIED;
-       uint8_t show_flags = 0;
+       uint16_t show_flags = 0;
 
        if (argv_find(argv, argc, "vrf", &idx_vrf))
                vrf = argv[++idx_vrf]->arg;
@@ -4357,6 +4616,9 @@ DEFUN(show_bgp_l2vpn_evpn_summary, show_bgp_l2vpn_evpn_summary_cmd,
                        as = (as_t)atoi(argv[idx + 1]->arg);
        }
 
+       if (argv_find(argv, argc, "terse", &idx))
+               SET_FLAG(show_flags, BGP_SHOW_OPT_TERSE);
+
        if (argv_find(argv, argc, "wide", &idx))
                SET_FLAG(show_flags, BGP_SHOW_OPT_WIDE);
 
@@ -6057,6 +6319,9 @@ void bgp_config_write_evpn_info(struct vty *vty, struct bgp *bgp, afi_t afi,
        if (bgp->evpn_info->advertise_svi_macip)
                vty_out(vty, "  advertise-svi-ip\n");
 
+       if (bgp->resolve_overlay_index)
+               vty_out(vty, "  enable-resolve-overlay-index\n");
+
        if (bgp_mh_info->host_routes_use_l3nhg !=
                        BGP_EVPN_MH_USE_ES_L3NHG_DEF) {
                if (bgp_mh_info->host_routes_use_l3nhg)
@@ -6103,21 +6368,40 @@ void bgp_config_write_evpn_info(struct vty *vty, struct bgp *bgp, afi_t afi,
                vty_out(vty, "  flooding disable\n");
 
        if (CHECK_FLAG(bgp->af_flags[AFI_L2VPN][SAFI_EVPN],
-                      BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST)) {
+                      BGP_L2VPN_EVPN_ADV_IPV4_UNICAST)) {
                if (bgp->adv_cmd_rmap[AFI_IP][SAFI_UNICAST].name)
                        vty_out(vty, "  advertise ipv4 unicast route-map %s\n",
                                bgp->adv_cmd_rmap[AFI_IP][SAFI_UNICAST].name);
                else
-                       vty_out(vty, "  advertise ipv4 unicast\n");
+                       vty_out(vty,
+                               "  advertise ipv4 unicast\n");
+       } else if (CHECK_FLAG(bgp->af_flags[AFI_L2VPN][SAFI_EVPN],
+                  BGP_L2VPN_EVPN_ADV_IPV4_UNICAST_GW_IP)) {
+               if (bgp->adv_cmd_rmap[AFI_IP][SAFI_UNICAST].name)
+                       vty_out(vty,
+                               "  advertise ipv4 unicast gateway-ip route-map %s\n",
+                               bgp->adv_cmd_rmap[AFI_IP][SAFI_UNICAST].name);
+               else
+                       vty_out(vty, "  advertise ipv4 unicast gateway-ip\n");
        }
 
        if (CHECK_FLAG(bgp->af_flags[AFI_L2VPN][SAFI_EVPN],
-                      BGP_L2VPN_EVPN_ADVERTISE_IPV6_UNICAST)) {
+                      BGP_L2VPN_EVPN_ADV_IPV6_UNICAST)) {
                if (bgp->adv_cmd_rmap[AFI_IP6][SAFI_UNICAST].name)
-                       vty_out(vty, "  advertise ipv6 unicast route-map %s\n",
+                       vty_out(vty,
+                               "  advertise ipv6 unicast route-map %s\n",
+                               bgp->adv_cmd_rmap[AFI_IP6][SAFI_UNICAST].name);
+               else
+                       vty_out(vty,
+                               "  advertise ipv6 unicast\n");
+       } else if (CHECK_FLAG(bgp->af_flags[AFI_L2VPN][SAFI_EVPN],
+                             BGP_L2VPN_EVPN_ADV_IPV6_UNICAST_GW_IP)) {
+               if (bgp->adv_cmd_rmap[AFI_IP6][SAFI_UNICAST].name)
+                       vty_out(vty,
+                               "  advertise ipv6 unicast gateway-ip route-map %s\n",
                                bgp->adv_cmd_rmap[AFI_IP6][SAFI_UNICAST].name);
                else
-                       vty_out(vty, "  advertise ipv6 unicast\n");
+                       vty_out(vty, "  advertise ipv6 unicast gateway-ip\n");
        }
 
        if (CHECK_FLAG(bgp->af_flags[AFI_L2VPN][SAFI_EVPN],
@@ -6226,6 +6510,8 @@ void bgp_ethernetvpn_init(void)
        install_element(BGP_EVPN_NODE, &bgp_evpn_use_es_l3nhg_cmd);
        install_element(BGP_EVPN_NODE, &bgp_evpn_ead_evi_rx_disable_cmd);
        install_element(BGP_EVPN_NODE, &bgp_evpn_ead_evi_tx_disable_cmd);
+       install_element(BGP_EVPN_NODE,
+                       &bgp_evpn_enable_resolve_overlay_index_cmd);
 
        /* test commands */
        install_element(BGP_EVPN_NODE, &test_es_add_cmd);
@@ -6237,6 +6523,8 @@ void bgp_ethernetvpn_init(void)
        install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_es_vrf_cmd);
        install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_nh_cmd);
        install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_vni_cmd);
+       install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_vni_remote_ip_hash_cmd);
+       install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_vni_svi_hash_cmd);
        install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_summary_cmd);
        install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_cmd);
        install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_rd_cmd);
index 33f6e4f1b607060a35abb3f05a1c3bb689246af8..137365ddbf27b7fce97d94af851942597d350bf0 100644 (file)
@@ -28,6 +28,10 @@ extern void bgp_ethernetvpn_init(void);
 #define L2VPN_HELP_STR        "Layer 2 Virtual Private Network\n"
 #define EVPN_HELP_STR        "Ethernet Virtual Private Network\n"
 
+extern int argv_find_and_parse_oly_idx(struct cmd_token **argv, int argc,
+                                      int *oly_idx,
+                                      enum overlay_index_type *oly);
+
 /* Parse type from "type <ead|1|...>", return -1 on failure */
 extern int bgp_evpn_cli_parse_type(int *type, struct cmd_token **argv,
                                   int argc);
index b244c872580771b7ef5274149c6021c1d754ed06..23baa0184e4e2980e71b80e7404d0b8c603787ab 100644 (file)
@@ -641,13 +641,12 @@ int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len,
                                 __func__, type);
                }
        }
-       if (bpem->match_packet_length_num || bpem->match_fragment_num ||
-           bpem->match_tcpflags_num || bpem->match_dscp_num ||
-           bpem->match_packet_length_num || bpem->match_icmp_code_num ||
-           bpem->match_icmp_type_num || bpem->match_port_num ||
-           bpem->match_src_port_num || bpem->match_dst_port_num ||
-           bpem->match_protocol_num || bpem->match_bitmask ||
-           bpem->match_flowlabel_num)
+       if (bpem->match_packet_length_num || bpem->match_fragment_num
+           || bpem->match_tcpflags_num || bpem->match_dscp_num
+           || bpem->match_icmp_code_num || bpem->match_icmp_type_num
+           || bpem->match_port_num || bpem->match_src_port_num
+           || bpem->match_dst_port_num || bpem->match_protocol_num
+           || bpem->match_bitmask || bpem->match_flowlabel_num)
                bpem->type = BGP_PBR_IPSET;
        else if ((bpem->match_bitmask_iprule & PREFIX_SRC_PRESENT) ||
                 (bpem->match_bitmask_iprule & PREFIX_DST_PRESENT))
index 6bcb31e652f1ff96701ab1ffef29de2549329137..4cc096d8e7c4ff90276f882f9e0dc2ee29d8d74b 100644 (file)
@@ -811,7 +811,7 @@ void bgp_start_routeadv(struct bgp *bgp)
                         sizeof(bgp->update_delay_peers_resume_time));
 
        for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
-               if (peer->status != Established)
+               if (!peer_established(peer))
                        continue;
                BGP_TIMER_OFF(peer->t_routeadv);
                BGP_TIMER_ON(peer->t_routeadv, bgp_routeadv_timer, 0);
@@ -1004,7 +1004,7 @@ static void bgp_maxmed_onstartup_begin(struct bgp *bgp)
 
 static void bgp_maxmed_onstartup_process_status_change(struct peer *peer)
 {
-       if (peer->status == Established && !peer->bgp->established) {
+       if (peer_established(peer) && !peer->bgp->established) {
                bgp_maxmed_onstartup_begin(peer->bgp);
        }
 }
@@ -1066,7 +1066,7 @@ static void bgp_update_delay_begin(struct bgp *bgp)
 
 static void bgp_update_delay_process_status_change(struct peer *peer)
 {
-       if (peer->status == Established) {
+       if (peer_established(peer)) {
                if (!peer->bgp->established++) {
                        bgp_update_delay_begin(peer->bgp);
                        zlog_info(
@@ -1102,7 +1102,7 @@ void bgp_fsm_change_status(struct peer *peer, int status)
 
        if (status == Established)
                bgp->established_peers++;
-       else if ((peer->status == Established) && (status != Established))
+       else if ((peer_established(peer)) && (status != Established))
                bgp->established_peers--;
 
        if (bgp_debug_neighbor_events(peer)) {
@@ -1235,7 +1235,7 @@ int bgp_stop(struct peer *peer)
        }
 
        /* Increment Dropped count. */
-       if (peer->status == Established) {
+       if (peer_established(peer)) {
                peer->dropped++;
 
                /* bgp log-neighbor-changes of neighbor Down */
@@ -1396,8 +1396,7 @@ int bgp_stop(struct peer *peer)
                /* Received ORF prefix-filter */
                peer->orf_plist[afi][safi] = NULL;
 
-               if ((peer->status == OpenConfirm)
-                   || (peer->status == Established)) {
+               if ((peer->status == OpenConfirm) || (peer_established(peer))) {
                        /* ORF received prefix-filter pnt */
                        snprintf(orf_name, sizeof(orf_name), "%s.%d.%d",
                                 peer->host, afi, safi);
index bdab2ec36a95a7d40400b9270b5c02d32f4833b1..73ca9f07e02f3cc786382579febe9829bf5ac58a 100644 (file)
@@ -89,8 +89,8 @@ int bgp_parse_fec_update(void)
                bgp_set_valid_label(&dest->local_label);
        }
        SET_FLAG(dest->flags, BGP_NODE_LABEL_CHANGED);
-       bgp_dest_unlock_node(dest);
        bgp_process(bgp, dest, afi, safi);
+       bgp_dest_unlock_node(dest);
        return 1;
 }
 
index ec73ebb2964132545b1c056dca5bdad78638225d..02b7e648697c6e6209a97e02fa1ca993c012a887 100644 (file)
@@ -200,8 +200,8 @@ static void bgp_process_mac_rescan_table(struct bgp *bgp, struct peer *peer,
                                                AFI_L2VPN, SAFI_EVPN, &prd,
                                                p, label_pnt, num_labels,
                                                pi->addpath_rx_id ? 1 : 0,
-                                               pi->addpath_rx_id, pfx_buf,
-                                               sizeof(pfx_buf));
+                                               pi->addpath_rx_id, NULL,
+                                               pfx_buf, sizeof(pfx_buf));
                                        zlog_debug(
                                                   "%s skip update of %s marked as removed",
                                                   peer->host, pfx_buf);
@@ -239,7 +239,7 @@ static void bgp_mac_rescan_evpn_table(struct bgp *bgp, struct ethaddr *macaddr)
                if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
                        continue;
 
-               if (peer->status != Established)
+               if (!peer_established(peer))
                        continue;
 
                if (CHECK_FLAG(peer->af_flags[afi][safi],
index eb85936f0f47c260d1827457bd924698ab65d1df..196e56a9372c6fb7cf0c65f8612519cbad6da58b 100644 (file)
@@ -144,3 +144,4 @@ DEFINE_MTYPE(BGPD, BGP_SRV6_L3VPN, "BGP prefix-sid srv6 l3vpn servcie");
 DEFINE_MTYPE(BGPD, BGP_SRV6_VPN, "BGP prefix-sid srv6 vpn service");
 DEFINE_MTYPE(BGPD, BGP_SRV6_SID, "BGP srv6 segment-id");
 DEFINE_MTYPE(BGPD, BGP_SRV6_FUNCTION, "BGP srv6 function");
+DEFINE_MTYPE(BGPD, EVPN_REMOTE_IP, "BGP EVPN Remote IP hash entry");
index c5ba37149801da1e0d9cdc90decebb1b118b917b..0021fa9c3d897d749bdda83fd0fc09168aa6d2b9 100644 (file)
@@ -142,4 +142,6 @@ DECLARE_MTYPE(BGP_SRV6_VPN);
 DECLARE_MTYPE(BGP_SRV6_SID);
 DECLARE_MTYPE(BGP_SRV6_FUNCTION);
 
+DECLARE_MTYPE(EVPN_REMOTE_IP);
+
 #endif /* _QUAGGA_BGP_MEMORY_H */
index 5189d7ba8ff9243b5f8be0d7b9a3cba98e45b38e..ab22aee1ca5de26d4a758c21bd95ad8b99a4f497 100644 (file)
@@ -182,24 +182,52 @@ int bgp_router_destroy(struct nb_cb_destroy_args *args)
                        for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, tmp_bgp)) {
                                if (tmp_bgp->inst_type != BGP_INSTANCE_TYPE_VRF)
                                        continue;
-                               if (CHECK_FLAG(tmp_bgp->af_flags[AFI_IP][SAFI_UNICAST],
-                                              BGP_CONFIG_MPLSVPN_TO_VRF_IMPORT) ||
-                                   CHECK_FLAG(tmp_bgp->af_flags[AFI_IP6][SAFI_UNICAST],
-                                              BGP_CONFIG_MPLSVPN_TO_VRF_IMPORT) ||
-                                   CHECK_FLAG(tmp_bgp->af_flags[AFI_IP][SAFI_UNICAST],
-                                              BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT) ||
-                                   CHECK_FLAG(tmp_bgp->af_flags[AFI_IP6][SAFI_UNICAST],
-                                              BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT) ||
-                                   CHECK_FLAG(tmp_bgp->af_flags[AFI_IP][SAFI_UNICAST],
-                                              BGP_CONFIG_VRF_TO_VRF_EXPORT) ||
-                                   CHECK_FLAG(tmp_bgp->af_flags[AFI_IP6][SAFI_UNICAST],
-                                              BGP_CONFIG_VRF_TO_VRF_EXPORT) ||
-                                   (bgp == bgp_get_evpn() &&
-                                   (CHECK_FLAG(tmp_bgp->af_flags[AFI_L2VPN][SAFI_EVPN],
-                                               BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST) ||
-                                    CHECK_FLAG(tmp_bgp->af_flags[AFI_L2VPN][SAFI_EVPN],
-                                               BGP_L2VPN_EVPN_ADVERTISE_IPV6_UNICAST))) ||
-                                   (tmp_bgp->vnihash && hashcount(tmp_bgp->vnihash))) {
+                               if (CHECK_FLAG(tmp_bgp->af_flags[AFI_IP]
+                                                               [SAFI_UNICAST],
+                                              BGP_CONFIG_MPLSVPN_TO_VRF_IMPORT)
+                                   || CHECK_FLAG(
+                                              tmp_bgp->af_flags[AFI_IP6]
+                                                               [SAFI_UNICAST],
+                                              BGP_CONFIG_MPLSVPN_TO_VRF_IMPORT)
+                                   || CHECK_FLAG(
+                                              tmp_bgp->af_flags[AFI_IP]
+                                                               [SAFI_UNICAST],
+                                              BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT)
+                                   || CHECK_FLAG(
+                                              tmp_bgp->af_flags[AFI_IP6]
+                                                               [SAFI_UNICAST],
+                                              BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT)
+                                   || CHECK_FLAG(
+                                              tmp_bgp->af_flags[AFI_IP]
+                                                               [SAFI_UNICAST],
+                                              BGP_CONFIG_VRF_TO_VRF_EXPORT)
+                                   || CHECK_FLAG(
+                                              tmp_bgp->af_flags[AFI_IP6]
+                                                               [SAFI_UNICAST],
+                                              BGP_CONFIG_VRF_TO_VRF_EXPORT)
+                                   || (bgp == bgp_get_evpn()
+                                       && (CHECK_FLAG(
+                                                   tmp_bgp->af_flags
+                                                           [AFI_L2VPN]
+                                                           [SAFI_EVPN],
+                                                   BGP_L2VPN_EVPN_ADV_IPV4_UNICAST)
+                                           || CHECK_FLAG(
+                                                      tmp_bgp->af_flags
+                                                              [AFI_L2VPN]
+                                                              [SAFI_EVPN],
+                                                      BGP_L2VPN_EVPN_ADV_IPV4_UNICAST_GW_IP)
+                                           || CHECK_FLAG(
+                                                      tmp_bgp->af_flags
+                                                              [AFI_L2VPN]
+                                                              [SAFI_EVPN],
+                                                      BGP_L2VPN_EVPN_ADV_IPV6_UNICAST)
+                                           || CHECK_FLAG(
+                                                      tmp_bgp->af_flags
+                                                              [AFI_L2VPN]
+                                                              [SAFI_EVPN],
+                                                      BGP_L2VPN_EVPN_ADV_IPV6_UNICAST_GW_IP)))
+                                   || (tmp_bgp->vnihash
+                                       && hashcount(tmp_bgp->vnihash))) {
                                        snprintf(
                                                args->errmsg, args->errmsg_len,
                                                "Cannot delete default BGP instance. Dependent VRF instances exist\n");
index 137f0a6b59dca11a8bee219e66ca9e21d4a10693..a51816116e530a3ce2e592b1fe819c3d223b3968 100644 (file)
@@ -581,7 +581,7 @@ static int bgp_accept(struct thread *thread)
 
        SET_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER);
        /* Make dummy peer until read Open packet. */
-       if (peer1->status == Established
+       if (peer_established(peer1)
            && CHECK_FLAG(peer1->sflags, PEER_STATUS_NSF_MODE)) {
                /* If we have an existing established connection with graceful
                 * restart
index 46942a0bea24926a7201887797356c75d5c4f4c8..e7bad42f9741a345f2dfe13470f6fb6626f4a8fd 100644 (file)
@@ -414,7 +414,7 @@ void bgp_connected_add(struct bgp *bgp, struct connected *ifc)
                for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
                        if (peer->conf_if
                            && (strcmp(peer->conf_if, ifc->ifp->name) == 0)
-                           && peer->status != Established
+                           && !peer_established(peer)
                            && !CHECK_FLAG(peer->flags,
                                           PEER_FLAG_IFPEER_V6ONLY)) {
                                if (peer_active(peer))
@@ -835,6 +835,18 @@ static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp,
                        bnc->metric, bnc->path_count);
                if (peer)
                        vty_out(vty, ", peer %s", peer->host);
+               if (bnc->is_evpn_gwip_nexthop)
+                       vty_out(vty, " EVPN Gateway IP");
+               vty_out(vty, "\n");
+               bgp_show_nexthops_detail(vty, bgp, bnc);
+       } else if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_EVPN_INCOMPLETE)) {
+               vty_out(vty,
+                       " %s overlay index unresolved [IGP metric %d], #paths %d",
+                       inet_ntop(bnc->prefix.family, &bnc->prefix.u.prefix,
+                                 buf, sizeof(buf)),
+                       bnc->metric, bnc->path_count);
+               if (bnc->is_evpn_gwip_nexthop)
+                       vty_out(vty, " EVPN Gateway IP");
                vty_out(vty, "\n");
                bgp_show_nexthops_detail(vty, bgp, bnc);
        } else {
@@ -844,6 +856,8 @@ static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp,
                        bnc->path_count);
                if (peer)
                        vty_out(vty, ", peer %s", peer->host);
+               if (bnc->is_evpn_gwip_nexthop)
+                       vty_out(vty, " EVPN Gateway IP");
                vty_out(vty, "\n");
                if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED))
                        vty_out(vty, "  Must be Connected\n");
index fe0a9646a01f81dc6b28ce74eced120233babb36..16c2b6c65a8ad36c5f4a5d04d1d9f5dc15f2fa64 100644 (file)
@@ -56,6 +56,10 @@ struct bgp_nexthop_cache {
        time_t last_update;
        uint16_t flags;
 
+/*
+ * If the nexthop is EVPN gateway IP NH, VALID flag is set only if the nexthop
+ * is RIB reachable as well as MAC/IP is present
+ */
 #define BGP_NEXTHOP_VALID             (1 << 0)
 #define BGP_NEXTHOP_REGISTERED        (1 << 1)
 #define BGP_NEXTHOP_CONNECTED         (1 << 2)
@@ -64,11 +68,29 @@ struct bgp_nexthop_cache {
 #define BGP_STATIC_ROUTE_EXACT_MATCH  (1 << 5)
 #define BGP_NEXTHOP_LABELED_VALID     (1 << 6)
 
+/*
+ * This flag is added for EVPN gateway IP nexthops.
+ * If the nexthop is RIB reachable, but a MAC/IP is not yet
+ * resolved, this flag is set.
+ * Following table explains the combination of L3 and L2 reachability w.r.t.
+ * VALID and INCOMPLETE flags
+ *
+ *                | MACIP resolved | MACIP unresolved
+ *----------------|----------------|------------------
+ * L3 reachable   | VALID      = 1 | VALID      = 0
+ *                | INCOMPLETE = 0 | INCOMPLETE = 1
+ * ---------------|----------------|--------------------
+ * L3 unreachable | VALID      = 0 | VALID      = 0
+ *                | INCOMPLETE = 0 | INCOMPLETE = 0
+ */
+#define BGP_NEXTHOP_EVPN_INCOMPLETE (1 << 7)
+
        uint16_t change_flags;
 
 #define BGP_NEXTHOP_CHANGED           (1 << 0)
 #define BGP_NEXTHOP_METRIC_CHANGED    (1 << 1)
 #define BGP_NEXTHOP_CONNECTED_CHANGED (1 << 2)
+#define BGP_NEXTHOP_MACIP_CHANGED (1 << 3)
 
        /* Back pointer to the cache tree this entry belongs to. */
        struct bgp_nexthop_cache_head *tree;
@@ -79,6 +101,11 @@ struct bgp_nexthop_cache {
        LIST_HEAD(path_list, bgp_path_info) paths;
        unsigned int path_count;
        struct bgp *bgp;
+
+       /* This flag is set to TRUE for a bnc that is gateway IP overlay index
+        * nexthop.
+        */
+       bool is_evpn_gwip_nexthop;
 };
 
 extern int bgp_nexthop_cache_compare(const struct bgp_nexthop_cache *a,
index 4b4a3716e614999bdae0bcac246527c7034ca8dd..742ef217d97b224ec60d60421bbcc2b038ad3e17 100644 (file)
@@ -53,7 +53,6 @@ static void register_zebra_rnh(struct bgp_nexthop_cache *bnc,
                               int is_bgp_static_route);
 static void unregister_zebra_rnh(struct bgp_nexthop_cache *bnc,
                                 int is_bgp_static_route);
-static void evaluate_paths(struct bgp_nexthop_cache *bnc);
 static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p);
 static int bgp_nht_ifp_initial(struct thread *thread);
 
@@ -244,6 +243,9 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop,
                }
        }
 
+       if (pi && is_route_parent_evpn(pi))
+               bnc->is_evpn_gwip_nexthop = true;
+
        if (is_bgp_static_route) {
                SET_FLAG(bnc->flags, BGP_STATIC_ROUTE);
 
@@ -331,7 +333,7 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop,
                return 1;
        else if (safi == SAFI_UNICAST && pi
                 && pi->sub_type == BGP_ROUTE_IMPORTED && pi->extra
-                && pi->extra->num_labels) {
+                && pi->extra->num_labels && !bnc->is_evpn_gwip_nexthop) {
                return bgp_isvalid_labeled_nexthop(bnc);
        } else
                return (bgp_isvalid_nexthop(bnc));
@@ -387,6 +389,7 @@ static void bgp_process_nexthop_update(struct bgp_nexthop_cache *bnc,
        struct nexthop *nhlist_head = NULL;
        struct nexthop *nhlist_tail = NULL;
        int i;
+       bool evpn_resolved = false;
 
        bnc->last_update = bgp_clock();
        bnc->change_flags = 0;
@@ -417,7 +420,8 @@ static void bgp_process_nexthop_update(struct bgp_nexthop_cache *bnc,
                if (!bnc->nexthop_num)
                        UNSET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED);
 
-               bnc->flags |= BGP_NEXTHOP_VALID;
+               if (!bnc->is_evpn_gwip_nexthop)
+                       bnc->flags |= BGP_NEXTHOP_VALID;
                bnc->metric = nhr->metric;
                bnc->nexthop_num = nhr->nexthop_num;
 
@@ -488,7 +492,40 @@ static void bgp_process_nexthop_update(struct bgp_nexthop_cache *bnc,
                }
                bnc_nexthop_free(bnc);
                bnc->nexthop = nhlist_head;
+
+               /*
+                * Gateway IP nexthop is L3 reachable. Mark it as
+                * BGP_NEXTHOP_VALID only if it is recursively resolved with a
+                * remote EVPN RT-2.
+                * Else, mark it as BGP_NEXTHOP_EVPN_INCOMPLETE.
+                * When its mapping with EVPN RT-2 is established, unset
+                * BGP_NEXTHOP_EVPN_INCOMPLETE and set BGP_NEXTHOP_VALID.
+                */
+               if (bnc->is_evpn_gwip_nexthop) {
+                       evpn_resolved = bgp_evpn_is_gateway_ip_resolved(bnc);
+
+                       if (BGP_DEBUG(nht, NHT)) {
+                               char buf2[PREFIX2STR_BUFFER];
+
+                               prefix2str(&bnc->prefix, buf2, sizeof(buf2));
+                               zlog_debug(
+                                       "EVPN gateway IP %s recursive MAC/IP lookup %s",
+                                       buf2,
+                                       (evpn_resolved ? "successful"
+                                                      : "failed"));
+                       }
+
+                       if (evpn_resolved) {
+                               bnc->flags |= BGP_NEXTHOP_VALID;
+                               bnc->flags &= ~BGP_NEXTHOP_EVPN_INCOMPLETE;
+                               bnc->change_flags |= BGP_NEXTHOP_MACIP_CHANGED;
+                       } else {
+                               bnc->flags |= BGP_NEXTHOP_EVPN_INCOMPLETE;
+                               bnc->flags &= ~BGP_NEXTHOP_VALID;
+                       }
+               }
        } else {
+               bnc->flags &= ~BGP_NEXTHOP_EVPN_INCOMPLETE;
                bnc->flags &= ~BGP_NEXTHOP_VALID;
                bnc->flags &= ~BGP_NEXTHOP_LABELED_VALID;
                bnc->nexthop_num = nhr->nexthop_num;
@@ -694,6 +731,7 @@ void bgp_cleanup_nexthops(struct bgp *bgp)
                        UNSET_FLAG(bnc->flags, BGP_NEXTHOP_VALID);
                        UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED);
                        UNSET_FLAG(bnc->flags, BGP_NEXTHOP_PEER_NOTIFIED);
+                       UNSET_FLAG(bnc->flags, BGP_NEXTHOP_EVPN_INCOMPLETE);
                }
        }
 }
@@ -888,7 +926,7 @@ static void unregister_zebra_rnh(struct bgp_nexthop_cache *bnc,
  * RETURNS:
  *   void.
  */
-static void evaluate_paths(struct bgp_nexthop_cache *bnc)
+void evaluate_paths(struct bgp_nexthop_cache *bnc)
 {
        struct bgp_dest *dest;
        struct bgp_path_info *path;
@@ -942,16 +980,18 @@ static void evaluate_paths(struct bgp_nexthop_cache *bnc)
                 * In case of unicast routes that were imported from vpn
                 * and that have labels, they are valid only if there are
                 * nexthops with labels
+                *
+                * If the nexthop is EVPN gateway-IP,
+                * do not check for a valid label.
                 */
 
                bool bnc_is_valid_nexthop = false;
                bool path_valid = false;
 
-               if (safi == SAFI_UNICAST &&
-                       path->sub_type == BGP_ROUTE_IMPORTED &&
-                       path->extra &&
-                       path->extra->num_labels) {
-
+               if (safi == SAFI_UNICAST && path->sub_type == BGP_ROUTE_IMPORTED
+                   && path->extra && path->extra->num_labels
+                   && (path->attr->evpn_overlay.type
+                       != OVERLAY_INDEX_GATEWAY_IP)) {
                        bnc_is_valid_nexthop =
                                bgp_isvalid_labeled_nexthop(bnc) ? true : false;
                } else {
index 9268b225ca02888cb3eb95c9aa0bbd21883685b0..e006aa4469cddd745e379d066a101072e5a8c27b 100644 (file)
@@ -90,6 +90,7 @@ extern void bgp_nht_register_nexthops(struct bgp *bgp);
  */
 extern void bgp_nht_reg_enhe_cap_intfs(struct peer *peer);
 extern void bgp_nht_dereg_enhe_cap_intfs(struct peer *peer);
+extern void evaluate_paths(struct bgp_nexthop_cache *bnc);
 
 /* APIs for setting up and allocating L3 nexthop group ids */
 extern uint32_t bgp_l3nhg_id_alloc(void);
index 62982881d8011a5876c27e8a7ad17466ee96081f..3c01c3b486654aa012834fda5059956a4bc57f81 100644 (file)
@@ -232,7 +232,7 @@ void bgp_update_restarted_peers(struct peer *peer)
        if (bgp_debug_neighbor_events(peer))
                zlog_debug("Peer %s: Checking restarted", peer->host);
 
-       if (peer->status == Established) {
+       if (peer_established(peer)) {
                peer->update_delay_over = 1;
                peer->bgp->restarted_peers++;
                bgp_check_update_delay(peer->bgp);
@@ -255,7 +255,7 @@ void bgp_update_implicit_eors(struct peer *peer)
        if (bgp_debug_neighbor_events(peer))
                zlog_debug("Peer %s: Checking implicit EORs", peer->host);
 
-       if (peer->status == Established) {
+       if (peer_established(peer)) {
                peer->update_delay_over = 1;
                peer->bgp->implicit_eors++;
                bgp_check_update_delay(peer->bgp);
@@ -404,7 +404,7 @@ int bgp_generate_updgrp_packets(struct thread *thread)
         * if peer is Established and updates are not on hold (as part of
         * update-delay processing).
         */
-       if (peer->status != Established)
+       if (!peer_established(peer))
                return 0;
 
        if ((peer->bgp->main_peers_update_hold)
@@ -1019,7 +1019,7 @@ static int bgp_collision_detect(struct peer *new, struct in_addr remote_id)
         * states. Note that a peer GR is handled by closing the existing
         * connection upon receipt of new one.
         */
-       if (peer->status == Established || peer->status == Clearing) {
+       if (peer_established(peer) || peer->status == Clearing) {
                bgp_notify_send(new, BGP_NOTIFY_CEASE,
                                BGP_NOTIFY_CEASE_COLLISION_RESOLUTION);
                return -1;
@@ -1542,7 +1542,7 @@ static int bgp_update_receive(struct peer *peer, bgp_size_t size)
        struct bgp_nlri nlris[NLRI_TYPE_MAX];
 
        /* Status must be Established. */
-       if (peer->status != Established) {
+       if (!peer_established(peer)) {
                flog_err(EC_BGP_INVALID_STATUS,
                         "%s [FSM] Update packet received under status %s",
                         peer->host,
@@ -1732,7 +1732,7 @@ static int bgp_update_receive(struct peer *peer, bgp_size_t size)
                    && nlri_ret != BGP_NLRI_PARSE_ERROR_PREFIX_OVERFLOW) {
                        flog_err(EC_BGP_UPDATE_RCV,
                                 "%s [Error] Error parsing NLRI", peer->host);
-                       if (peer->status == Established)
+                       if (peer_established(peer))
                                bgp_notify_send(
                                        peer, BGP_NOTIFY_UPDATE_ERR,
                                        i <= NLRI_WITHDRAW
@@ -1955,7 +1955,7 @@ static int bgp_route_refresh_receive(struct peer *peer, bgp_size_t size)
        }
 
        /* Status must be Established. */
-       if (peer->status != Established) {
+       if (!peer_established(peer)) {
                flog_err(
                        EC_BGP_INVALID_STATUS,
                        "%s [Error] Route refresh packet received under status %s",
@@ -2258,7 +2258,7 @@ static int bgp_route_refresh_receive(struct peer *peer, bgp_size_t size)
                        bgp_set_stale_route(peer, afi, safi);
                }
 
-               if (peer->status == Established)
+               if (peer_established(peer))
                        thread_add_timer(bm->master,
                                         bgp_refresh_stalepath_timer_expire,
                                         paf, peer->bgp->stalepath_time,
@@ -2490,7 +2490,7 @@ int bgp_capability_receive(struct peer *peer, bgp_size_t size)
        }
 
        /* Status must be Established. */
-       if (peer->status != Established) {
+       if (!peer_established(peer)) {
                flog_err(
                        EC_BGP_NO_CAP,
                        "%s [Error] Dynamic capability packet received under status %s",
@@ -2711,7 +2711,7 @@ int bgp_packet_process_error(struct thread *thread)
                           peer->host, peer->fd, code);
 
        /* Closed connection or error on the socket */
-       if (peer->status == Established) {
+       if (peer_established(peer)) {
                if ((CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART)
                     || CHECK_FLAG(peer->flags,
                                   PEER_FLAG_GRACEFUL_RESTART_HELPER))
index c61aedb560d11ab1b75ae62c20cf316ee4b99bc7..4637cef3eb8055778ed3727fb0e025164d5c147b 100644 (file)
@@ -125,6 +125,7 @@ static const struct message bgp_pmsi_tnltype_str[] = {
 };
 
 #define VRFID_NONE_STR "-"
+#define SOFT_RECONFIG_TASK_MAX_PREFIX 25000
 
 DEFINE_HOOK(bgp_process,
            (struct bgp * bgp, afi_t afi, safi_t safi, struct bgp_dest *bn,
@@ -2347,7 +2348,7 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest,
                        if (BGP_PATH_HOLDDOWN(pi1))
                                continue;
                        if (pi1->peer != bgp->peer_self)
-                               if (pi1->peer->status != Established)
+                               if (!peer_established(pi1->peer))
                                        continue;
 
                        new_select = pi1;
@@ -2432,7 +2433,7 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest,
 
                if (pi->peer && pi->peer != bgp->peer_self
                    && !CHECK_FLAG(pi->peer->sflags, PEER_STATUS_NSF_WAIT))
-                       if (pi->peer->status != Established) {
+                       if (!peer_established(pi->peer)) {
 
                                if (debug)
                                        zlog_debug(
@@ -2502,7 +2503,7 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest,
                        if (pi->peer && pi->peer != bgp->peer_self
                            && !CHECK_FLAG(pi->peer->sflags,
                                           PEER_STATUS_NSF_WAIT))
-                               if (pi->peer->status != Established)
+                               if (!peer_established(pi->peer))
                                        continue;
 
                        if (!bgp_path_info_nexthop_cmp(pi, new_select)) {
@@ -3141,6 +3142,14 @@ void bgp_process(struct bgp *bgp, struct bgp_dest *dest, afi_t afi, safi_t safi)
                return;
        }
 
+       if (CHECK_FLAG(dest->flags, BGP_NODE_SOFT_RECONFIG)) {
+               if (BGP_DEBUG(update, UPDATE_OUT))
+                       zlog_debug(
+                               "Soft reconfigure table in progress for route %p",
+                               dest);
+               return;
+       }
+
        if (wq == NULL)
                return;
 
@@ -3442,23 +3451,6 @@ struct bgp_path_info *info_make(int type, int sub_type, unsigned short instance,
        return new;
 }
 
-static void overlay_index_update(struct attr *attr,
-                                union gw_addr *gw_ip)
-{
-       if (!attr)
-               return;
-       if (gw_ip == NULL) {
-               struct bgp_route_evpn eo;
-
-               memset(&eo, 0, sizeof(eo));
-               bgp_attr_set_evpn_overlay(attr, &eo);
-       } else {
-               struct bgp_route_evpn eo = {.gw_ip = *gw_ip};
-
-               bgp_attr_set_evpn_overlay(attr, &eo);
-       }
-}
-
 static bool overlay_index_equal(afi_t afi, struct bgp_path_info *path,
                                union gw_addr *gw_ip)
 {
@@ -3641,6 +3633,11 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
        if (has_valid_label)
                assert(label != NULL);
 
+       /* Update overlay index of the attribute */
+       if (afi == AFI_L2VPN && evpn)
+               memcpy(&attr->evpn_overlay, evpn,
+                      sizeof(struct bgp_route_evpn));
+
        /* When peer's soft reconfiguration enabled.  Record input packet in
           Adj-RIBs-In.  */
        if (!soft_reconfig
@@ -3816,12 +3813,6 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
                goto filtered;
        }
 
-       /* Update Overlay Index */
-       if (afi == AFI_L2VPN) {
-               overlay_index_update(&new_attr,
-                                    evpn == NULL ? NULL : &evpn->gw_ip);
-       }
-
        /* The flag BGP_NODE_FIB_INSTALL_PENDING is for the following
         * condition :
         * Suppress fib is enabled
@@ -3856,10 +3847,7 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
                    && (!has_valid_label
                        || memcmp(&(bgp_path_info_extra_get(pi))->label, label,
                                  num_labels * sizeof(mpls_label_t))
-                                  == 0)
-                   && (overlay_index_equal(
-                              afi, pi,
-                              evpn == NULL ? NULL : &evpn->gw_ip))) {
+                                  == 0)) {
                        if (get_active_bdc_from_pi(pi, afi, safi)
                            && peer->sort == BGP_PEER_EBGP
                            && CHECK_FLAG(pi->flags, BGP_PATH_HISTORY)) {
@@ -3867,7 +3855,7 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
                                        bgp_debug_rdpfxpath2str(
                                                afi, safi, prd, p, label,
                                                num_labels, addpath_id ? 1 : 0,
-                                               addpath_id, pfx_buf,
+                                               addpath_id, evpn, pfx_buf,
                                                sizeof(pfx_buf));
                                        zlog_debug("%s rcvd %s", peer->host,
                                                   pfx_buf);
@@ -3893,7 +3881,7 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
                                        bgp_debug_rdpfxpath2str(
                                                afi, safi, prd, p, label,
                                                num_labels, addpath_id ? 1 : 0,
-                                               addpath_id, pfx_buf,
+                                               addpath_id, evpn, pfx_buf,
                                                sizeof(pfx_buf));
                                        zlog_debug(
                                                "%s rcvd %s...duplicate ignored",
@@ -3920,8 +3908,8 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
                        if (bgp_debug_update(peer, p, NULL, 1)) {
                                bgp_debug_rdpfxpath2str(
                                        afi, safi, prd, p, label, num_labels,
-                                       addpath_id ? 1 : 0, addpath_id, pfx_buf,
-                                       sizeof(pfx_buf));
+                                       addpath_id ? 1 : 0, addpath_id, evpn,
+                                       pfx_buf, sizeof(pfx_buf));
                                zlog_debug(
                                        "%s rcvd %s, flapped quicker than processing",
                                        peer->host, pfx_buf);
@@ -3934,7 +3922,7 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
                if (bgp_debug_update(peer, p, NULL, 1)) {
                        bgp_debug_rdpfxpath2str(afi, safi, prd, p, label,
                                                num_labels, addpath_id ? 1 : 0,
-                                               addpath_id, pfx_buf,
+                                               addpath_id, evpn, pfx_buf,
                                                sizeof(pfx_buf));
                        zlog_debug("%s rcvd %s", peer->host, pfx_buf);
                }
@@ -4207,8 +4195,8 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
                }
 
                bgp_debug_rdpfxpath2str(afi, safi, prd, p, label, num_labels,
-                                       addpath_id ? 1 : 0, addpath_id, pfx_buf,
-                                       sizeof(pfx_buf));
+                                       addpath_id ? 1 : 0, addpath_id, evpn,
+                                       pfx_buf, sizeof(pfx_buf));
                zlog_debug("%s rcvd %s", peer->host, pfx_buf);
        }
 
@@ -4239,11 +4227,6 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
                }
        }
 
-       /* Update Overlay Index */
-       if (afi == AFI_L2VPN) {
-               overlay_index_update(new->attr,
-                                    evpn == NULL ? NULL : &evpn->gw_ip);
-       }
        /* Nexthop reachability check. */
        if (((afi == AFI_IP || afi == AFI_IP6)
            && (safi == SAFI_UNICAST || safi == SAFI_LABELED_UNICAST))
@@ -4353,8 +4336,8 @@ filtered:
                }
 
                bgp_debug_rdpfxpath2str(afi, safi, prd, p, label, num_labels,
-                                       addpath_id ? 1 : 0, addpath_id, pfx_buf,
-                                       sizeof(pfx_buf));
+                                       addpath_id ? 1 : 0, addpath_id, evpn,
+                                       pfx_buf, sizeof(pfx_buf));
                zlog_debug("%s rcvd UPDATE about %s -- DENIED due to: %s",
                           peer->host, pfx_buf, reason);
        }
@@ -4438,8 +4421,8 @@ int bgp_withdraw(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
                        if (bgp_debug_update(peer, p, NULL, 1)) {
                                bgp_debug_rdpfxpath2str(
                                        afi, safi, prd, p, label, num_labels,
-                                       addpath_id ? 1 : 0, addpath_id, pfx_buf,
-                                       sizeof(pfx_buf));
+                                       addpath_id ? 1 : 0, addpath_id, NULL,
+                                       pfx_buf, sizeof(pfx_buf));
                                zlog_debug(
                                        "%s withdrawing route %s not in adj-in",
                                        peer->host, pfx_buf);
@@ -4458,8 +4441,8 @@ int bgp_withdraw(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
        /* Logging. */
        if (bgp_debug_update(peer, p, NULL, 1)) {
                bgp_debug_rdpfxpath2str(afi, safi, prd, p, label, num_labels,
-                                       addpath_id ? 1 : 0, addpath_id, pfx_buf,
-                                       sizeof(pfx_buf));
+                                       addpath_id ? 1 : 0, addpath_id, NULL,
+                                       pfx_buf, sizeof(pfx_buf));
                zlog_debug("%s rcvd UPDATE about %s -- withdrawn", peer->host,
                           pfx_buf);
        }
@@ -4479,8 +4462,8 @@ int bgp_withdraw(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
                }
        } else if (bgp_debug_update(peer, p, NULL, 1)) {
                bgp_debug_rdpfxpath2str(afi, safi, prd, p, label, num_labels,
-                                       addpath_id ? 1 : 0, addpath_id, pfx_buf,
-                                       sizeof(pfx_buf));
+                                       addpath_id ? 1 : 0, addpath_id, NULL,
+                                       pfx_buf, sizeof(pfx_buf));
                zlog_debug("%s Can't find the route %s", peer->host, pfx_buf);
        }
 
@@ -4524,7 +4507,7 @@ static int bgp_announce_route_timer_expired(struct thread *t)
        paf = THREAD_ARG(t);
        peer = paf->peer;
 
-       if (peer->status != Established)
+       if (!peer_established(peer))
                return 0;
 
        if (!peer->afc_nego[paf->afi][paf->safi])
@@ -4591,6 +4574,60 @@ void bgp_announce_route_all(struct peer *peer)
                bgp_announce_route(peer, afi, safi);
 }
 
+/* Flag or unflag bgp_dest to determine whether it should be treated by
+ * bgp_soft_reconfig_table_task.
+ * Flag if flag is true. Unflag if flag is false.
+ */
+static void bgp_soft_reconfig_table_flag(struct bgp_table *table, bool flag)
+{
+       struct bgp_dest *dest;
+       struct bgp_adj_in *ain;
+
+       if (!table)
+               return;
+
+       for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) {
+               for (ain = dest->adj_in; ain; ain = ain->next) {
+                       if (ain->peer != NULL)
+                               break;
+               }
+               if (flag && ain != NULL && ain->peer != NULL)
+                       SET_FLAG(dest->flags, BGP_NODE_SOFT_RECONFIG);
+               else
+                       UNSET_FLAG(dest->flags, BGP_NODE_SOFT_RECONFIG);
+       }
+}
+
+static int bgp_soft_reconfig_table_update(struct peer *peer,
+                                         struct bgp_dest *dest,
+                                         struct bgp_adj_in *ain, afi_t afi,
+                                         safi_t safi, struct prefix_rd *prd)
+{
+       struct bgp_path_info *pi;
+       uint32_t num_labels = 0;
+       mpls_label_t *label_pnt = NULL;
+       struct bgp_route_evpn evpn;
+
+       for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next)
+               if (pi->peer == peer)
+                       break;
+
+       if (pi && pi->extra)
+               num_labels = pi->extra->num_labels;
+       if (num_labels)
+               label_pnt = &pi->extra->label[0];
+       if (pi)
+               memcpy(&evpn, bgp_attr_get_evpn_overlay(pi->attr),
+                      sizeof(evpn));
+       else
+               memset(&evpn, 0, sizeof(evpn));
+
+       return bgp_update(peer, bgp_dest_get_prefix(dest), ain->addpath_rx_id,
+                         ain->attr, afi, safi, ZEBRA_ROUTE_BGP,
+                         BGP_ROUTE_NORMAL, prd, label_pnt, num_labels, 1,
+                         &evpn);
+}
+
 static void bgp_soft_reconfig_table(struct peer *peer, afi_t afi, safi_t safi,
                                    struct bgp_table *table,
                                    struct prefix_rd *prd)
@@ -4607,32 +4644,8 @@ static void bgp_soft_reconfig_table(struct peer *peer, afi_t afi, safi_t safi,
                        if (ain->peer != peer)
                                continue;
 
-                       struct bgp_path_info *pi;
-                       uint32_t num_labels = 0;
-                       mpls_label_t *label_pnt = NULL;
-                       struct bgp_route_evpn evpn;
-
-                       for (pi = bgp_dest_get_bgp_path_info(dest); pi;
-                            pi = pi->next)
-                               if (pi->peer == peer)
-                                       break;
-
-                       if (pi && pi->extra)
-                               num_labels = pi->extra->num_labels;
-                       if (num_labels)
-                               label_pnt = &pi->extra->label[0];
-                       if (pi)
-                               memcpy(&evpn,
-                                      bgp_attr_get_evpn_overlay(pi->attr),
-                                      sizeof(evpn));
-                       else
-                               memset(&evpn, 0, sizeof(evpn));
-
-                       ret = bgp_update(peer, bgp_dest_get_prefix(dest),
-                                        ain->addpath_rx_id, ain->attr, afi,
-                                        safi, ZEBRA_ROUTE_BGP,
-                                        BGP_ROUTE_NORMAL, prd, label_pnt,
-                                        num_labels, 1, &evpn);
+                       ret = bgp_soft_reconfig_table_update(peer, dest, ain,
+                                                            afi, safi, prd);
 
                        if (ret < 0) {
                                bgp_dest_unlock_node(dest);
@@ -4641,18 +4654,201 @@ static void bgp_soft_reconfig_table(struct peer *peer, afi_t afi, safi_t safi,
                }
 }
 
+/* Do soft reconfig table per bgp table.
+ * Walk on SOFT_RECONFIG_TASK_MAX_PREFIX bgp_dest,
+ * when BGP_NODE_SOFT_RECONFIG is set,
+ * reconfig bgp_dest for list of table->soft_reconfig_peers peers.
+ * Schedule a new thread to continue the job.
+ * Without splitting the full job into several part,
+ * vtysh waits for the job to finish before responding to a BGP command
+ */
+static int bgp_soft_reconfig_table_task(struct thread *thread)
+{
+       uint32_t iter, max_iter;
+       int ret;
+       struct bgp_dest *dest;
+       struct bgp_adj_in *ain;
+       struct peer *peer;
+       struct bgp_table *table;
+       struct prefix_rd *prd;
+       struct listnode *node, *nnode;
+
+       table = THREAD_ARG(thread);
+       prd = NULL;
+
+       max_iter = SOFT_RECONFIG_TASK_MAX_PREFIX;
+       if (table->soft_reconfig_init) {
+               /* first call of the function with a new srta structure.
+                * Don't do any treatment this time on nodes
+                * in order vtysh to respond quickly
+                */
+               max_iter = 0;
+       }
+
+       for (iter = 0, dest = bgp_table_top(table); (dest && iter < max_iter);
+            dest = bgp_route_next(dest)) {
+               if (!CHECK_FLAG(dest->flags, BGP_NODE_SOFT_RECONFIG))
+                       continue;
+
+               UNSET_FLAG(dest->flags, BGP_NODE_SOFT_RECONFIG);
+
+               for (ain = dest->adj_in; ain; ain = ain->next) {
+                       for (ALL_LIST_ELEMENTS(table->soft_reconfig_peers, node,
+                                              nnode, peer)) {
+                               if (ain->peer != peer)
+                                       continue;
+
+                               ret = bgp_soft_reconfig_table_update(
+                                       peer, dest, ain, table->afi,
+                                       table->safi, prd);
+                               iter++;
+
+                               if (ret < 0) {
+                                       bgp_dest_unlock_node(dest);
+                                       listnode_delete(
+                                               table->soft_reconfig_peers,
+                                               peer);
+                                       bgp_announce_route(peer, table->afi,
+                                                          table->safi);
+                                       if (list_isempty(
+                                                   table->soft_reconfig_peers)) {
+                                               list_delete(
+                                                       &table->soft_reconfig_peers);
+                                               bgp_soft_reconfig_table_flag(
+                                                       table, false);
+                                               return 0;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       /* we're either starting the initial iteration,
+        * or we're going to continue an ongoing iteration
+        */
+       if (dest || table->soft_reconfig_init) {
+               table->soft_reconfig_init = false;
+               thread_add_event(bm->master, bgp_soft_reconfig_table_task,
+                                table, 0, &table->soft_reconfig_thread);
+               return 0;
+       }
+       /* we're done, clean up the background iteration context info and
+       schedule route annoucement
+       */
+       for (ALL_LIST_ELEMENTS(table->soft_reconfig_peers, node, nnode, peer)) {
+               listnode_delete(table->soft_reconfig_peers, peer);
+               bgp_announce_route(peer, table->afi, table->safi);
+       }
+
+       list_delete(&table->soft_reconfig_peers);
+
+       return 0;
+}
+
+
+/* Cancel soft_reconfig_table task matching bgp instance, bgp_table
+ * and peer.
+ * - bgp cannot be NULL
+ * - if table and peer are NULL, cancel all threads within the bgp instance
+ * - if table is NULL and peer is not,
+ * remove peer in all threads within the bgp instance
+ * - if peer is NULL, cancel all threads matching table within the bgp instance
+ */
+void bgp_soft_reconfig_table_task_cancel(const struct bgp *bgp,
+                                        const struct bgp_table *table,
+                                        const struct peer *peer)
+{
+       struct peer *npeer;
+       struct listnode *node, *nnode;
+       int afi, safi;
+       struct bgp_table *ntable;
+
+       if (!bgp)
+               return;
+
+       FOREACH_AFI_SAFI (afi, safi) {
+               ntable = bgp->rib[afi][safi];
+               if (!ntable)
+                       continue;
+               if (table && table != ntable)
+                       continue;
+
+               for (ALL_LIST_ELEMENTS(ntable->soft_reconfig_peers, node, nnode,
+                                      npeer)) {
+                       if (peer && peer != npeer)
+                               continue;
+                       listnode_delete(ntable->soft_reconfig_peers, npeer);
+               }
+
+               if (!ntable->soft_reconfig_peers
+                   || !list_isempty(ntable->soft_reconfig_peers))
+                       continue;
+
+               list_delete(&ntable->soft_reconfig_peers);
+               bgp_soft_reconfig_table_flag(ntable, false);
+               BGP_TIMER_OFF(ntable->soft_reconfig_thread);
+       }
+}
+
 void bgp_soft_reconfig_in(struct peer *peer, afi_t afi, safi_t safi)
 {
        struct bgp_dest *dest;
        struct bgp_table *table;
+       struct listnode *node, *nnode;
+       struct peer *npeer;
+       struct peer_af *paf;
 
-       if (peer->status != Established)
+       if (!peer_established(peer))
                return;
 
        if ((safi != SAFI_MPLS_VPN) && (safi != SAFI_ENCAP)
-           && (safi != SAFI_EVPN))
-               bgp_soft_reconfig_table(peer, afi, safi, NULL, NULL);
-       else
+           && (safi != SAFI_EVPN)) {
+               table = peer->bgp->rib[afi][safi];
+               if (!table)
+                       return;
+
+               table->soft_reconfig_init = true;
+
+               if (!table->soft_reconfig_peers)
+                       table->soft_reconfig_peers = list_new();
+               npeer = NULL;
+               /* add peer to the table soft_reconfig_peers if not already
+                * there
+                */
+               for (ALL_LIST_ELEMENTS(table->soft_reconfig_peers, node, nnode,
+                                      npeer)) {
+                       if (peer == npeer)
+                               break;
+               }
+               if (peer != npeer)
+                       listnode_add(table->soft_reconfig_peers, peer);
+
+               /* (re)flag all bgp_dest in table. Existing soft_reconfig_in job
+                * on table would start back at the beginning.
+                */
+               bgp_soft_reconfig_table_flag(table, true);
+
+               if (!table->soft_reconfig_thread)
+                       thread_add_event(bm->master,
+                                        bgp_soft_reconfig_table_task, table, 0,
+                                        &table->soft_reconfig_thread);
+               /* Cancel bgp_announce_route_timer_expired threads.
+                * bgp_announce_route_timer_expired threads have been scheduled
+                * to announce routes as soon as the soft_reconfigure process
+                * finishes.
+                * In this case, soft_reconfigure is also scheduled by using
+                * a thread but is planned after the
+                * bgp_announce_route_timer_expired threads. It means that,
+                * without cancelling the threads, the route announcement task
+                * would run before the soft reconfiguration one. That would
+                * useless and would block vtysh during several seconds. Route
+                * announcements are rescheduled as soon as the soft_reconfigure
+                * process finishes.
+                */
+               paf = peer_af_find(peer, afi, safi);
+               if (paf)
+                       bgp_stop_announce_route_timer(paf);
+       } else
                for (dest = bgp_table_top(peer->bgp->rib[afi][safi]); dest;
                     dest = bgp_route_next(dest)) {
                        table = bgp_dest_get_bgp_table_info(dest);
@@ -4826,10 +5022,8 @@ static void bgp_clear_route_table(struct peer *peer, afi_t afi, safi_t safi,
                while (ain) {
                        ain_next = ain->next;
 
-                       if (ain->peer == peer) {
+                       if (ain->peer == peer)
                                bgp_adj_in_remove(dest, ain);
-                               bgp_dest_unlock_node(dest);
-                       }
 
                        ain = ain_next;
                }
@@ -4935,10 +5129,8 @@ void bgp_clear_adj_in(struct peer *peer, afi_t afi, safi_t safi)
                while (ain) {
                        ain_next = ain->next;
 
-                       if (ain->peer == peer) {
+                       if (ain->peer == peer)
                                bgp_adj_in_remove(dest, ain);
-                               bgp_dest_unlock_node(dest);
-                       }
 
                        ain = ain_next;
                }
@@ -5964,6 +6156,7 @@ void bgp_static_add(struct bgp *bgp)
        struct bgp_table *table;
        struct bgp_static *bgp_static;
 
+       SET_FLAG(bgp->flags, BGP_FLAG_FORCE_STATIC_PROCESS);
        FOREACH_AFI_SAFI (afi, safi)
                for (dest = bgp_table_top(bgp->route[afi][safi]); dest;
                     dest = bgp_route_next(dest)) {
@@ -5990,6 +6183,7 @@ void bgp_static_add(struct bgp *bgp)
                                        safi);
                        }
                }
+       UNSET_FLAG(bgp->flags, BGP_FLAG_FORCE_STATIC_PROCESS);
 }
 
 /* Called from bgp_delete().  Delete all static routes from the BGP
@@ -9647,6 +9841,11 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
                json_nexthop_global = json_object_new_object();
        }
 
+       if (safi == SAFI_EVPN) {
+               if (!json_paths)
+                       vty_out(vty, "  Route %pRN", bn);
+       }
+
        if (path->extra) {
                char tag_buf[30];
 
@@ -9658,12 +9857,8 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
                }
                if (safi == SAFI_EVPN) {
                        if (!json_paths) {
-                               vty_out(vty, "  Route %pFX",
-                                       (struct prefix_evpn *)
-                                               bgp_dest_get_prefix(bn));
                                if (tag_buf[0] != '\0')
                                        vty_out(vty, " VNI %s", tag_buf);
-                               vty_out(vty, "\n");
                        } else {
                                if (tag_buf[0])
                                        json_object_string_add(json_path, "VNI",
@@ -9710,6 +9905,27 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
                }
        }
 
+       if (safi == SAFI_EVPN
+           && attr->evpn_overlay.type == OVERLAY_INDEX_GATEWAY_IP) {
+               char gwip_buf[INET6_ADDRSTRLEN];
+
+               if (is_evpn_prefix_ipaddr_v4((struct prefix_evpn *)&bn->p))
+                       inet_ntop(AF_INET, &attr->evpn_overlay.gw_ip.ipv4,
+                                 gwip_buf, sizeof(gwip_buf));
+               else
+                       inet_ntop(AF_INET6, &attr->evpn_overlay.gw_ip.ipv6,
+                                 gwip_buf, sizeof(gwip_buf));
+
+               if (json_paths)
+                       json_object_string_add(json_path, "gatewayIP",
+                                              gwip_buf);
+               else
+                       vty_out(vty, " Gateway IP %s", gwip_buf);
+       }
+
+       if (safi == SAFI_EVPN)
+               vty_out(vty, "\n");
+
        /* Line1 display AS-path, Aggregator */
        if (attr->aspath) {
                if (json_paths) {
@@ -10569,13 +10785,13 @@ 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, uint8_t show_flags);
+                             safi_t safi, uint16_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, char *rd, int is_last,
                          unsigned long *output_cum, unsigned long *total_cum,
-                         unsigned long *json_header_depth, uint8_t show_flags,
+                         unsigned long *json_header_depth, uint16_t show_flags,
                          enum rpki_states rpki_target_state)
 {
        struct bgp_path_info *pi;
@@ -10994,7 +11210,7 @@ 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;
+       uint16_t show_flags = 0;
 
        show_msg = (!use_json && type == bgp_show_type_normal);
 
@@ -11036,7 +11252,7 @@ int bgp_show_table_rd(struct vty *vty, struct bgp *bgp, safi_t safi,
 }
 static int bgp_show(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
                    enum bgp_show_type type, void *output_arg,
-                   uint8_t show_flags, enum rpki_states rpki_target_state)
+                   uint16_t show_flags, enum rpki_states rpki_target_state)
 {
        struct bgp_table *table;
        unsigned long json_header_depth = 0;
@@ -11076,7 +11292,7 @@ static int bgp_show(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
 }
 
 static void bgp_show_all_instances_routes_vty(struct vty *vty, afi_t afi,
-                                             safi_t safi, uint8_t show_flags)
+                                             safi_t safi, uint16_t show_flags)
 {
        struct listnode *node, *nnode;
        struct bgp *bgp;
@@ -11582,7 +11798,7 @@ 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;
+       uint16_t show_flags = 0;
        int ret;
 
        if (uj)
@@ -11625,7 +11841,7 @@ 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;
+       uint16_t show_flags = 0;
 
        if (uj)
                SET_FLAG(show_flags, BGP_SHOW_OPT_JSON);
@@ -11705,7 +11921,7 @@ 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;
+       uint16_t show_flags = 0;
 
        if (uj) {
                argc--;
@@ -11909,7 +12125,7 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd,
        int exact_match = 0;
        struct bgp *bgp = NULL;
        int idx = 0;
-       uint8_t show_flags = 0;
+       uint16_t show_flags = 0;
 
        /* [<ipv4|ipv6> [all]] */
        if (all) {
@@ -12022,7 +12238,7 @@ DEFPY(show_ip_bgp_json, show_ip_bgp_json_cmd,
        char *prefix_version = NULL;
        char *bgp_community_alias = NULL;
        bool first = true;
-       uint8_t show_flags = 0;
+       uint16_t show_flags = 0;
        enum rpki_states rpki_target_state = RPKI_NOT_BEING_USED;
 
        if (uj) {
@@ -12343,7 +12559,7 @@ DEFPY (show_ip_bgp_instance_all,
        safi_t safi = SAFI_UNICAST;
        struct bgp *bgp = NULL;
        int idx = 0;
-       uint8_t show_flags = 0;
+       uint16_t show_flags = 0;
 
        if (uj) {
                argc--;
@@ -12368,7 +12584,7 @@ static int bgp_show_regexp(struct vty *vty, struct bgp *bgp, const char *regstr,
 {
        regex_t *regex;
        int rc;
-       uint8_t show_flags = 0;
+       uint16_t show_flags = 0;
 
        if (use_json)
                SET_FLAG(show_flags, BGP_SHOW_OPT_JSON);
@@ -12396,7 +12612,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;
+       uint16_t show_flags = 0;
 
        plist = prefix_list_lookup(afi, prefix_list_str);
        if (plist == NULL) {
@@ -12414,7 +12630,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;
+       uint16_t show_flags = 0;
 
        as_list = as_list_lookup(filter);
        if (as_list == NULL) {
@@ -12432,7 +12648,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;
+       uint16_t show_flags = 0;
 
        rmap = route_map_lookup_by_name(rmap_str);
        if (!rmap) {
@@ -12446,7 +12662,7 @@ static int bgp_show_route_map(struct vty *vty, struct bgp *bgp,
 
 static int bgp_show_community(struct vty *vty, struct bgp *bgp,
                              const char *comstr, int exact, afi_t afi,
-                             safi_t safi, uint8_t show_flags)
+                             safi_t safi, uint16_t show_flags)
 {
        struct community *com;
        int ret = 0;
@@ -12471,7 +12687,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;
+       uint16_t show_flags = 0;
 
        list = community_list_lookup(bgp_clist, com, 0, COMMUNITY_LIST_MASTER);
        if (list == NULL) {
@@ -12491,7 +12707,7 @@ static int bgp_show_prefix_longer(struct vty *vty, struct bgp *bgp,
 {
        int ret;
        struct prefix *p;
-       uint8_t show_flags = 0;
+       uint16_t show_flags = 0;
 
        p = prefix_new();
 
@@ -13284,7 +13500,7 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table,
               afi_t afi, safi_t safi, enum bgp_show_adj_route_type type,
               const char *rmap_name, json_object *json, json_object *json_ar,
               json_object *json_scode, json_object *json_ocode,
-              uint8_t show_flags, int *header1, int *header2, char *rd_str,
+              uint16_t show_flags, int *header1, int *header2, char *rd_str,
               unsigned long *output_count, unsigned long *filtered_count)
 {
        struct bgp_adj_in *ain;
@@ -13494,7 +13710,7 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table,
 
 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, uint8_t show_flags)
+                          const char *rmap_name, uint16_t show_flags)
 {
        struct bgp *bgp;
        struct bgp_table *table;
@@ -13685,7 +13901,7 @@ 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;
+       uint16_t show_flags = 0;
 
        if (uj)
                SET_FLAG(show_flags, BGP_SHOW_OPT_JSON);
@@ -13741,7 +13957,7 @@ DEFPY (show_ip_bgp_instance_neighbor_advertised_route,
        enum bgp_show_adj_route_type type = bgp_show_adj_route_advertised;
        int idx = 0;
        bool first = true;
-       uint8_t show_flags = 0;
+       uint16_t show_flags = 0;
 
        if (uj) {
                argc--;
@@ -13923,7 +14139,7 @@ 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;
+       uint16_t show_flags = 0;
 
        if (use_json)
                SET_FLAG(show_flags, BGP_SHOW_OPT_JSON);
@@ -13968,7 +14184,7 @@ 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;
+       uint16_t show_flags = 0;
 
        if (uj) {
                argc--;
index 6d6008ff554d99582e92ce9e18d80fb3db3df1aa..3e3b018e830bc42a97b74f075b7bde50efa319be 100644 (file)
@@ -591,6 +591,7 @@ DECLARE_HOOK(bgp_process,
 #define BGP_SHOW_OPT_ESTABLISHED (1 << 5)
 #define BGP_SHOW_OPT_FAILED (1 << 6)
 #define BGP_SHOW_OPT_DETAIL (1 << 7)
+#define BGP_SHOW_OPT_TERSE (1 << 8)
 
 /* Prototypes. */
 extern void bgp_rib_remove(struct bgp_dest *dest, struct bgp_path_info *pi,
@@ -603,6 +604,9 @@ extern void bgp_announce_route(struct peer *, afi_t, safi_t);
 extern void bgp_stop_announce_route_timer(struct peer_af *paf);
 extern void bgp_announce_route_all(struct peer *);
 extern void bgp_default_originate(struct peer *, afi_t, safi_t, int);
+extern void bgp_soft_reconfig_table_task_cancel(const struct bgp *bgp,
+                                               const struct bgp_table *table,
+                                               const struct peer *peer);
 extern void bgp_soft_reconfig_in(struct peer *, afi_t, safi_t);
 extern void bgp_clear_route(struct peer *, afi_t, safi_t);
 extern void bgp_clear_route_all(struct peer *);
index 7692bb7ffefdd394567b309a2be473034811794e..9a7b7b3cf29be3b22352233c46fc5df018c3809b 100644 (file)
@@ -1084,6 +1084,71 @@ static const struct route_map_rule_cmd route_match_evpn_rd_cmd = {
        route_match_rd_free
 };
 
+static enum route_map_cmd_result_t
+route_set_evpn_gateway_ip(void *rule, const struct prefix *prefix, void *object)
+{
+       struct ipaddr *gw_ip = rule;
+       struct bgp_path_info *path;
+       struct prefix_evpn *evp;
+
+       if (prefix->family != AF_EVPN)
+               return RMAP_OKAY;
+
+       evp = (struct prefix_evpn *)prefix;
+       if (evp->prefix.route_type != BGP_EVPN_IP_PREFIX_ROUTE)
+               return RMAP_OKAY;
+
+       if ((is_evpn_prefix_ipaddr_v4(evp) && IPADDRSZ(gw_ip) != 4)
+           || (is_evpn_prefix_ipaddr_v6(evp) && IPADDRSZ(gw_ip) != 16))
+               return RMAP_OKAY;
+
+       path = object;
+
+       /* Set gateway-ip value. */
+       path->attr->evpn_overlay.type = OVERLAY_INDEX_GATEWAY_IP;
+       memcpy(&path->attr->evpn_overlay.gw_ip, &gw_ip->ip.addr,
+              IPADDRSZ(gw_ip));
+
+       return RMAP_OKAY;
+}
+
+/*
+ * Route map `evpn gateway-ip' compile function.
+ * Given string is converted to struct ipaddr structure
+ */
+static void *route_set_evpn_gateway_ip_compile(const char *arg)
+{
+       struct ipaddr *gw_ip = NULL;
+       int ret;
+
+       gw_ip = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct ipaddr));
+
+       ret = str2ipaddr(arg, gw_ip);
+       if (ret < 0) {
+               XFREE(MTYPE_ROUTE_MAP_COMPILED, gw_ip);
+               return NULL;
+       }
+       return gw_ip;
+}
+
+/* Free route map's compiled `evpn gateway_ip' value. */
+static void route_set_evpn_gateway_ip_free(void *rule)
+{
+       struct ipaddr *gw_ip = rule;
+
+       XFREE(MTYPE_ROUTE_MAP_COMPILED, gw_ip);
+}
+
+/* Route map commands for set evpn gateway-ip ipv4. */
+struct route_map_rule_cmd route_set_evpn_gateway_ip_ipv4_cmd = {
+       "evpn gateway-ip ipv4", route_set_evpn_gateway_ip,
+       route_set_evpn_gateway_ip_compile, route_set_evpn_gateway_ip_free};
+
+/* Route map commands for set evpn gateway-ip ipv6. */
+struct route_map_rule_cmd route_set_evpn_gateway_ip_ipv6_cmd = {
+       "evpn gateway-ip ipv6", route_set_evpn_gateway_ip,
+       route_set_evpn_gateway_ip_compile, route_set_evpn_gateway_ip_free};
+
 /* Route map commands for VRF route leak with source vrf matching */
 static enum route_map_cmd_result_t
 route_match_vrl_source_vrf(void *rule, const struct prefix *prefix,
@@ -3452,7 +3517,7 @@ static void bgp_route_map_process_peer(const char *rmap_name,
            && (strcmp(rmap_name, filter->map[RMAP_IN].name) == 0)) {
                filter->map[RMAP_IN].map = map;
 
-               if (route_update && peer->status == Established) {
+               if (route_update && peer_established(peer)) {
                        if (CHECK_FLAG(peer->af_flags[afi][safi],
                                       PEER_FLAG_SOFT_RECONFIG)) {
                                if (bgp_debug_update(peer, NULL, NULL, 1))
@@ -3767,7 +3832,6 @@ static void bgp_route_map_process_update_cb(char *rmap_name)
                bgp_route_map_process_update(bgp, rmap_name, 1);
 
 #ifdef ENABLE_BGP_VNC
-               /* zlog_debug("%s: calling vnc_routemap_update", __func__); */
                vnc_routemap_update(bgp, __func__);
 #endif
        }
@@ -3807,12 +3871,14 @@ static void bgp_route_map_mark_update(const char *rmap_name)
                                                   BGP_POLICY_ROUTE_MAP,
                                                   rmap_name, 1, 1);
        } else {
-               for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp))
+               for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
                        bgp_route_map_process_update(bgp, rmap_name, 0);
 #ifdef ENABLE_BGP_VNC
-               zlog_debug("%s: calling vnc_routemap_update", __func__);
-               vnc_routemap_update(bgp, __func__);
+                       vnc_routemap_update(bgp, __func__);
 #endif
+               }
+
+               vpn_policy_routemap_event(rmap_name);
        }
 }
 
@@ -4066,6 +4132,148 @@ DEFUN_YANG (no_match_evpn_rd,
        return nb_cli_apply_changes(vty, NULL);
 }
 
+DEFUN_YANG (set_evpn_gw_ip_ipv4,
+           set_evpn_gw_ip_ipv4_cmd,
+           "set evpn gateway-ip ipv4 A.B.C.D",
+           SET_STR
+           EVPN_HELP_STR
+           "Set gateway IP for prefix advertisement route\n"
+           "IPv4 address\n"
+           "Gateway IP address in IPv4 format\n")
+{
+       int ret;
+       union sockunion su;
+       const char *xpath =
+               "./set-action[action='frr-bgp-route-map:set-evpn-gateway-ip-ipv4']";
+       char xpath_value[XPATH_MAXLEN];
+
+       ret = str2sockunion(argv[4]->arg, &su);
+       if (ret < 0) {
+               vty_out(vty, "%% Malformed gateway IP\n");
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       if (su.sin.sin_addr.s_addr == 0
+           || IPV4_CLASS_DE(ntohl(su.sin.sin_addr.s_addr))) {
+               vty_out(vty,
+                       "%% Gateway IP cannot be 0.0.0.0, multicast or reserved\n");
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+
+       snprintf(xpath_value, sizeof(xpath_value),
+                "%s/rmap-set-action/frr-bgp-route-map:evpn-gateway-ip-ipv4",
+                xpath);
+
+       nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, argv[4]->arg);
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFUN_YANG (no_set_evpn_gw_ip_ipv4,
+           no_set_evpn_gw_ip_ipv4_cmd,
+           "no set evpn gateway-ip ipv4 A.B.C.D",
+           NO_STR
+           SET_STR
+           EVPN_HELP_STR
+           "Set gateway IP for prefix advertisement route\n"
+           "IPv4 address\n"
+           "Gateway IP address in IPv4 format\n")
+{
+       int ret;
+       union sockunion su;
+       const char *xpath =
+               "./set-action[action='frr-bgp-route-map:set-evpn-gateway-ip-ipv4']";
+
+       ret = str2sockunion(argv[5]->arg, &su);
+       if (ret < 0) {
+               vty_out(vty, "%% Malformed gateway IP\n");
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       if (su.sin.sin_addr.s_addr == 0
+           || IPV4_CLASS_DE(ntohl(su.sin.sin_addr.s_addr))) {
+               vty_out(vty,
+                       "%% Gateway IP cannot be 0.0.0.0, multicast or reserved\n");
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFUN_YANG (set_evpn_gw_ip_ipv6,
+           set_evpn_gw_ip_ipv6_cmd,
+           "set evpn gateway-ip ipv6 X:X::X:X",
+           SET_STR
+           EVPN_HELP_STR
+           "Set gateway IP for prefix advertisement route\n"
+           "IPv6 address\n"
+           "Gateway IP address in IPv6 format\n")
+{
+       int ret;
+       union sockunion su;
+       const char *xpath =
+               "./set-action[action='frr-bgp-route-map:set-evpn-gateway-ip-ipv6']";
+       char xpath_value[XPATH_MAXLEN];
+
+       ret = str2sockunion(argv[4]->arg, &su);
+       if (ret < 0) {
+               vty_out(vty, "%% Malformed gateway IP\n");
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       if (IN6_IS_ADDR_LINKLOCAL(&su.sin6.sin6_addr)
+           || IN6_IS_ADDR_MULTICAST(&su.sin6.sin6_addr)) {
+               vty_out(vty,
+                       "%% Gateway IP cannot be a linklocal or multicast address\n");
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+
+       snprintf(xpath_value, sizeof(xpath_value),
+                "%s/rmap-set-action/frr-bgp-route-map:evpn-gateway-ip-ipv6",
+                xpath);
+
+       nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, argv[4]->arg);
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFUN_YANG (no_set_evpn_gw_ip_ipv6,
+           no_set_evpn_gw_ip_ipv6_cmd,
+           "no set evpn gateway-ip ipv6 X:X::X:X",
+           NO_STR
+           SET_STR
+           EVPN_HELP_STR
+           "Set gateway IP for prefix advertisement route\n"
+           "IPv4 address\n"
+           "Gateway IP address in IPv4 format\n")
+{
+       int ret;
+       union sockunion su;
+       const char *xpath =
+               "./set-action[action='frr-bgp-route-map:set-evpn-gateway-ip-ipv6']";
+
+       ret = str2sockunion(argv[5]->arg, &su);
+       if (ret < 0) {
+               vty_out(vty, "%% Malformed gateway IP\n");
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       if (IN6_IS_ADDR_LINKLOCAL(&su.sin6.sin6_addr)
+           || IN6_IS_ADDR_MULTICAST(&su.sin6.sin6_addr)) {
+               vty_out(vty,
+                       "%% Gateway IP cannot be a linklocal or multicast address\n");
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
 DEFPY_YANG(match_vrl_source_vrf,
       match_vrl_source_vrf_cmd,
       "match source-vrf NAME$vrf_name",
@@ -6123,6 +6331,8 @@ void bgp_route_map_init(void)
        route_map_install_match(&route_match_evpn_default_route_cmd);
        route_map_install_match(&route_match_vrl_source_vrf_cmd);
 
+       route_map_install_set(&route_set_evpn_gateway_ip_ipv4_cmd);
+       route_map_install_set(&route_set_evpn_gateway_ip_ipv6_cmd);
        route_map_install_set(&route_set_table_id_cmd);
        route_map_install_set(&route_set_srte_color_cmd);
        route_map_install_set(&route_set_ip_nexthop_cmd);
@@ -6166,6 +6376,10 @@ void bgp_route_map_init(void)
        install_element(RMAP_NODE, &no_match_evpn_rd_cmd);
        install_element(RMAP_NODE, &match_evpn_default_route_cmd);
        install_element(RMAP_NODE, &no_match_evpn_default_route_cmd);
+       install_element(RMAP_NODE, &set_evpn_gw_ip_ipv4_cmd);
+       install_element(RMAP_NODE, &no_set_evpn_gw_ip_ipv4_cmd);
+       install_element(RMAP_NODE, &set_evpn_gw_ip_ipv6_cmd);
+       install_element(RMAP_NODE, &no_set_evpn_gw_ip_ipv6_cmd);
        install_element(RMAP_NODE, &match_vrl_source_vrf_cmd);
        install_element(RMAP_NODE, &no_match_vrl_source_vrf_cmd);
 
index b165c5d0eebf13a9f34e068d8a26d357b79f4c05..1254591b87d26b5694f8db6b501591cc76e51522 100644 (file)
@@ -371,6 +371,20 @@ const struct frr_yang_module_info frr_bgp_route_map_info = {
                                .destroy = lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_two_octet_as_specific_destroy,
                        }
                },
+               {
+                       .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:evpn-gateway-ip-ipv4",
+                       .cbs = {
+                               .modify = lib_route_map_entry_set_action_rmap_set_action_evpn_gateway_ip_ipv4_modify,
+                               .destroy = lib_route_map_entry_set_action_rmap_set_action_evpn_gateway_ip_ipv4_destroy,
+                       }
+               },
+               {
+                       .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:evpn-gateway-ip-ipv6",
+                       .cbs = {
+                               .modify = lib_route_map_entry_set_action_rmap_set_action_evpn_gateway_ip_ipv6_modify,
+                               .destroy = lib_route_map_entry_set_action_rmap_set_action_evpn_gateway_ip_ipv6_destroy,
+                       }
+               },
                {
                        .xpath = NULL,
                },
index a15f521513a27b30437741d1759e5cf135cc5125..f0e492eb617da0de9af206d3dcf41c2ca58deb9b 100644 (file)
@@ -130,6 +130,14 @@ int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_bandwidth_mod
 int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_bandwidth_destroy(struct nb_cb_destroy_args *args);
 int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_two_octet_as_specific_modify(struct nb_cb_modify_args *args);
 int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_two_octet_as_specific_destroy(struct nb_cb_destroy_args *args);
+int lib_route_map_entry_set_action_rmap_set_action_evpn_gateway_ip_ipv4_modify(
+       struct nb_cb_modify_args *args);
+int lib_route_map_entry_set_action_rmap_set_action_evpn_gateway_ip_ipv4_destroy(
+       struct nb_cb_destroy_args *args);
+int lib_route_map_entry_set_action_rmap_set_action_evpn_gateway_ip_ipv6_modify(
+       struct nb_cb_modify_args *args);
+int lib_route_map_entry_set_action_rmap_set_action_evpn_gateway_ip_ipv6_destroy(
+       struct nb_cb_destroy_args *args);
 
 #ifdef __cplusplus
 }
index ff08c16a829231dfab0ec75201c1a3317253c6ec..e541d117bee8b48447d006642ac5dabf514f2be1 100644 (file)
@@ -2637,3 +2637,107 @@ lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_two_octet_as_spec
 {
        return lib_route_map_entry_set_destroy(args);
 }
+
+/*
+ * XPath:
+ * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:evpn-gateway-ip-ipv4
+ */
+int lib_route_map_entry_set_action_rmap_set_action_evpn_gateway_ip_ipv4_modify(
+       struct nb_cb_modify_args *args)
+{
+       struct routemap_hook_context *rhc;
+       const char *type;
+       int rv;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               /* Add configuration. */
+               rhc = nb_running_get_entry(args->dnode, NULL, true);
+               type = yang_dnode_get_string(args->dnode, NULL);
+
+               /* Set destroy information. */
+               rhc->rhc_shook = generic_set_delete;
+               rhc->rhc_rule = "evpn gateway-ip ipv4";
+               rhc->rhc_event = RMAP_EVENT_SET_DELETED;
+
+               rv = generic_set_add(rhc->rhc_rmi, "evpn gateway-ip ipv4", type,
+                                    args->errmsg, args->errmsg_len);
+               if (rv != CMD_SUCCESS) {
+                       rhc->rhc_shook = NULL;
+                       return NB_ERR_INCONSISTENCY;
+               }
+       }
+
+       return NB_OK;
+}
+
+int lib_route_map_entry_set_action_rmap_set_action_evpn_gateway_ip_ipv4_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               return lib_route_map_entry_set_destroy(args);
+       }
+
+       return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:evpn-gateway-ip-ipv6
+ */
+int lib_route_map_entry_set_action_rmap_set_action_evpn_gateway_ip_ipv6_modify(
+       struct nb_cb_modify_args *args)
+{
+       struct routemap_hook_context *rhc;
+       const char *type;
+       int rv;
+
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               /* Add configuration. */
+               rhc = nb_running_get_entry(args->dnode, NULL, true);
+               type = yang_dnode_get_string(args->dnode, NULL);
+
+               /* Set destroy information. */
+               rhc->rhc_shook = generic_set_delete;
+               rhc->rhc_rule = "evpn gateway-ip ipv6";
+               rhc->rhc_event = RMAP_EVENT_SET_DELETED;
+
+               rv = generic_set_add(rhc->rhc_rmi, "evpn gateway-ip ipv6", type,
+                                    args->errmsg, args->errmsg_len);
+               if (rv != CMD_SUCCESS) {
+                       rhc->rhc_shook = NULL;
+                       return NB_ERR_INCONSISTENCY;
+               }
+       }
+
+       return NB_OK;
+}
+
+int lib_route_map_entry_set_action_rmap_set_action_evpn_gateway_ip_ipv6_destroy(
+       struct nb_cb_destroy_args *args)
+{
+       switch (args->event) {
+       case NB_EV_VALIDATE:
+       case NB_EV_PREPARE:
+       case NB_EV_ABORT:
+               break;
+       case NB_EV_APPLY:
+               return lib_route_map_entry_set_destroy(args);
+       }
+
+       return NB_OK;
+}
index 61a6467ab647ef68a45ba0d817eed0c86b237a06..4baa730c8dacff6ca73e003e30f06583134e0817 100644 (file)
@@ -689,12 +689,12 @@ static struct bgp_path_info *bgp4PathAttrLookup(struct variable *v, oid name[],
                dest = bgp_node_lookup(bgp->rib[AFI_IP][SAFI_UNICAST],
                                       (struct prefix *)addr);
                if (dest) {
-                       bgp_dest_unlock_node(dest);
-
                        for (path = bgp_dest_get_bgp_path_info(dest); path;
                             path = path->next)
                                if (sockunion_same(&path->peer->su, &su))
                                        return path;
+
+                       bgp_dest_unlock_node(dest);
                }
        } else {
                offset = name + v->namelen;
index 68b460149c2c4f95d0097d0958702089a7ed83fe..8a5ed2442f716c2511bb46fa5cd307a80a69961f 100644 (file)
@@ -31,6 +31,7 @@
 #include "linklist.h"
 #include "bgpd.h"
 #include "bgp_advertise.h"
+#include "bgpd/bgp_trace.h"
 
 struct bgp_table {
        /* table belongs to this instance */
@@ -42,6 +43,13 @@ struct bgp_table {
 
        int lock;
 
+       /* soft_reconfig_table in progress */
+       bool soft_reconfig_init;
+       struct thread *soft_reconfig_thread;
+
+       /* list of peers on which soft_reconfig_table has to run */
+       struct list *soft_reconfig_peers;
+
        struct route_table *route_table;
        uint64_t version;
 };
@@ -96,7 +104,7 @@ struct bgp_node {
 
        mpls_label_t local_label;
 
-       uint8_t flags;
+       uint16_t flags;
 #define BGP_NODE_PROCESS_SCHEDULED     (1 << 0)
 #define BGP_NODE_USER_CLEAR             (1 << 1)
 #define BGP_NODE_LABEL_CHANGED          (1 << 2)
@@ -105,6 +113,7 @@ struct bgp_node {
 #define BGP_NODE_FIB_INSTALL_PENDING    (1 << 5)
 #define BGP_NODE_FIB_INSTALLED          (1 << 6)
 #define BGP_NODE_LABEL_REQUESTED        (1 << 7)
+#define BGP_NODE_SOFT_RECONFIG (1 << 8)
 
        struct bgp_addpath_node_data tx_addpath;
 
@@ -175,6 +184,7 @@ static inline struct bgp_dest *bgp_dest_parent_nolock(struct bgp_dest *dest)
  */
 static inline void bgp_dest_unlock_node(struct bgp_dest *dest)
 {
+       frrtrace(1, frr_bgp, bgp_dest_unlock, dest);
        bgp_delete_listnode(dest);
        route_unlock_node(bgp_dest_to_rnode(dest));
 }
@@ -248,6 +258,7 @@ bgp_node_lookup(const struct bgp_table *const table, const struct prefix *p)
  */
 static inline struct bgp_dest *bgp_dest_lock_node(struct bgp_dest *dest)
 {
+       frrtrace(1, frr_bgp, bgp_dest_lock, dest);
        struct route_node *rn = route_lock_node(bgp_dest_to_rnode(dest));
 
        return bgp_dest_from_rnode(rn);
index 2600eda42eb27083993f0377851e74536e8a14c9..b8545188a438400bceb6ae7ce18e7e1ff8fb161f 100644 (file)
@@ -1705,13 +1705,13 @@ int update_group_adjust_soloness(struct peer *peer, int set)
 
        if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
                peer_lonesoul_or_not(peer, set);
-               if (peer->status == Established)
+               if (peer_established(peer))
                        bgp_announce_route_all(peer);
        } else {
                group = peer->group;
                for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
                        peer_lonesoul_or_not(peer, set);
-                       if (peer->status == Established)
+                       if (peer_established(peer))
                                bgp_announce_route_all(peer);
                }
        }
@@ -1901,7 +1901,7 @@ void subgroup_trigger_write(struct update_subgroup *subgrp)
         * will trigger a write job on the I/O thread.
         */
        SUBGRP_FOREACH_PEER (subgrp, paf)
-               if (paf->peer->status == Established)
+               if (peer_established(paf->peer))
                        thread_add_timer_msec(
                                bm->master, bgp_generate_updgrp_packets,
                                paf->peer, 0,
index bb0c95e32feda647ffab3fcf2e05d47830f9e6a6..4dd7597e5f74af791d1a94a582a117d059b4cccd 100644 (file)
@@ -829,6 +829,7 @@ void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw)
                                struct bgp_path_info_extra tmp_pie;
 
                                tmp_attr = *pi->attr;
+                               tmp_attr.aspath = attr.aspath;
 
                                prep_for_rmap_apply(&tmp_pi, &tmp_pie, dest, pi,
                                                    pi->peer, &tmp_attr);
@@ -842,7 +843,6 @@ void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw)
                                        continue;
                                } else {
                                        new_attr = bgp_attr_intern(&tmp_attr);
-                                       new_attr->aspath = attr.aspath;
 
                                        subgroup_announce_reset_nhop(
                                                (peer_cap_enhe(peer, afi, safi)
@@ -883,7 +883,7 @@ void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw)
                /* If default route is present in the local RIB, advertise the
                 * route
                 */
-               if (dest != NULL) {
+               if (dest) {
                        for (pi = bgp_dest_get_bgp_path_info(dest); pi;
                             pi = pi->next) {
                                if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED))
@@ -895,6 +895,7 @@ void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw)
                                                        dest, subgrp, &attr,
                                                        pi);
                        }
+                       bgp_dest_unlock_node(dest);
                }
        } else {
                if (!CHECK_FLAG(subgrp->sflags,
@@ -907,7 +908,7 @@ void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw)
                         * clear adj_out for the 0.0.0.0/0 prefix in the BGP
                         * table.
                         */
-                       if (dest != NULL) {
+                       if (dest) {
                                /* Remove the adjacency for the previously
                                 * advertised default route
                                 */
@@ -923,6 +924,7 @@ void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw)
                                        /* Free allocated information.  */
                                        adj_free(adj);
                                }
+                               bgp_dest_unlock_node(dest);
                        }
 
                        /* Advertise the default route */
index 6418decd16a3d25df13b6e6a5193d72f78f5d01b..038ef4f79841279b17459fdb312df4272839484b 100644 (file)
@@ -862,6 +862,7 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp)
                        bgp_debug_rdpfxpath2str(afi, safi, prd, dest_p,
                                                label_pnt, num_labels,
                                                addpath_encode, addpath_tx_id,
+                                               &adv->baa->attr->evpn_overlay,
                                                pfx_buf, sizeof(pfx_buf));
                        zlog_debug("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s",
                                   subgrp->update_group->id, subgrp->id,
@@ -1031,7 +1032,7 @@ struct bpacket *subgroup_withdraw_packet(struct update_subgroup *subgrp)
 
                        bgp_debug_rdpfxpath2str(afi, safi, prd, dest_p, NULL, 0,
                                                addpath_encode, addpath_tx_id,
-                                               pfx_buf, sizeof(pfx_buf));
+                                               NULL, pfx_buf, sizeof(pfx_buf));
                        zlog_debug("u%" PRIu64 ":s%" PRIu64" send UPDATE %s -- unreachable",
                                   subgrp->update_group->id, subgrp->id,
                                   pfx_buf);
index 2feba00806b442f52f37ade24d8f11fb2e2a3914..de4f5a59b646a22879b2037143dce70a00a6ea41 100644 (file)
@@ -10425,7 +10425,7 @@ DEFUN (show_bgp_vrfs,
                        if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE))
                                continue;
                        peers_cfg++;
-                       if (peer->status == Established)
+                       if (peer_established(peer))
                                peers_estb++;
                }
 
@@ -10794,8 +10794,7 @@ static void bgp_show_peer_reset(struct vty * vty, struct peer *peer,
 static inline bool bgp_has_peer_failed(struct peer *peer, afi_t afi,
                                       safi_t safi)
 {
-       return ((peer->status != Established) ||
-               !peer->afc_recv[afi][safi]);
+       return ((!peer_established(peer)) || !peer->afc_recv[afi][safi]);
 }
 
 static void bgp_show_failed_summary(struct vty *vty, struct bgp *bgp,
@@ -10822,7 +10821,7 @@ static void bgp_show_failed_summary(struct vty *vty, struct bgp *bgp,
                                    peer->dropped);
                peer_uptime(peer->uptime, timebuf, BGP_UPTIME_LEN,
                            use_json, json_peer);
-               if (peer->status == Established)
+               if (peer_established(peer))
                        json_object_string_add(json_peer, "lastResetDueTo",
                                               "AFI/SAFI Not Negotiated");
                else
@@ -10845,7 +10844,7 @@ static void bgp_show_failed_summary(struct vty *vty, struct bgp *bgp,
                        peer->dropped,
                        peer_uptime(peer->uptime, timebuf,
                                    BGP_UPTIME_LEN, 0, NULL));
-               if (peer->status == Established)
+               if (peer_established(peer))
                        vty_out(vty, "  AFI/SAFI Not Negotiated\n");
                else
                        bgp_show_peer_reset(vty, peer, NULL,
@@ -10902,7 +10901,7 @@ static bool bgp_show_summary_is_peer_filtered(struct peer *peer,
 /* Show BGP peer's summary information. */
 static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
                            struct peer *fpeer, int as_type, as_t as,
-                           uint8_t show_flags)
+                           uint16_t show_flags)
 {
        struct peer *peer;
        struct listnode *node, *nnode;
@@ -10911,6 +10910,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
        char neighbor_buf[VTY_BUFSIZ];
        int neighbor_col_default_width = 16;
        int len, failed_count = 0;
+       unsigned int filtered_count = 0;
        int max_neighbor_width = 0;
        int pfx_rcd_safi;
        json_object *json = NULL;
@@ -10923,6 +10923,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
        bool show_established =
                CHECK_FLAG(show_flags, BGP_SHOW_OPT_ESTABLISHED);
        bool show_wide = CHECK_FLAG(show_flags, BGP_SHOW_OPT_WIDE);
+       bool show_terse = CHECK_FLAG(show_flags, BGP_SHOW_OPT_TERSE);
 
        /* labeled-unicast routes are installed in the unicast table so in order
         * to
@@ -10940,6 +10941,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
                for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
                        if (bgp_show_summary_is_peer_filtered(peer, fpeer,
                                                              as_type, as)) {
+                               filtered_count++;
                                count++;
                                continue;
                        }
@@ -10965,6 +10967,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
                for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
                        if (bgp_show_summary_is_peer_filtered(peer, fpeer,
                                                              as_type, as)) {
+                               filtered_count++;
                                count++;
                                continue;
                        }
@@ -11019,12 +11022,12 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
                        json_object_free(json);
                } else {
                        vty_out(vty, "%% No failed BGP neighbors found\n");
-                       vty_out(vty, "\nTotal number of neighbors %d\n", count);
                }
                return CMD_SUCCESS;
        }
 
        count = 0;              /* Reset the value as its used again */
+       filtered_count = 0;
        for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
                if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE))
                        continue;
@@ -11181,63 +11184,75 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
                                        json_object_boolean_true_add(
                                                json, "dampeningEnabled");
                        } else {
-                               if (bgp_maxmed_onstartup_configured(bgp)
-                                   && bgp->maxmed_active)
-                                       vty_out(vty,
-                                               "Max-med on-startup active\n");
-                               if (bgp->v_maxmed_admin)
-                                       vty_out(vty,
-                                               "Max-med administrative active\n");
+                               if (!show_terse) {
+                                       if (bgp_maxmed_onstartup_configured(bgp)
+                                           && bgp->maxmed_active)
+                                               vty_out(vty,
+                                                       "Max-med on-startup active\n");
+                                       if (bgp->v_maxmed_admin)
+                                               vty_out(vty,
+                                                       "Max-med administrative active\n");
 
-                               vty_out(vty, "BGP table version %" PRIu64 "\n",
-                                       bgp_table_version(bgp->rib[afi][safi]));
+                                       vty_out(vty,
+                                               "BGP table version %" PRIu64
+                                               "\n",
+                                               bgp_table_version(
+                                                       bgp->rib[afi][safi]));
 
-                               ents = bgp_table_count(bgp->rib[afi][safi]);
-                               vty_out(vty,
-                                       "RIB entries %ld, using %s of memory\n",
-                                       ents,
-                                       mtype_memstr(
-                                               memstrbuf, sizeof(memstrbuf),
-                                               ents
-                                                       * sizeof(struct
-                                                                bgp_dest)));
-
-                               /* Peer related usage */
-                               ents = bgp->af_peer_count[afi][safi];
-                               vty_out(vty, "Peers %ld, using %s of memory\n",
-                                       ents,
-                                       mtype_memstr(
-                                               memstrbuf, sizeof(memstrbuf),
-                                               ents * sizeof(struct peer)));
+                                       ents = bgp_table_count(
+                                               bgp->rib[afi][safi]);
+                                       vty_out(vty,
+                                               "RIB entries %ld, using %s of memory\n",
+                                               ents,
+                                               mtype_memstr(
+                                                       memstrbuf,
+                                                       sizeof(memstrbuf),
+                                                       ents
+                                                               * sizeof(
+                                                                       struct
+                                                                       bgp_dest)));
 
-                               if ((ents = listcount(bgp->group)))
+                                       /* Peer related usage */
+                                       ents = bgp->af_peer_count[afi][safi];
                                        vty_out(vty,
-                                               "Peer groups %ld, using %s of memory\n",
+                                               "Peers %ld, using %s of memory\n",
                                                ents,
                                                mtype_memstr(
                                                        memstrbuf,
                                                        sizeof(memstrbuf),
-                                                       ents * sizeof(struct
-                                                                     peer_group)));
+                                                       ents
+                                                               * sizeof(
+                                                                       struct
+                                                                       peer)));
 
-                               if (CHECK_FLAG(bgp->af_flags[afi][safi],
-                                              BGP_CONFIG_DAMPENING))
-                                       vty_out(vty, "Dampening enabled.\n");
-                               vty_out(vty, "\n");
+                                       if ((ents = listcount(bgp->group)))
+                                               vty_out(vty,
+                                                       "Peer groups %ld, using %s of memory\n",
+                                                       ents,
+                                                       mtype_memstr(
+                                                               memstrbuf,
+                                                               sizeof(memstrbuf),
+                                                               ents
+                                                                       * sizeof(
+                                                                               struct
+                                                                               peer_group)));
+
+                                       if (CHECK_FLAG(bgp->af_flags[afi][safi],
+                                                      BGP_CONFIG_DAMPENING))
+                                               vty_out(vty,
+                                                       "Dampening enabled.\n");
+                               }
+                               if (show_failed) {
+                                       vty_out(vty, "\n");
 
-                               /* Subtract 8 here because 'Neighbor' is
-                                * 8 characters */
-                               vty_out(vty, "Neighbor");
-                               vty_out(vty, "%*s", max_neighbor_width - 8,
-                                       " ");
-                               if (show_failed)
+                                       /* Subtract 8 here because 'Neighbor' is
+                                        * 8 characters */
+                                       vty_out(vty, "Neighbor");
+                                       vty_out(vty, "%*s",
+                                               max_neighbor_width - 8, " ");
                                        vty_out(vty,
                                                BGP_SHOW_SUMMARY_HEADER_FAILED);
-                               else
-                                       vty_out(vty,
-                                               show_wide
-                                                       ? BGP_SHOW_SUMMARY_HEADER_ALL_WIDE
-                                                       : BGP_SHOW_SUMMARY_HEADER_ALL);
+                               }
                        }
                }
 
@@ -11251,11 +11266,11 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
 
                if (use_json) {
                        json_peer = NULL;
-
                        if (bgp_show_summary_is_peer_filtered(peer, fpeer,
-                                                             as_type, as))
+                                                             as_type, as)) {
+                               filtered_count++;
                                continue;
-
+                       }
                        if (show_failed &&
                            bgp_has_peer_failed(peer, afi, safi)) {
                                json_peer = json_object_new_object();
@@ -11263,8 +11278,10 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
                                                        json_peer, 0, use_json);
                        } else if (!show_failed) {
                                if (show_established
-                                   && bgp_has_peer_failed(peer, afi, safi))
+                                   && bgp_has_peer_failed(peer, afi, safi)) {
+                                       filtered_count++;
                                        continue;
+                               }
 
                                json_peer = json_object_new_object();
                                if (peer_dynamic_neighbor(peer)) {
@@ -11406,8 +11423,10 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
                                               json_peer);
                } else {
                        if (bgp_show_summary_is_peer_filtered(peer, fpeer,
-                                                             as_type, as))
+                                                             as_type, as)) {
+                               filtered_count++;
                                continue;
+                       }
                        if (show_failed &&
                            bgp_has_peer_failed(peer, afi, safi)) {
                                bgp_show_failed_summary(vty, bgp, peer, NULL,
@@ -11415,8 +11434,27 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
                                                        use_json);
                        } else if (!show_failed) {
                                if (show_established
-                                   && bgp_has_peer_failed(peer, afi, safi))
+                                   && bgp_has_peer_failed(peer, afi, safi)) {
+                                       filtered_count++;
                                        continue;
+                               }
+
+                               if ((count - filtered_count) == 1) {
+                                       /* display headline before the first
+                                        * neighbor line */
+                                       vty_out(vty, "\n");
+
+                                       /* Subtract 8 here because 'Neighbor' is
+                                        * 8 characters */
+                                       vty_out(vty, "Neighbor");
+                                       vty_out(vty, "%*s",
+                                               max_neighbor_width - 8, " ");
+                                       vty_out(vty,
+                                               show_wide
+                                                       ? BGP_SHOW_SUMMARY_HEADER_ALL_WIDE
+                                                       : BGP_SHOW_SUMMARY_HEADER_ALL);
+                               }
+
                                memset(dn_flag, '\0', sizeof(dn_flag));
                                if (peer_dynamic_neighbor(peer)) {
                                        dn_flag[0] = '*';
@@ -11472,7 +11510,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
                                                            BGP_UPTIME_LEN, 0,
                                                            NULL));
 
-                               if (peer->status == Established) {
+                               if (peer_established(peer)) {
                                        if (peer->afc_recv[afi][safi]) {
                                                if (CHECK_FLAG(
                                                            bgp->flags,
@@ -11541,6 +11579,8 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
        if (use_json) {
                json_object_object_add(json, "peers", json_peers);
                json_object_int_add(json, "failedPeers", failed_count);
+               json_object_int_add(json, "displayedPeers",
+                                   count - filtered_count);
                json_object_int_add(json, "totalPeers", count);
                json_object_int_add(json, "dynamicPeers", dn_count);
 
@@ -11551,9 +11591,22 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
                                             json, JSON_C_TO_STRING_PRETTY));
                json_object_free(json);
        } else {
-               if (count)
-                       vty_out(vty, "\nTotal number of neighbors %d\n", count);
-               else {
+               if (count) {
+                       if (filtered_count == count)
+                               vty_out(vty, "\n%% No matching neighbor\n");
+                       else {
+                               if (show_failed)
+                                       vty_out(vty, "\nDisplayed neighbors %d",
+                                               failed_count);
+                               else if (as_type != AS_UNSPECIFIED || as
+                                        || fpeer || show_established)
+                                       vty_out(vty, "\nDisplayed neighbors %d",
+                                               count - filtered_count);
+
+                               vty_out(vty, "\nTotal number of neighbors %d\n",
+                                       count);
+                       }
+               } else {
                        vty_out(vty, "No %s neighbor is configured\n",
                                get_afi_safi_str(afi, safi, false));
                }
@@ -11570,7 +11623,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
 
 static void bgp_show_summary_afi_safi(struct vty *vty, struct bgp *bgp, int afi,
                                      int safi, struct peer *fpeer, int as_type,
-                                     as_t as, uint8_t show_flags)
+                                     as_t as, uint16_t show_flags)
 {
        int is_first = 1;
        int afi_wildcard = (afi == AFI_MAX);
@@ -11608,10 +11661,12 @@ static void bgp_show_summary_afi_safi(struct vty *vty, struct bgp *bgp, int afi,
                                                                         safi,
                                                                         true));
                                        } else {
-                                               vty_out(vty, "\n%s Summary:\n",
+                                               vty_out(vty,
+                                                       "\n%s Summary (%s):\n",
                                                        get_afi_safi_str(afi,
                                                                         safi,
-                                                                        false));
+                                                                        false),
+                                                       bgp->name_pretty);
                                        }
                                }
                                bgp_show_summary(vty, bgp, afi, safi, fpeer,
@@ -11632,7 +11687,8 @@ static void bgp_show_summary_afi_safi(struct vty *vty, struct bgp *bgp, int afi,
                if (use_json)
                        vty_out(vty, "{}\n");
                else
-                       vty_out(vty, "%% No BGP neighbors found\n");
+                       vty_out(vty, "%% No BGP neighbors found in %s\n",
+                               bgp->name_pretty);
        }
 }
 
@@ -11640,7 +11696,7 @@ static void bgp_show_all_instances_summary_vty(struct vty *vty, afi_t afi,
                                               safi_t safi,
                                               const char *neighbor,
                                               int as_type, as_t as,
-                                              uint8_t show_flags)
+                                              uint16_t show_flags)
 {
        struct listnode *node, *nnode;
        struct bgp *bgp;
@@ -11664,11 +11720,6 @@ static void bgp_show_all_instances_summary_vty(struct vty *vty, afi_t afi,
                                (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
                                        ? VRF_DEFAULT_NAME
                                        : bgp->name);
-               } else {
-                       vty_out(vty, "\nInstance %s:\n",
-                               (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
-                                       ? VRF_DEFAULT_NAME
-                                       : bgp->name);
                }
                if (neighbor) {
                        fpeer = peer_lookup_in_view(vty, bgp, neighbor,
@@ -11688,7 +11739,7 @@ static void bgp_show_all_instances_summary_vty(struct vty *vty, afi_t afi,
 
 int bgp_show_summary_vty(struct vty *vty, const char *name, afi_t afi,
                         safi_t safi, const char *neighbor, int as_type,
-                        as_t as, uint8_t show_flags)
+                        as_t as, uint16_t show_flags)
 {
        struct bgp *bgp;
        bool use_json = CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON);
@@ -11750,7 +11801,7 @@ int bgp_show_summary_vty(struct vty *vty, const char *name, afi_t afi,
 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
-      "]] [all$all] summary [established|failed] [<neighbor <A.B.C.D|X:X::X:X|WORD>|remote-as <(1-4294967295)|internal|external>>] [wide] [json$uj]",
+      "]] [all$all] summary [established|failed] [<neighbor <A.B.C.D|X:X::X:X|WORD>|remote-as <(1-4294967295)|internal|external>>] [terse] [wide] [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"
@@ -11765,6 +11816,7 @@ DEFPY(show_ip_bgp_summary, show_ip_bgp_summary_cmd,
       "AS number\n"
       "Internal (iBGP) AS sessions\n"
       "External (eBGP) AS sessions\n"
+      "Shorten the information on BGP instances\n"
       "Increase table width for longer output\n" JSON_STR)
 {
        char *vrf = NULL;
@@ -11772,7 +11824,7 @@ DEFPY(show_ip_bgp_summary, show_ip_bgp_summary_cmd,
        safi_t safi = SAFI_MAX;
        as_t as = 0; /* 0 means AS filter not set */
        int as_type = AS_UNSPECIFIED;
-       uint8_t show_flags = 0;
+       uint16_t show_flags = 0;
 
        int idx = 0;
 
@@ -11807,6 +11859,9 @@ DEFPY(show_ip_bgp_summary, show_ip_bgp_summary_cmd,
                        as = (as_t)atoi(argv[idx + 1]->arg);
        }
 
+       if (argv_find(argv, argc, "terse", &idx))
+               SET_FLAG(show_flags, BGP_SHOW_OPT_TERSE);
+
        if (argv_find(argv, argc, "wide", &idx))
                SET_FLAG(show_flags, BGP_SHOW_OPT_WIDE);
 
@@ -11901,7 +11956,7 @@ static void bgp_show_neighnor_graceful_restart_rbit(struct vty *vty,
 
        if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_ADV)
            && (CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV))
-           && (p->status == Established)) {
+           && (peer_established(p))) {
 
                if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_BIT_RCV))
                        rbit_status = true;
@@ -11933,7 +11988,7 @@ static void bgp_show_neighbor_graceful_restart_remote_mode(struct vty *vty,
                vty_out(vty, "\n    Remote GR Mode: ");
 
        if (CHECK_FLAG(peer->cap, PEER_CAP_RESTART_ADV)
-           && (peer->status == Established)) {
+           && (peer_established(peer))) {
 
                if ((peer->nsf_af_count == 0)
                    && !CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV)) {
@@ -13121,7 +13176,7 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
                        json_neigh, "bgpState",
                        lookup_msg(bgp_status_msg, p->status, NULL));
 
-               if (p->status == Established) {
+               if (peer_established(p)) {
                        time_t uptime;
 
                        uptime = bgp_clock();
@@ -13239,7 +13294,7 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
                vty_out(vty, "  BGP state = %s",
                        lookup_msg(bgp_status_msg, p->status, NULL));
 
-               if (p->status == Established)
+               if (peer_established(p))
                        vty_out(vty, ", up for %8s",
                                peer_uptime(p->uptime, timebuf, BGP_UPTIME_LEN,
                                            0, NULL));
@@ -13289,7 +13344,7 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
                }
        }
        /* Capability. */
-       if (p->status == Established) {
+       if (peer_established(p)) {
                if (p->cap || p->afc_adv[AFI_IP][SAFI_UNICAST]
                    || p->afc_recv[AFI_IP][SAFI_UNICAST]
                    || p->afc_adv[AFI_IP][SAFI_MULTICAST]
@@ -14201,7 +14256,7 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
                        json_grace_send = json_object_new_object();
                        json_grace_recv = json_object_new_object();
 
-                       if ((p->status == Established)
+                       if ((peer_established(p))
                            && CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV)) {
                                FOREACH_AFI_SAFI (afi, safi) {
                                        if (CHECK_FLAG(p->af_sflags[afi][safi],
@@ -14254,7 +14309,7 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
                                json_neigh, "gracefulRestartInfo", json_grace);
                } else {
                        vty_out(vty, "  Graceful restart information:\n");
-                       if ((p->status == Established)
+                       if ((peer_established(p))
                            && CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV)) {
 
                                vty_out(vty, "    End-of-RIB send: ");
@@ -14653,7 +14708,7 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
        if (use_json) {
                json_object_int_add(json_neigh, "connectRetryTimer",
                                    p->v_connect);
-               if (p->status == Established && p->rtt)
+               if (peer_established(p) && p->rtt)
                        json_object_int_add(json_neigh, "estimatedRttInMsecs",
                                            p->rtt);
                if (p->t_start)
@@ -14690,7 +14745,7 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
        } else {
                vty_out(vty, "BGP Connect Retry Timer in Seconds: %d\n",
                        p->v_connect);
-               if (p->status == Established && p->rtt)
+               if (peer_established(p) && p->rtt)
                        vty_out(vty, "Estimated round trip time: %d ms\n",
                                p->rtt);
                if (p->t_start)
index 2531488d0de22472ecba47d110307e5a6a4e573f..04a47f6f62c5fd646a1a72bf120f128d4731bc7d 100644 (file)
@@ -186,7 +186,7 @@ int bgp_vty_find_and_parse_bgp(struct vty *vty, struct cmd_token **argv,
                               int argc, struct bgp **bgp, bool use_json);
 extern int bgp_show_summary_vty(struct vty *vty, const char *name, afi_t afi,
                                safi_t safi, const char *neighbor, int as_type,
-                               as_t as, uint8_t show_flags);
+                               as_t as, uint16_t show_flags);
 extern int bgp_clear_star_soft_in(const char *name, char *errmsg,
                                  size_t errmsg_len);
 extern int bgp_clear_star_soft_out(const char *name, char *errmsg,
index e3a795c6f15382cdf491038a1c2853c394819d1e..5d3176537bb2816fddaffc14000498035419afad 100644 (file)
@@ -155,7 +155,7 @@ static void bgp_start_interface_nbrs(struct bgp *bgp, struct interface *ifp)
 
        for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
                if (peer->conf_if && (strcmp(peer->conf_if, ifp->name) == 0)
-                   && peer->status != Established) {
+                   && !peer_established(peer)) {
                        if (peer_active(peer))
                                BGP_EVENT_ADD(peer, BGP_Stop);
                        BGP_EVENT_ADD(peer, BGP_Start);
@@ -1058,9 +1058,19 @@ static bool update_ipv4nh_for_route_install(int nh_othervrf, struct bgp *nh_bgp,
         * connected routes leaked into a VRF.
         */
        if (is_evpn) {
-               api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX;
-               SET_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_ONLINK);
-               api_nh->ifindex = nh_bgp->l3vni_svi_ifindex;
+
+               /*
+                * If the nexthop is EVPN overlay index gateway IP,
+                * treat the nexthop as NEXTHOP_TYPE_IPV4
+                * Else, mark the nexthop as onlink.
+                */
+               if (attr->evpn_overlay.type == OVERLAY_INDEX_GATEWAY_IP)
+                       api_nh->type = NEXTHOP_TYPE_IPV4;
+               else {
+                       api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX;
+                       SET_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_ONLINK);
+                       api_nh->ifindex = nh_bgp->l3vni_svi_ifindex;
+               }
        } else if (nh_othervrf &&
                 api_nh->gate.ipv4.s_addr == INADDR_ANY) {
                api_nh->type = NEXTHOP_TYPE_IFINDEX;
@@ -1085,9 +1095,19 @@ static bool update_ipv6nh_for_route_install(int nh_othervrf, struct bgp *nh_bgp,
        api_nh->vrf_id = nh_bgp->vrf_id;
 
        if (is_evpn) {
-               api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX;
-               SET_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_ONLINK);
-               api_nh->ifindex = nh_bgp->l3vni_svi_ifindex;
+
+               /*
+                * If the nexthop is EVPN overlay index gateway IP,
+                * treat the nexthop as NEXTHOP_TYPE_IPV4
+                * Else, mark the nexthop as onlink.
+                */
+               if (attr->evpn_overlay.type == OVERLAY_INDEX_GATEWAY_IP)
+                       api_nh->type = NEXTHOP_TYPE_IPV6;
+               else {
+                       api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX;
+                       SET_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_ONLINK);
+                       api_nh->ifindex = nh_bgp->l3vni_svi_ifindex;
+               }
        } else if (nh_othervrf) {
                if (IN6_IS_ADDR_UNSPECIFIED(nexthop)) {
                        api_nh->type = NEXTHOP_TYPE_IFINDEX;
@@ -1392,8 +1412,13 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
                        api_nh->label_num = 1;
                        api_nh->labels[0] = label;
                }
-               memcpy(&api_nh->rmac, &(mpinfo->attr->rmac),
-                      sizeof(struct ethaddr));
+
+               if (is_evpn
+                   && mpinfo->attr->evpn_overlay.type
+                              != OVERLAY_INDEX_GATEWAY_IP)
+                       memcpy(&api_nh->rmac, &(mpinfo->attr->rmac),
+                              sizeof(struct ethaddr));
+
                api_nh->weight = nh_weight;
 
                if (mpinfo->extra
@@ -2444,8 +2469,6 @@ static int bgp_zebra_route_notify_owner(int command, struct zclient *zclient,
        if (!dest)
                return -1;
 
-       bgp_dest_unlock_node(dest);
-
        switch (note) {
        case ZAPI_ROUTE_INSTALLED:
                new_select = NULL;
@@ -2474,6 +2497,8 @@ static int bgp_zebra_route_notify_owner(int command, struct zclient *zclient,
                                flog_err(EC_BGP_INVALID_ROUTE,
                                         "selected route %pRN not found",
                                         dest);
+
+                               bgp_dest_unlock_node(dest);
                                return -1;
                        }
                }
@@ -2504,6 +2529,8 @@ static int bgp_zebra_route_notify_owner(int command, struct zclient *zclient,
                          __func__, dest);
                break;
        }
+
+       bgp_dest_unlock_node(dest);
        return 0;
 }
 
@@ -2805,6 +2832,7 @@ static int bgp_zebra_process_local_vni(ZAPI_CALLBACK_ARGS)
        struct in_addr vtep_ip = {INADDR_ANY};
        vrf_id_t tenant_vrf_id = VRF_DEFAULT;
        struct in_addr mcast_grp = {INADDR_ANY};
+       ifindex_t svi_ifindex = 0;
 
        s = zclient->ibuf;
        vni = stream_getl(s);
@@ -2812,6 +2840,7 @@ static int bgp_zebra_process_local_vni(ZAPI_CALLBACK_ARGS)
                vtep_ip.s_addr = stream_get_ipv4(s);
                stream_get(&tenant_vrf_id, s, sizeof(vrf_id_t));
                mcast_grp.s_addr = stream_get_ipv4(s);
+               stream_get(&svi_ifindex, s, sizeof(ifindex_t));
        }
 
        bgp = bgp_lookup_by_vrf_id(vrf_id);
@@ -2819,16 +2848,17 @@ static int bgp_zebra_process_local_vni(ZAPI_CALLBACK_ARGS)
                return 0;
 
        if (BGP_DEBUG(zebra, ZEBRA))
-               zlog_debug("Rx VNI %s VRF %s VNI %u tenant-vrf %s",
-                          (cmd == ZEBRA_VNI_ADD) ? "add" : "del",
-                          vrf_id_to_name(vrf_id), vni,
-                          vrf_id_to_name(tenant_vrf_id));
+               zlog_debug(
+                       "Rx VNI %s VRF %s VNI %u tenant-vrf %s SVI ifindex %u",
+                       (cmd == ZEBRA_VNI_ADD) ? "add" : "del",
+                       vrf_id_to_name(vrf_id), vni,
+                       vrf_id_to_name(tenant_vrf_id), svi_ifindex);
 
        if (cmd == ZEBRA_VNI_ADD)
                return bgp_evpn_local_vni_add(
                        bgp, vni,
                        vtep_ip.s_addr != INADDR_ANY ? vtep_ip : bgp->router_id,
-                       tenant_vrf_id, mcast_grp);
+                       tenant_vrf_id, mcast_grp, svi_ifindex);
        else
                return bgp_evpn_local_vni_del(bgp, vni);
 }
index 33429d1d780139564492e3262c6cb775e2526004..49562e587467da16e402ae7634cc28841a20ea95 100644 (file)
@@ -892,6 +892,8 @@ int peer_af_delete(struct peer *peer, afi_t afi, safi_t safi)
                return -1;
 
        bgp = peer->bgp;
+       bgp_soft_reconfig_table_task_cancel(bgp, bgp->rib[afi][safi], peer);
+
        bgp_stop_announce_route_timer(af);
 
        if (PAF_SUBGRP(af)) {
@@ -2153,7 +2155,7 @@ static int peer_activate_af(struct peer *peer, afi_t afi, safi_t safi)
        if (!active && peer_active(peer)) {
                bgp_timer_set(peer);
        } else {
-               if (peer->status == Established) {
+               if (peer_established(peer)) {
                        if (CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_RCV)) {
                                peer->afc_adv[afi][safi] = 1;
                                bgp_capability_send(peer, afi, safi,
@@ -2276,7 +2278,7 @@ static bool non_peergroup_deactivate_af(struct peer *peer, afi_t afi,
                return true;
        }
 
-       if (peer->status == Established) {
+       if (peer_established(peer)) {
                if (CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_RCV)) {
                        peer->afc_adv[afi][safi] = 0;
                        peer->afc_nego[afi][safi] = 0;
@@ -2406,6 +2408,8 @@ int peer_delete(struct peer *peer)
        bgp = peer->bgp;
        accept_peer = CHECK_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER);
 
+       bgp_soft_reconfig_table_task_cancel(bgp, NULL, peer);
+
        bgp_keepalives_off(peer);
        bgp_reads_off(peer);
        bgp_writes_off(peer);
@@ -3572,6 +3576,8 @@ int bgp_delete(struct bgp *bgp)
 
        assert(bgp);
 
+       bgp_soft_reconfig_table_task_cancel(bgp, NULL, NULL);
+
        /* make sure we withdraw any exported routes */
        vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, AFI_IP, bgp_get_default(),
                           bgp);
@@ -4111,7 +4117,7 @@ void peer_change_action(struct peer *peer, afi_t afi, safi_t safi,
        if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
                return;
 
-       if (peer->status != Established)
+       if (!peer_established(peer))
                return;
 
        if (type == peer_change_reset) {
@@ -4603,7 +4609,7 @@ static int peer_af_flag_modify(struct peer *peer, afi_t afi, safi_t safi,
 
        /* Execute action when peer is established.  */
        if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)
-           && peer->status == Established) {
+           && peer_established(peer)) {
                if (!set && flag == PEER_FLAG_SOFT_RECONFIG)
                        bgp_clear_adj_in(peer, afi, safi);
                else {
@@ -4656,7 +4662,7 @@ static int peer_af_flag_modify(struct peer *peer, afi_t afi, safi_t safi,
                                  set != member_invert);
 
                        /* Execute flag action on peer-group member. */
-                       if (member->status == Established) {
+                       if (peer_established(member)) {
                                if (!set && flag == PEER_FLAG_SOFT_RECONFIG)
                                        bgp_clear_adj_in(member, afi, safi);
                                else {
@@ -5058,7 +5064,7 @@ int peer_default_originate_set(struct peer *peer, afi_t afi, safi_t safi,
        /* Check if handling a regular peer. */
        if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
                /* Update peer route announcements. */
-               if (peer->status == Established && peer->afc_nego[afi][safi]) {
+               if (peer_established(peer) && peer->afc_nego[afi][safi]) {
                        update_group_adjust_peer(peer_af_find(peer, afi, safi));
                        bgp_default_originate(peer, afi, safi, 0);
                        bgp_announce_route(peer, afi, safi);
@@ -5094,8 +5100,7 @@ int peer_default_originate_set(struct peer *peer, afi_t afi, safi_t safi,
                }
 
                /* Update peer route announcements. */
-               if (member->status == Established
-                   && member->afc_nego[afi][safi]) {
+               if (peer_established(member) && member->afc_nego[afi][safi]) {
                        update_group_adjust_peer(
                                peer_af_find(member, afi, safi));
                        bgp_default_originate(member, afi, safi, 0);
@@ -5135,7 +5140,7 @@ int peer_default_originate_unset(struct peer *peer, afi_t afi, safi_t safi)
        /* Check if handling a regular peer. */
        if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
                /* Update peer route announcements. */
-               if (peer->status == Established && peer->afc_nego[afi][safi]) {
+               if (peer_established(peer) && peer->afc_nego[afi][safi]) {
                        update_group_adjust_peer(peer_af_find(peer, afi, safi));
                        bgp_default_originate(peer, afi, safi, 1);
                        bgp_announce_route(peer, afi, safi);
@@ -5166,7 +5171,7 @@ int peer_default_originate_unset(struct peer *peer, afi_t afi, safi_t safi)
                member->default_rmap[afi][safi].map = NULL;
 
                /* Update peer route announcements. */
-               if (member->status == Established && member->afc_nego[afi][safi]) {
+               if (peer_established(member) && member->afc_nego[afi][safi]) {
                        update_group_adjust_peer(peer_af_find(member, afi, safi));
                        bgp_default_originate(member, afi, safi, 1);
                        bgp_announce_route(member, afi, safi);
@@ -5216,10 +5221,10 @@ static void peer_on_policy_change(struct peer *peer, afi_t afi, safi_t safi,
 {
        if (outbound) {
                update_group_adjust_peer(peer_af_find(peer, afi, safi));
-               if (peer->status == Established)
+               if (peer_established(peer))
                        bgp_announce_route(peer, afi, safi);
        } else {
-               if (peer->status != Established)
+               if (!peer_established(peer))
                        return;
 
                if (CHECK_FLAG(peer->af_flags[afi][safi],
@@ -5415,7 +5420,7 @@ int peer_timers_connect_set(struct peer *peer, uint32_t connect)
 
        /* Skip peer-group mechanics for regular peers. */
        if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
-               if (peer->status != Established) {
+               if (!peer_established(peer)) {
                        if (peer_active(peer))
                                BGP_EVENT_ADD(peer, BGP_Stop);
                        BGP_EVENT_ADD(peer, BGP_Start);
@@ -5436,7 +5441,7 @@ int peer_timers_connect_set(struct peer *peer, uint32_t connect)
                member->connect = connect;
                member->v_connect = connect;
 
-               if (member->status != Established) {
+               if (!peer_established(member)) {
                        if (peer_active(member))
                                BGP_EVENT_ADD(member, BGP_Stop);
                        BGP_EVENT_ADD(member, BGP_Start);
@@ -5469,7 +5474,7 @@ int peer_timers_connect_unset(struct peer *peer)
 
        /* Skip peer-group mechanics for regular peers. */
        if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
-               if (peer->status != Established) {
+               if (!peer_established(peer)) {
                        if (peer_active(peer))
                                BGP_EVENT_ADD(peer, BGP_Stop);
                        BGP_EVENT_ADD(peer, BGP_Start);
@@ -5490,7 +5495,7 @@ int peer_timers_connect_unset(struct peer *peer)
                member->connect = 0;
                member->v_connect = peer->bgp->default_connect_retry;
 
-               if (member->status != Established) {
+               if (!peer_established(member)) {
                        if (peer_active(member))
                                BGP_EVENT_ADD(member, BGP_Stop);
                        BGP_EVENT_ADD(member, BGP_Start);
@@ -5517,7 +5522,7 @@ int peer_advertise_interval_set(struct peer *peer, uint32_t routeadv)
        if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
                /* Update peer route announcements. */
                update_group_adjust_peer_afs(peer);
-               if (peer->status == Established)
+               if (peer_established(peer))
                        bgp_announce_route_all(peer);
 
                /* Skip peer-group mechanics for regular peers. */
@@ -5540,7 +5545,7 @@ int peer_advertise_interval_set(struct peer *peer, uint32_t routeadv)
 
                /* Update peer route announcements. */
                update_group_adjust_peer_afs(member);
-               if (member->status == Established)
+               if (peer_established(member))
                        bgp_announce_route_all(member);
        }
 
@@ -5574,7 +5579,7 @@ int peer_advertise_interval_unset(struct peer *peer)
        if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
                /* Update peer route announcements. */
                update_group_adjust_peer_afs(peer);
-               if (peer->status == Established)
+               if (peer_established(peer))
                        bgp_announce_route_all(peer);
 
                /* Skip peer-group mechanics for regular peers. */
@@ -5599,7 +5604,7 @@ int peer_advertise_interval_unset(struct peer *peer)
 
                /* Update peer route announcements. */
                update_group_adjust_peer_afs(member);
-               if (member->status == Established)
+               if (peer_established(member))
                        bgp_announce_route_all(member);
        }
 
@@ -7144,7 +7149,7 @@ int peer_maximum_prefix_set(struct peer *peer, afi_t afi, safi_t safi,
        /* Check if handling a regular peer. */
        if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
                /* Re-check if peer violates maximum-prefix. */
-               if ((peer->status == Established) && (peer->afc[afi][safi]))
+               if ((peer_established(peer)) && (peer->afc[afi][safi]))
                        bgp_maximum_prefix_overflow(peer, afi, safi, 1);
 
                /* Skip peer-group mechanics for regular peers. */
@@ -7181,7 +7186,7 @@ int peer_maximum_prefix_set(struct peer *peer, afi_t afi, safi_t safi,
                                   PEER_FLAG_MAX_PREFIX_WARNING);
 
                /* Re-check if peer violates maximum-prefix. */
-               if ((member->status == Established) && (member->afc[afi][safi]))
+               if ((peer_established(member)) && (member->afc[afi][safi]))
                        bgp_maximum_prefix_overflow(member, afi, safi, 1);
        }
 
@@ -7466,7 +7471,7 @@ int peer_clear_soft(struct peer *peer, afi_t afi, safi_t safi,
 {
        struct peer_af *paf;
 
-       if (peer->status != Established)
+       if (!peer_established(peer))
                return 0;
 
        if (!peer->afc[afi][safi])
@@ -7825,8 +7830,7 @@ void bgp_terminate(void)
 
        for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp))
                for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer))
-                       if (peer->status == Established
-                           || peer->status == OpenSent
+                       if (peer_established(peer) || peer->status == OpenSent
                            || peer->status == OpenConfirm)
                                bgp_notify_send(peer, BGP_NOTIFY_CEASE,
                                                BGP_NOTIFY_CEASE_PEER_UNCONFIG);
@@ -7887,7 +7891,8 @@ struct peer *peer_lookup_in_view(struct vty *vty, struct bgp *bgp,
                                        json_no, JSON_C_TO_STRING_PRETTY));
                        json_object_free(json_no);
                } else
-                       vty_out(vty, "No such neighbor in this view/vrf\n");
+                       vty_out(vty, "No such neighbor in %s\n",
+                               bgp->name_pretty);
                return NULL;
        }
 
index ffac20c218977e40801d7754dab0a312c2f9a1ea..776f4b0a21c8ed7a98e37fe8e594a0d1444f49d1 100644 (file)
@@ -510,16 +510,18 @@ struct bgp {
        uint16_t af_flags[AFI_MAX][SAFI_MAX];
 #define BGP_CONFIG_DAMPENING                           (1 << 0)
 /* l2vpn evpn flags - 1 << 0 is used for DAMPENNG */
-#define BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST          (1 << 1)
-#define BGP_L2VPN_EVPN_ADVERTISE_IPV6_UNICAST          (1 << 2)
-#define BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV4          (1 << 3)
-#define BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV6          (1 << 4)
+#define BGP_L2VPN_EVPN_ADV_IPV4_UNICAST (1 << 1)
+#define BGP_L2VPN_EVPN_ADV_IPV4_UNICAST_GW_IP (1 << 2)
+#define BGP_L2VPN_EVPN_ADV_IPV6_UNICAST (1 << 3)
+#define BGP_L2VPN_EVPN_ADV_IPV6_UNICAST_GW_IP (1 << 4)
+#define BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV4 (1 << 5)
+#define BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV6 (1 << 6)
 /* import/export between address families */
-#define BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT               (1 << 5)
-#define BGP_CONFIG_MPLSVPN_TO_VRF_IMPORT               (1 << 6)
+#define BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT (1 << 7)
+#define BGP_CONFIG_MPLSVPN_TO_VRF_IMPORT (1 << 8)
 /* vrf-route leaking flags */
-#define BGP_CONFIG_VRF_TO_VRF_IMPORT                   (1 << 7)
-#define BGP_CONFIG_VRF_TO_VRF_EXPORT                   (1 << 8)
+#define BGP_CONFIG_VRF_TO_VRF_IMPORT (1 << 9)
+#define BGP_CONFIG_VRF_TO_VRF_EXPORT (1 << 10)
 
        /* BGP per AF peer count */
        uint32_t af_peer_count[AFI_MAX][SAFI_MAX];
@@ -638,6 +640,14 @@ struct bgp {
        /* EVI hash table */
        struct hash *vnihash;
 
+       /*
+        * VNI hash table based on SVI ifindex as its key.
+        * We use SVI ifindex as key to lookup a VNI table for gateway IP
+        * overlay index recursive lookup.
+        * For this purpose, a hashtable is added which optimizes this lookup.
+        */
+       struct hash *vni_svi_hash;
+
        /* EVPN enable - advertise gateway macip routes */
        int advertise_gw_macip;
 
@@ -683,6 +693,15 @@ struct bgp {
        /* Hash table of EVPN nexthops maintained per-tenant-VRF */
        struct hash *evpn_nh_table;
 
+       /*
+        * Flag resolve_overlay_index is used for recursive resolution
+        * procedures for EVPN type-5 route's gateway IP overlay index.
+        * When this flag is set, we build remote-ip-hash for
+        * all L2VNIs and resolve overlay index nexthops using this hash.
+        * Overlay index nexthops remain unresolved if this flag is not set.
+        */
+       bool resolve_overlay_index;
+
        /* vrf flags */
        uint32_t vrf_flags;
 #define BGP_VRF_AUTO                        (1 << 0)
@@ -2328,11 +2347,9 @@ static inline char *timestamp_string(time_t ts)
        return ctime(&tbuf);
 }
 
-static inline int peer_established(struct peer *peer)
+static inline bool peer_established(struct peer *peer)
 {
-       if (peer->status == Established)
-               return 1;
-       return 0;
+       return peer->status == Established;
 }
 
 static inline int peer_dynamic_neighbor(struct peer *peer)
index 8c455c6ea5e88ee4834f49a0c48faf3775df5ae5..f89ef7b0d256e5d6c022c5127baf0c8355cd2610 100644 (file)
@@ -2179,7 +2179,7 @@ int rfapi_close(void *handle)
                vnc_zlog_debug_verbose("%s administrative close rfd=%p",
                                       __func__, rfd);
 
-               if (h && h->rfp_methods.close_cb) {
+               if (h->rfp_methods.close_cb) {
                        vnc_zlog_debug_verbose(
                                "%s calling close callback rfd=%p", __func__,
                                rfd);
index b2732a40b4857cc1fd698a4d6bddacfc622d1c05..51e051d68897a817878616c65819dd51d0932fc8 100644 (file)
@@ -2592,10 +2592,8 @@ static void rfapiCopyUnEncap2VPN(struct bgp_path_info *encap_bpi,
                 * instrumentation to debug segfault of 091127
                 */
                vnc_zlog_debug_verbose("%s: vpn_bpi=%p", __func__, vpn_bpi);
-               if (vpn_bpi) {
-                       vnc_zlog_debug_verbose("%s: vpn_bpi->extra=%p",
-                                              __func__, vpn_bpi->extra);
-               }
+               vnc_zlog_debug_verbose("%s: vpn_bpi->extra=%p", __func__,
+                                      vpn_bpi->extra);
 
                vpn_bpi->extra->vnc.import.un_family = AF_INET;
                vpn_bpi->extra->vnc.import.un.addr4 =
index 20265f4aadef96ff3dc37c789a82942d57ec653b..8f282c07909219afbfe07f36df5ba1cfb6aa4da5 100644 (file)
@@ -395,8 +395,11 @@ def setup(app):
     # printfrr extensions
     app.add_object_type("frrfmt", "frrfmt", parse_node=parse_frrfmt)
 
-    # css overrides for HTML theme
-    app.add_stylesheet("overrides.css")
+    if "add_css_file" in dir(app):
+        app.add_css_file("overrides.css")
+    else:
+        app.add_stylesheet("overrides.css")
+
     # load Pygments lexer for FRR config syntax
     #
     # NB: in Pygments 2.2+ this can be done with `load_lexer_from_file`, but we
index 8885dcfce3637abbd51856f0b5f892514c695bc4..ba03aa9045ffa4edca6d75347d5e141463977068 100644 (file)
@@ -312,6 +312,20 @@ Here's an example of launching ``zebra`` and ``bgpd`` inside ``gdb`` on router
           --gdb-breakpoints=nb_config_diff \
           all-protocol-startup
 
+Detecting Memleaks with Valgrind
+""""""""""""""""""""""""""""""""
+
+Topotest can automatically launch all daemons with ``valgrind`` to check for
+memleaks. This is enabled by specifying 1 or 2 CLI arguments.
+``--valgrind-memleaks`` will enable general memleak detection, and
+``--valgrind-extra`` enables extra functionality including generating a
+suppression file. The suppression file ``tools/valgrind.supp`` is used when
+memleak detection is enabled.
+
+.. code:: shell
+
+   pytest --valgrind-memleaks all-protocol-startup
+
 .. _topotests_docker:
 
 Running Tests with Docker
diff --git a/doc/requirements.txt b/doc/requirements.txt
new file mode 100644 (file)
index 0000000..debc7f1
--- /dev/null
@@ -0,0 +1 @@
+sphinx==4.0.2
index 2def835f0bbab8a9de7db5b65b89694a7c80e0cd..6a0249f3166859266edccfd574165dd9724202b9 100644 (file)
@@ -58,7 +58,17 @@ Basic Config Commands
 
 .. clicmd:: hostname HOSTNAME
 
-   Set hostname of the router.
+   Set hostname of the router. It is only for current ``vtysh``, it will not be
+   saved to any configuration file even with ``write file``.
+
+.. clicmd:: domainname DOMAINNAME
+
+   Set domainname of the router. It is only for current ``vtysh``, it will not
+   be saved to any configuration file even with ``write file``.
+
+.. clicmd:: domainname DOMAINNAME
+
+   Set domainname of the router.
 
 .. clicmd:: password PASSWORD
 
@@ -170,11 +180,17 @@ Basic Config Commands
    is used to start the daemon then this command is turned on by default
    and cannot be turned off and the [no] form of the command is dissallowed.
 
-.. clicmd:: log-filter WORD [DAEMON]
+.. clicmd:: log filtered-file [FILENAME [LEVEL]]
+
+   Configure a destination file for filtered logs with the
+   :clicmd:`log filter-text WORD` command.
+
+.. clicmd:: log filter-text WORD
 
    This command forces logs to be filtered on a specific string. A log message
    will only be printed if it matches on one of the filters in the log-filter
-   table. Can be daemon independent.
+   table.  The filter only applies to file logging targets configured with
+   :clicmd:`log filtered-file [FILENAME [LEVEL]]`.
 
    .. note::
 
@@ -183,10 +199,15 @@ Basic Config Commands
       Log filters prevent this but you should still expect a small performance
       hit due to filtering each of all those logs.
 
-.. clicmd:: log-filter clear [DAEMON]
+   .. note::
+
+      This setting is not saved to ``frr.conf`` and not shown in
+      :clicmd:`show running-config`.  It is intended for ephemeral debugging
+      purposes only.
+
+.. clicmd:: clear log filter-text
 
-   This command clears all current filters in the log-filter table. Can be
-   daemon independent.
+   This command clears all current filters in the log-filter table.
 
 
 .. clicmd:: log immediate-mode
index 0e01b8c3e404145d9d7e12c92754bee6c52e995c..7f23f7a633837bea8f72d9d6e2fff8e6acca2bd8 100644 (file)
@@ -442,7 +442,7 @@ Require policy on EBGP
 
       exit1# show bgp summary
 
-      IPv4 Unicast Summary:
+      IPv4 Unicast Summary (VRF default):
       BGP router identifier 10.10.10.1, local AS number 65001 vrf-id 0
       BGP table version 4
       RIB entries 7, using 1344 bytes of memory
@@ -2696,6 +2696,115 @@ remote VTEP.
 Note that you should not enable both the advertise-svi-ip and the advertise-default-gw
 at the same time.
 
+.. _bgp-evpn-overlay-index-gateway-ip:
+
+EVPN Overlay Index Gateway IP
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Draft https://tools.ietf.org/html/draft-ietf-bess-evpn-prefix-advertisement-11
+explains the use of overlay indexes for recursive route resolution for EVPN
+type-5 route.
+
+We support gateway IP overlay index.
+A gateway IP, advertised with EVPN prefix route, is used to find an EVPN MAC/IP
+route with its IP field same as the gateway IP. This MAC/IP entry provides the
+nexthop VTEP and the tunnel information required for the VxLAN encapsulation.
+
+Functionality:
+
+::
+
+  .      +--------+ BGP  +--------+ BGP  +--------+      +--------+
+    SN1  |        | IPv4 |        | EVPN |        |      |        |
+   ======+ Host1  +------+   PE1  +------+   PE2  +------+  Host2 +
+         |        |      |        |      |        |      |        |
+         +--------+      +--------+      +--------+      +--------+
+
+Consider above topology where prefix SN1 is connected behind host1. Host1
+advertises SN1 to PE1 over BGP IPv4 session. PE1 advertises SN1 to PE2 using
+EVPN type-5 route with host1 IP as the gateway IP. PE1 also advertises
+Host1 MAC/IP as type-2 route which is used to resolve host1 gateway IP.
+
+PE2 receives this type-5 route and imports it into the vrf based on route
+targets. BGP prefix imported into the vrf uses gateway IP as its BGP nexthop.
+This route is installed into zebra if following conditions are satisfied:
+1. Gateway IP nexthop is L3 reachable.
+2. PE2 has received EVPN type-2 route with IP field set to gateway IP.
+
+Topology requirements:
+1. This feature is supported for asymmetric routing model only. While
+   sending packets to SN1, ingress PE (PE2) performs routing and
+   egress PE (PE1) performs only bridging.
+2. This feature supports only tratitional(non vlan-aware) bridge model. Bridge
+   interface associated with L2VNI is an L3 interface. i.e., this interface is
+   configured with an address in the L2VNI subnet. Note that the gateway IP
+   should also have an address in the same subnet.
+3. As this feature works in asymmetric routing model, all L2VNIs and corresponding
+   VxLAN and bridge interfaces should be present at all the PEs.
+4. L3VNI configuration is required to generate and import EVPN type-5 routes.
+   L3VNI VxLAN and bridge interfaces also should be present.
+
+A PE can use one of the following two mechanisms to advertise an EVPN type-5
+route with gateway IP.
+
+1. CLI to add gateway IP while generating EVPN type-5 route from a BGP IPv4/IPv6
+prefix:
+
+.. index:: advertise <ipv4|ipv6> unicast [gateway-ip]
+.. clicmd:: [no] advertise <ipv4|ipv6> unicast [gateway-ip]
+
+When this CLI is configured for a BGP vrf under L2VPN EVPN address family, EVPN
+type-5 routes are generated for BGP prefixes in the vrf. Nexthop of the BGP
+prefix becomes the gateway IP of the corresponding type-5 route.
+
+If the above command is configured without the "gateway-ip" keyword, type-5
+routes are generated without overlay index.
+
+2. Add gateway IP to EVPN type-5 route using a route-map:
+
+.. index:: set evpn gateway-ip <ipv4|ipv6> <addr>
+.. clicmd:: [no] set evpn gateway-ip <ipv4|ipv6> <addr>
+
+When route-map with above set clause is applied as outbound policy in BGP, it
+will set the gateway-ip in EVPN type-5 NLRI.
+
+Example configuration:
+
+.. code-block:: frr
+
+   router bgp 100
+    neighbor 192.168.0.1 remote-as 101
+    !
+    address-family ipv4 l2vpn evpn
+     neighbor 192.168.0.1 route-map RMAP out
+    exit-address-family
+   !
+   route-map RMAP permit 10
+    set evpn gateway-ip 10.0.0.1
+    set evpn gateway-ip 10::1
+
+A PE that receives a type-5 route with gateway IP overlay index should have
+"enable-resolve-overlay-index" configuration enabled to recursively resolve the
+overlay index nexthop and install the prefix into zebra.
+
+.. index:: enable-resolve-overlay-index
+.. clicmd:: [no] enable-resolve-overlay-index
+
+Example configuration:
+
+.. code-block:: frr
+
+   router bgp 65001
+    bgp router-id 192.168.100.1
+    no bgp ebgp-requires-policy
+    neighbor 10.0.1.2 remote-as 65002
+    !
+    address-family l2vpn evpn
+     neighbor 10.0.1.2 activate
+     advertise-all-vni
+     enable-resolve-overlay-index
+    exit-address-family
+   !
+
 EVPN Multihoming
 ^^^^^^^^^^^^^^^^
 
@@ -3258,7 +3367,7 @@ structure is extended with :clicmd:`show bgp [afi] [safi]`.
 
       exit1# show ip bgp summary wide
 
-      IPv4 Unicast Summary:
+      IPv4 Unicast Summary (VRF default):
       BGP router identifier 192.168.100.1, local AS number 65534 vrf-id 0
       BGP table version 3
       RIB entries 5, using 920 bytes of memory
@@ -3310,6 +3419,13 @@ structure is extended with :clicmd:`show bgp [afi] [safi]`.
    address-family. The remote-as filter can be used in combination with the
    failed, established filters.
 
+.. clicmd:: show bgp [afi] [safi] [all] summary terse [json]
+
+   Shorten the output. Do not show the following information about the BGP
+   instances: the number of RIB entries, the table version and the used memory.
+   The ``terse`` option can be used in combination with the remote-as, neighbor,
+   failed and established filters, and with the ``wide`` option as well.
+
 .. clicmd:: show bgp [afi] [safi] [neighbor [PEER] [routes|advertised-routes|received-routes] [json]
 
    This command shows information on a specific BGP peer of the relevant
index e0aec404432ec0af2536056645c6065fce437bae..6db58b07c317e8283ececa77469e4561b2801b67 100644 (file)
@@ -386,16 +386,17 @@ def setup(app):
     # node later on
     app.add_object_type("clicmd", "clicmd", indextemplate="pair: %s; configuration command")
 
-    # css overrides for HTML theme
-    # Note sphinx version differences
-    sver = vparse(sphinx.__version__)
-
-    if sver < vparse("1.8.0"):
-        app.add_stylesheet("overrides.css")
-        app.add_javascript("overrides.js")
+    # I dont care how stupid this is
+    if "add_js_file" in dir(app):
+        app.add_js_file("overrides.js")
     else:
+        app.add_javascript("overrides.js")
+
+    if "add_css_file" in dir(app):
         app.add_css_file("overrides.css")
-        app.add_js_file("overrides.js")
+    else:
+        app.add_stylesheet("overrides.css")
+
 
     # load Pygments lexer for FRR config syntax
     #
index 2b478d334eb4ffc0b976886366c161b30528d46e..7c01b6f136bd073262ec68b3e7b1dabd1d0e361b 100644 (file)
@@ -18,13 +18,6 @@ OSPF6 router
 
    Set router's Router-ID.
 
-.. clicmd:: interface IFNAME area (0-4294967295)
-
-.. clicmd:: interface IFNAME area A.B.C.D
-
-   Bind interface to specified area, and start sending OSPF packets. `area` can
-   be specified as 0.
-
 .. clicmd:: timers throttle spf (0-600000) (0-600000) (0-600000)
 
    This command sets the initial `delay`, the `initial-holdtime`
@@ -77,19 +70,48 @@ OSPF6 router
    Use this command to control the maximum number of parallel routes that
    OSPFv3 can support. The default is 64.
 
+.. clicmd:: write-multiplier (1-100)
+
+   Use this command to tune the amount of work done in the packet read and
+   write threads before relinquishing control. The parameter is the number
+   of packets to process before returning. The default value of this parameter
+   is 20.
+
 
 .. _ospf6-area:
 
 OSPF6 area
 ==========
 
-Area support for OSPFv3 is not yet implemented.
+.. index:: [no] area A.B.C.D nssa
+.. clicmd:: [no] area A.B.C.D nssa
+
+NSSA Support in OSPFv3
+=======================
+
+The configuration of NSSA areas in OSPFv3 is supported using the CLI command
+area A.B.C.D nssa  in ospf6 router configuration mode.
+The following functionalities are implemented as per RFC 3101:
+
+1. Advertising Type-7 LSA into NSSA area when external route is redistributed
+   into OSPFv3
+2. Processing Type-7 LSA received from neighbor and installing route in the
+   route table
+3. Support for NSSA ABR functionality which is generating Type-5 LSA when
+   backbone area is configured. Currently translation od TYpe-7 LSA to Type-5 LSA
+   is enabled by default.
+4. Support for NSSA Translator functionality when there are multiple NSSA ABR
+   in an area
 
 .. _ospf6-interface:
 
 OSPF6 interface
 ===============
 
+.. clicmd:: ipv6 ospf6 area <A.B.C.D|(0-4294967295)>
+
+   Enable OSPFv3 on the interface and add it to the specified area.
+
 .. clicmd:: ipv6 ospf6 cost COST
 
    Sets interface's output cost. Default value depends on the interface
@@ -247,12 +269,12 @@ Example of ospf6d configured on one interface and area:
 .. code-block:: frr
 
    interface eth0
+    ipv6 ospf6 area 0.0.0.0
     ipv6 ospf6 instance-id 0
    !
    router ospf6
     ospf6 router-id 212.17.55.53
     area 0.0.0.0 range 2001:770:105:2::/64
-    interface eth0 area 0.0.0.0
    !
 
 
@@ -264,6 +286,7 @@ Larger example with policy and various options set:
    debug ospf6 neighbor state
    !
    interface fxp0
+    ipv6 ospf6 area 0.0.0.0
     ipv6 ospf6 cost 1
     ipv6 ospf6 hello-interval 10
     ipv6 ospf6 dead-interval 40
@@ -284,7 +307,6 @@ Larger example with policy and various options set:
    router ospf6
     router-id 255.1.1.1
     redistribute static route-map static-ospf6
-    interface fxp0 area 0.0.0.0
    !
    access-list access4 permit 127.0.0.1/32
    !
index 38c18e5526655b967733b9dd38792e5dfe77be22..c566059121791b8de9298d05b713faae2f3b6fc3 100644 (file)
@@ -285,7 +285,7 @@ called `intra-area routes`.
 
     Stub links may also be used as a way to describe links on which OSPF is
     *not* spoken, known as `passive interfaces`, see
-    :clicmd:`passive-interface INTERFACE`.
+    :clicmd:`ip ospf passive [A.B.C.D]`.
 
 - Network LSA
 
index 211d5bd9f3b8ed0116152993e58cb879ebc901dc..692ce8c1b2b225c66cb445d85ca7cffe54f55dfe 100644 (file)
@@ -147,17 +147,11 @@ To start OSPF process you have to specify the OSPF router.
    detail argument, all changes in adjacency status are shown. Without detail,
    only changes to full or regressions are shown.
 
-.. clicmd:: passive-interface INTERFACE
+.. clicmd:: passive-interface default
 
-
-   Do not speak OSPF interface on the
-   given interface, but do advertise the interface as a stub link in the
-   router-:abbr:`LSA (Link State Advertisement)` for this router. This
-   allows one to advertise addresses on such connected interfaces without
-   having to originate AS-External/Type-5 LSAs (which have global flooding
-   scope) - as would occur if connected addresses were redistributed into
-   OSPF (:ref:`redistribute-routes-to-ospf`). This is the only way to
-   advertise non-OSPF links into stub areas.
+   Make all interfaces that belong to this router passive by default. For the
+   description of passive interface look at :clicmd:`ip ospf passive [A.B.C.D]`.
+   Per-interface configuration takes precedence over the default value.
 
 .. clicmd:: timers throttle spf (0-600000) (0-600000) (0-600000)
 
@@ -305,6 +299,13 @@ To start OSPF process you have to specify the OSPF router.
    a specific destination. The upper limit may differ if you change the value
    of MULTIPATH_NUM during compilation. The default is MULTIPATH_NUM (64).
 
+.. clicmd:: write-multiplier (1-100)
+
+   Use this command to tune the amount of work done in the packet read and
+   write threads before relinquishing control. The parameter is the number
+   of packets to process before returning. The defult value of this parameter
+   is 20.
+
 .. _ospf-area:
 
 Areas
@@ -617,6 +618,16 @@ Interfaces
    Set number of seconds for InfTransDelay value. LSAs' age should be
    incremented by this value when transmitting. The default value is 1 second.
 
+.. clicmd:: ip ospf passive [A.B.C.D]
+
+   Do not speak OSPF on the interface, but do advertise the interface as a stub
+   link in the router-:abbr:`LSA (Link State Advertisement)` for this router.
+   This allows one to advertise addresses on such connected interfaces without
+   having to originate AS-External/Type-5 LSAs (which have global flooding
+   scope) - as would occur if connected addresses were redistributed into
+   OSPF (:ref:`redistribute-routes-to-ospf`). This is the only way to
+   advertise non-OSPF links into stub areas.
+
 .. clicmd:: ip ospf area (A.B.C.D|(0-4294967295))
 
 
@@ -653,12 +664,8 @@ Redistribution
    NSSA areas and are not redistributed at all into Stub areas, where external
    routes are not permitted.
 
-   Note that for connected routes, one may instead use the `passive-interface`
-   configuration.
-
-.. seealso::
-
-   clicmd:`passive-interface INTERFACE`.
+   Note that for connected routes, one may instead use the
+   :clicmd:`ip ospf passive [A.B.C.D]` configuration.
 
 .. clicmd:: default-information originate
 
@@ -1118,6 +1125,7 @@ of networks between the areas:
     ip ospf message-digest-key 1 md5 ABCDEFGHIJK
    !
    interface ppp0
+    ip ospf passive
    !
    interface br0
     ip ospf authentication message-digest
@@ -1126,7 +1134,6 @@ of networks between the areas:
    router ospf
     ospf router-id 192.168.0.1
     redistribute connected
-    passive interface ppp0
     network 192.168.0.0/24 area 0.0.0.0
     network 10.0.0.0/16 area 0.0.0.0
     network 192.168.1.0/24 area 0.0.0.1
index cb2b3eb69e30dfd7091819adb8fe99c723cc3af2..8fc36c0e5f10dca4e6b33366ea11c1b4b69d09d9 100644 (file)
@@ -55,5 +55,14 @@ RUN apk add \
                --no-cache \
                --allow-untrusted /pkgs/apk/*/*.apk \
        && rm -rf /pkgs
+
+# Own the config / PID files
+RUN mkdir -p /var/run/frr
+RUN chown -R frr:frr /etc/frr /var/run/frr
+
+# Simple init manager for reaping processes and forwarding signals
+ENTRYPOINT ["/sbin/tini", "--"]
+
+# Default CMD starts watchfrr
 COPY docker/alpine/docker-start /usr/lib/frr/docker-start
-CMD [ "/sbin/tini", "--", "/usr/lib/frr/docker-start" ]
+CMD ["/usr/lib/frr/docker-start"]
index 3f7737d3bf6efd1403aeeafff1c4e6351c46aaf3..c20df42e8e716a4a1dcc7a45fa2aa174a8e6260f 100755 (executable)
@@ -1,12 +1,4 @@
-#!/bin/sh
+#!/bin/ash
 
-set -e
-
-##
-# For volume mounts...
-##
-chown -R frr:frr /etc/frr || true
-/usr/lib/frr/frrinit.sh start
-
-# Sleep forever
-exec tail -f /dev/null
+source /usr/lib/frr/frrcommon.sh
+/usr/lib/frr/watchfrr $(daemon_list)
index 748b5345a16ae39df5b5c0a13f5a8adf0a56adca..303a33fe4ac16c7aae28cc62f1b2d0a45723953f 100644 (file)
@@ -39,5 +39,19 @@ COPY --from=centos-7-builder /rpmbuild/RPMS/ /pkgs/rpm/
 
 RUN yum install -y /pkgs/rpm/*/*.rpm \
     && rm -rf /pkgs
+
+# Own the config / PID files
+RUN mkdir -p /var/run/frr
+RUN chown -R frr:frr /etc/frr /var/run/frr
+
+# Add tini because no CentOS7 package
+ENV TINI_VERSION v0.19.0
+ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /sbin/tini
+RUN chmod +x /sbin/tini
+
+# Simple init manager for reaping processes and forwarding signals
+ENTRYPOINT ["/sbin/tini", "--"]
+
+# Default CMD starts watchfrr
 COPY docker/centos-7/docker-start /usr/lib/frr/docker-start
-CMD [ "/usr/lib/frr/docker-start" ]
+CMD ["/usr/lib/frr/docker-start"]
index a3913245b6c886f887ef3008bf47f995dca7cee7..d954142ab983cb3cf2078ea8198ac188358c64ef 100755 (executable)
@@ -1,12 +1,4 @@
-#!/bin/sh
+#!/bin/bash
 
-set -e
-
-##
-# Change owner for docker volume mount
-##
-chown -R frr:frr /etc/frr
-/usr/lib/frr/frrinit.sh start
-
-# Sleep forever
-exec tail -f /dev/null
+source /usr/lib/frr/frrcommon.sh
+/usr/lib/frr/watchfrr $(daemon_list)
index e273be055b1c17a449f06937aaea54fa39968afc..8a0c28e13bca013c24050412e5ac831581fbf57c 100644 (file)
@@ -40,5 +40,19 @@ COPY --from=centos-8-builder /rpmbuild/RPMS/ /pkgs/rpm/
 
 RUN yum install -y /pkgs/rpm/*/*.rpm \
     && rm -rf /pkgs
+
+# Own the config / PID files
+RUN mkdir -p /var/run/frr
+RUN chown -R frr:frr /etc/frr /var/run/frr
+
+# Add tini because no CentOS8 package
+ENV TINI_VERSION v0.19.0
+ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /sbin/tini
+RUN chmod +x /sbin/tini
+
+# Simple init manager for reaping processes and forwarding signals
+ENTRYPOINT ["/sbin/tini", "--"]
+
+# Default CMD starts watchfrr
 COPY docker/centos-8/docker-start /usr/lib/frr/docker-start
-CMD [ "/usr/lib/frr/docker-start" ]
+CMD ["/usr/lib/frr/docker-start"]
index 935b22209e45f3bcc4291e390386b190da83a768..d954142ab983cb3cf2078ea8198ac188358c64ef 100755 (executable)
@@ -1,9 +1,4 @@
-#!/bin/sh
+#!/bin/bash
 
-set -e
-
-chown -R frr:frr /etc/frr
-/usr/lib/frr/frrinit.sh start
-
-# Sleep forever
-exec tail -f /dev/null
+source /usr/lib/frr/frrcommon.sh
+/usr/lib/frr/watchfrr $(daemon_list)
index cc9217f10342a376a3040e33752652b4d1a705f4..7476e5fe3e7b5239f29b03055d473d78b0cf00be 100644 (file)
@@ -6,8 +6,8 @@ ENV APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=DontWarn
 
 RUN apt-get update && \
     apt-get install -y libpcre3-dev apt-transport-https ca-certificates curl wget logrotate \
-    libc-ares2 libjson-c3 vim procps libreadline7 gnupg2 lsb-release apt-utils && \
-    rm -rf /var/lib/apt/lists/*
+    libc-ares2 libjson-c3 vim procps libreadline7 gnupg2 lsb-release apt-utils \
+    tini && rm -rf /var/lib/apt/lists/*
 
 RUN curl -s https://deb.frrouting.org/frr/keys.asc | apt-key add -
 RUN echo deb https://deb.frrouting.org/frr $(lsb_release -s -c) frr-stable | tee -a /etc/apt/sources.list.d/frr.list
@@ -16,5 +16,13 @@ RUN apt-get update && \
     apt-get install -y frr frr-pythontools && \
     rm -rf /var/lib/apt/lists/*
 
-ADD docker-start /usr/sbin/docker-start
-CMD ["/usr/sbin/docker-start"]
+# Own the config / PID files
+RUN mkdir -p /var/run/frr
+RUN chown -R frr:frr /etc/frr /var/run/frr
+
+# Simple init manager for reaping processes and forwarding signals
+ENTRYPOINT ["/usr/bin/tini", "--"]
+
+# Default CMD starts watchfrr
+COPY docker-start /usr/lib/frr/docker-start
+CMD ["/usr/lib/frr/docker-start"]
index a0f31f5ac52217fd4ae5ca6524b497f3b8c8ca0c..d954142ab983cb3cf2078ea8198ac188358c64ef 100755 (executable)
@@ -1,12 +1,4 @@
-#!/bin/sh
+#!/bin/bash
 
-set -e
-
-##
-# For volume mounts...
-##
-chown -R frr:frr /etc/frr
-/etc/init.d/frr start
-
-# Sleep forever
-exec tail -f /dev/null
+source /usr/lib/frr/frrcommon.sh
+/usr/lib/frr/watchfrr $(daemon_list)
index 71fde305e6913961117da2c3b1c98c3e2183f58f..8b7557db1dc187be67b124897a06ebd986c2f092 100644 (file)
@@ -11,6 +11,7 @@ RUN apt update && \
       install-info build-essential libsystemd-dev libsnmp-dev perl \
       libcap-dev python2 libelf-dev \
       sudo gdb curl iputils-ping time \
+      libgrpc++-dev libgrpc-dev protobuf-compiler-grpc \
       mininet iproute2 iperf && \
       curl https://bootstrap.pypa.io/pip/2.7/get-pip.py --output /tmp/get-pip.py && \
       python2 /tmp/get-pip.py && \
@@ -57,6 +58,7 @@ RUN cd ~/frr && \
        --sbindir=/usr/lib/frr \
        --sysconfdir=/etc/frr \
        --enable-vtysh \
+       --enable-grpc \
        --enable-pimd \
        --enable-sharpd \
        --enable-multipath=64 \
index 3a978cae33369b24604527b05ce51900dc737d99..47de929fc3cb494f2b4ae9ca69446d42483c39f2 100644 (file)
@@ -919,6 +919,8 @@ eigrp_cli_init(void)
        install_element(EIGRP_NODE, &eigrp_neighbor_cmd);
        install_element(EIGRP_NODE, &eigrp_redistribute_source_metric_cmd);
 
+       vrf_cmd_init(NULL, &eigrpd_privs);
+
        install_node(&eigrp_interface_node);
        if_cmd_init();
 
index c1f5e49ecaf0296a2b3385b38853b8f2dd482ebd..ffda0f8643bc5932d8d12874ade83a61bac6ccc6 100644 (file)
@@ -270,7 +270,7 @@ const char *isis_adj_name(const struct isis_adjacency *adj)
 
        struct isis_dynhn *dyn;
 
-       dyn = dynhn_find_by_id(adj->sysid);
+       dyn = dynhn_find_by_id(adj->circuit->isis, adj->sysid);
        if (dyn)
                return dyn->hostname;
        else
@@ -401,7 +401,7 @@ void isis_adj_print(struct isis_adjacency *adj)
 
        if (!adj)
                return;
-       dyn = dynhn_find_by_id(adj->sysid);
+       dyn = dynhn_find_by_id(adj->circuit->isis, adj->sysid);
        if (dyn)
                zlog_debug("%s", dyn->hostname);
 
@@ -537,7 +537,7 @@ void isis_adj_print_vty(struct isis_adjacency *adj, struct vty *vty,
                vty_out(vty, "    SNPA: %s", snpa_print(adj->snpa));
                if (adj->circuit
                    && (adj->circuit->circ_type == CIRCUIT_T_BROADCAST)) {
-                       dyn = dynhn_find_by_id(adj->lanid);
+                       dyn = dynhn_find_by_id(adj->circuit->isis, adj->lanid);
                        if (dyn)
                                vty_out(vty, ", LAN id: %s.%02x", dyn->hostname,
                                        adj->lanid[ISIS_SYS_ID_LEN]);
index 4fa28a4ad91a2d92fc13c670e59c170245c682d3..bccb9065f4cdfefd9c5728689bb59ef3623023fe 100644 (file)
@@ -78,12 +78,14 @@ DEFINE_HOOK(isis_circuit_del_hook, (struct isis_circuit *circuit), (circuit));
 
 static void isis_circuit_enable(struct isis_circuit *circuit)
 {
-       struct isis_area *area;
+       struct isis_area *area = circuit->area;
        struct interface *ifp = circuit->interface;
 
-       area = isis_area_lookup(circuit->tag, ifp->vrf_id);
-       if (area)
-               isis_area_add_circuit(area, circuit);
+       if (!area) {
+               area = isis_area_lookup(circuit->tag, ifp->vrf_id);
+               if (area)
+                       isis_area_add_circuit(area, circuit);
+       }
 
        if (if_is_operative(ifp))
                isis_csm_state_change(IF_UP_FROM_Z, circuit, ifp);
@@ -1074,10 +1076,8 @@ static int isis_interface_config_write(struct vty *vty)
 
        isis = isis_lookup_by_vrfid(vrf->vrf_id);
 
-       if (isis == NULL) {
-               vty_out(vty, "ISIS routing instance not found");
+       if (isis == NULL)
                return 0;
-       }
 
        FOR_ALL_INTERFACES (vrf, ifp) {
                /* IF name */
index decd3e8922810f3947ff92d86575a094b9ed36c5..ade6e8222023a715c61640eea949d01e2a88d168 100644 (file)
 
 DEFINE_MTYPE_STATIC(ISISD, ISIS_DYNHN, "ISIS dyn hostname");
 
-extern struct host host;
-
-struct list *dyn_cache = NULL;
 static int dyn_cache_cleanup(struct thread *);
 
 void dyn_cache_init(struct isis *isis)
 {
-       if (dyn_cache == NULL)
-               dyn_cache = list_new();
+       isis->dyn_cache = list_new();
        if (!CHECK_FLAG(im->options, F_ISIS_UNIT_TEST))
                thread_add_timer(master, dyn_cache_cleanup, isis, 120,
                                 &isis->t_dync_clean);
-       return;
 }
 
-void dyn_cache_cleanup_all(void)
+void dyn_cache_finish(struct isis *isis)
 {
        struct listnode *node, *nnode;
        struct isis_dynhn *dyn;
 
-       for (ALL_LIST_ELEMENTS(dyn_cache, node, nnode, dyn)) {
-               list_delete_node(dyn_cache, node);
+       thread_cancel(&isis->t_dync_clean);
+
+       for (ALL_LIST_ELEMENTS(isis->dyn_cache, node, nnode, dyn)) {
+               list_delete_node(isis->dyn_cache, node);
                XFREE(MTYPE_ISIS_DYNHN, dyn);
        }
+
+       list_delete(&isis->dyn_cache);
 }
 
 static int dyn_cache_cleanup(struct thread *thread)
@@ -79,10 +78,10 @@ static int dyn_cache_cleanup(struct thread *thread)
 
        isis->t_dync_clean = NULL;
 
-       for (ALL_LIST_ELEMENTS(dyn_cache, node, nnode, dyn)) {
+       for (ALL_LIST_ELEMENTS(isis->dyn_cache, node, nnode, dyn)) {
                if ((now - dyn->refresh) < MAX_LSP_LIFETIME)
                        continue;
-               list_delete_node(dyn_cache, node);
+               list_delete_node(isis->dyn_cache, node);
                XFREE(MTYPE_ISIS_DYNHN, dyn);
        }
 
@@ -92,54 +91,55 @@ static int dyn_cache_cleanup(struct thread *thread)
        return ISIS_OK;
 }
 
-struct isis_dynhn *dynhn_find_by_id(const uint8_t *id)
+struct isis_dynhn *dynhn_find_by_id(struct isis *isis, const uint8_t *id)
 {
        struct listnode *node = NULL;
        struct isis_dynhn *dyn = NULL;
 
-       for (ALL_LIST_ELEMENTS_RO(dyn_cache, node, dyn))
+       for (ALL_LIST_ELEMENTS_RO(isis->dyn_cache, node, dyn))
                if (memcmp(dyn->id, id, ISIS_SYS_ID_LEN) == 0)
                        return dyn;
 
        return NULL;
 }
 
-struct isis_dynhn *dynhn_find_by_name(const char *hostname)
+struct isis_dynhn *dynhn_find_by_name(struct isis *isis, const char *hostname)
 {
        struct listnode *node = NULL;
        struct isis_dynhn *dyn = NULL;
 
-       for (ALL_LIST_ELEMENTS_RO(dyn_cache, node, dyn))
+       for (ALL_LIST_ELEMENTS_RO(isis->dyn_cache, node, dyn))
                if (strncmp(dyn->hostname, hostname, 255) == 0)
                        return dyn;
 
        return NULL;
 }
 
-void isis_dynhn_insert(const uint8_t *id, const char *hostname, int level)
+void isis_dynhn_insert(struct isis *isis, const uint8_t *id,
+                      const char *hostname, int level)
 {
        struct isis_dynhn *dyn;
 
-       dyn = dynhn_find_by_id(id);
+       dyn = dynhn_find_by_id(isis, id);
        if (!dyn) {
                dyn = XCALLOC(MTYPE_ISIS_DYNHN, sizeof(struct isis_dynhn));
                memcpy(dyn->id, id, ISIS_SYS_ID_LEN);
                dyn->level = level;
-               listnode_add(dyn_cache, dyn);
+               listnode_add(isis->dyn_cache, dyn);
        }
 
        snprintf(dyn->hostname, sizeof(dyn->hostname), "%s", hostname);
        dyn->refresh = time(NULL);
 }
 
-void isis_dynhn_remove(const uint8_t *id)
+void isis_dynhn_remove(struct isis *isis, const uint8_t *id)
 {
        struct isis_dynhn *dyn;
 
-       dyn = dynhn_find_by_id(id);
+       dyn = dynhn_find_by_id(isis, id);
        if (!dyn)
                return;
-       listnode_delete(dyn_cache, dyn);
+       listnode_delete(isis->dyn_cache, dyn);
        XFREE(MTYPE_ISIS_DYNHN, dyn);
 }
 
@@ -158,7 +158,7 @@ void dynhn_print_all(struct vty *vty, struct isis *isis)
        if (!isis->sysid_set)
                return;
        vty_out(vty, "Level  System ID      Dynamic Hostname\n");
-       for (ALL_LIST_ELEMENTS_RO(dyn_cache, node, dyn)) {
+       for (ALL_LIST_ELEMENTS_RO(isis->dyn_cache, node, dyn)) {
                vty_out(vty, "%-7d", dyn->level);
                vty_out(vty, "%-15s%-15s\n", sysid_print(dyn->id),
                        dyn->hostname);
@@ -169,14 +169,15 @@ void dynhn_print_all(struct vty *vty, struct isis *isis)
        return;
 }
 
-struct isis_dynhn *dynhn_snmp_next(const uint8_t *id, int level)
+struct isis_dynhn *dynhn_snmp_next(struct isis *isis, const uint8_t *id,
+                                  int level)
 {
        struct listnode *node = NULL;
        struct isis_dynhn *dyn = NULL;
        struct isis_dynhn *found_dyn = NULL;
        int res;
 
-       for (ALL_LIST_ELEMENTS_RO(dyn_cache, node, dyn)) {
+       for (ALL_LIST_ELEMENTS_RO(isis->dyn_cache, node, dyn)) {
                res = memcmp(dyn->id, id, ISIS_SYS_ID_LEN);
 
                if (res < 0)
index 8d25582e49c3fc635a59d241337de4de5c9853d4..afb8b51b1fbf66a4b825a1fd47e59323f6a19891 100644 (file)
@@ -31,14 +31,16 @@ struct isis_dynhn {
 };
 
 void dyn_cache_init(struct isis *isis);
-void dyn_cache_cleanup_all(void);
-void isis_dynhn_insert(const uint8_t *id, const char *hostname, int level);
-void isis_dynhn_remove(const uint8_t *id);
-struct isis_dynhn *dynhn_find_by_id(const uint8_t *id);
-struct isis_dynhn *dynhn_find_by_name(const char *hostname);
+void dyn_cache_finish(struct isis *isis);
+void isis_dynhn_insert(struct isis *isis, const uint8_t *id,
+                      const char *hostname, int level);
+void isis_dynhn_remove(struct isis *isis, const uint8_t *id);
+struct isis_dynhn *dynhn_find_by_id(struct isis *isis, const uint8_t *id);
+struct isis_dynhn *dynhn_find_by_name(struct isis *isis, const char *hostname);
 void dynhn_print_all(struct vty *vty, struct isis *isis);
 
 /* Snmp support */
-struct isis_dynhn *dynhn_snmp_next(const uint8_t *id, int level);
+struct isis_dynhn *dynhn_snmp_next(struct isis *isis, const uint8_t *id,
+                                  int level);
 
 #endif /* _ZEBRA_ISIS_DYNHN_H */
index 056e29e8de81c78e34a15604b986f0d5e1ae7638..814ba8fc2a130c4cd802f4e2bdff4da309989d8f 100644 (file)
@@ -533,11 +533,11 @@ static void lsp_update_data(struct isis_lsp *lsp, struct isis_lsp_hdr *hdr,
 
        if (area->dynhostname && lsp->tlvs->hostname
            && lsp->hdr.rem_lifetime) {
-               isis_dynhn_insert(lsp->hdr.lsp_id, lsp->tlvs->hostname,
-                                 (lsp->hdr.lsp_bits & LSPBIT_IST)
-                                                 == IS_LEVEL_1_AND_2
-                                         ? IS_LEVEL_2
-                                         : IS_LEVEL_1);
+               isis_dynhn_insert(
+                       area->isis, lsp->hdr.lsp_id, lsp->tlvs->hostname,
+                       (lsp->hdr.lsp_bits & LSPBIT_IST) == IS_LEVEL_1_AND_2
+                               ? IS_LEVEL_2
+                               : IS_LEVEL_1);
        }
 
        return;
@@ -700,7 +700,7 @@ void lspid_print(uint8_t *lsp_id, char *dest, size_t dest_len, char dynhost,
        char id[SYSID_STRLEN];
 
        if (dynhost)
-               dyn = dynhn_find_by_id(lsp_id);
+               dyn = dynhn_find_by_id(isis, lsp_id);
        else
                dyn = NULL;
 
index d3d081d37624c7cc5ec3e4b4b5634c6bd65bcb60..d49ad8485ec7bb2bc80ad3ebd1c4e1577bc2447d 100644 (file)
@@ -458,6 +458,7 @@ const char *print_sys_hostname(const uint8_t *sysid)
 {
        struct isis_dynhn *dyn;
        struct isis *isis = NULL;
+       struct listnode *node;
 
        if (!sysid)
                return "nullsysid";
@@ -467,9 +468,11 @@ const char *print_sys_hostname(const uint8_t *sysid)
        if (isis && !CHECK_FLAG(im->options, F_ISIS_UNIT_TEST))
                return cmd_hostname_get();
 
-       dyn = dynhn_find_by_id(sysid);
-       if (dyn)
-               return dyn->hostname;
+       for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) {
+               dyn = dynhn_find_by_id(isis, sysid);
+               if (dyn)
+                       return dyn->hostname;
+       }
 
        return sysid_print(sysid);
 }
index 755378a9b7ecde5ef1bd44e246dc14fb400bad56..f219632acf794c0f22d0ed64ffacd5cbdd14a76d 100644 (file)
@@ -315,7 +315,7 @@ void isis_notif_adj_state_change(const struct isis_adjacency *adj,
        struct yang_data *data;
        struct isis_circuit *circuit = adj->circuit;
        struct isis_area *area = circuit->area;
-       struct isis_dynhn *dyn = dynhn_find_by_id(adj->sysid);
+       struct isis_dynhn *dyn = dynhn_find_by_id(circuit->isis, adj->sysid);
 
        notif_prep_instance_hdr(xpath, area, "default", arguments);
        notif_prepr_iface_hdr(xpath, circuit, arguments);
index fa2f9a7669357fe98752fc8fc0553184636a159d..d530faa151856aeb4214da66652a4da1ddc5f1df 100644 (file)
@@ -1654,6 +1654,10 @@ static uint8_t *isis_snmp_find_router(struct variable *v, oid *name,
        oid *oid_idx;
        size_t oid_idx_len;
        size_t off = 0;
+       struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
+
+       if (isis == NULL)
+               return NULL;
 
        *write_method = NULL;
 
@@ -1687,7 +1691,7 @@ static uint8_t *isis_snmp_find_router(struct variable *v, oid *name,
 
                cmp_level = (int)oid_idx[ISIS_SYS_ID_LEN + 1];
 
-               dyn = dynhn_find_by_id(cmp_buf);
+               dyn = dynhn_find_by_id(isis, cmp_buf);
 
                if (dyn == NULL || dyn->level != cmp_level)
                        return NULL;
@@ -1739,7 +1743,7 @@ static uint8_t *isis_snmp_find_router(struct variable *v, oid *name,
                 */
                cmp_level = (int)(IS_LEVEL_2 + 1);
 
-       dyn = dynhn_snmp_next(cmp_buf, cmp_level);
+       dyn = dynhn_snmp_next(isis, cmp_buf, cmp_level);
 
        if (dyn == NULL)
                return NULL;
index a19fcc240f5a911a48e9a31fac26014bd6e544a0..2c1b6e932fed8feebf70cd42b2cd8a773afc6a5c 100644 (file)
@@ -187,7 +187,7 @@ DEFUN (show_lsp_flooding,
                vty_out(vty, "Area %s:\n",
                        area->area_tag ? area->area_tag : "null");
                if (lspid) {
-                       lsp = lsp_for_arg(head, lspid, isis);
+                       lsp = lsp_for_sysid(head, lspid, isis);
                        if (lsp)
                                lsp_print_flooding(vty, lsp, isis);
                        continue;
index 77b18f9cf7b67b20ea53142386d131364d6e6b4d..6c1308af0a90e887209da35b3cd6af82bcbba9b5 100644 (file)
@@ -229,6 +229,7 @@ void isis_finish(struct isis *isis)
 
        isis_redist_free(isis);
        list_delete(&isis->area_list);
+       dyn_cache_finish(isis);
        XFREE(MTYPE_ISIS, isis);
 }
 
@@ -402,7 +403,7 @@ struct isis_area *isis_area_create(const char *area_tag, const char *vrf_name)
                                continue;
 
                        circuit = ifp->info;
-                       if (circuit)
+                       if (circuit && strmatch(circuit->tag, area->area_tag))
                                isis_area_add_circuit(area, circuit);
                }
        }
@@ -715,6 +716,8 @@ void isis_vrf_init(void)
 {
        vrf_init(isis_vrf_new, isis_vrf_enable, isis_vrf_disable,
                 isis_vrf_delete, isis_vrf_enable);
+
+       vrf_cmd_init(NULL, &isisd_privs);
 }
 
 void isis_terminate()
@@ -1076,6 +1079,23 @@ DEFUN(show_isis_interface_arg,
                                          vrf_name, all_vrf);
 }
 
+static int id_to_sysid(struct isis *isis, const char *id, uint8_t *sysid)
+{
+       struct isis_dynhn *dynhn;
+
+       memset(sysid, 0, ISIS_SYS_ID_LEN);
+       if (id) {
+               if (sysid2buff(sysid, id) == 0) {
+                       dynhn = dynhn_find_by_name(isis, id);
+                       if (dynhn == NULL)
+                               return -1;
+                       memcpy(sysid, dynhn->id, ISIS_SYS_ID_LEN);
+               }
+       }
+
+       return 0;
+}
+
 static void isis_neighbor_common(struct vty *vty, const char *id, char detail,
                                 struct isis *isis, uint8_t *sysid)
 {
@@ -1131,7 +1151,6 @@ int show_isis_neighbor_common(struct vty *vty, const char *id, char detail,
                              const char *vrf_name, bool all_vrf)
 {
        struct listnode *node;
-       struct isis_dynhn *dynhn;
        uint8_t sysid[ISIS_SYS_ID_LEN];
        struct isis *isis;
 
@@ -1140,29 +1159,27 @@ int show_isis_neighbor_common(struct vty *vty, const char *id, char detail,
                return CMD_SUCCESS;
        }
 
-       memset(sysid, 0, ISIS_SYS_ID_LEN);
-       if (id) {
-               if (sysid2buff(sysid, id) == 0) {
-                       dynhn = dynhn_find_by_name(id);
-                       if (dynhn == NULL) {
-                               vty_out(vty, "Invalid system id %s\n", id);
-                               return CMD_SUCCESS;
-                       }
-                       memcpy(sysid, dynhn->id, ISIS_SYS_ID_LEN);
-               }
-       }
-
        if (vrf_name) {
                if (all_vrf) {
                        for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) {
+                               if (id_to_sysid(isis, id, sysid)) {
+                                       vty_out(vty, "Invalid system id %s\n",
+                                               id);
+                                       return CMD_SUCCESS;
+                               }
                                isis_neighbor_common(vty, id, detail, isis,
                                                     sysid);
                        }
                        return CMD_SUCCESS;
                }
                isis = isis_lookup_by_vrfname(vrf_name);
-               if (isis != NULL)
+               if (isis != NULL) {
+                       if (id_to_sysid(isis, id, sysid)) {
+                               vty_out(vty, "Invalid system id %s\n", id);
+                               return CMD_SUCCESS;
+                       }
                        isis_neighbor_common(vty, id, detail, isis, sysid);
+               }
        }
 
        return CMD_SUCCESS;
@@ -1218,7 +1235,6 @@ int clear_isis_neighbor_common(struct vty *vty, const char *id, const char *vrf_
                               bool all_vrf)
 {
        struct listnode *node;
-       struct isis_dynhn *dynhn;
        uint8_t sysid[ISIS_SYS_ID_LEN];
        struct isis *isis;
 
@@ -1227,27 +1243,27 @@ int clear_isis_neighbor_common(struct vty *vty, const char *id, const char *vrf_
                return CMD_SUCCESS;
        }
 
-       memset(sysid, 0, ISIS_SYS_ID_LEN);
-       if (id) {
-               if (sysid2buff(sysid, id) == 0) {
-                       dynhn = dynhn_find_by_name(id);
-                       if (dynhn == NULL) {
-                               vty_out(vty, "Invalid system id %s\n", id);
-                               return CMD_SUCCESS;
-                       }
-                       memcpy(sysid, dynhn->id, ISIS_SYS_ID_LEN);
-               }
-       }
        if (vrf_name) {
                if (all_vrf) {
-                       for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis))
+                       for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) {
+                               if (id_to_sysid(isis, id, sysid)) {
+                                       vty_out(vty, "Invalid system id %s\n",
+                                               id);
+                                       return CMD_SUCCESS;
+                               }
                                isis_neighbor_common_clear(vty, id, sysid,
                                                           isis);
+                       }
                        return CMD_SUCCESS;
                }
                isis = isis_lookup_by_vrfname(vrf_name);
-               if (isis != NULL)
+               if (isis != NULL) {
+                       if (id_to_sysid(isis, id, sysid)) {
+                               vty_out(vty, "Invalid system id %s\n", id);
+                               return CMD_SUCCESS;
+                       }
                        isis_neighbor_common_clear(vty, id, sysid, isis);
+               }
        }
 
        return CMD_SUCCESS;
@@ -2154,21 +2170,21 @@ DEFUN(show_isis_summary, show_isis_summary_cmd,
        return CMD_SUCCESS;
 }
 
-struct isis_lsp *lsp_for_arg(struct lspdb_head *head, const char *argv,
-                            struct isis *isis)
+struct isis_lsp *lsp_for_sysid(struct lspdb_head *head, const char *sysid_str,
+                              struct isis *isis)
 {
        char sysid[255] = {0};
-       uint8_t number[3];
+       uint8_t number[3] = {0};
        const char *pos;
        uint8_t lspid[ISIS_SYS_ID_LEN + 2] = {0};
        struct isis_dynhn *dynhn;
        struct isis_lsp *lsp = NULL;
 
-       if (!argv)
+       if (!sysid_str)
                return NULL;
 
        /*
-        * extract fragment and pseudo id from the string argv
+        * extract fragment and pseudo id from the string sysid_str
         * in the forms:
         * (a) <systemid/hostname>.<pseudo-id>-<framenent> or
         * (b) <systemid/hostname>.<pseudo-id> or
@@ -2176,10 +2192,10 @@ struct isis_lsp *lsp_for_arg(struct lspdb_head *head, const char *argv,
         * Where systemid is in the form:
         * xxxx.xxxx.xxxx
         */
-       if (argv)
-               strlcpy(sysid, argv, sizeof(sysid));
-       if (argv && strlen(argv) > 3) {
-               pos = argv + strlen(argv) - 3;
+       strlcpy(sysid, sysid_str, sizeof(sysid));
+
+       if (strlen(sysid_str) > 3) {
+               pos = sysid_str + strlen(sysid_str) - 3;
                if (strncmp(pos, "-", 1) == 0) {
                        memcpy(number, ++pos, 2);
                        lspid[ISIS_SYS_ID_LEN + 1] =
@@ -2192,19 +2208,18 @@ struct isis_lsp *lsp_for_arg(struct lspdb_head *head, const char *argv,
                        memcpy(number, ++pos, 2);
                        lspid[ISIS_SYS_ID_LEN] =
                                (uint8_t)strtol((char *)number, NULL, 16);
-                       sysid[pos - argv - 1] = '\0';
+                       sysid[pos - sysid_str - 1] = '\0';
                }
        }
 
        /*
-        * Try to find the lsp-id if the argv
-        * string is in
-        * the form
+        * Try to find the lsp-id if the sysid_str
+        * is in the form
         * hostname.<pseudo-id>-<fragment>
         */
        if (sysid2buff(lspid, sysid)) {
                lsp = lsp_search(head, lspid);
-       } else if ((dynhn = dynhn_find_by_name(sysid))) {
+       } else if ((dynhn = dynhn_find_by_name(isis, sysid))) {
                memcpy(lspid, dynhn->id, ISIS_SYS_ID_LEN);
                lsp = lsp_search(head, lspid);
        } else if (strncmp(cmd_hostname_get(), sysid, 15) == 0) {
@@ -2217,15 +2232,15 @@ struct isis_lsp *lsp_for_arg(struct lspdb_head *head, const char *argv,
 
 void show_isis_database_lspdb(struct vty *vty, struct isis_area *area,
                              int level, struct lspdb_head *lspdb,
-                             const char *argv, int ui_level)
+                             const char *sysid_str, int ui_level)
 {
        struct isis_lsp *lsp;
        int lsp_count;
 
        if (lspdb_count(lspdb) > 0) {
-               lsp = lsp_for_arg(lspdb, argv, area->isis);
+               lsp = lsp_for_sysid(lspdb, sysid_str, area->isis);
 
-               if (lsp != NULL || argv == NULL) {
+               if (lsp != NULL || sysid_str == NULL) {
                        vty_out(vty, "IS-IS Level-%d link-state database:\n",
                                level + 1);
 
@@ -2241,7 +2256,7 @@ void show_isis_database_lspdb(struct vty *vty, struct isis_area *area,
                        else
                                lsp_print(lsp, vty, area->dynhostname,
                                          area->isis);
-               } else if (argv == NULL) {
+               } else if (sysid_str == NULL) {
                        lsp_count =
                                lsp_print_all(vty, lspdb, ui_level,
                                              area->dynhostname, area->isis);
@@ -2251,7 +2266,7 @@ void show_isis_database_lspdb(struct vty *vty, struct isis_area *area,
        }
 }
 
-static void show_isis_database_common(struct vty *vty, const char *argv,
+static void show_isis_database_common(struct vty *vty, const char *sysid_str,
                                      int ui_level, struct isis *isis)
 {
        struct listnode *node;
@@ -2267,7 +2282,7 @@ static void show_isis_database_common(struct vty *vty, const char *argv,
 
                for (level = 0; level < ISIS_LEVELS; level++)
                        show_isis_database_lspdb(vty, area, level,
-                                                &area->lspdb[level], argv,
+                                                &area->lspdb[level], sysid_str,
                                                 ui_level);
        }
 }
@@ -2287,8 +2302,8 @@ static void show_isis_database_common(struct vty *vty, const char *argv,
  * [ show isis database detail <sysid>.<pseudo-id>-<fragment-number> ]
  * [ show isis database detail <hostname>.<pseudo-id>-<fragment-number> ]
  */
-static int show_isis_database(struct vty *vty, const char *argv, int ui_level,
-                             const char *vrf_name, bool all_vrf)
+static int show_isis_database(struct vty *vty, const char *sysid_str,
+                             int ui_level, const char *vrf_name, bool all_vrf)
 {
        struct listnode *node;
        struct isis *isis;
@@ -2296,14 +2311,15 @@ static int show_isis_database(struct vty *vty, const char *argv, int ui_level,
        if (vrf_name) {
                if (all_vrf) {
                        for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis))
-                               show_isis_database_common(vty, argv, ui_level,
-                                                         isis);
+                               show_isis_database_common(vty, sysid_str,
+                                                         ui_level, isis);
 
                        return CMD_SUCCESS;
                }
                isis = isis_lookup_by_vrfname(vrf_name);
                if (isis)
-                       show_isis_database_common(vty, argv, ui_level, isis);
+                       show_isis_database_common(vty, sysid_str, ui_level,
+                                                 isis);
        }
 
        return CMD_SUCCESS;
index 9d0b57e9f6834ba4040f02c6da4d3ce5bf0e7eea..60dcf066dde9b54bea0197dd3dbcc186e200ee84 100644 (file)
@@ -95,6 +95,7 @@ struct isis {
        struct thread *t_dync_clean;      /* dynamic hostname cache cleanup thread */
        uint32_t circuit_ids_used[8];     /* 256 bits to track circuit ids 1 through 255 */
        int snmp_notifications;
+       struct list *dyn_cache;
 
        struct route_table *ext_info[REDIST_PROTOCOL_COUNT];
 };
@@ -273,8 +274,8 @@ void isis_area_destroy(struct isis_area *area);
 void isis_filter_update(struct access_list *access);
 void isis_prefix_list_update(struct prefix_list *plist);
 void print_debug(struct vty *, int, int);
-struct isis_lsp *lsp_for_arg(struct lspdb_head *head, const char *argv,
-                            struct isis *isis);
+struct isis_lsp *lsp_for_sysid(struct lspdb_head *head, const char *sysid_str,
+                              struct isis *isis);
 
 void isis_area_invalidate_routes(struct isis_area *area, int levels);
 void isis_area_verify_routes(struct isis_area *area);
index 244938933b4574a49a197b9a734914b72eea6821..a3f361ed9de66babb90724cdb2de8f761ce70b7f 100644 (file)
@@ -60,6 +60,8 @@ typedef unsigned int word_t;
  */
 typedef struct {word_t *data; size_t n, m; } bitfield_t;
 
+DECLARE_MTYPE(BITFIELD);
+
 /**
  * Initialize the bits.
  * @v: an instance of bitfield_t struct.
@@ -70,7 +72,7 @@ typedef struct {word_t *data; size_t n, m; } bitfield_t;
        do {                                                                   \
                (v).n = 0;                                                     \
                (v).m = ((N) / WORD_SIZE + 1);                                 \
-               (v).data = calloc(1, ((v).m * sizeof(word_t)));                \
+               (v).data = XCALLOC(MTYPE_BITFIELD, ((v).m * sizeof(word_t)));  \
        } while (0)
 
 /**
@@ -193,7 +195,7 @@ static inline unsigned int bf_find_next_set_bit(bitfield_t v,
  */
 #define bf_free(v)                                                             \
        do {                                                                   \
-               free((v).data);                                                \
+               XFREE(MTYPE_BITFIELD, (v).data);                               \
                (v).data = NULL;                                               \
        } while (0)
 
index 008f98a34cb73467d2c28692256293f658b72ebd..7be54907ed02e66d03d7f9f72fab364ce0515680 100644 (file)
@@ -1058,6 +1058,7 @@ int cmd_execute_command(vector vline, struct vty *vty,
                return saved_ret;
 
        if (ret != CMD_SUCCESS && ret != CMD_WARNING
+           && ret != CMD_ERR_AMBIGUOUS && ret != CMD_ERR_INCOMPLETE
            && ret != CMD_NOT_MY_INSTANCE && ret != CMD_WARNING_CONFIG_FAILED) {
                /* This assumes all nodes above CONFIG_NODE are childs of
                 * CONFIG_NODE */
@@ -1071,6 +1072,7 @@ int cmd_execute_command(vector vline, struct vty *vty,
                        ret = cmd_execute_command_real(vline, FILTER_RELAXED,
                                                       vty, cmd, 0);
                        if (ret == CMD_SUCCESS || ret == CMD_WARNING
+                           || ret == CMD_ERR_AMBIGUOUS || ret == CMD_ERR_INCOMPLETE
                            || ret == CMD_NOT_MY_INSTANCE
                            || ret == CMD_WARNING_CONFIG_FAILED)
                                return ret;
@@ -1269,6 +1271,7 @@ int command_config_read_one_line(struct vty *vty,
        while (!(use_daemon && ret == CMD_SUCCESS_DAEMON)
               && !(!use_daemon && ret == CMD_ERR_NOTHING_TODO)
               && ret != CMD_SUCCESS && ret != CMD_WARNING
+              && ret != CMD_ERR_AMBIGUOUS && ret != CMD_ERR_INCOMPLETE
               && ret != CMD_NOT_MY_INSTANCE && ret != CMD_WARNING_CONFIG_FAILED
               && ret != CMD_NO_LEVEL_UP)
                ret = cmd_execute_command_real(vline, FILTER_STRICT, vty, cmd,
@@ -1496,7 +1499,7 @@ static void permute(struct graph_node *start, struct vty *vty)
 static void print_cmd(struct vty *vty, const char *cmd)
 {
        int i, j, len = strlen(cmd);
-       char buf[len];
+       char buf[len + 1];
        bool skip = false;
 
        j = 0;
index bbfe01b569c3f4116e49e6e4ad63abdfb8e731d6..970ed297fc7142a7616ca759bacd020eb0a9d1e3 100644 (file)
@@ -123,15 +123,6 @@ extern "C" {
 #define assume(x)
 #endif
 
-/* pure = function does not modify memory & return value is the same if
- * memory hasn't changed (=> allows compiler to optimize)
- *
- * Mostly autodetected by the compiler if function body is available (i.e.
- * static inline functions in headers).  Since that implies it should only be
- * used in headers for non-inline functions, the "extern" is included here.
- */
-#define ext_pure       extern __attribute__((pure))
-
 /* for helper functions defined inside macros */
 #define macro_inline   static inline __attribute__((unused))
 #define macro_pure     static inline __attribute__((unused, pure))
@@ -356,7 +347,11 @@ extern "C" {
 #define PRIx64 "Lx"
 
 #else /* !_FRR_ATTRIBUTE_PRINTFRR */
+#ifdef __NetBSD__
+#define PRINTFRR(a, b) __attribute__((format(gnu_syslog, a, b)))
+#else
 #define PRINTFRR(a, b) __attribute__((format(printf, a, b)))
+#endif
 
 /* frr-format plugin is C-only for now, so no point in doing these shenanigans
  * for C++...  (also they can break some C++ stuff...)
index b3803141df2eaad93cf039b4e6abc6495ae6055a..e37b4f55b00bb4e1cef7eb45e62b154fc186738d 100644 (file)
--- a/lib/if.c
+++ b/lib/if.c
@@ -266,20 +266,23 @@ void if_update_to_new_vrf(struct interface *ifp, vrf_id_t vrf_id)
                char oldpath[XPATH_MAXLEN];
                char newpath[XPATH_MAXLEN];
 
-               if_dnode = yang_dnode_getf(
-                       running_config->dnode,
-                       "/frr-interface:lib/interface[name='%s'][vrf='%s']/vrf",
-                       ifp->name, old_vrf->name);
+               snprintf(oldpath, sizeof(oldpath),
+                        "/frr-interface:lib/interface[name='%s'][vrf='%s']",
+                        ifp->name, old_vrf->name);
+               snprintf(newpath, sizeof(newpath),
+                        "/frr-interface:lib/interface[name='%s'][vrf='%s']",
+                        ifp->name, vrf->name);
+
+               if_dnode = yang_dnode_getf(running_config->dnode, "%s/vrf",
+                                          oldpath);
 
                if (if_dnode) {
-                       yang_dnode_get_path(lyd_parent(if_dnode), oldpath,
-                                           sizeof(oldpath));
                        yang_dnode_change_leaf(if_dnode, vrf->name);
-                       yang_dnode_get_path(lyd_parent(if_dnode), newpath,
-                                           sizeof(newpath));
                        nb_running_move_tree(oldpath, newpath);
                        running_config->version++;
                }
+
+               vty_update_xpath(oldpath, newpath);
        }
 }
 
index afeb89c5922ab9a00578b224c4f2eb88a48a9d0e..e8a6b89f8910a794e5e7436c93ccf1f68d205dc5 100644 (file)
@@ -79,7 +79,6 @@ void ls_node_del(struct ls_node *node)
                return;
 
        XFREE(MTYPE_LS_DB, node);
-       node = NULL;
 }
 
 int ls_node_same(struct ls_node *n1, struct ls_node *n2)
@@ -168,7 +167,6 @@ void ls_attributes_del(struct ls_attributes *attr)
        ls_attributes_srlg_del(attr);
 
        XFREE(MTYPE_LS_DB, attr);
-       attr = NULL;
 }
 
 int ls_attributes_same(struct ls_attributes *l1, struct ls_attributes *l2)
@@ -221,7 +219,6 @@ void ls_prefix_del(struct ls_prefix *pref)
                return;
 
        XFREE(MTYPE_LS_DB, pref);
-       pref = NULL;
 }
 
 int ls_prefix_same(struct ls_prefix *p1, struct ls_prefix *p2)
@@ -839,7 +836,6 @@ void ls_ted_del(struct ls_ted *ted)
        subnets_fini(&ted->subnets);
 
        XFREE(MTYPE_LS_DB, ted);
-       ted = NULL;
 }
 
 void ls_ted_del_all(struct ls_ted *ted)
index 721e57a62804cdd1678f2b30b623ded72bd43867..f01497dead4042b62b9d45a50477369b888f33dd 100644 (file)
@@ -111,13 +111,14 @@ int zlog_filter_dump(char *buf, size_t max_size)
        return len;
 }
 
-static int search_buf(const char *buf)
+static int search_buf(const char *buf, size_t len)
 {
        char *found = NULL;
 
        frr_with_mutex(&logfilterlock) {
                for (int i = 0; i < zlog_filter_count; i++) {
-                       found = strstr(buf, zlog_filters[i]);
+                       found = memmem(buf, len, zlog_filters[i],
+                                      strlen(zlog_filters[i]));
                        if (found != NULL)
                                return 0;
                }
@@ -131,12 +132,15 @@ static void zlog_filterfile_fd(struct zlog_target *zt, struct zlog_msg *msgs[],
 {
        struct zlog_msg *msgfilt[nmsgs];
        size_t i, o = 0;
+       const char *text;
+       size_t text_len;
 
        for (i = 0; i < nmsgs; i++) {
-               if (zlog_msg_prio(msgs[i]) >= LOG_DEBUG
-                   && search_buf(zlog_msg_text(msgs[i], NULL)) < 0)
-                       continue;
-
+               if (zlog_msg_prio(msgs[i]) >= LOG_DEBUG) {
+                       text = zlog_msg_text(msgs[i], &text_len);
+                       if (search_buf(text, text_len) < 0)
+                               continue;
+               }
                msgfilt[o++] = msgs[i];
        }
 
index 9dbf216d31521bae8db4f4d7079b16d56f1686d1..cbb8de897646231f2a6fe45a50650c1fa8405d27 100644 (file)
@@ -34,6 +34,7 @@
 #define ZLOG_MAXLVL(a, b) MAX(a, b)
 
 DEFINE_HOOK(zlog_rotate, (), ());
+DEFINE_HOOK(zlog_cli_show, (struct vty * vty), (vty));
 
 static const int log_default_lvl = LOG_DEBUG;
 
@@ -57,7 +58,7 @@ static struct zlog_cfg_filterfile zt_filterfile = {
        },
 };
 
-static const char *zlog_progname;
+const char *zlog_progname;
 static const char *zlog_protoname;
 
 static const struct facility_map {
@@ -94,7 +95,14 @@ static const char * const zlog_priority[] = {
        "notifications", "informational", "debugging", NULL,
 };
 
-static const char *facility_name(int facility)
+const char *zlog_priority_str(int priority)
+{
+       if (priority > LOG_DEBUG)
+               return "???";
+       return zlog_priority[priority];
+}
+
+const char *facility_name(int facility)
 {
        const struct facility_map *fm;
 
@@ -104,7 +112,7 @@ static const char *facility_name(int facility)
        return "";
 }
 
-static int facility_match(const char *str)
+int facility_match(const char *str)
 {
        const struct facility_map *fm;
 
@@ -194,6 +202,8 @@ DEFUN_NOSH (show_logging,
        vty_out(vty, "Record priority: %s\n",
                (zt_file.record_priority ? "enabled" : "disabled"));
        vty_out(vty, "Timestamp precision: %d\n", zt_file.ts_subsec);
+
+       hook_call(zlog_cli_show, vty);
        return CMD_SUCCESS;
 }
 
@@ -588,8 +598,9 @@ DEFUN (no_config_log_filterfile,
 
 DEFPY (log_filter,
        log_filter_cmd,
-       "[no] log-filter WORD$filter",
+       "[no] log filter-text WORD$filter",
        NO_STR
+       "Logging control\n"
        FILTER_LOG_STR
        "String to filter by\n")
 {
@@ -616,8 +627,9 @@ DEFPY (log_filter,
 /* Clear all log filters */
 DEFPY (log_filter_clear,
        log_filter_clear_cmd,
-       "clear log-filter",
+       "clear log filter-text",
        CLEAR_STR
+       "Logging control\n"
        FILTER_LOG_STR)
 {
        zlog_filter_clear();
@@ -627,8 +639,9 @@ DEFPY (log_filter_clear,
 /* Show log filter */
 DEFPY (show_log_filter,
        show_log_filter_cmd,
-       "show log-filter",
+       "show logging filter-text",
        SHOW_STR
+       "Show current logging configuration\n"
        FILTER_LOG_STR)
 {
        char log_filters[ZLOG_FILTERS_MAX * (ZLOG_FILTER_LENGTH_MAX + 3)] = "";
index f0fb7d3dba0235db5be51355d048bf15fe79611a..db46b3cb5b22b0bf48e75c260ce7f11bdf15d1af 100644 (file)
@@ -34,9 +34,14 @@ extern void log_config_write(struct vty *vty);
 extern int log_level_match(const char *s);
 extern void log_show_syslog(struct vty *vty);
 
+extern int facility_match(const char *str);
+extern const char *facility_name(int facility);
+
 DECLARE_HOOK(zlog_rotate, (), ());
 extern void zlog_rotate(void);
 
+DECLARE_HOOK(zlog_cli_show, (struct vty * vty), (vty));
+
 #ifdef __cplusplus
 }
 #endif
index 0dc8e905247acf462b9fec70a617f3fd34024856..18811777ae40b4aa8fd05b3b836b9ff4c95eadcf 100644 (file)
@@ -36,6 +36,7 @@ struct memgroup **mg_insert = &mg_first;
 
 DEFINE_MGROUP(LIB, "libfrr");
 DEFINE_MTYPE(LIB, TMP, "Temporary memory");
+DEFINE_MTYPE(LIB, BITFIELD, "Bitfield memory");
 
 static inline void mt_count_alloc(struct memtype *mt, size_t size, void *ptr)
 {
index 47af77018959d803e3889ed6ff17c34f0c32da3f..6edd5184efd9b37bffd07f21b255b64ee883c03d 100644 (file)
@@ -696,14 +696,14 @@ int nb_candidate_edit(struct nb_config *candidate,
                                                   NULL, LYD_NEW_PATH_UPDATE,
                                                   &dep_dnode);
                                /* Create default nodes */
-                               if (!err)
+                               if (!err && dep_dnode)
                                        err = lyd_new_implicit_tree(
                                                dep_dnode,
                                                LYD_IMPLICIT_NO_STATE, NULL);
                                if (err) {
                                        flog_warn(
                                                EC_LIB_LIBYANG,
-                                               "%s: lyd_new_path(%s) failed: %d",
+                                               "%s: dependency: lyd_new_path(%s) failed: %d",
                                                __func__, dep_xpath, err);
                                        return NB_ERR;
                                }
index 807d1252c45bcd4c886322af07a41fd060504dca..71f07dfe86d283697de7eb6e1483ead76707d33d 100644 (file)
@@ -1222,7 +1222,7 @@ void HandleUnaryExecute(
                                                 frr::NAME##Response>(         \
                        (cdb), &frr::Northbound::AsyncService::Request##NAME,  \
                        &HandleUnary##NAME, #NAME);                            \
-               _rpcState->do_request(service, _cq);                           \
+               _rpcState->do_request(service, s_cq);                          \
        } while (0)
 
 #define REQUEST_NEWRPC_STREAMING(NAME, cdb)                                    \
@@ -1231,7 +1231,7 @@ void HandleUnaryExecute(
                                                 frr::NAME##Response>(         \
                        (cdb), &frr::Northbound::AsyncService::Request##NAME,  \
                        &HandleStreaming##NAME, #NAME);                        \
-               _rpcState->do_request(service, _cq);                           \
+               _rpcState->do_request(service, s_cq);                          \
        } while (0)
 
 struct grpc_pthread_attr {
@@ -1239,6 +1239,10 @@ struct grpc_pthread_attr {
        unsigned long port;
 };
 
+// Capture these objects so we can try to shut down cleanly
+static std::unique_ptr<grpc::Server> s_server;
+static grpc::ServerCompletionQueue *s_cq;
+
 static void *grpc_pthread_start(void *arg)
 {
        struct frr_pthread *fpt = static_cast<frr_pthread *>(arg);
@@ -1249,7 +1253,6 @@ static void *grpc_pthread_start(void *arg)
        std::stringstream server_address;
        frr::Northbound::AsyncService *service =
                new frr::Northbound::AsyncService();
-       grpc::ServerCompletionQueue *_cq;
 
        frr_pthread_set_name(fpt);
 
@@ -1258,8 +1261,8 @@ static void *grpc_pthread_start(void *arg)
                                 grpc::InsecureServerCredentials());
        builder.RegisterService(service);
        auto cq = builder.AddCompletionQueue();
-       _cq = cq.get();
-       auto server = builder.BuildAndStart();
+       s_cq = cq.get();
+       s_server = builder.BuildAndStart();
 
        /* Schedule all RPC handlers */
        REQUEST_NEWRPC(GetCapabilities, NULL);
@@ -1284,10 +1287,12 @@ static void *grpc_pthread_start(void *arg)
                void *tag;
                bool ok;
 
-               _cq->Next(&tag, &ok);
+               s_cq->Next(&tag, &ok);
+               if (!ok)
+                       break;
+
                grpc_debug("%s: Got next from CompletionQueue, %p %d", __func__,
                           tag, ok);
-               GPR_ASSERT(ok);
 
                RpcStateBase *rpc = static_cast<RpcStateBase *>(tag);
                CallState state = rpc->doCallback();
@@ -1302,10 +1307,9 @@ static void *grpc_pthread_start(void *arg)
                 * user indicating Finish() for cleanup.
                 */
                if (state == FINISH)
-                       rpc->do_request(service, _cq);
+                       rpc->do_request(service, s_cq);
        }
 
-       /*NOTREACHED*/
        return NULL;
 }
 
@@ -1326,16 +1330,30 @@ static int frr_grpc_init(uint port)
                         __func__, safe_strerror(errno));
                return -1;
        }
-       pthread_detach(fpt->thread);
 
        return 0;
 }
 
 static int frr_grpc_finish(void)
 {
-       if (fpt)
+       // Shutdown the grpc server
+       if (s_server) {
+               s_server->Shutdown();
+               s_cq->Shutdown();
+
+               // And drain the queue
+               void *ignore;
+               bool ok;
+
+               while (s_cq->Next(&ignore, &ok))
+                       ;
+       }
+
+       if (fpt) {
+               pthread_join(fpt->thread, NULL);
                frr_pthread_destroy(fpt);
-       // TODO: cancel the gRPC pthreads gracefully.
+       }
+
        return 0;
 }
 
index 5b6b64eaebba560c8f0f84204e17922424a1c995..4d76ae153666c6a6b91881ca2c697dbe7380a03e 100644 (file)
@@ -366,6 +366,10 @@ DECLARE_QOBJ_TYPE(route_map);
        (strmatch(A, "frr-bgp-route-map:ipv4-vpn-address"))
 #define IS_SET_BGP_IPV4_NH(A)                                                  \
        (strmatch(A, "frr-bgp-route-map:set-ipv4-nexthop"))
+#define IS_SET_BGP_EVPN_GATEWAY_IP_IPV4(A)                                     \
+       (strmatch(A, "frr-bgp-route-map:set-evpn-gateway-ip-ipv4"))
+#define IS_SET_BGP_EVPN_GATEWAY_IP_IPV6(A)                                     \
+       (strmatch(A, "frr-bgp-route-map:set-evpn-gateway-ip-ipv6"))
 
 /* Prototypes. */
 extern void route_map_init(void);
index e11b9eea7416cc5d8d45ad55e34220fb35fa88ca..bf982cfa2ba2c0ab4dac52a5234a76976f444536 100644 (file)
@@ -1248,6 +1248,16 @@ void route_map_action_show(struct vty *vty, struct lyd_node *dnode,
                        yang_dnode_get_string(
                                dnode,
                                "./rmap-set-action/frr-bgp-route-map:ipv4-nexthop"));
+       } else if (IS_SET_BGP_EVPN_GATEWAY_IP_IPV4(action)) {
+               vty_out(vty, " set evpn gateway-ip ipv4 %s\n",
+                       yang_dnode_get_string(
+                               dnode,
+                               "./rmap-set-action/frr-bgp-route-map:evpn-gateway-ip-ipv4"));
+       } else if (IS_SET_BGP_EVPN_GATEWAY_IP_IPV6(action)) {
+               vty_out(vty, " set evpn gateway-ip ipv6 %s\n",
+                       yang_dnode_get_string(
+                               dnode,
+                               "./rmap-set-action/frr-bgp-route-map:evpn-gateway-ip-ipv6"));
        }
 }
 
index bdd12b262b0ec4d42d554f041b474417f988d5bd..c185091a4bce114bf471621cf55ccf7c7c04f8bb 100644 (file)
@@ -1,6 +1,10 @@
 #ifndef _FRR_ROUTING_NB_H_
 #define _FRR_ROUTING_NB_H_
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 extern const struct frr_yang_module_info frr_routing_info;
 
 /* Mandatory callbacks. */
@@ -28,4 +32,8 @@ DECLARE_HOOK(routing_conf_event, (struct nb_cb_create_args *args), (args));
 
 void routing_control_plane_protocols_register_vrf_dependency(void);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* _FRR_ROUTING_NB_H_ */
index ceb769ef7607112b9bc0d459034f9a71fbe5624a..ccb94b2f7604ab88c2913d08bdea9cf62d206f59 100644 (file)
@@ -129,6 +129,8 @@ struct srv6_locator *srv6_locator_alloc(const char *name)
        locator = XCALLOC(MTYPE_SRV6_LOCATOR, sizeof(struct srv6_locator));
        strlcpy(locator->name, name, sizeof(locator->name));
        locator->chunks = list_new();
+       locator->chunks->del = (void (*)(void *))srv6_locator_chunk_free;
+
        QOBJ_REG(locator, srv6_locator);
        return locator;
 }
@@ -144,7 +146,12 @@ struct srv6_locator_chunk *srv6_locator_chunk_alloc(void)
 
 void srv6_locator_free(struct srv6_locator *locator)
 {
-       XFREE(MTYPE_SRV6_LOCATOR, locator);
+       if (locator) {
+               QOBJ_UNREG(locator);
+               list_delete(&locator->chunks);
+
+               XFREE(MTYPE_SRV6_LOCATOR, locator);
+       }
 }
 
 void srv6_locator_chunk_free(struct srv6_locator_chunk *chunk)
index 7e383dce80874fa03384396d3726ce0a06ff07a7..5dec69ee7ea67b29ab00f16f70cfd456959be720 100644 (file)
@@ -197,29 +197,25 @@ static inline void route_table_set_info(struct route_table *table, void *d)
        table->info = d;
 }
 
-/* ext_pure => extern __attribute__((pure))
- *   does not modify memory (but depends on mem), allows compiler to optimize
- */
-
 extern void route_table_finish(struct route_table *table);
-ext_pure struct route_node *route_top(struct route_table *table);
-ext_pure struct route_node *route_next(struct route_node *node);
-ext_pure struct route_node *route_next_until(struct route_node *node,
-                                            const struct route_node *limit);
+extern struct route_node *route_top(struct route_table *table);
+extern struct route_node *route_next(struct route_node *node);
+extern struct route_node *route_next_until(struct route_node *node,
+                                          const struct route_node *limit);
 extern struct route_node *route_node_get(struct route_table *table,
                                         union prefixconstptr pu);
-ext_pure struct route_node *route_node_lookup(struct route_table *table,
-                                             union prefixconstptr pu);
-ext_pure struct route_node *route_node_lookup_maynull(struct route_table *table,
-                                                     union prefixconstptr pu);
-ext_pure struct route_node *route_node_match(struct route_table *table,
-                                            union prefixconstptr pu);
-ext_pure struct route_node *route_node_match_ipv4(struct route_table *table,
-                                                 const struct in_addr *addr);
-ext_pure struct route_node *route_node_match_ipv6(struct route_table *table,
-                                                 const struct in6_addr *addr);
-
-ext_pure unsigned long route_table_count(struct route_table *table);
+extern struct route_node *route_node_lookup(struct route_table *table,
+                                           union prefixconstptr pu);
+extern struct route_node *route_node_lookup_maynull(struct route_table *table,
+                                                   union prefixconstptr pu);
+extern struct route_node *route_node_match(struct route_table *table,
+                                          union prefixconstptr pu);
+extern struct route_node *route_node_match_ipv4(struct route_table *table,
+                                               const struct in_addr *addr);
+extern struct route_node *route_node_match_ipv6(struct route_table *table,
+                                               const struct in6_addr *addr);
+
+extern unsigned long route_table_count(struct route_table *table);
 
 extern struct route_node *route_node_create(route_table_delegate_t *delegate,
                                            struct route_table *table);
@@ -228,10 +224,10 @@ extern void route_node_destroy(route_table_delegate_t *delegate,
                               struct route_table *table,
                               struct route_node *node);
 
-ext_pure struct route_node *route_table_get_next(struct route_table *table,
-                                                union prefixconstptr pu);
-ext_pure int route_table_prefix_iter_cmp(const struct prefix *p1,
-                                        const struct prefix *p2);
+extern struct route_node *route_table_get_next(struct route_table *table,
+                                              union prefixconstptr pu);
+extern int route_table_prefix_iter_cmp(const struct prefix *p1,
+                                      const struct prefix *p2);
 
 /*
  * Iterator functions.
index de29f45f8f1377c72a99e1ef4bf1319e71735d3b..03d9a62c0f138b6b5fbde171e42268d83cd09408 100644 (file)
--- a/lib/vrf.c
+++ b/lib/vrf.c
@@ -582,29 +582,38 @@ void vrf_init(int (*create)(struct vrf *), int (*enable)(struct vrf *),
        cmd_variable_handler_register(vrf_var_handlers);
 }
 
+static void vrf_terminate_single(struct vrf *vrf)
+{
+       /* Clear configured flag and invoke delete. */
+       UNSET_FLAG(vrf->status, VRF_CONFIGURED);
+       vrf_delete(vrf);
+}
+
 /* Terminate VRF module. */
 void vrf_terminate(void)
 {
-       struct vrf *vrf;
+       struct vrf *vrf, *tmp;
 
        if (debug_vrf)
                zlog_debug("%s: Shutting down vrf subsystem", __func__);
 
-       while (!RB_EMPTY(vrf_id_head, &vrfs_by_id)) {
-               vrf = RB_ROOT(vrf_id_head, &vrfs_by_id);
+       RB_FOREACH_SAFE (vrf, vrf_id_head, &vrfs_by_id, tmp) {
+               if (vrf->vrf_id == VRF_DEFAULT)
+                       continue;
 
-               /* Clear configured flag and invoke delete. */
-               UNSET_FLAG(vrf->status, VRF_CONFIGURED);
-               vrf_delete(vrf);
+               vrf_terminate_single(vrf);
        }
 
-       while (!RB_EMPTY(vrf_name_head, &vrfs_by_name)) {
-               vrf = RB_ROOT(vrf_name_head, &vrfs_by_name);
+       RB_FOREACH_SAFE (vrf, vrf_name_head, &vrfs_by_name, tmp) {
+               if (vrf->vrf_id == VRF_DEFAULT)
+                       continue;
 
-               /* Clear configured flag and invoke delete. */
-               UNSET_FLAG(vrf->status, VRF_CONFIGURED);
-               vrf_delete(vrf);
+               vrf_terminate_single(vrf);
        }
+
+       /* Finally terminate default VRF */
+       vrf = vrf_lookup_by_id(VRF_DEFAULT);
+       vrf_terminate_single(vrf);
 }
 
 int vrf_socket(int domain, int type, int protocol, vrf_id_t vrf_id,
@@ -818,10 +827,24 @@ DEFUN_YANG (no_vrf,
                return CMD_WARNING_CONFIG_FAILED;
        }
 
+       if (vrf_get_backend() == VRF_BACKEND_VRF_LITE) {
+               /*
+                * Remove the VRF interface config. Currently, we allow to
+                * remove only inactive VRFs, so we use VRF_DEFAULT_NAME here,
+                * because when the VRF is removed from kernel, the interface
+                * is moved to the default VRF. If we ever allow removing
+                * active VRFs, this code have to be updated accordingly.
+                */
+               snprintf(xpath_list, sizeof(xpath_list),
+                        "/frr-interface:lib/interface[name='%s'][vrf='%s']",
+                        vrfname, VRF_DEFAULT_NAME);
+               nb_cli_enqueue_change(vty, xpath_list, NB_OP_DESTROY, NULL);
+       }
+
        snprintf(xpath_list, sizeof(xpath_list), FRR_VRF_KEY_XPATH, vrfname);
 
        nb_cli_enqueue_change(vty, xpath_list, NB_OP_DESTROY, NULL);
-       return nb_cli_apply_changes(vty, xpath_list);
+       return nb_cli_apply_changes(vty, NULL);
 }
 
 
index 6853fc33013bac1196006431b19717ccdad06173..50d116c564b2efe382322940707b6fe249117560 100644 (file)
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -82,6 +82,9 @@ extern struct host host;
 /* Vector which store each vty structure. */
 static vector vtyvec;
 
+/* Vector for vtysh connections. */
+static vector vtyshvec;
+
 /* Vty timeout value. */
 static unsigned long vty_timeout_val = VTY_TIMEOUT_DEFAULT;
 
@@ -2038,6 +2041,7 @@ static int vtysh_accept(struct thread *thread)
        vty->wfd = sock;
        vty->type = VTY_SHELL_SERV;
        vty->node = VIEW_NODE;
+       vector_set_index(vtyshvec, sock, vty);
 
        vty_event(VTYSH_READ, vty);
 
@@ -2211,8 +2215,12 @@ void vty_close(struct vty *vty)
        }
 
        /* Unset vector. */
-       if (vty->fd != -1)
-               vector_unset(vtyvec, vty->fd);
+       if (vty->fd != -1) {
+               if (vty->type == VTY_SHELL_SERV)
+                       vector_unset(vtyshvec, vty->fd);
+               else
+                       vector_unset(vtyvec, vty->fd);
+       }
 
        if (vty->wfd > 0 && vty->type == VTY_FILE)
                fsync(vty->wfd);
@@ -2571,6 +2579,41 @@ void vty_log_fixed(char *buf, size_t len)
        }
 }
 
+static void update_xpath(struct vty *vty, const char *oldpath,
+                        const char *newpath)
+{
+       int i;
+
+       for (i = 0; i < vty->xpath_index; i++) {
+               if (!frrstr_startswith(vty->xpath[i], oldpath))
+                       break;
+
+               char *tmp = frrstr_replace(vty->xpath[i], oldpath, newpath);
+               strlcpy(vty->xpath[i], tmp, sizeof(vty->xpath[0]));
+               XFREE(MTYPE_TMP, tmp);
+       }
+}
+
+void vty_update_xpath(const char *oldpath, const char *newpath)
+{
+       struct vty *vty;
+       unsigned int i;
+
+       for (i = 0; i < vector_active(vtyshvec); i++) {
+               if ((vty = vector_slot(vtyshvec, i)) == NULL)
+                       continue;
+
+               update_xpath(vty, oldpath, newpath);
+       }
+
+       for (i = 0; i < vector_active(vtyvec); i++) {
+               if ((vty = vector_slot(vtyvec, i)) == NULL)
+                       continue;
+
+               update_xpath(vty, oldpath, newpath);
+       }
+}
+
 int vty_config_enter(struct vty *vty, bool private_config, bool exclusive)
 {
        if (exclusive && nb_running_lock(NB_CLIENT_CLI, vty)) {
@@ -3114,6 +3157,7 @@ void vty_init(struct thread_master *master_thread, bool do_command_logging)
        vty_save_cwd();
 
        vtyvec = vector_init(VECTOR_MIN_SIZE);
+       vtyshvec = vector_init(VECTOR_MIN_SIZE);
 
        vty_master = master_thread;
 
@@ -3165,4 +3209,8 @@ void vty_terminate(void)
                vtyvec = NULL;
                Vvty_serv_thread = NULL;
        }
+       if (vtyshvec) {
+               vector_free(vtyshvec);
+               vtyshvec = NULL;
+       }
 }
index 10fbb16a47eefc04517611289b5994eb9be730bd..70ec4fcd849744d900d616d5b648cfbf1de4069d 100644 (file)
--- a/lib/vty.h
+++ b/lib/vty.h
@@ -327,6 +327,7 @@ extern void vty_close(struct vty *);
 extern char *vty_get_cwd(void);
 extern void vty_log(const char *level, const char *proto, const char *msg,
                    struct timestamp_control *);
+extern void vty_update_xpath(const char *oldpath, const char *newpath);
 extern int vty_config_enter(struct vty *vty, bool private_config,
                            bool exclusive);
 extern void vty_config_exit(struct vty *);
index 10dda5ba0efce1872971c1289bf7f097f06d796a..4a70881b579ad58f3982d0fad0fb65ec80d1432e 100644 (file)
@@ -3880,9 +3880,8 @@ static int zclient_read(struct thread *thread)
        length -= ZEBRA_HEADER_SIZE;
 
        if (zclient_debug)
-               zlog_debug("zclient 0x%p command %s VRF %u",
-                          (void *)zclient, zserv_command_string(command),
-                          vrf_id);
+               zlog_debug("zclient %p command %s VRF %u", zclient,
+                          zserv_command_string(command), vrf_id);
 
        switch (command) {
        case ZEBRA_CAPABILITIES:
index 3b624117de769cbd45ae0c3a3e96389e30bc3485..6a02dcb922c8c6afb82d66f6136ae0f7a36895c0 100644 (file)
 #define static_cast(l, r) (r)
 #endif
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #ifndef HAVE_STRLCAT
 size_t strlcat(char *__restrict dest,
               const char *__restrict src, size_t destsize);
@@ -379,4 +383,8 @@ typedef uint32_t route_tag_t;
 #define ROUTE_TAG_MAX UINT32_MAX
 #define ROUTE_TAG_PRI PRIu32
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* _ZEBRA_H */
index 89ab9265d1c3bc2df0d370a8b51f97409fe4592c..6fd52cae62b744efa9c5289dacc5f5483ffd93b2 100644 (file)
@@ -67,6 +67,7 @@ DEFINE_HOOK(zlog_aux_init, (const char *prefix, int prio_min),
 char zlog_prefix[128];
 size_t zlog_prefixsz;
 int zlog_tmpdirfd = -1;
+int zlog_instance = -1;
 
 static atomic_bool zlog_ec = true, zlog_xid = true;
 
@@ -107,6 +108,7 @@ struct zlog_msg {
        size_t stackbufsz;
        char *text;
        size_t textlen;
+       size_t hdrlen;
 
        /* This is always ISO8601 with sub-second precision 9 here, it's
         * converted for callers as needed.  ts_dot points to the "."
@@ -116,8 +118,23 @@ struct zlog_msg {
         * Valid if ZLOG_TS_ISO8601 is set.
         * (0 if timestamp has not been formatted yet)
         */
-       uint32_t ts_flags;
        char ts_str[32], *ts_dot, ts_zonetail[8];
+       uint32_t ts_flags;
+
+       /* "mmm dd hh:mm:ss" for 3164 legacy syslog - too dissimilar from
+        * the above, so just kept separately here.
+        */
+       uint32_t ts_3164_flags;
+       char ts_3164_str[16];
+
+       /* at the time of writing, 16 args was the actual maximum of arguments
+        * to a single zlog call.  Particularly printing flag bitmasks seems
+        * to drive this.  That said, the overhead of dynamically sizing this
+        * probably outweighs the value.  If anything, a printfrr extension
+        * for printing flag bitmasks might be a good idea.
+        */
+       struct fmt_outpos argpos[24];
+       size_t n_argpos;
 };
 
 /* thread-local log message buffering
@@ -204,8 +221,15 @@ static inline void zlog_tls_set(struct zlog_tls *val)
 #endif
 
 #ifdef CAN_DO_TLS
-static long zlog_gettid(void)
+static intmax_t zlog_gettid(void)
 {
+#ifndef __OpenBSD__
+       /* accessing a TLS variable is much faster than a syscall */
+       static thread_local intmax_t cached_tid = -1;
+       if (cached_tid != -1)
+               return cached_tid;
+#endif
+
        long rv = -1;
 #ifdef HAVE_PTHREAD_GETTHREADID_NP
        rv = pthread_getthreadid_np();
@@ -225,6 +249,10 @@ static long zlog_gettid(void)
        rv = mach_thread_self();
        mach_port_deallocate(mach_task_self(), rv);
 #endif
+
+#ifndef __OpenBSD__
+       cached_tid = rv;
+#endif
        return rv;
 }
 
@@ -244,7 +272,7 @@ void zlog_tls_buffer_init(void)
        for (i = 0; i < array_size(zlog_tls->msgp); i++)
                zlog_tls->msgp[i] = &zlog_tls->msgs[i];
 
-       snprintfrr(mmpath, sizeof(mmpath), "logbuf.%ld", zlog_gettid());
+       snprintfrr(mmpath, sizeof(mmpath), "logbuf.%jd", zlog_gettid());
 
        mmfd = openat(zlog_tmpdirfd, mmpath,
                      O_RDWR | O_CREAT | O_EXCL | O_CLOEXEC, 0600);
@@ -311,7 +339,7 @@ void zlog_tls_buffer_fini(void)
        zlog_tls_free(zlog_tls);
        zlog_tls_set(NULL);
 
-       snprintfrr(mmpath, sizeof(mmpath), "logbuf.%ld", zlog_gettid());
+       snprintfrr(mmpath, sizeof(mmpath), "logbuf.%jd", zlog_gettid());
        if (do_unlink && unlinkat(zlog_tmpdirfd, mmpath, 0))
                zlog_err("unlink logbuf: %s (%d)", strerror(errno), errno);
 }
@@ -326,6 +354,24 @@ void zlog_tls_buffer_fini(void)
 }
 #endif
 
+void zlog_msg_pid(struct zlog_msg *msg, intmax_t *pid, intmax_t *tid)
+{
+#ifndef __OpenBSD__
+       static thread_local intmax_t cached_pid = -1;
+       if (cached_pid != -1)
+               *pid = cached_pid;
+       else
+               cached_pid = *pid = (intmax_t)getpid();
+#else
+       *pid = (intmax_t)getpid();
+#endif
+#ifdef CAN_DO_TLS
+       *tid = zlog_gettid();
+#else
+       *tid = *pid;
+#endif
+}
+
 static inline void zlog_tls_free(void *arg)
 {
        struct zlog_tls *zlog_tls = arg;
@@ -592,15 +638,19 @@ const char *zlog_msg_text(struct zlog_msg *msg, size_t *textlen)
                if (need)
                        need += bputch(&fb, ' ');
 
-               hdrlen = need;
+               msg->hdrlen = hdrlen = need;
                assert(hdrlen < msg->stackbufsz);
 
+               fb.outpos = msg->argpos;
+               fb.outpos_n = array_size(msg->argpos);
+               fb.outpos_i = 0;
+
                va_copy(args, msg->args);
                need += vbprintfrr(&fb, msg->fmt, args);
                va_end(args);
 
                msg->textlen = need;
-               need += bputch(&fb, '\0');
+               need += bputch(&fb, '\n');
 
                if (need <= msg->stackbufsz)
                        msg->text = msg->stackbuf;
@@ -612,25 +662,42 @@ const char *zlog_msg_text(struct zlog_msg *msg, size_t *textlen)
                        fb.buf = msg->text;
                        fb.len = need;
                        fb.pos = msg->text + hdrlen;
+                       fb.outpos_i = 0;
 
                        va_copy(args, msg->args);
                        vbprintfrr(&fb, msg->fmt, args);
                        va_end(args);
 
-                       bputch(&fb, '\0');
+                       bputch(&fb, '\n');
                }
+
+               msg->n_argpos = fb.outpos_i;
        }
        if (textlen)
                *textlen = msg->textlen;
        return msg->text;
 }
 
+void zlog_msg_args(struct zlog_msg *msg, size_t *hdrlen, size_t *n_argpos,
+                  const struct fmt_outpos **argpos)
+{
+       if (!msg->text)
+               zlog_msg_text(msg, NULL);
+
+       if (hdrlen)
+               *hdrlen = msg->hdrlen;
+       if (n_argpos)
+               *n_argpos = msg->n_argpos;
+       if (argpos)
+               *argpos = msg->argpos;
+}
+
 #define ZLOG_TS_FORMAT         (ZLOG_TS_ISO8601 | ZLOG_TS_LEGACY)
 #define ZLOG_TS_FLAGS          ~ZLOG_TS_PREC
 
-size_t zlog_msg_ts(struct zlog_msg *msg, char *out, size_t outsz,
-                  uint32_t flags)
+size_t zlog_msg_ts(struct zlog_msg *msg, struct fbuf *out, uint32_t flags)
 {
+       size_t outsz = out ? (out->buf + out->len - out->pos) : 0;
        size_t len1;
 
        if (!(flags & ZLOG_TS_FORMAT))
@@ -672,36 +739,78 @@ size_t zlog_msg_ts(struct zlog_msg *msg, char *out, size_t outsz,
                len1 = strlen(msg->ts_str);
 
        if (flags & ZLOG_TS_LEGACY) {
-               if (len1 + 1 > outsz)
-                       return 0;
+               if (!out)
+                       return len1;
+
+               if (len1 > outsz) {
+                       memset(out->pos, 0, outsz);
+                       out->pos += outsz;
+                       return len1;
+               }
 
                /* just swap out the formatting, faster than redoing it */
                for (char *p = msg->ts_str; p < msg->ts_str + len1; p++) {
                        switch (*p) {
                        case '-':
-                               *out++ = '/';
+                               *out->pos++ = '/';
                                break;
                        case 'T':
-                               *out++ = ' ';
+                               *out->pos++ = ' ';
                                break;
                        default:
-                               *out++ = *p;
+                               *out->pos++ = *p;
                        }
                }
-               *out = '\0';
                return len1;
        } else {
                size_t len2 = strlen(msg->ts_zonetail);
 
-               if (len1 + len2 + 1 > outsz)
-                       return 0;
-               memcpy(out, msg->ts_str, len1);
-               memcpy(out + len1, msg->ts_zonetail, len2);
-               out[len1 + len2] = '\0';
+               if (!out)
+                       return len1 + len2;
+
+               if (len1 + len2 > outsz) {
+                       memset(out->pos, 0, outsz);
+                       out->pos += outsz;
+                       return len1 + len2;
+               }
+
+               memcpy(out->pos, msg->ts_str, len1);
+               out->pos += len1;
+               memcpy(out->pos, msg->ts_zonetail, len2);
+               out->pos += len2;
                return len1 + len2;
        }
 }
 
+size_t zlog_msg_ts_3164(struct zlog_msg *msg, struct fbuf *out, uint32_t flags)
+{
+       flags &= ZLOG_TS_UTC;
+
+       if (!msg->ts_3164_str[0] || flags != msg->ts_3164_flags) {
+               /* these are "hardcoded" in RFC3164, so they're here too... */
+               static const char *const months[12] = {
+                       "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+                       "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
+               };
+               struct tm tm;
+
+               /* RFC3164 explicitly asks for local time, but common usage
+                * also includes UTC.
+                */
+               if (flags & ZLOG_TS_UTC)
+                       gmtime_r(&msg->ts.tv_sec, &tm);
+               else
+                       localtime_r(&msg->ts.tv_sec, &tm);
+
+               snprintfrr(msg->ts_3164_str, sizeof(msg->ts_3164_str),
+                          "%3s %2d %02d:%02d:%02d", months[tm.tm_mon],
+                          tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
+
+               msg->ts_3164_flags = flags;
+       }
+       return bputs(out, msg->ts_3164_str);
+}
+
 void zlog_set_prefix_ec(bool enable)
 {
        atomic_store_explicit(&zlog_ec, enable, memory_order_relaxed);
@@ -777,6 +886,7 @@ void zlog_init(const char *progname, const char *protoname,
 {
        zlog_uid = uid;
        zlog_gid = gid;
+       zlog_instance = instance;
 
        if (instance) {
                snprintfrr(zlog_tmpdir, sizeof(zlog_tmpdir),
index c421c16f38835dfe63a0b12a8bb3d06c146f82b4..d9c8952ac553c8c6c66a4fa321e610d86867e820 100644 (file)
 #include "frrcu.h"
 #include "memory.h"
 #include "hook.h"
+#include "printfrr.h"
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+DECLARE_MGROUP(LOG);
+
 extern char zlog_prefix[];
 extern size_t zlog_prefixsz;
 extern int zlog_tmpdirfd;
+extern int zlog_instance;
+extern const char *zlog_progname;
 
 struct xref_logmsg {
        struct xref xref;
@@ -143,9 +148,18 @@ struct zlog_msg;
 extern int zlog_msg_prio(struct zlog_msg *msg);
 extern const struct xref_logmsg *zlog_msg_xref(struct zlog_msg *msg);
 
-/* pass NULL as textlen if you don't need it. */
+/* text is NOT \0 terminated; instead there is a \n after textlen since the
+ * logging targets would jump extra hoops otherwise for a single byte.  (the
+ * \n is not included in textlen)
+ *
+ * calling this with NULL textlen is likely wrong.
+ * use  "%.*s", (int)textlen, text  when passing to printf-like functions
+ */
 extern const char *zlog_msg_text(struct zlog_msg *msg, size_t *textlen);
 
+extern void zlog_msg_args(struct zlog_msg *msg, size_t *hdrlen,
+                         size_t *n_argpos, const struct fmt_outpos **argpos);
+
 /* timestamp formatting control flags */
 
 /* sub-second digit count */
@@ -161,9 +175,18 @@ extern const char *zlog_msg_text(struct zlog_msg *msg, size_t *textlen);
 /* default is local time zone */
 #define ZLOG_TS_UTC            (1 << 10)
 
-extern size_t zlog_msg_ts(struct zlog_msg *msg, char *out, size_t outsz,
+extern size_t zlog_msg_ts(struct zlog_msg *msg, struct fbuf *out,
                          uint32_t flags);
 
+/* "mmm dd hh:mm:ss" for RFC3164 syslog.  Only ZLOG_TS_UTC for flags. */
+extern size_t zlog_msg_ts_3164(struct zlog_msg *msg, struct fbuf *out,
+                              uint32_t flags);
+
+/* currently just returns the current PID/TID since we never write another
+ * thread's messages
+ */
+extern void zlog_msg_pid(struct zlog_msg *msg, intmax_t *pid, intmax_t *tid);
+
 /* This list & struct implements the actual logging targets.  It is accessed
  * lock-free from all threads, and thus MUST only be changed atomically, i.e.
  * RCU.
@@ -254,6 +277,8 @@ extern void zlog_tls_buffer_fini(void);
 /* Enable or disable 'immediate' output - default is to buffer messages. */
 extern void zlog_set_immediate(bool set_p);
 
+extern const char *zlog_priority_str(int priority);
+
 #ifdef __cplusplus
 }
 #endif
index 7799fbfda75015d81a3309cf69525dcb52fd102a..48785ad298568aae6398ab25e474701216140c7c 100644 (file)
@@ -31,7 +31,6 @@
  * absolute end.
  */
 
-DECLARE_MGROUP(LOG);
 DEFINE_MGROUP_ACTIVEATEXIT(LOG, "logging subsystem");
 
 DEFINE_MTYPE_STATIC(LOG, LOG_FD,        "log file target");
@@ -79,13 +78,17 @@ void zlog_fd(struct zlog_target *zt, struct zlog_msg *msgs[], size_t nmsgs)
                int prio = zlog_msg_prio(msg);
 
                if (prio <= zt->prio_min) {
+                       struct fbuf fbuf = {
+                               .buf = ts_buf,
+                               .pos = ts_pos,
+                               .len = sizeof(ts_buf),
+                       };
+
                        iov[iovpos].iov_base = ts_pos;
-                       if (iovpos > 0)
-                               *ts_pos++ = '\n';
-                       ts_pos += zlog_msg_ts(msg, ts_pos,
-                                             sizeof(ts_buf) - 1
-                                                     - (ts_pos - ts_buf),
-                                             ZLOG_TS_LEGACY | zte->ts_subsec);
+                       zlog_msg_ts(msg, &fbuf,
+                                   ZLOG_TS_LEGACY | zte->ts_subsec);
+                       ts_pos = fbuf.pos;
+
                        *ts_pos++ = ' ';
                        iov[iovpos].iov_len =
                                ts_pos - (char *)iov[iovpos].iov_base;
@@ -107,7 +110,7 @@ void zlog_fd(struct zlog_target *zt, struct zlog_msg *msgs[], size_t nmsgs)
 
                        iov[iovpos].iov_base =
                                (char *)zlog_msg_text(msg, &textlen);
-                       iov[iovpos].iov_len = textlen;
+                       iov[iovpos].iov_len = textlen + 1;
 
                        iovpos++;
                }
@@ -120,11 +123,6 @@ void zlog_fd(struct zlog_target *zt, struct zlog_msg *msgs[], size_t nmsgs)
                if (iovpos > 0 && (ts_buf + sizeof(ts_buf) - ts_pos < TS_LEN
                                   || i + 1 == nmsgs
                                   || array_size(iov) - iovpos < 5)) {
-                       iov[iovpos].iov_base = (char *)"\n";
-                       iov[iovpos].iov_len = 1;
-
-                       iovpos++;
-
                        writev(fd, iov, iovpos);
 
                        iovpos = 0;
@@ -439,13 +437,16 @@ static void zlog_syslog(struct zlog_target *zt, struct zlog_msg *msgs[],
 {
        size_t i;
        struct zlt_syslog *zte = container_of(zt, struct zlt_syslog, zt);
+       const char *text;
+       size_t text_len;
 
        for (i = 0; i < nmsgs; i++) {
                if (zlog_msg_prio(msgs[i]) > zt->prio_min)
                        continue;
 
-               syslog(zlog_msg_prio(msgs[i]) | zte->syslog_facility, "%s",
-                      zlog_msg_text(msgs[i], NULL));
+               text = zlog_msg_text(msgs[i], &text_len);
+               syslog(zlog_msg_prio(msgs[i]) | zte->syslog_facility, "%.*s",
+                      (int)text_len, text);
        }
 }
 
index c2111a7706ff2cf61804bf33144c9b821d843ad9..54b785020727b8d53cc2b015a73b0adc30bbdaf6 100644 (file)
@@ -118,6 +118,7 @@ static struct quagga_signal_t sighandlers[] = {
 static const struct frr_yang_module_info *const nhrpd_yang_modules[] = {
        &frr_filter_info,
        &frr_interface_info,
+       &frr_vrf_info,
 };
 
 FRR_DAEMON_INFO(nhrpd, NHRP, .vty_port = NHRP_VTY_PORT,
index 420ea12ec1e23c9771370a11aaee54af9d216ed0..963fa4d9957c9cf9f6966e6567146050030fc23e 100644 (file)
@@ -1260,6 +1260,8 @@ void nhrp_config_init(void)
        install_element(CONFIG_NODE, &nhrp_multicast_nflog_group_cmd);
        install_element(CONFIG_NODE, &no_nhrp_multicast_nflog_group_cmd);
 
+       vrf_cmd_init(NULL, &nhrpd_privs);
+
        /* interface specific commands */
        install_node(&nhrp_interface_node);
 
index 1af8aed1a9c3474e3bef1ee3330e21272843a56c..f289bf26b933279eb71250b2770d3b50bfb56296 100644 (file)
 #include "ospf6_asbr.h"
 #include "ospf6_abr.h"
 #include "ospf6d.h"
+#include "ospf6_nssa.h"
 
 unsigned char conf_debug_ospf6_abr;
 
-int ospf6_is_router_abr(struct ospf6 *o)
+bool ospf6_check_and_set_router_abr(struct ospf6 *o)
 {
        struct listnode *node;
        struct ospf6_area *oa;
        int area_count = 0;
+       bool is_backbone = false;
 
-       for (ALL_LIST_ELEMENTS_RO(o->area_list, node, oa))
+       for (ALL_LIST_ELEMENTS_RO(o->area_list, node, oa)) {
+               if (IS_OSPF6_DEBUG_ABR)
+                       zlog_debug("%s, area_id %pI4", __func__, &oa->area_id);
                if (IS_AREA_ENABLED(oa))
                        area_count++;
 
-       if (area_count > 1)
-               return 1;
-       return 0;
+               if (o->backbone == oa)
+                       is_backbone = true;
+       }
+
+       if ((area_count > 1) && (is_backbone)) {
+               if (IS_OSPF6_DEBUG_ABR)
+                       zlog_debug("%s : set flag OSPF6_FLAG_ABR", __func__);
+               SET_FLAG(o->flag, OSPF6_FLAG_ABR);
+               return true;
+       } else {
+               if (IS_OSPF6_DEBUG_ABR)
+                       zlog_debug("%s : reset flag OSPF6_FLAG_ABR", __func__);
+               UNSET_FLAG(o->flag, OSPF6_FLAG_ABR);
+               return false;
+       }
 }
 
 static int ospf6_abr_nexthops_belong_to_area(struct ospf6_route *route,
@@ -156,37 +172,72 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route,
        uint16_t type;
        int is_debug = 0;
 
+       if (IS_OSPF6_DEBUG_ABR)
+               zlog_debug("%s : start area %s, route %pFX", __func__,
+                          area->name, &route->prefix);
+
+       if (route->type == OSPF6_DEST_TYPE_ROUTER)
+               summary_table = area->summary_router;
+       else
+               summary_table = area->summary_prefix;
+
+       summary = ospf6_route_lookup(&route->prefix, summary_table);
+       if (summary) {
+               old = ospf6_lsdb_lookup(summary->path.origin.type,
+                                       summary->path.origin.id,
+                                       area->ospf6->router_id, area->lsdb);
+               /* Reset the OSPF6_LSA_UNAPPROVED flag */
+               if (old)
+                       UNSET_FLAG(old->flag, OSPF6_LSA_UNAPPROVED);
+       }
+
        /* Only destination type network, range or ASBR are considered */
        if (route->type != OSPF6_DEST_TYPE_NETWORK
            && route->type != OSPF6_DEST_TYPE_RANGE
            && ((route->type != OSPF6_DEST_TYPE_ROUTER)
                || !CHECK_FLAG(route->path.router_bits, OSPF6_ROUTER_BIT_E))) {
+               if (IS_OSPF6_DEBUG_ABR)
+                       zlog_debug(
+                               "%s: Route type %d flag 0x%x is none of network, range nor ASBR, ignore",
+                               __func__, route->type, route->path.router_bits);
                return 0;
        }
 
        /* AS External routes are never considered */
        if (route->path.type == OSPF6_PATH_TYPE_EXTERNAL1
            || route->path.type == OSPF6_PATH_TYPE_EXTERNAL2) {
+               if (IS_OSPF6_DEBUG_ABR)
+                       zlog_debug("%s : Path type is external, skip",
+                                  __func__);
                return 0;
        }
 
        /* do not generate if the path's area is the same as target area */
        if (route->path.area_id == area->area_id) {
+               if (IS_OSPF6_DEBUG_ABR)
+                       zlog_debug(
+                               "%s: The route is in the area itself, ignore",
+                               __func__);
                return 0;
        }
 
        /* do not generate if the nexthops belongs to the target area */
        if (ospf6_abr_nexthops_belong_to_area(route, area)) {
+               if (IS_OSPF6_DEBUG_ABR)
+                       zlog_debug(
+                               "%s: The route's nexthop is in the same area, ignore",
+                               __func__);
                return 0;
        }
 
        if (route->type == OSPF6_DEST_TYPE_ROUTER) {
                if (ADV_ROUTER_IN_PREFIX(&route->prefix)
                    == area->ospf6->router_id) {
-                       zlog_debug(
-                               "%s: Skipping ASBR announcement for ABR (%pI4)",
-                               __func__,
-                               &ADV_ROUTER_IN_PREFIX(&route->prefix));
+                       if (IS_OSPF6_DEBUG_ABR)
+                               zlog_debug(
+                                       "%s: Skipping ASBR announcement for ABR (%pI4)",
+                                       __func__,
+                                       &ADV_ROUTER_IN_PREFIX(&route->prefix));
                        return 0;
                }
        }
@@ -195,12 +246,12 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route,
                if (IS_OSPF6_DEBUG_ABR
                    || IS_OSPF6_DEBUG_ORIGINATE(INTER_ROUTER)) {
                        is_debug++;
-                       zlog_debug(
-                               "Originating summary in area %s for ASBR %pI4",
-                               area->name,
-                               &ADV_ROUTER_IN_PREFIX(&route->prefix));
+                       if (IS_OSPF6_DEBUG_ABR)
+                               zlog_debug(
+                                       "Originating summary in area %s for ASBR %pI4",
+                                       area->name,
+                                       &ADV_ROUTER_IN_PREFIX(&route->prefix));
                }
-               summary_table = area->summary_router;
        } else {
                if (IS_OSPF6_DEBUG_ABR
                    || IS_OSPF6_DEBUG_ORIGINATE(INTER_PREFIX))
@@ -235,15 +286,8 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route,
                        zlog_debug(
                                "Originating summary in area %s for %pFX cost %u",
                                area->name, &route->prefix, route->path.cost);
-               summary_table = area->summary_prefix;
        }
 
-       summary = ospf6_route_lookup(&route->prefix, summary_table);
-       if (summary)
-               old = ospf6_lsdb_lookup(summary->path.origin.type,
-                                       summary->path.origin.id,
-                                       area->ospf6->router_id, area->lsdb);
-
        /* if this route has just removed, remove corresponding LSA */
        if (CHECK_FLAG(route->flag, OSPF6_ROUTE_REMOVE)) {
                if (is_debug)
@@ -496,9 +540,15 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route,
        /* create LSA */
        lsa = ospf6_lsa_create(lsa_header);
 
+       /* Reset the unapproved flag */
+       UNSET_FLAG(lsa->flag, OSPF6_LSA_UNAPPROVED);
+
        /* Originate */
        ospf6_lsa_originate_area(lsa, area);
 
+       if (IS_OSPF6_DEBUG_ABR)
+               zlog_debug("%s : finish area %s", __func__, area->name);
+
        return 1;
 }
 
@@ -566,8 +616,7 @@ ospf6_abr_range_summary_needs_update(struct ospf6_route *range, uint32_t cost)
        return (redo_summary);
 }
 
-static void ospf6_abr_range_update(struct ospf6_route *range,
-                                  struct ospf6 *ospf6)
+void ospf6_abr_range_update(struct ospf6_route *range, struct ospf6 *ospf6)
 {
        uint32_t cost = 0;
        struct listnode *node, *nnode;
@@ -579,6 +628,10 @@ static void ospf6_abr_range_update(struct ospf6_route *range,
        /* update range's cost and active flag */
        cost = ospf6_abr_range_compute_cost(range, ospf6);
 
+       if (IS_OSPF6_DEBUG_ABR)
+               zlog_debug("%s: range %pFX, cost %d", __func__, &range->prefix,
+                          cost);
+
        /* Non-zero cost is a proxy for active longer prefixes in this range.
         * If there are active routes covered by this range AND either the
         * configured
@@ -595,6 +648,9 @@ static void ospf6_abr_range_update(struct ospf6_route *range,
         */
 
        if (ospf6_abr_range_summary_needs_update(range, cost)) {
+               if (IS_OSPF6_DEBUG_ABR)
+                       zlog_debug("%s: range %pFX update", __func__,
+                                  &range->prefix);
                for (ALL_LIST_ELEMENTS(ospf6->area_list, node, nnode, oa))
                        summary_orig +=
                                ospf6_abr_originate_summary_to_area(range, oa);
@@ -628,6 +684,8 @@ void ospf6_abr_originate_summary(struct ospf6_route *route, struct ospf6 *ospf6)
        struct ospf6_area *oa;
        struct ospf6_route *range = NULL;
 
+       if (IS_OSPF6_DEBUG_ABR)
+               zlog_debug("%s: route %pFX", __func__, &route->prefix);
 
        if (route->type == OSPF6_DEST_TYPE_NETWORK) {
                oa = ospf6_area_lookup(route->path.area_id, ospf6);
@@ -1301,7 +1359,7 @@ void ospf6_abr_reexport(struct ospf6_area *oa)
        struct ospf6_route *route;
 
        /* if not a ABR return success */
-       if (!ospf6_is_router_abr(oa->ospf6))
+       if (!ospf6_check_and_set_router_abr(oa->ospf6))
                return;
 
        /* Redo summaries if required */
index 6a912ac63055e4781b9fed5456d44bcaa7629705..a5f0f124b9421fa48d503820a3dc4590238ef0e3 100644 (file)
@@ -56,8 +56,9 @@ struct ospf6_inter_router_lsa {
        }
 
 #define OSPF6_ABR_RANGE_CLEAR_COST(range) (range->path.cost = OSPF_AREA_RANGE_COST_UNSPEC)
+#define IS_OSPF6_ABR(o) ((o)->flag & OSPF6_FLAG_ABR)
 
-extern int ospf6_is_router_abr(struct ospf6 *o);
+extern bool ospf6_check_and_set_router_abr(struct ospf6 *o);
 
 extern void ospf6_abr_enable_area(struct ospf6_area *oa);
 extern void ospf6_abr_disable_area(struct ospf6_area *oa);
@@ -88,5 +89,8 @@ extern void ospf6_abr_old_path_update(struct ospf6_route *old_route,
                                      struct ospf6_route_table *table);
 extern void ospf6_abr_init(void);
 extern void ospf6_abr_reexport(struct ospf6_area *oa);
+extern void ospf6_abr_range_update(struct ospf6_route *range,
+                                  struct ospf6 *ospf6);
+extern void ospf6_abr_remove_unapproved_summaries(struct ospf6 *ospf6);
 
 #endif /*OSPF6_ABR_H*/
index d65e40279dc57c0cf6818ae82b3071f1266b1e3b..355b8441bd462b4727e976b78054fbb9e132e711 100644 (file)
 #include "ospf6_asbr.h"
 #include "ospf6d.h"
 #include "lib/json.h"
+#include "ospf6_nssa.h"
 
 DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_AREA,      "OSPF6 area");
 DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_PLISTNAME, "Prefix list name");
 
+int str2area_id(const char *str, uint32_t *area_id, int *area_id_fmt)
+{
+       char *ep;
+
+       *area_id = htonl(strtoul(str, &ep, 10));
+       if (*ep && inet_pton(AF_INET, str, area_id) != 1)
+               return -1;
+
+       *area_id_fmt =
+               !*ep ? OSPF6_AREA_FMT_DECIMAL : OSPF6_AREA_FMT_DOTTEDQUAD;
+
+       return 0;
+}
+
+void area_id2str(char *buf, int len, uint32_t area_id, int area_id_fmt)
+{
+       if (area_id_fmt == OSPF6_AREA_FMT_DECIMAL)
+               snprintf(buf, len, "%u", ntohl(area_id));
+       else
+               inet_ntop(AF_INET, &area_id, buf, len);
+}
+
 int ospf6_area_cmp(void *va, void *vb)
 {
        struct ospf6_area *oa = (struct ospf6_area *)va;
@@ -60,6 +83,7 @@ int ospf6_area_cmp(void *va, void *vb)
 static void ospf6_area_lsdb_hook_add(struct ospf6_lsa *lsa)
 {
        switch (ntohs(lsa->header->type)) {
+
        case OSPF6_LSTYPE_ROUTER:
        case OSPF6_LSTYPE_NETWORK:
                if (IS_OSPF6_DEBUG_EXAMIN_TYPE(lsa->header->type)) {
@@ -82,6 +106,10 @@ static void ospf6_area_lsdb_hook_add(struct ospf6_lsa *lsa)
                                         (struct ospf6_area *)lsa->lsdb->data);
                break;
 
+       case OSPF6_LSTYPE_TYPE_7:
+               ospf6_asbr_lsa_add(lsa);
+               break;
+
        default:
                break;
        }
@@ -111,7 +139,9 @@ static void ospf6_area_lsdb_hook_remove(struct ospf6_lsa *lsa)
                ospf6_abr_examin_summary(lsa,
                                         (struct ospf6_area *)lsa->lsdb->data);
                break;
-
+       case OSPF6_LSTYPE_TYPE_7:
+               ospf6_asbr_lsa_remove(lsa, NULL);
+               break;
        default:
                break;
        }
@@ -516,7 +546,7 @@ DEFUN (area_range,
                ospf6_route_add(range, oa->range_table);
        }
 
-       if (ospf6_is_router_abr(ospf6)) {
+       if (ospf6_check_and_set_router_abr(ospf6)) {
                /* Redo summaries if required */
                ospf6_abr_prefix_resummarize(ospf6);
        }
@@ -562,7 +592,7 @@ DEFUN (no_area_range,
                return CMD_SUCCESS;
        }
 
-       if (ospf6_is_router_abr(oa->ospf6)) {
+       if (ospf6_check_and_set_router_abr(oa->ospf6)) {
                /* Blow away the aggregated LSA and route */
                SET_FLAG(range->flag, OSPF6_ROUTE_REMOVE);
 
@@ -611,6 +641,8 @@ void ospf6_area_config_write(struct vty *vty, struct ospf6 *ospf6)
                        else
                                vty_out(vty, " area %s stub\n", oa->name);
                }
+               if (IS_AREA_NSSA(oa))
+                       vty_out(vty, " area %s nssa\n", oa->name);
                if (PREFIX_NAME_IN(oa))
                        vty_out(vty, " area %s filter-list prefix %s in\n",
                                oa->name, PREFIX_NAME_IN(oa));
@@ -1216,6 +1248,48 @@ DEFUN (no_ospf6_area_stub_no_summary,
        return CMD_SUCCESS;
 }
 
+DEFUN(ospf6_area_nssa, ospf6_area_nssa_cmd,
+      "area <A.B.C.D|(0-4294967295)> nssa",
+      "OSPF6 area parameters\n"
+      "OSPF6 area ID in IP address format\n"
+      "OSPF6 area ID as a decimal value\n"
+      "Configure OSPF6 area as nssa\n")
+{
+       int idx_ipv4_number = 1;
+       struct ospf6_area *area;
+
+       VTY_DECLVAR_CONTEXT(ospf6, ospf6);
+       OSPF6_CMD_AREA_GET(argv[idx_ipv4_number]->arg, area, ospf6);
+
+       if (!ospf6_area_nssa_set(ospf6, area)) {
+               vty_out(vty,
+                       "First deconfigure all virtual link through this area\n");
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       return CMD_SUCCESS;
+}
+
+DEFUN(no_ospf6_area_nssa, no_ospf6_area_nssa_cmd,
+      "no area <A.B.C.D|(0-4294967295)> nssa",
+      NO_STR
+      "OSPF6 area parameters\n"
+      "OSPF6 area ID in IP address format\n"
+      "OSPF6 area ID as a decimal value\n"
+      "Configure OSPF6 area as nssa\n")
+{
+       int idx_ipv4_number = 2;
+       struct ospf6_area *area;
+
+       VTY_DECLVAR_CONTEXT(ospf6, ospf6);
+       OSPF6_CMD_AREA_GET(argv[idx_ipv4_number]->arg, area, ospf6);
+
+       ospf6_area_nssa_unset(ospf6, area);
+
+       return CMD_SUCCESS;
+}
+
+
 void ospf6_area_init(void)
 {
        install_element(VIEW_NODE, &show_ipv6_ospf6_spf_tree_cmd);
@@ -1237,6 +1311,10 @@ void ospf6_area_init(void)
 
        install_element(OSPF6_NODE, &area_filter_list_cmd);
        install_element(OSPF6_NODE, &no_area_filter_list_cmd);
+
+       /* "area nssa" commands. */
+       install_element(OSPF6_NODE, &ospf6_area_nssa_cmd);
+       install_element(OSPF6_NODE, &no_ospf6_area_nssa_cmd);
 }
 
 void ospf6_area_interface_delete(struct ospf6_interface *oi)
index 761fe75f73a5b1dc6d78a754c6258c7e1cbd9b96..dd4d019015caf440656b711d2debd59021d5b4a7 100644 (file)
@@ -31,6 +31,7 @@ struct ospf6_area {
        /* Area-ID */
        in_addr_t area_id;
 
+#define OSPF6_AREA_FMT_UNSET      0
 #define OSPF6_AREA_FMT_DOTTEDQUAD 1
 #define OSPF6_AREA_FMT_DECIMAL    2
        /* Area-ID string */
@@ -106,34 +107,46 @@ struct ospf6_area {
 
        uint32_t full_nbrs; /* Fully adjacent neighbors. */
        uint8_t intra_prefix_originate; /* Force intra_prefix lsa originate */
+       uint8_t NSSATranslatorRole;     /* NSSA configured role */
+#define OSPF6_NSSA_ROLE_NEVER     0
+#define OSPF6_NSSA_ROLE_CANDIDATE 1
+#define OSPF6_NSSA_ROLE_ALWAYS    2
+       uint8_t NSSATranslatorState; /* NSSA operational role */
+#define OSPF6_NSSA_TRANSLATE_DISABLED 0
+#define OSPF6_NSSA_TRANSLATE_ENABLED  1
 };
 
+#define OSPF6_AREA_DEFAULT    0x00
 #define OSPF6_AREA_ENABLE     0x01
 #define OSPF6_AREA_ACTIVE     0x02
 #define OSPF6_AREA_TRANSIT    0x04 /* TransitCapability */
 #define OSPF6_AREA_STUB       0x08
+#define OSPF6_AREA_NSSA       0x10
 
 #define IS_AREA_ENABLED(oa) (CHECK_FLAG ((oa)->flag, OSPF6_AREA_ENABLE))
 #define IS_AREA_ACTIVE(oa) (CHECK_FLAG ((oa)->flag, OSPF6_AREA_ACTIVE))
 #define IS_AREA_TRANSIT(oa) (CHECK_FLAG ((oa)->flag, OSPF6_AREA_TRANSIT))
 #define IS_AREA_STUB(oa) (CHECK_FLAG ((oa)->flag, OSPF6_AREA_STUB))
+#define IS_AREA_NSSA(oa) (CHECK_FLAG((oa)->flag, OSPF6_AREA_NSSA))
 
 #define OSPF6_CMD_AREA_GET(str, oa, ospf6)                                     \
        {                                                                      \
-               char *ep;                                                      \
-               uint32_t area_id = htonl(strtoul(str, &ep, 10));               \
-               if (*ep && inet_pton(AF_INET, str, &area_id) != 1) {           \
+               uint32_t area_id;                                              \
+               int format, ret;                                               \
+               ret = str2area_id(str, &area_id, &format);                     \
+               if (ret) {                                                     \
                        vty_out(vty, "Malformed Area-ID: %s\n", str);          \
-                       return CMD_SUCCESS;                                    \
+                       return CMD_WARNING;                                    \
                }                                                              \
-               int format = !*ep ? OSPF6_AREA_FMT_DECIMAL                     \
-                                 : OSPF6_AREA_FMT_DOTTEDQUAD;                 \
                oa = ospf6_area_lookup(area_id, ospf6);                        \
                if (oa == NULL)                                                \
                        oa = ospf6_area_create(area_id, ospf6, format);        \
        }
 
 /* prototypes */
+extern int str2area_id(const char *str, uint32_t *area_id, int *area_id_fmt);
+extern void area_id2str(char *buf, int len, uint32_t area_id, int area_id_fmt);
+
 extern int ospf6_area_cmp(void *va, void *vb);
 
 extern struct ospf6_area *ospf6_area_create(uint32_t, struct ospf6 *, int);
index 35f50898a686fb42053cd3d809ee092f2969fc21..ba355a347e3b1922bbef3029af72ac8f974ff352 100644 (file)
 #include "ospf6_intra.h"
 #include "ospf6_flood.h"
 #include "ospf6d.h"
+#include "ospf6_spf.h"
+#include "ospf6_nssa.h"
 #include "lib/json.h"
 
 DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_EXTERNAL_INFO, "OSPF6 ext. info");
 DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_DIST_ARGS,     "OSPF6 Distribute arguments");
 DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_REDISTRIBUTE, "OSPF6 Redistribute arguments");
 
-static void ospf6_asbr_redistribute_set(int type, vrf_id_t vrf_id);
+static void ospf6_asbr_redistribute_set(struct ospf6 *ospf6, int type);
 static void ospf6_asbr_redistribute_unset(struct ospf6 *ospf6,
                                          struct ospf6_redist *red, int type);
 
@@ -69,8 +71,8 @@ unsigned char conf_debug_ospf6_asbr = 0;
 #define ZROUTE_NAME(x) zebra_route_string(x)
 
 /* AS External LSA origination */
-static void ospf6_as_external_lsa_originate(struct ospf6_route *route,
-                                           struct ospf6 *ospf6)
+void ospf6_as_external_lsa_originate(struct ospf6_route *route,
+                                    struct ospf6 *ospf6)
 {
        char buffer[OSPF6_MAX_LSASIZE];
        struct ospf6_lsa_header *lsa_header;
@@ -175,6 +177,8 @@ int ospf6_orig_as_external_lsa(struct thread *thread)
 
        if (oi->state == OSPF6_INTERFACE_DOWN)
                return 0;
+       if (IS_AREA_NSSA(oi->area))
+               return 0;
 
        type = htons(OSPF6_LSTYPE_AS_EXTERNAL);
        adv_router = oi->area->ospf6->router_id;
@@ -458,13 +462,48 @@ void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old,
        }
 }
 
+/* Check if the forwarding address is local address */
+static int ospf6_ase_forward_address_check(struct ospf6 *ospf6,
+                                          struct in6_addr *fwd_addr)
+{
+       struct listnode *anode, *node, *cnode;
+       struct ospf6_interface *oi;
+       struct ospf6_area *oa;
+       struct interface *ifp;
+       struct connected *c;
+
+       for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, anode, oa)) {
+               for (ALL_LIST_ELEMENTS_RO(oa->if_list, node, oi)) {
+                       if (!if_is_operative(oi->interface)
+                           || oi->type == OSPF_IFTYPE_VIRTUALLINK)
+                               continue;
+
+                       ifp = oi->interface;
+                       for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, c)) {
+                               if (IPV6_ADDR_SAME(&c->address->u.prefix6,
+                                                  fwd_addr))
+                                       return 0;
+                       }
+               }
+       }
+
+       return 1;
+}
+
 void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa)
 {
        struct ospf6_as_external_lsa *external;
        struct prefix asbr_id;
-       struct ospf6_route *asbr_entry, *route, *old;
+       struct ospf6_route *asbr_entry, *route, *old = NULL;
        struct ospf6_path *path;
        struct ospf6 *ospf6;
+       int type;
+       struct ospf6_area *oa = NULL;
+       struct prefix fwd_addr;
+       ptrdiff_t offset;
+
+       type = ntohs(lsa->header->type);
+       oa = lsa->lsdb->data;
 
        external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END(
                lsa->header);
@@ -495,11 +534,53 @@ void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa)
 
        ospf6_linkstate_prefix(lsa->header->adv_router, htonl(0), &asbr_id);
        asbr_entry = ospf6_route_lookup(&asbr_id, ospf6->brouter_table);
-       if (asbr_entry == NULL
-           || !CHECK_FLAG(asbr_entry->path.router_bits, OSPF6_ROUTER_BIT_E)) {
+       if (asbr_entry == NULL) {
                if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
                        zlog_debug("ASBR entry not found: %pFX", &asbr_id);
                return;
+       } else {
+               /* The router advertising external LSA can be ASBR or ABR */
+               if (!CHECK_FLAG(asbr_entry->path.router_bits,
+                               OSPF6_ROUTER_BIT_E)) {
+                       if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
+                               zlog_debug(
+                                       "External bit reset ASBR route entry : %pFX",
+                                       &asbr_id);
+                       return;
+               }
+       }
+
+       /* Check the forwarding address */
+       if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_F)) {
+               offset = sizeof(*external)
+                        + OSPF6_PREFIX_SPACE(external->prefix.prefix_length);
+               memset(&fwd_addr, 0, sizeof(struct prefix));
+               fwd_addr.family = AF_INET6;
+               fwd_addr.prefixlen = IPV6_MAX_PREFIXLEN;
+               memcpy(&fwd_addr.u.prefix6, (caddr_t)external + offset,
+                      sizeof(struct in6_addr));
+
+               if (!IN6_IS_ADDR_UNSPECIFIED(&fwd_addr.u.prefix6)) {
+                       if (!ospf6_ase_forward_address_check(
+                                   ospf6, &fwd_addr.u.prefix6)) {
+                               if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
+                                       zlog_debug(
+                                               "Fwd address %pFX is local address",
+                                               &fwd_addr);
+                               return;
+                       }
+
+                       /* Find the forwarding entry */
+                       asbr_entry = ospf6_route_lookup_bestmatch(
+                               &fwd_addr, ospf6->route_table);
+                       if (asbr_entry == NULL) {
+                               if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
+                                       zlog_debug(
+                                               "Fwd address not found: %pFX",
+                                               &fwd_addr);
+                               return;
+                       }
+               }
        }
 
        route = ospf6_route_create();
@@ -540,22 +621,38 @@ void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa)
 
        if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
                zlog_debug(
-                       "%s: AS-External %u route add %pFX cost %u(%u) nh %u",
-                       __func__,
+                       "%s: %s %u route add %pFX cost %u(%u) nh %u", __func__,
+                       (type == OSPF6_LSTYPE_AS_EXTERNAL) ? "AS-External"
+                                                          : "NSSA",
                        (route->path.type == OSPF6_PATH_TYPE_EXTERNAL1) ? 1 : 2,
                        &route->prefix, route->path.cost, route->path.u.cost_e2,
                        listcount(route->nh_list));
 
-       old = ospf6_route_lookup(&route->prefix, ospf6->route_table);
+       if (type == OSPF6_LSTYPE_AS_EXTERNAL)
+               old = ospf6_route_lookup(&route->prefix, ospf6->route_table);
+       else if (type == OSPF6_LSTYPE_TYPE_7)
+               old = ospf6_route_lookup(&route->prefix, oa->route_table);
        if (!old) {
+               if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
+                       zlog_debug("%s: Adding new route", __func__);
                /* Add the new route to ospf6 instance route table. */
-               ospf6_route_add(route, ospf6->route_table);
+               if (type == OSPF6_LSTYPE_AS_EXTERNAL)
+                       ospf6_route_add(route, ospf6->route_table);
+               /* Add the route to the area route table */
+               else if (type == OSPF6_LSTYPE_TYPE_7) {
+                       ospf6_route_add(route, oa->route_table);
+               }
        } else {
                /* RFC 2328 16.4 (6)
                 * ECMP: Keep new equal preference path in current
                 * route's path list, update zebra with new effective
                 * list along with addition of ECMP path.
                 */
+               if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
+                       zlog_debug("%s : old route %pFX cost %u(%u) nh %u",
+                                  __func__, &route->prefix, route->path.cost,
+                                  route->path.u.cost_e2,
+                                  listcount(route->nh_list));
                ospf6_asbr_update_route_ecmp_path(old, route, ospf6);
        }
 }
@@ -568,24 +665,42 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa,
        struct ospf6_route *route, *nroute, *route_to_del;
        struct ospf6_area *oa = NULL;
        struct ospf6 *ospf6;
+       int type;
+       bool debug = false;
 
        external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END(
                lsa->header);
 
-       if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
-               zlog_debug("Withdraw AS-External route for %s", lsa->name);
+       if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL) || (IS_OSPF6_DEBUG_NSSA))
+               debug = true;
 
        ospf6 = ospf6_get_by_lsdb(lsa);
-       if (ospf6_is_router_abr(ospf6))
-               oa = ospf6->backbone;
-       else
-               oa = listnode_head(ospf6->area_list);
+       type = ntohs(lsa->header->type);
+
+       if (type == OSPF6_LSTYPE_TYPE_7) {
+               if (debug)
+                       zlog_debug("%s: Withdraw  Type 7 route for %s",
+                                  __func__, lsa->name);
+               oa = lsa->lsdb->data;
+       } else {
+               if (debug)
+                       zlog_debug("%s: Withdraw AS-External route for %s",
+                                  __func__, lsa->name);
 
-       if (oa == NULL)
+               if (ospf6_check_and_set_router_abr(ospf6))
+                       oa = ospf6->backbone;
+               else
+                       oa = listgetdata(listhead(ospf6->area_list));
+       }
+
+       if (oa == NULL) {
+               if (debug)
+                       zlog_debug("%s: Invalid area", __func__);
                return;
+       }
 
        if (lsa->header->adv_router == oa->ospf6->router_id) {
-               if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))
+               if (debug)
                        zlog_debug("Ignore self-originated AS-External-LSA");
                return;
        }
@@ -623,22 +738,23 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa,
        prefix.prefixlen = external->prefix.prefix_length;
        ospf6_prefix_in6_addr(&prefix.u.prefix6, external, &external->prefix);
 
-       route = ospf6_route_lookup(&prefix, oa->ospf6->route_table);
+       if (type == OSPF6_LSTYPE_TYPE_7)
+               route = ospf6_route_lookup(&prefix, oa->route_table);
+       else
+               route = ospf6_route_lookup(&prefix, oa->ospf6->route_table);
+
        if (route == NULL) {
-               if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
+               if (debug)
                        zlog_debug("AS-External route %pFX not found", &prefix);
-               }
-
                ospf6_route_delete(route_to_del);
                return;
        }
 
-       if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
+       if (debug)
                zlog_debug(
                        "%s: Current route %pFX cost %u e2 %u, route to del cost %u e2 %u",
                        __func__, &prefix, route->path.cost, route->path.u.cost_e2,
                        route_to_del->path.cost, route_to_del->path.u.cost_e2);
-       }
 
        for (ospf6_route_lock(route);
             route && ospf6_route_is_prefix(&prefix, route); route = nroute) {
@@ -690,7 +806,7 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa,
                                        continue;
                                }
 
-                               if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
+                               if (debug) {
                                        zlog_debug(
                                                "%s: route %pFX path found with cost %u nh %u to remove.",
                                                __func__, &prefix, route->path.cost,
@@ -731,7 +847,7 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa,
                                                             o_path->nh_list);
                                }
 
-                               if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
+                               if (debug) {
                                        zlog_debug(
                                                "%s: AS-External %u route %pFX update paths %u nh %u",
                                                __func__,
@@ -774,8 +890,13 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa,
                                                h_path->origin.adv_router;
                                        }
                                } else {
-                                       ospf6_route_remove(
-                                               route, oa->ospf6->route_table);
+                                       if (type == OSPF6_LSTYPE_TYPE_7)
+                                               ospf6_route_remove(
+                                                       route, oa->route_table);
+                                       else
+                                               ospf6_route_remove(
+                                                       route,
+                                                       oa->ospf6->route_table);
                                }
                        }
                        continue;
@@ -790,7 +911,7 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa,
                                || (route->path.cost != route_to_del->path.cost)
                                || (route->path.u.cost_e2
                                    != route_to_del->path.u.cost_e2))) {
-                               if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
+                               if (debug) {
                                        zlog_debug(
                                                "%s: route %pFX to delete is not same, cost %u del cost %u. skip",
                                                __func__, &prefix, route->path.cost,
@@ -805,7 +926,7 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa,
                            || (route->path.origin.id != lsa->header->id))
                                continue;
                }
-               if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
+               if (debug) {
                        zlog_debug(
                                "%s: AS-External %u route remove %pFX cost %u(%u) nh %u",
                                __func__,
@@ -815,7 +936,10 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa,
                                &route->prefix, route->path.cost, route->path.u.cost_e2,
                                listcount(route->nh_list));
                }
-               ospf6_route_remove(route, oa->ospf6->route_table);
+               if (type == OSPF6_LSTYPE_TYPE_7)
+                       ospf6_route_remove(route, oa->route_table);
+               else
+                       ospf6_route_remove(route, oa->ospf6->route_table);
        }
        if (route != NULL)
                ospf6_route_unlock(route);
@@ -937,7 +1061,7 @@ void ospf6_asbr_distribute_list_update(int type, struct ospf6 *ospf6)
                              &ospf6->t_distribute_update);
 }
 
-static void ospf6_asbr_routemap_update(const char *mapname)
+void ospf6_asbr_routemap_update(const char *mapname)
 {
        int type;
        struct listnode *node, *nnode;
@@ -987,8 +1111,7 @@ static void ospf6_asbr_routemap_update(const char *mapname)
                                                                type));
                                ospf6_asbr_redistribute_unset(ospf6, red, type);
                                ospf6_asbr_routemap_set(red, mapname);
-                               ospf6_asbr_redistribute_set(
-                                               type, ospf6->vrf_id);
+                               ospf6_asbr_redistribute_set(ospf6, type);
                        }
                }
        }
@@ -1015,7 +1138,7 @@ static void ospf6_asbr_routemap_event(const char *name)
 
 int ospf6_asbr_is_asbr(struct ospf6 *o)
 {
-       return o->external_table->count;
+       return (o->external_table->count || IS_OSPF6_ASBR(o));
 }
 
 struct ospf6_redist *ospf6_redist_lookup(struct ospf6 *ospf6, int type,
@@ -1050,6 +1173,8 @@ static struct ospf6_redist *ospf6_redist_add(struct ospf6 *ospf6, int type,
 
        red = XCALLOC(MTYPE_OSPF6_REDISTRIBUTE, sizeof(struct ospf6_redist));
        red->instance = instance;
+       red->dmetric.type = -1;
+       red->dmetric.value = -1;
        ROUTEMAP_NAME(red) = NULL;
        ROUTEMAP(red) = NULL;
 
@@ -1072,9 +1197,44 @@ static void ospf6_redist_del(struct ospf6 *ospf6, struct ospf6_redist *red,
        }
 }
 
-static void ospf6_asbr_redistribute_set(int type, vrf_id_t vrf_id)
+/*Set the status of the ospf instance to ASBR based on the status parameter,
+ * rechedule SPF calculation, originate router LSA*/
+void ospf6_asbr_status_update(struct ospf6 *ospf6, int status)
+{
+       struct listnode *lnode, *lnnode;
+       struct ospf6_area *oa;
+
+       zlog_info("ASBR[%s:Status:%d]: Update", ospf6->name, status);
+
+       if (status) {
+               if (IS_OSPF6_ASBR(ospf6)) {
+                       zlog_info("ASBR[%s:Status:%d]: Already ASBR",
+                                 ospf6->name, status);
+                       return;
+               }
+               SET_FLAG(ospf6->flag, OSPF6_FLAG_ASBR);
+       } else {
+               if (!IS_OSPF6_ASBR(ospf6)) {
+                       zlog_info("ASBR[%s:Status:%d]: Already non ASBR",
+                                 ospf6->name, status);
+                       return;
+               }
+               UNSET_FLAG(ospf6->flag, OSPF6_FLAG_ASBR);
+       }
+
+       /* Transition from/to status ASBR, schedule timer. */
+       ospf6_spf_schedule(ospf6, OSPF6_SPF_FLAGS_ASBR_STATUS_CHANGE);
+
+       /* Reoriginate router LSA for all areas */
+       for (ALL_LIST_ELEMENTS(ospf6->area_list, lnode, lnnode, oa))
+               OSPF6_ROUTER_LSA_SCHEDULE(oa);
+}
+
+static void ospf6_asbr_redistribute_set(struct ospf6 *ospf6, int type)
 {
-       ospf6_zebra_redistribute(type, vrf_id);
+       ospf6_zebra_redistribute(type, ospf6->vrf_id);
+
+       ospf6_asbr_status_update(ospf6, ++ospf6->redist_count);
 }
 
 static void ospf6_asbr_redistribute_unset(struct ospf6 *ospf6,
@@ -1096,6 +1256,7 @@ static void ospf6_asbr_redistribute_unset(struct ospf6 *ospf6,
        }
 
        ospf6_asbr_routemap_unset(red);
+       ospf6_asbr_status_update(ospf6, --ospf6->redist_count);
 }
 
 /* When an area is unstubified, flood all the external LSAs in the area */
@@ -1139,35 +1300,6 @@ void ospf6_asbr_remove_externals_from_area(struct ospf6_area *oa)
        }
 }
 
-/* Update ASBR status. */
-static void ospf6_asbr_status_update(struct ospf6 *ospf6, uint8_t status)
-{
-       struct listnode *lnode, *lnnode;
-       struct ospf6_area *oa;
-
-       zlog_info("ASBR[%s:Status:%d]: Update", ospf6->name, status);
-
-       if (status) {
-               if (IS_OSPF6_ASBR(ospf6)) {
-                       zlog_info("ASBR[%s:Status:%d]: Already ASBR",
-                                 ospf6->name, status);
-                       return;
-               }
-               SET_FLAG(ospf6->flag, OSPF6_FLAG_ASBR);
-       } else {
-               if (!IS_OSPF6_ASBR(ospf6)) {
-                       zlog_info("ASBR[%s:Status:%d]: Already non ASBR",
-                                 ospf6->name, status);
-                       return;
-               }
-               UNSET_FLAG(ospf6->flag, OSPF6_FLAG_ASBR);
-       }
-
-       ospf6_spf_schedule(ospf6, OSPF6_SPF_FLAGS_ASBR_STATUS_CHANGE);
-       for (ALL_LIST_ELEMENTS(ospf6->area_list, lnode, lnnode, oa))
-               OSPF6_ROUTER_LSA_SCHEDULE(oa);
-}
-
 void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex,
                                 struct prefix *prefix,
                                 unsigned int nexthop_num,
@@ -1175,6 +1307,8 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex,
                                 struct ospf6 *ospf6)
 {
        route_map_result_t ret;
+       struct listnode *lnode;
+       struct ospf6_area *oa;
        struct ospf6_route troute;
        struct ospf6_external_info tinfo;
        struct ospf6_route *route, *match;
@@ -1236,8 +1370,13 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex,
                        if (troute.path.metric_type)
                                match->path.metric_type =
                                        troute.path.metric_type;
+                       else
+                               match->path.metric_type =
+                                       metric_type(ospf6, type, 0);
                        if (troute.path.cost)
                                match->path.cost = troute.path.cost;
+                       else
+                               match->path.cost = metric_value(ospf6, type, 0);
                        if (!IN6_IS_ADDR_UNSPECIFIED(&tinfo.forwarding))
                                memcpy(&info->forwarding, &tinfo.forwarding,
                                       sizeof(struct in6_addr));
@@ -1276,6 +1415,11 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex,
                match->path.origin.id = htonl(info->id);
                ospf6_as_external_lsa_originate(match, ospf6);
                ospf6_asbr_status_update(ospf6, ospf6->redistribute);
+               for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, lnode, oa)) {
+                       if (IS_AREA_NSSA(oa))
+                               ospf6_nssa_lsa_originate(match, oa);
+               }
+
                return;
        }
 
@@ -1293,8 +1437,12 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex,
        if (ROUTEMAP(red)) {
                if (troute.path.metric_type)
                        route->path.metric_type = troute.path.metric_type;
+               else
+                       route->path.metric_type = metric_type(ospf6, type, 0);
                if (troute.path.cost)
                        route->path.cost = troute.path.cost;
+               else
+                       route->path.cost = metric_value(ospf6, type, 0);
                if (!IN6_IS_ADDR_UNSPECIFIED(&tinfo.forwarding))
                        memcpy(&info->forwarding, &tinfo.forwarding,
                               sizeof(struct in6_addr));
@@ -1334,13 +1482,19 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex,
        route->path.origin.id = htonl(info->id);
        ospf6_as_external_lsa_originate(route, ospf6);
        ospf6_asbr_status_update(ospf6, ospf6->redistribute);
+       for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, lnode, oa)) {
+               if (IS_AREA_NSSA(oa))
+                       ospf6_nssa_lsa_originate(route, oa);
+       }
 }
 
 void ospf6_asbr_redistribute_remove(int type, ifindex_t ifindex,
                                    struct prefix *prefix, struct ospf6 *ospf6)
 {
+       struct ospf6_area *oa;
        struct ospf6_route *match;
        struct ospf6_external_info *info = NULL;
+       struct listnode *lnode;
        struct route_node *node;
        struct ospf6_lsa *lsa;
        struct prefix prefix_id;
@@ -1369,8 +1523,27 @@ void ospf6_asbr_redistribute_remove(int type, ifindex_t ifindex,
 
        lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL),
                                htonl(info->id), ospf6->router_id, ospf6->lsdb);
-       if (lsa)
+       if (lsa) {
+               if (IS_OSPF6_DEBUG_ASBR) {
+                       zlog_debug("withdraw type 5 LSA for route %pFX",
+                                  prefix);
+               }
                ospf6_lsa_purge(lsa);
+       }
+
+       /* Delete the NSSA LSA */
+       for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, lnode, oa)) {
+               lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_TYPE_7),
+                                       htonl(info->id), ospf6->router_id,
+                                       oa->lsdb);
+               if (lsa) {
+                       if (IS_OSPF6_DEBUG_ASBR) {
+                               zlog_debug("withdraw type 7 LSA for route %pFX",
+                                          prefix);
+                       }
+                       ospf6_lsa_purge(lsa);
+               }
+       }
 
        /* remove binding in external_id_table */
        prefix_id.family = AF_INET;
@@ -1404,12 +1577,13 @@ DEFUN (ospf6_redistribute,
        if (type < 0)
                return CMD_WARNING_CONFIG_FAILED;
 
-       red = ospf6_redist_add(ospf6, type, 0);
+       red = ospf6_redist_lookup(ospf6, type, 0);
        if (!red)
-               return CMD_SUCCESS;
+               ospf6_redist_add(ospf6, type, 0);
+       else
+               ospf6_asbr_redistribute_unset(ospf6, red, type);
 
-       ospf6_asbr_redistribute_unset(ospf6, red, type);
-       ospf6_asbr_redistribute_set(type, ospf6->vrf_id);
+       ospf6_asbr_redistribute_set(ospf6, type);
 
        return CMD_SUCCESS;
 }
@@ -1434,13 +1608,14 @@ DEFUN (ospf6_redistribute_routemap,
        if (type < 0)
                return CMD_WARNING_CONFIG_FAILED;
 
-       red = ospf6_redist_add(ospf6, type, 0);
+       red = ospf6_redist_lookup(ospf6, type, 0);
        if (!red)
-               return CMD_SUCCESS;
+               red = ospf6_redist_add(ospf6, type, 0);
+       else
+               ospf6_asbr_redistribute_unset(ospf6, red, type);
 
-       ospf6_asbr_redistribute_unset(ospf6, red, type);
        ospf6_asbr_routemap_set(red, argv[idx_word]->arg);
-       ospf6_asbr_redistribute_set(type, ospf6->vrf_id);
+       ospf6_asbr_redistribute_set(ospf6, type);
 
        return CMD_SUCCESS;
 }
@@ -2278,11 +2453,20 @@ static struct ospf6_lsa_handler as_external_handler = {
        .lh_get_prefix_str = ospf6_as_external_lsa_get_prefix_str,
        .lh_debug = 0};
 
+static struct ospf6_lsa_handler nssa_external_handler = {
+       .lh_type = OSPF6_LSTYPE_TYPE_7,
+       .lh_name = "NSSA",
+       .lh_short_name = "Type7",
+       .lh_show = ospf6_as_external_lsa_show,
+       .lh_get_prefix_str = ospf6_as_external_lsa_get_prefix_str,
+       .lh_debug = 0};
+
 void ospf6_asbr_init(void)
 {
        ospf6_routemap_init();
 
        ospf6_install_lsa_handler(&as_external_handler);
+       ospf6_install_lsa_handler(&nssa_external_handler);
 
        install_element(VIEW_NODE, &show_ipv6_ospf6_redistribute_cmd);
 
index 4774ac435a1bbc1e65ea316482cae79d07ebd50c..418c157f368912f1fa878a1864c1dfc334c8d5e7 100644 (file)
@@ -71,6 +71,7 @@ struct ospf6_as_external_lsa {
        }
 
 extern void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa);
+
 extern void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa,
                                  struct ospf6_route *asbr_entry);
 extern void ospf6_asbr_lsentry_add(struct ospf6_route *asbr_entry,
@@ -106,4 +107,9 @@ extern void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old,
 extern void ospf6_asbr_distribute_list_update(int type, struct ospf6 *ospf6);
 struct ospf6_redist *ospf6_redist_lookup(struct ospf6 *ospf6, int type,
                                         unsigned short instance);
+extern void ospf6_asbr_routemap_update(const char *mapname);
+extern void ospf6_as_external_lsa_originate(struct ospf6_route *route,
+                                           struct ospf6 *ospf6);
+extern void ospf6_asbr_status_update(struct ospf6 *ospf6, int status);
+
 #endif /* OSPF6_ASBR_H */
index 76e81aab7b853f295c7c7a69d2e43cf0c66bb683..05b43189e9a16c706a7dc91956e1ee713a6b89e9 100644 (file)
@@ -40,6 +40,7 @@
 #include "ospf6_neighbor.h"
 
 #include "ospf6_flood.h"
+#include "ospf6_nssa.h"
 
 unsigned char conf_debug_ospf6_flooding;
 
@@ -213,12 +214,19 @@ void ospf6_install_lsa(struct ospf6_lsa *lsa)
 {
        struct timeval now;
        struct ospf6_lsa *old;
+       struct ospf6_area *area = NULL;
 
        /* Remove the old instance from all neighbors' Link state
           retransmission list (RFC2328 13.2 last paragraph) */
        old = ospf6_lsdb_lookup(lsa->header->type, lsa->header->id,
                                lsa->header->adv_router, lsa->lsdb);
        if (old) {
+               if (ntohs(lsa->header->type) == OSPF6_LSTYPE_TYPE_7) {
+                       if (IS_OSPF6_DEBUG_NSSA)
+                               zlog_debug("%s : old LSA %s", __func__,
+                                          lsa->name);
+                       lsa->external_lsa_id = old->external_lsa_id;
+               }
                THREAD_OFF(old->expire);
                THREAD_OFF(old->refresh);
                ospf6_flood_clear(old);
@@ -265,6 +273,22 @@ void ospf6_install_lsa(struct ospf6_lsa *lsa)
        lsa->installed = now;
        ospf6_lsdb_add(lsa, lsa->lsdb);
 
+       if (ntohs(lsa->header->type) == OSPF6_LSTYPE_TYPE_7) {
+               area = OSPF6_AREA(lsa->lsdb->data);
+               ospf6_translated_nssa_refresh(area, lsa, NULL);
+               ospf6_schedule_abr_task(area->ospf6);
+       }
+
+       if (ntohs(lsa->header->type) == OSPF6_LSTYPE_ROUTER) {
+               area = OSPF6_AREA(lsa->lsdb->data);
+               if (old == NULL) {
+                       if (IS_OSPF6_DEBUG_LSA_TYPE(lsa->header->type)
+                           || IS_OSPF6_DEBUG_EXAMIN_TYPE(lsa->header->type))
+                               zlog_debug("%s: New router LSA %s", __func__,
+                                          lsa->name);
+                       ospf6_abr_nssa_check_status(area->ospf6);
+               }
+       }
        return;
 }
 
@@ -370,7 +394,8 @@ void ospf6_flood_interface(struct ospf6_neighbor *from, struct ospf6_lsa *lsa,
                        continue;
                }
 
-               if (oi->area->ospf6->inst_shutdown) {
+               if ((oi->area->ospf6->inst_shutdown)
+                   || CHECK_FLAG(lsa->flag, OSPF6_LSA_FLUSH)) {
                        if (is_debug)
                                zlog_debug(
                                        "%s: Send LSA %s (age %d) update now",
@@ -486,7 +511,12 @@ static void ospf6_flood_process(struct ospf6_neighbor *from,
                        continue;
 
                if (ntohs(lsa->header->type) == OSPF6_LSTYPE_AS_EXTERNAL
-                   && IS_AREA_STUB(oa))
+                   && (IS_AREA_STUB(oa) || IS_AREA_NSSA(oa)))
+                       continue;
+
+               /* Check for NSSA LSA */
+               if (ntohs(lsa->header->type) == OSPF6_LSTYPE_TYPE_7
+                   && !IS_AREA_NSSA(oa) && !OSPF6_LSA_IS_MAXAGE(lsa))
                        continue;
 
                ospf6_flood_area(from, lsa, oa);
@@ -526,7 +556,7 @@ static void ospf6_flood_clear_interface(struct ospf6_lsa *lsa,
        }
 }
 
-static void ospf6_flood_clear_area(struct ospf6_lsa *lsa, struct ospf6_area *oa)
+void ospf6_flood_clear_area(struct ospf6_lsa *lsa, struct ospf6_area *oa)
 {
        struct listnode *node, *nnode;
        struct ospf6_interface *oi;
@@ -555,7 +585,11 @@ static void ospf6_flood_clear_process(struct ospf6_lsa *lsa,
                        continue;
 
                if (ntohs(lsa->header->type) == OSPF6_LSTYPE_AS_EXTERNAL
-                   && IS_AREA_STUB(oa))
+                   && (IS_AREA_STUB(oa) || (IS_AREA_NSSA(oa))))
+                       continue;
+               /* Check for NSSA LSA */
+               if (ntohs(lsa->header->type) == OSPF6_LSTYPE_TYPE_7
+                   && !IS_AREA_NSSA(oa))
                        continue;
 
                ospf6_flood_clear_area(lsa, oa);
@@ -567,6 +601,8 @@ void ospf6_flood_clear(struct ospf6_lsa *lsa)
        struct ospf6 *ospf6;
 
        ospf6 = ospf6_get_by_lsdb(lsa);
+       if (ospf6 == NULL)
+               return;
        ospf6_flood_clear_process(lsa, ospf6);
 }
 
@@ -775,6 +811,18 @@ void ospf6_receive_lsa(struct ospf6_neighbor *from,
        ismore_recent = 1;
        assert(from);
 
+       /* if we receive a LSA with invalid seqnum drop it */
+       if (ntohl(lsa_header->seqnum) - 1 == OSPF_MAX_SEQUENCE_NUMBER) {
+               if (IS_OSPF6_DEBUG_EXAMIN_TYPE(lsa_header->type)) {
+                       zlog_debug(
+                               "received lsa [%s Id:%pI4 Adv:%pI4] with invalid seqnum 0x%x, ignore",
+                               ospf6_lstype_name(lsa_header->type),
+                               &lsa_header->id, &lsa_header->adv_router,
+                               ntohl(lsa_header->seqnum));
+               }
+               return;
+       }
+
        /* make lsa structure for received lsa */
        new = ospf6_lsa_create(lsa_header);
 
@@ -938,11 +986,12 @@ void ospf6_receive_lsa(struct ospf6_neighbor *from,
                /* if no database copy, should go above state (5) */
                assert(old);
 
-               if (is_debug) {
-                       zlog_debug(
-                               "Received is not newer, on the neighbor's request-list");
-                       zlog_debug("BadLSReq, discard the received LSA");
-               }
+               zlog_warn(
+                       "Received is not newer, on the neighbor %s request-list",
+                       from->name);
+               zlog_warn(
+                       "BadLSReq, discard the received LSA lsa %s send badLSReq",
+                       new->name);
 
                /* BadLSReq */
                thread_add_event(master, bad_lsreq, from, 0, NULL);
index 6931024fff43d0a74202a39a84113fe28dbd1cfc..5515a1c3feac8ada7e0e4571961267c5b9e96e1a 100644 (file)
@@ -67,4 +67,6 @@ extern void ospf6_flood_interface(struct ospf6_neighbor *from,
 extern int ospf6_lsupdate_send_neighbor_now(struct ospf6_neighbor *on,
                                            struct ospf6_lsa *lsa);
 
+extern void ospf6_flood_clear_area(struct ospf6_lsa *lsa,
+                                  struct ospf6_area *oa);
 #endif /* OSPF6_FLOOD_H */
index f037ea1f4dbc0669713a5446fd69df89fe374e7e..553967e2e3364c5fd0a5b30b4b440621ae4ecea7 100644 (file)
@@ -36,6 +36,7 @@
 #include "ospf6_message.h"
 #include "ospf6_route.h"
 #include "ospf6_area.h"
+#include "ospf6_abr.h"
 #include "ospf6_interface.h"
 #include "ospf6_neighbor.h"
 #include "ospf6_intra.h"
@@ -184,6 +185,8 @@ struct ospf6_interface *ospf6_interface_create(struct interface *ifp)
 
        oi = XCALLOC(MTYPE_OSPF6_IF, sizeof(struct ospf6_interface));
 
+       oi->obuf = ospf6_fifo_new();
+
        oi->area = (struct ospf6_area *)NULL;
        oi->neighbor_list = list_new();
        oi->neighbor_list->cmp = ospf6_neighbor_cmp;
@@ -242,6 +245,8 @@ void ospf6_interface_delete(struct ospf6_interface *oi)
 
        QOBJ_UNREG(oi);
 
+       ospf6_fifo_free(oi->obuf);
+
        for (ALL_LIST_ELEMENTS(oi->neighbor_list, node, nnode, on))
                ospf6_neighbor_delete(on);
 
@@ -330,31 +335,6 @@ ospf6_interface_get_linklocal_address(struct interface *ifp)
        return l;
 }
 
-void ospf6_interface_if_add(struct interface *ifp)
-{
-       struct ospf6_interface *oi;
-       unsigned int iobuflen;
-
-       oi = (struct ospf6_interface *)ifp->info;
-       if (oi == NULL)
-               return;
-
-       /* Try to adjust I/O buffer size with IfMtu */
-       if (oi->ifmtu == 0)
-               oi->ifmtu = ifp->mtu6;
-       iobuflen = ospf6_iobuf_size(ifp->mtu6);
-       if (oi->ifmtu > iobuflen) {
-               if (IS_OSPF6_DEBUG_INTERFACE)
-                       zlog_debug(
-                               "Interface %s: IfMtu is adjusted to I/O buffer size: %d.",
-                               ifp->name, iobuflen);
-               oi->ifmtu = iobuflen;
-       }
-
-       /* interface start */
-       ospf6_interface_state_update(oi->interface);
-}
-
 void ospf6_interface_state_update(struct interface *ifp)
 {
        struct ospf6_interface *oi;
@@ -725,20 +705,17 @@ int interface_up(struct thread *thread)
 
        /* check physical interface is up */
        if (!if_is_operative(oi->interface)) {
-               if (IS_OSPF6_DEBUG_INTERFACE)
-                       zlog_debug(
-                               "Interface %s is down, can't execute [InterfaceUp]",
-                               oi->interface->name);
+               zlog_warn("Interface %s is down, can't execute [InterfaceUp]",
+                         oi->interface->name);
                return 0;
        }
 
        /* check interface has a link-local address */
        if (!(ospf6_interface_get_linklocal_address(oi->interface)
              || if_is_loopback_or_vrf(oi->interface))) {
-               if (IS_OSPF6_DEBUG_INTERFACE)
-                       zlog_debug(
-                               "Interface %s has no link local address, can't execute [InterfaceUp]",
-                               oi->interface->name);
+               zlog_warn(
+                       "Interface %s has no link local address, can't execute [InterfaceUp]",
+                       oi->interface->name);
                return 0;
        }
 
@@ -755,7 +732,7 @@ int interface_up(struct thread *thread)
 
        /* If no area assigned, return */
        if (oi->area == NULL) {
-               zlog_debug(
+               zlog_warn(
                        "%s: Not scheduleing Hello for %s as there is no area assigned yet",
                        __func__, oi->interface->name);
                return 0;
@@ -912,6 +889,15 @@ int interface_down(struct thread *thread)
                ospf6_sso(oi->interface->ifindex, &allspfrouters6,
                          IPV6_LEAVE_GROUP, ospf6->fd);
 
+       /* deal with write fifo */
+       ospf6_fifo_flush(oi->obuf);
+       if (oi->on_write_q) {
+               listnode_delete(ospf6->oi_write_q, oi);
+               if (list_isempty(ospf6->oi_write_q))
+                       thread_cancel(&ospf6->t_write);
+               oi->on_write_q = 0;
+       }
+
        ospf6_interface_state_change(OSPF6_INTERFACE_DOWN, oi);
 
        return 0;
@@ -1197,6 +1183,26 @@ static int ospf6_interface_show(struct vty *vty, struct interface *ifp,
        return 0;
 }
 
+/* Find the global address to be used as a forwarding address in NSSA LSA.*/
+struct in6_addr *ospf6_interface_get_global_address(struct interface *ifp)
+{
+       struct listnode *n;
+       struct connected *c;
+       struct in6_addr *l = (struct in6_addr *)NULL;
+
+       /* for each connected address */
+       for (ALL_LIST_ELEMENTS_RO(ifp->connected, n, c)) {
+               /* if family not AF_INET6, ignore */
+               if (c->address->family != AF_INET6)
+                       continue;
+
+               if (!IN6_IS_ADDR_LINKLOCAL(&c->address->u.prefix6))
+                       l = &c->address->u.prefix6;
+       }
+       return l;
+}
+
+
 static int show_ospf6_interface_common(struct vty *vty, vrf_id_t vrf_id,
                                       int argc, struct cmd_token **argv,
                                       int idx_ifname, int intf_idx,
@@ -1618,7 +1624,146 @@ DEFUN(show_ipv6_ospf6_interface_prefix, show_ipv6_ospf6_interface_prefix_cmd,
        return CMD_SUCCESS;
 }
 
+void ospf6_interface_start(struct ospf6_interface *oi)
+{
+       struct ospf6 *ospf6;
+       struct ospf6_area *oa;
+
+       if (oi->area_id_format == OSPF6_AREA_FMT_UNSET)
+               return;
+
+       if (oi->area)
+               return;
+
+       ospf6 = ospf6_lookup_by_vrf_id(oi->interface->vrf_id);
+       if (!ospf6)
+               return;
+
+       oa = ospf6_area_lookup(oi->area_id, ospf6);
+       if (oa == NULL)
+               oa = ospf6_area_create(oi->area_id, ospf6, oi->area_id_format);
+
+       /* attach interface to area */
+       listnode_add(oa->if_list, oi);
+       oi->area = oa;
+
+       SET_FLAG(oa->flag, OSPF6_AREA_ENABLE);
+
+       /* start up */
+       ospf6_interface_enable(oi);
+
+       /* If the router is ABR, originate summary routes */
+       if (ospf6_check_and_set_router_abr(ospf6))
+               ospf6_abr_enable_area(oa);
+}
+
+void ospf6_interface_stop(struct ospf6_interface *oi)
+{
+       struct ospf6_area *oa;
+
+       oa = oi->area;
+       if (!oa)
+               return;
+
+       ospf6_interface_disable(oi);
+
+       listnode_delete(oa->if_list, oi);
+       oi->area = NULL;
+
+       if (oa->if_list->count == 0) {
+               UNSET_FLAG(oa->flag, OSPF6_AREA_ENABLE);
+               ospf6_abr_disable_area(oa);
+       }
+}
+
 /* interface variable set command */
+DEFUN (ipv6_ospf6_area,
+       ipv6_ospf6_area_cmd,
+       "ipv6 ospf6 area <A.B.C.D|(0-4294967295)>",
+       IP6_STR
+       OSPF6_STR
+       "Specify the OSPF6 area ID\n"
+       "OSPF6 area ID in IPv4 address notation\n"
+       "OSPF6 area ID in decimal notation\n")
+{
+       VTY_DECLVAR_CONTEXT(interface, ifp);
+       struct ospf6_interface *oi;
+       int idx_ipv4 = 3;
+       uint32_t area_id;
+       int format;
+       int ipv6_count = 0;
+
+       assert(ifp);
+
+       oi = (struct ospf6_interface *)ifp->info;
+       if (oi == NULL)
+               oi = ospf6_interface_create(ifp);
+       assert(oi);
+
+       if (oi->area) {
+               vty_out(vty, "%s already attached to Area %s\n",
+                       oi->interface->name, oi->area->name);
+               return CMD_SUCCESS;
+       }
+
+       /* if more than OSPF6_MAX_IF_ADDRS are configured on this interface
+        * then don't allow ospfv3 to be configured
+        */
+       ipv6_count = connected_count_by_family(ifp, AF_INET6);
+       if (oi->ifmtu == OSPF6_DEFAULT_MTU && ipv6_count > OSPF6_MAX_IF_ADDRS) {
+               vty_out(vty,
+                       "can not configure OSPFv3 on if %s, must have less than %d interface addresses but has %d addresses\n",
+                       ifp->name, OSPF6_MAX_IF_ADDRS, ipv6_count);
+               return CMD_WARNING_CONFIG_FAILED;
+       } else if (oi->ifmtu >= OSPF6_JUMBO_MTU
+                  && ipv6_count > OSPF6_MAX_IF_ADDRS_JUMBO) {
+               vty_out(vty,
+                       "can not configure OSPFv3 on if %s, must have less than %d interface addresses but has %d addresses\n",
+                       ifp->name, OSPF6_MAX_IF_ADDRS_JUMBO, ipv6_count);
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       if (str2area_id(argv[idx_ipv4]->arg, &area_id, &format)) {
+               vty_out(vty, "Malformed Area-ID: %s\n", argv[idx_ipv4]->arg);
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       oi->area_id = area_id;
+       oi->area_id_format = format;
+
+       ospf6_interface_start(oi);
+
+       return CMD_SUCCESS;
+}
+
+DEFUN (no_ipv6_ospf6_area,
+       no_ipv6_ospf6_area_cmd,
+       "no ipv6 ospf6 area [<A.B.C.D|(0-4294967295)>]",
+       NO_STR
+       IP6_STR
+       OSPF6_STR
+       "Specify the OSPF6 area ID\n"
+       "OSPF6 area ID in IPv4 address notation\n"
+       "OSPF6 area ID in decimal notation\n")
+{
+       VTY_DECLVAR_CONTEXT(interface, ifp);
+       struct ospf6_interface *oi;
+
+       assert(ifp);
+
+       oi = (struct ospf6_interface *)ifp->info;
+       if (oi == NULL)
+               oi = ospf6_interface_create(ifp);
+       assert(oi);
+
+       ospf6_interface_stop(oi);
+
+       oi->area_id = 0;
+       oi->area_id_format = OSPF6_AREA_FMT_UNSET;
+
+       return CMD_SUCCESS;
+}
+
 DEFUN (ipv6_ospf6_ifmtu,
        ipv6_ospf6_ifmtu_cmd,
        "ipv6 ospf6 ifmtu (1-65535)",
@@ -1840,6 +1985,38 @@ DEFUN (no_auto_cost_reference_bandwidth,
 }
 
 
+DEFUN (ospf6_write_multiplier,
+       ospf6_write_multiplier_cmd,
+       "write-multiplier (1-100)",
+       "Write multiplier\n"
+       "Maximum number of interface serviced per write\n")
+{
+       VTY_DECLVAR_CONTEXT(ospf6, o);
+       uint32_t write_oi_count;
+
+       write_oi_count = strtol(argv[1]->arg, NULL, 10);
+       if (write_oi_count < 1 || write_oi_count > 100) {
+               vty_out(vty, "write-multiplier value is invalid\n");
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       o->write_oi_count = write_oi_count;
+       return CMD_SUCCESS;
+}
+
+DEFUN (no_ospf6_write_multiplier,
+       no_ospf6_write_multiplier_cmd,
+       "no write-multiplier (1-100)",
+       NO_STR
+       "Write multiplier\n"
+       "Maximum number of interface serviced per write\n")
+{
+       VTY_DECLVAR_CONTEXT(ospf6, o);
+
+       o->write_oi_count = OSPF6_WRITE_INTERFACE_COUNT_DEFAULT;
+       return CMD_SUCCESS;
+}
+
 DEFUN (ipv6_ospf6_hellointerval,
        ipv6_ospf6_hellointerval_cmd,
        "ipv6 ospf6 hello-interval (1-65535)",
@@ -2314,6 +2491,7 @@ static int config_write_ospf6_interface(struct vty *vty, struct vrf *vrf)
 {
        struct ospf6_interface *oi;
        struct interface *ifp;
+       char buf[INET_ADDRSTRLEN];
 
        FOR_ALL_INTERFACES (vrf, ifp) {
                oi = (struct ospf6_interface *)ifp->info;
@@ -2328,6 +2506,11 @@ static int config_write_ospf6_interface(struct vty *vty, struct vrf *vrf)
 
                if (ifp->desc)
                        vty_out(vty, " description %s\n", ifp->desc);
+               if (oi->area_id_format != OSPF6_AREA_FMT_UNSET) {
+                       area_id2str(buf, sizeof(buf), oi->area_id,
+                                   oi->area_id_format);
+                       vty_out(vty, " ipv6 ospf6 area %s\n", buf);
+               }
                if (oi->c_ifmtu)
                        vty_out(vty, " ipv6 ospf6 ifmtu %d\n", oi->c_ifmtu);
 
@@ -2407,7 +2590,9 @@ static int ospf6_ifp_create(struct interface *ifp)
        if (IS_OSPF6_DEBUG_ZEBRA(RECV))
                zlog_debug("Zebra Interface add: %s index %d mtu %d", ifp->name,
                           ifp->ifindex, ifp->mtu6);
-       ospf6_interface_if_add(ifp);
+
+       if (ifp->info)
+               ospf6_interface_start(ifp->info);
 
        return 0;
 }
@@ -2448,6 +2633,9 @@ static int ospf6_ifp_destroy(struct interface *ifp)
                zlog_debug("Zebra Interface delete: %s index %d mtu %d",
                           ifp->name, ifp->ifindex, ifp->mtu6);
 
+       if (ifp->info)
+               ospf6_interface_stop(ifp->info);
+
        return 0;
 }
 
@@ -2465,6 +2653,8 @@ void ospf6_interface_init(void)
                        &show_ipv6_ospf6_interface_ifname_prefix_cmd);
        install_element(VIEW_NODE, &show_ipv6_ospf6_interface_traffic_cmd);
 
+       install_element(INTERFACE_NODE, &ipv6_ospf6_area_cmd);
+       install_element(INTERFACE_NODE, &no_ipv6_ospf6_area_cmd);
        install_element(INTERFACE_NODE, &ipv6_ospf6_cost_cmd);
        install_element(INTERFACE_NODE, &no_ipv6_ospf6_cost_cmd);
        install_element(INTERFACE_NODE, &ipv6_ospf6_ifmtu_cmd);
@@ -2499,6 +2689,9 @@ void ospf6_interface_init(void)
        /* reference bandwidth commands */
        install_element(OSPF6_NODE, &auto_cost_reference_bandwidth_cmd);
        install_element(OSPF6_NODE, &no_auto_cost_reference_bandwidth_cmd);
+       /* write-multiplier commands */
+       install_element(OSPF6_NODE, &ospf6_write_multiplier_cmd);
+       install_element(OSPF6_NODE, &no_ospf6_write_multiplier_cmd);
 }
 
 /* Clear the specified interface structure */
index 48b2cbff7402e5a72a1020867f0ee28e2bceff92..530efc3bd24edcd6c9eeaa70c328e57b425fe37b 100644 (file)
@@ -39,6 +39,9 @@ struct ospf6_interface {
        /* back pointer */
        struct ospf6_area *area;
 
+       uint32_t area_id;
+       int area_id_format;
+
        /* list of ospf6 neighbor */
        struct list *neighbor_list;
 
@@ -53,6 +56,9 @@ struct ospf6_interface {
        /* I/F transmission delay */
        uint32_t transdelay;
 
+       /* Packet send buffer. */
+       struct ospf6_fifo *obuf; /* Output queue */
+
        /* Network Type */
        uint8_t type;
        bool type_cfg;
@@ -115,6 +121,9 @@ struct ospf6_interface {
 
        struct ospf6_route_table *route_connected;
 
+       /* last hello sent */
+       struct timeval last_hello;
+
        /* prefix-list name to filter connected prefix */
        char *plist_name;
 
@@ -127,6 +136,8 @@ struct ospf6_interface {
                char *profile;
        } bfd_config;
 
+       int on_write_q;
+
        /* Statistics Fields */
        uint32_t hello_in;
        uint32_t hello_out;
@@ -177,6 +188,9 @@ extern const char *const ospf6_interface_state_str[];
 
 /* Function Prototypes */
 
+extern void ospf6_interface_start(struct ospf6_interface *oi);
+extern void ospf6_interface_stop(struct ospf6_interface *oi);
+
 extern struct ospf6_interface *
 ospf6_interface_lookup_by_ifindex(ifindex_t, vrf_id_t vrf_id);
 extern struct ospf6_interface *ospf6_interface_create(struct interface *);
@@ -185,10 +199,11 @@ extern void ospf6_interface_delete(struct ospf6_interface *);
 extern void ospf6_interface_enable(struct ospf6_interface *);
 extern void ospf6_interface_disable(struct ospf6_interface *);
 
-extern void ospf6_interface_if_add(struct interface *);
 extern void ospf6_interface_state_update(struct interface *);
 extern void ospf6_interface_connected_route_update(struct interface *);
 extern void ospf6_interface_connected_route_add(struct connected *);
+extern struct in6_addr *
+ospf6_interface_get_global_address(struct interface *ifp);
 
 /* interface event */
 extern int interface_up(struct thread *);
index 12d11d45c1cac5bce1d27ad2b9c35f4fea5c3c83..c971c6180e8536cfe5e6889d27869b8e43909266 100644 (file)
@@ -182,7 +182,7 @@ static void ospf6_router_lsa_options_set(struct ospf6_area *oa,
        OSPF6_OPT_CLEAR_ALL(router_lsa->options);
        memcpy(router_lsa->options, oa->options, 3);
 
-       if (ospf6_is_router_abr(oa->ospf6))
+       if (ospf6_check_and_set_router_abr(oa->ospf6))
                SET_FLAG(router_lsa->bits, OSPF6_ROUTER_BIT_B);
        else
                UNSET_FLAG(router_lsa->bits, OSPF6_ROUTER_BIT_B);
@@ -193,6 +193,17 @@ static void ospf6_router_lsa_options_set(struct ospf6_area *oa,
                UNSET_FLAG(router_lsa->bits, OSPF6_ROUTER_BIT_E);
        }
 
+       /* If the router is ASBR and the area-type is NSSA set the
+        * translate bit in router LSA.
+        */
+       if (IS_AREA_NSSA(oa)
+           && (ospf6_asbr_is_asbr(oa->ospf6) || IS_OSPF6_ABR(oa->ospf6))) {
+               if (oa->NSSATranslatorRole == OSPF6_NSSA_ROLE_ALWAYS)
+                       SET_FLAG(router_lsa->bits, OSPF6_ROUTER_BIT_NT);
+       } else {
+               UNSET_FLAG(router_lsa->bits, OSPF6_ROUTER_BIT_NT);
+       }
+
        UNSET_FLAG(router_lsa->bits, OSPF6_ROUTER_BIT_V);
        UNSET_FLAG(router_lsa->bits, OSPF6_ROUTER_BIT_W);
 }
@@ -278,9 +289,8 @@ int ospf6_router_lsa_originate(struct thread *thread)
                        if ((caddr_t)lsdesc
                            == (caddr_t)router_lsa
                                       + sizeof(struct ospf6_router_lsa)) {
-                               if (IS_OSPF6_DEBUG_ORIGINATE(ROUTER))
-                                       zlog_debug(
-                                               "Size limit setting for Router-LSA too short");
+                               zlog_warn(
+                                       "Size limit setting for Router-LSA too short");
                                return 0;
                        }
 
@@ -2055,6 +2065,7 @@ void ospf6_intra_route_calculation(struct ospf6_area *oa)
        struct ospf6_lsa *lsa;
        void (*hook_add)(struct ospf6_route *) = NULL;
        void (*hook_remove)(struct ospf6_route *) = NULL;
+       char buf[PREFIX2STR_BUFFER];
 
        if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX))
                zlog_debug("Re-examin intra-routes for area %s", oa->name);
@@ -2076,6 +2087,12 @@ void ospf6_intra_route_calculation(struct ospf6_area *oa)
        oa->route_table->hook_remove = hook_remove;
 
        for (route = ospf6_route_head(oa->route_table); route; route = nroute) {
+               if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX)) {
+                       prefix2str(&route->prefix, buf, sizeof(buf));
+                       zlog_debug("%s: route %s, flag 0x%x", __func__, buf,
+                                  route->flag);
+               }
+
                nroute = ospf6_route_next(route);
                if (CHECK_FLAG(route->flag, OSPF6_ROUTE_REMOVE)
                    && CHECK_FLAG(route->flag, OSPF6_ROUTE_ADD)) {
@@ -2092,6 +2109,9 @@ void ospf6_intra_route_calculation(struct ospf6_area *oa)
                        route->flag = 0;
                } else {
                        /* Redo the summaries as things might have changed */
+                       if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX))
+                               zlog_debug("%s: Originate summary for route %s",
+                                          __func__, buf);
                        ospf6_abr_originate_summary(route, oa->ospf6);
                        route->flag = 0;
                }
@@ -2167,8 +2187,8 @@ void ospf6_intra_brouter_calculation(struct ospf6_area *oa)
 
        if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID(oa->area_id) ||
            IS_OSPF6_DEBUG_ROUTE(MEMORY))
-               zlog_info("%s: border-router calculation for area %s", __func__,
-                         oa->name);
+               zlog_debug("%s: border-router calculation for area %s",
+                          __func__, oa->name);
 
        hook_add = oa->ospf6->brouter_table->hook_add;
        hook_remove = oa->ospf6->brouter_table->hook_remove;
@@ -2189,8 +2209,8 @@ void ospf6_intra_brouter_calculation(struct ospf6_area *oa)
 
                if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_ID(brouter_id)
                    || IS_OSPF6_DEBUG_ROUTE(MEMORY)) {
-                       zlog_info("%p: mark as removing: area %s brouter %s",
-                                 (void *)brouter, oa->name, brouter_name);
+                       zlog_debug("%p: mark as removing: area %s brouter %s",
+                                  (void *)brouter, oa->name, brouter_name);
                        ospf6_brouter_debug_print(brouter);
                }
        }
@@ -2223,8 +2243,8 @@ void ospf6_intra_brouter_calculation(struct ospf6_area *oa)
 
                if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_ID(brouter_id)
                    || IS_OSPF6_DEBUG_ROUTE(MEMORY)) {
-                       zlog_info("%p: transfer: area %s brouter %s",
-                                 (void *)brouter, oa->name, brouter_name);
+                       zlog_debug("%p: transfer: area %s brouter %s",
+                                  (void *)brouter, oa->name, brouter_name);
                        ospf6_brouter_debug_print(brouter);
                }
        }
@@ -2297,7 +2317,7 @@ void ospf6_intra_brouter_calculation(struct ospf6_area *oa)
                                       brouter_id)
                            || IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID(
                                       oa->area_id))
-                               zlog_info(
+                               zlog_debug(
                                        "%s: brouter %s disappears via area %s",
                                        __func__, brouter_name, oa->name);
                        /* This is used to protect nbrouter from removed from
@@ -2325,8 +2345,9 @@ void ospf6_intra_brouter_calculation(struct ospf6_area *oa)
                                    brouter_id)
                            || IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID(
                                       oa->area_id))
-                               zlog_info("brouter %s still exists via area %s",
-                                         brouter_name, oa->name);
+                               zlog_debug(
+                                       "brouter %s still exists via area %s",
+                                       brouter_name, oa->name);
                        /* But re-originate summaries */
                        ospf6_abr_originate_summary(brouter, oa->ospf6);
                }
@@ -2341,8 +2362,8 @@ void ospf6_intra_brouter_calculation(struct ospf6_area *oa)
 
        if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID(oa->area_id) ||
            IS_OSPF6_DEBUG_ROUTE(MEMORY))
-               zlog_info("%s: border-router calculation for area %s: done",
-                         __func__, oa->name);
+               zlog_debug("%s: border-router calculation for area %s: done",
+                          __func__, oa->name);
 }
 
 static struct ospf6_lsa_handler router_handler = {
index f5f429b041dc1bd372bc3c14686a0cdc552183b2..d62719425289a05f9fdde8d8243f4b896de21003 100644 (file)
@@ -458,6 +458,7 @@ void ospf6_lsa_show_summary(struct vty *vty, struct ospf6_lsa *lsa,
        case OSPF6_LSTYPE_INTER_PREFIX:
        case OSPF6_LSTYPE_INTER_ROUTER:
        case OSPF6_LSTYPE_AS_EXTERNAL:
+       case OSPF6_LSTYPE_TYPE_7:
                if (use_json) {
                        json_object_string_add(
                                json_obj, "type",
@@ -486,7 +487,6 @@ void ospf6_lsa_show_summary(struct vty *vty, struct ospf6_lsa *lsa,
        case OSPF6_LSTYPE_ROUTER:
        case OSPF6_LSTYPE_NETWORK:
        case OSPF6_LSTYPE_GROUP_MEMBERSHIP:
-       case OSPF6_LSTYPE_TYPE_7:
        case OSPF6_LSTYPE_LINK:
        case OSPF6_LSTYPE_INTRA_PREFIX:
                while (handler->lh_get_prefix_str(lsa, buf, sizeof(buf), cnt)
@@ -623,8 +623,8 @@ void ospf6_lsa_show_internal(struct vty *vty, struct ospf6_lsa *lsa,
                vty_out(vty, "Flag: %x \n", lsa->flag);
                vty_out(vty, "Lock: %d \n", lsa->lock);
                vty_out(vty, "ReTx Count: %d\n", lsa->retrans_count);
-               vty_out(vty, "Threads: Expire: 0x%p, Refresh: 0x%p \n",
-                       (void *)lsa->expire, (void *)lsa->refresh);
+               vty_out(vty, "Threads: Expire: %p, Refresh: %p\n", lsa->expire,
+                       lsa->refresh);
                vty_out(vty, "\n");
        }
        return;
@@ -654,6 +654,7 @@ void ospf6_lsa_show(struct vty *vty, struct ospf6_lsa *lsa,
                                    ospf6_lsa_age_current(lsa));
                json_object_string_add(json_obj, "type",
                                       ospf6_lstype_name(lsa->header->type));
+               json_object_string_add(json_obj, "linkStateId", id);
                json_object_string_add(json_obj, "advertisingRouter",
                                       adv_router);
                json_object_int_add(json_obj, "lsSequenceNumber",
index 84c3b856311aeb83011ae4a02b208167bc0ecc4a..15b0d4ebbc8a845258e621075d9f970a858e5be3 100644 (file)
 #define OSPF6_SCOPE_AS         0x4000
 #define OSPF6_SCOPE_RESERVED   0x6000
 
+/* AS-external-LSA refresh method. */
+#define LSA_REFRESH_IF_CHANGED  0
+#define LSA_REFRESH_FORCE       1
+
+
 /* XXX U-bit handling should be treated here */
 #define OSPF6_LSA_SCOPE(type) (ntohs(type) & OSPF6_LSTYPE_SCOPE_MASK)
 
@@ -113,6 +118,7 @@ struct ospf6_lsa_header {
 #define OSPF6_LSA_IS_CHANGED(L1, L2) ospf6_lsa_is_changed (L1, L2)
 #define OSPF6_LSA_IS_SEQWRAP(L) ((L)->header->seqnum == htonl(OSPF_MAX_SEQUENCE_NUMBER + 1))
 
+
 struct ospf6_lsa {
        char name[64]; /* dump string */
 
@@ -133,6 +139,8 @@ struct ospf6_lsa {
 
        struct ospf6_lsdb *lsdb;
 
+       in_addr_t external_lsa_id;
+
        /* lsa instance */
        struct ospf6_lsa_header *header;
 };
@@ -143,6 +151,7 @@ struct ospf6_lsa {
 #define OSPF6_LSA_IMPLIEDACK 0x08
 #define OSPF6_LSA_UNAPPROVED 0x10
 #define OSPF6_LSA_SEQWRAPPED 0x20
+#define OSPF6_LSA_FLUSH      0x40
 
 struct ospf6_lsa_handler {
        uint16_t lh_type; /* host byte order */
index 18f121e3a2bc4f6405081bd09ac87b17f6df4ddd..304f03fde8a8373783d1b6a4ebbbccbc550fa35e 100644 (file)
@@ -320,9 +320,17 @@ int ospf6_lsdb_maxage_remover(struct ospf6_lsdb *lsdb)
        struct ospf6_lsa *lsa, *lsanext;
 
        for (ALL_LSDB(lsdb, lsa, lsanext)) {
-               if (!OSPF6_LSA_IS_MAXAGE(lsa))
+               if (!OSPF6_LSA_IS_MAXAGE(lsa)) {
+                       if (IS_OSPF6_DEBUG_LSA_TYPE(lsa->header->type))
+                               zlog_debug("Not MaxAge %s", lsa->name);
                        continue;
+               }
+
                if (lsa->retrans_count != 0) {
+                       if (IS_OSPF6_DEBUG_LSA_TYPE(lsa->header->type))
+                               zlog_debug("Remove MaxAge %s retrans_count %d",
+                                          lsa->name, lsa->retrans_count);
+
                        reschedule = 1;
                        continue;
                }
@@ -341,6 +349,7 @@ int ospf6_lsdb_maxage_remover(struct ospf6_lsdb *lsdb)
                        THREAD_OFF(lsa->refresh);
                        thread_execute(master, ospf6_lsa_refresh, lsa, 0);
                } else {
+                       zlog_debug("calling ospf6_lsdb_remove %s", lsa->name);
                        ospf6_lsdb_remove(lsa, lsdb);
                }
        }
index f83be7b49caaec9c124937283a302c2d9ed54730..5f23aab80af7ecbdec80664dc1d9db0f584be2eb 100644 (file)
@@ -50,6 +50,8 @@
 #include <netinet/ip6.h>
 
 DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_MESSAGE, "OSPF6 message");
+DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_PACKET, "OSPF6 packet");
+DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_FIFO, "OSPF6  FIFO queue");
 
 unsigned char conf_debug_ospf6_message[6] = {0x03, 0, 0, 0, 0, 0};
 static const struct message ospf6_message_type_str[] = {
@@ -252,6 +254,137 @@ void ospf6_lsack_print(struct ospf6_header *oh, int action)
        }
 }
 
+static struct ospf6_packet *ospf6_packet_new(size_t size)
+{
+       struct ospf6_packet *new;
+
+       new = XCALLOC(MTYPE_OSPF6_PACKET, sizeof(struct ospf6_packet));
+       new->s = stream_new(size);
+
+       return new;
+}
+
+static void ospf6_packet_free(struct ospf6_packet *op)
+{
+       if (op->s)
+               stream_free(op->s);
+
+       XFREE(MTYPE_OSPF6_PACKET, op);
+}
+
+struct ospf6_fifo *ospf6_fifo_new(void)
+{
+       struct ospf6_fifo *new;
+
+       new = XCALLOC(MTYPE_OSPF6_FIFO, sizeof(struct ospf6_fifo));
+       return new;
+}
+
+/* Add new packet to fifo. */
+static void ospf6_fifo_push(struct ospf6_fifo *fifo, struct ospf6_packet *op)
+{
+       if (fifo->tail)
+               fifo->tail->next = op;
+       else
+               fifo->head = op;
+
+       fifo->tail = op;
+
+       fifo->count++;
+}
+
+/* Add new packet to head of fifo. */
+static void ospf6_fifo_push_head(struct ospf6_fifo *fifo,
+                                struct ospf6_packet *op)
+{
+       op->next = fifo->head;
+
+       if (fifo->tail == NULL)
+               fifo->tail = op;
+
+       fifo->head = op;
+
+       fifo->count++;
+}
+
+/* Delete first packet from fifo. */
+static struct ospf6_packet *ospf6_fifo_pop(struct ospf6_fifo *fifo)
+{
+       struct ospf6_packet *op;
+
+       op = fifo->head;
+
+       if (op) {
+               fifo->head = op->next;
+
+               if (fifo->head == NULL)
+                       fifo->tail = NULL;
+
+               fifo->count--;
+       }
+
+       return op;
+}
+
+/* Return first fifo entry. */
+static struct ospf6_packet *ospf6_fifo_head(struct ospf6_fifo *fifo)
+{
+       return fifo->head;
+}
+
+/* Flush ospf packet fifo. */
+void ospf6_fifo_flush(struct ospf6_fifo *fifo)
+{
+       struct ospf6_packet *op;
+       struct ospf6_packet *next;
+
+       for (op = fifo->head; op; op = next) {
+               next = op->next;
+               ospf6_packet_free(op);
+       }
+       fifo->head = fifo->tail = NULL;
+       fifo->count = 0;
+}
+
+/* Free ospf packet fifo. */
+void ospf6_fifo_free(struct ospf6_fifo *fifo)
+{
+       ospf6_fifo_flush(fifo);
+
+       XFREE(MTYPE_OSPF6_FIFO, fifo);
+}
+
+static void ospf6_packet_add(struct ospf6_interface *oi,
+                            struct ospf6_packet *op)
+{
+       /* Add packet to end of queue. */
+       ospf6_fifo_push(oi->obuf, op);
+
+       /* Debug of packet fifo*/
+       /* ospf_fifo_debug (oi->obuf); */
+}
+
+static void ospf6_packet_add_top(struct ospf6_interface *oi,
+                                struct ospf6_packet *op)
+{
+       /* Add packet to head of queue. */
+       ospf6_fifo_push_head(oi->obuf, op);
+
+       /* Debug of packet fifo*/
+       /* ospf_fifo_debug (oi->obuf); */
+}
+
+static void ospf6_packet_delete(struct ospf6_interface *oi)
+{
+       struct ospf6_packet *op;
+
+       op = ospf6_fifo_pop(oi->obuf);
+
+       if (op)
+               ospf6_packet_free(op);
+}
+
+
 static void ospf6_hello_recv(struct in6_addr *src, struct in6_addr *dst,
                             struct ospf6_interface *oi,
                             struct ospf6_header *oh)
@@ -263,7 +396,10 @@ static void ospf6_hello_recv(struct in6_addr *src, struct in6_addr *dst,
        int neighborchange = 0;
        int neighbor_ifindex_change = 0;
        int backupseen = 0;
+       int64_t latency = 0;
+       struct timeval timestamp;
 
+       monotime(&timestamp);
        hello = (struct ospf6_hello *)((caddr_t)oh
                                       + sizeof(struct ospf6_header));
 
@@ -305,6 +441,17 @@ static void ospf6_hello_recv(struct in6_addr *src, struct in6_addr *dst,
                on->priority = hello->priority;
        }
 
+       /* check latency against hello period */
+       if (on->hello_in)
+               latency = monotime_since(&on->last_hello, NULL)
+                         - (oi->hello_interval * 1000000);
+       /* log if latency exceeds the hello period */
+       if (latency > (oi->hello_interval * 1000000))
+               zlog_warn("%s RX %pI4 high latency %" PRId64 "us.", __func__,
+                         &on->router_id, latency);
+       on->last_hello = timestamp;
+       on->hello_in++;
+
        /* Always override neighbor's source address */
        memcpy(&on->linklocal_addr, src, sizeof(struct in6_addr));
 
@@ -442,34 +589,34 @@ static void ospf6_dbdesc_recv_master(struct ospf6_header *oh,
                }
 
                if (CHECK_FLAG(dbdesc->bits, OSPF6_DBDESC_MSBIT)) {
-                       if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
-                               zlog_debug("Master/Slave bit mismatch");
+                       zlog_warn(
+                               "DbDesc recv: Master/Slave bit mismatch Nbr %s",
+                               on->name);
                        thread_add_event(master, seqnumber_mismatch, on, 0,
                                         NULL);
                        return;
                }
 
                if (CHECK_FLAG(dbdesc->bits, OSPF6_DBDESC_IBIT)) {
-                       if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
-                               zlog_debug("Initialize bit mismatch");
+                       zlog_warn("DbDesc recv: Initialize bit mismatch Nbr %s",
+                                 on->name);
                        thread_add_event(master, seqnumber_mismatch, on, 0,
                                         NULL);
                        return;
                }
 
                if (memcmp(on->options, dbdesc->options, sizeof(on->options))) {
-                       if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
-                               zlog_debug("Option field mismatch");
+                       zlog_warn("DbDesc recv: Option field mismatch Nbr %s",
+                                 on->name);
                        thread_add_event(master, seqnumber_mismatch, on, 0,
                                         NULL);
                        return;
                }
 
                if (ntohl(dbdesc->seqnum) != on->dbdesc_seqnum) {
-                       if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
-                               zlog_debug(
-                                       "Sequence number mismatch (%#lx expected)",
-                                       (unsigned long)on->dbdesc_seqnum);
+                       zlog_warn(
+                               "DbDesc recv: Sequence number mismatch Nbr %s (%#lx expected)",
+                               on->name, (unsigned long)on->dbdesc_seqnum);
                        thread_add_event(master, seqnumber_mismatch, on, 0,
                                         NULL);
                        return;
@@ -488,9 +635,9 @@ static void ospf6_dbdesc_recv_master(struct ospf6_header *oh,
                        return;
                }
 
-               if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
-                       zlog_debug("Not duplicate dbdesc in state %s",
-                                  ospf6_neighbor_state_str[on->state]);
+               zlog_warn(
+                       "DbDesc recv: Not duplicate dbdesc in state %s Nbr %s",
+                       ospf6_neighbor_state_str[on->state], on->name);
                thread_add_event(master, seqnumber_mismatch, on, 0, NULL);
                return;
 
@@ -530,7 +677,8 @@ static void ospf6_dbdesc_recv_master(struct ospf6_header *oh,
                }
 
                if (ntohs(his->header->type) == OSPF6_LSTYPE_AS_EXTERNAL
-                   && IS_AREA_STUB(on->ospf6_if->area)) {
+                   && (IS_AREA_STUB(on->ospf6_if->area)
+                       || IS_AREA_NSSA(on->ospf6_if->area))) {
                        if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
                                zlog_debug(
                                        "SeqNumMismatch (E-bit mismatch), discard");
@@ -662,34 +810,36 @@ static void ospf6_dbdesc_recv_slave(struct ospf6_header *oh,
                }
 
                if (!CHECK_FLAG(dbdesc->bits, OSPF6_DBDESC_MSBIT)) {
-                       if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
-                               zlog_debug("Master/Slave bit mismatch");
+                       zlog_warn(
+                               "DbDesc slave recv: Master/Slave bit mismatch Nbr %s",
+                               on->name);
                        thread_add_event(master, seqnumber_mismatch, on, 0,
                                         NULL);
                        return;
                }
 
                if (CHECK_FLAG(dbdesc->bits, OSPF6_DBDESC_IBIT)) {
-                       if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
-                               zlog_debug("Initialize bit mismatch");
+                       zlog_warn(
+                               "DbDesc slave recv: Initialize bit mismatch Nbr %s",
+                               on->name);
                        thread_add_event(master, seqnumber_mismatch, on, 0,
                                         NULL);
                        return;
                }
 
                if (memcmp(on->options, dbdesc->options, sizeof(on->options))) {
-                       if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
-                               zlog_debug("Option field mismatch");
+                       zlog_warn(
+                               "DbDesc slave recv: Option field mismatch Nbr %s",
+                               on->name);
                        thread_add_event(master, seqnumber_mismatch, on, 0,
                                         NULL);
                        return;
                }
 
                if (ntohl(dbdesc->seqnum) != on->dbdesc_seqnum + 1) {
-                       if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
-                               zlog_debug(
-                                       "Sequence number mismatch (%#lx expected)",
-                                       (unsigned long)on->dbdesc_seqnum + 1);
+                       zlog_warn(
+                               "DbDesc slave recv: Sequence number mismatch Nbr %s (%#lx expected)",
+                               on->name, (unsigned long)on->dbdesc_seqnum + 1);
                        thread_add_event(master, seqnumber_mismatch, on, 0,
                                         NULL);
                        return;
@@ -711,9 +861,9 @@ static void ospf6_dbdesc_recv_slave(struct ospf6_header *oh,
                        return;
                }
 
-               if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV_HDR))
-                       zlog_debug("Not duplicate dbdesc in state %s",
-                                  ospf6_neighbor_state_str[on->state]);
+               zlog_warn(
+                       "DbDesc slave recv: Not duplicate dbdesc in state %s Nbr %s",
+                       ospf6_neighbor_state_str[on->state], on->name);
                thread_add_event(master, seqnumber_mismatch, on, 0, NULL);
                return;
 
@@ -750,7 +900,8 @@ static void ospf6_dbdesc_recv_slave(struct ospf6_header *oh,
                }
 
                if (OSPF6_LSA_SCOPE(his->header->type) == OSPF6_SCOPE_AS
-                   && IS_AREA_STUB(on->ospf6_if->area)) {
+                   && (IS_AREA_STUB(on->ospf6_if->area)
+                       || IS_AREA_NSSA(on->ospf6_if->area))) {
                        if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
                                zlog_debug("E-bit mismatch with LSA Headers");
                        ospf6_lsa_delete(his);
@@ -886,12 +1037,10 @@ static void ospf6_lsreq_recv(struct in6_addr *src, struct in6_addr *dst,
                /* Find database copy */
                lsa = ospf6_lsdb_lookup(e->type, e->id, e->adv_router, lsdb);
                if (lsa == NULL) {
-                       if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV)) {
-                               zlog_debug(
-                                       "Can't find requested [%s Id:%pI4 Adv:%pI4]",
-                                       ospf6_lstype_name(e->type), &e->id,
-                                       &e->adv_router);
-                       }
+                       zlog_warn(
+                               "Can't find requested lsa [%s Id:%pI4 Adv:%pI4] send badLSReq",
+                               ospf6_lstype_name(e->type), &e->id,
+                               &e->adv_router);
                        thread_add_event(master, bad_lsreq, on, 0, NULL);
                        return;
                }
@@ -921,18 +1070,14 @@ static unsigned ospf6_prefixes_examin(
 
        while (length) {
                if (length < OSPF6_PREFIX_MIN_SIZE) {
-                       if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
-                                                  RECV_HDR))
-                               zlog_debug("%s: undersized IPv6 prefix header",
-                                          __func__);
+                       zlog_warn("%s: undersized IPv6 prefix header",
+                                 __func__);
                        return MSG_NG;
                }
                /* safe to look deeper */
                if (current->prefix_length > IPV6_MAX_BITLEN) {
-                       if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
-                                                  RECV_HDR))
-                               zlog_debug("%s: invalid PrefixLength (%u bits)",
-                                          __func__, current->prefix_length);
+                       zlog_warn("%s: invalid PrefixLength (%u bits)",
+                                 __func__, current->prefix_length);
                        return MSG_NG;
                }
                /* covers both fixed- and variable-sized fields */
@@ -940,10 +1085,7 @@ static unsigned ospf6_prefixes_examin(
                        OSPF6_PREFIX_MIN_SIZE
                        + OSPF6_PREFIX_SPACE(current->prefix_length);
                if (requested_pfx_bytes > length) {
-                       if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
-                                                  RECV_HDR))
-                               zlog_debug("%s: undersized IPv6 prefix",
-                                          __func__);
+                       zlog_warn("%s: undersized IPv6 prefix", __func__);
                        return MSG_NG;
                }
                /* next prefix */
@@ -953,11 +1095,9 @@ static unsigned ospf6_prefixes_examin(
                real_num_pfxs++;
        }
        if (real_num_pfxs != req_num_pfxs) {
-               if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
-                                          RECV_HDR))
-                       zlog_debug(
-                               "%s: IPv6 prefix number mismatch (%u required, %u real)",
-                               __func__, req_num_pfxs, real_num_pfxs);
+               zlog_warn(
+                       "%s: IPv6 prefix number mismatch (%u required, %u real)",
+                       __func__, req_num_pfxs, real_num_pfxs);
                return MSG_NG;
        }
        return MSG_OK;
@@ -986,10 +1126,7 @@ static unsigned ospf6_lsa_examin(struct ospf6_lsa_header *lsah,
        ltindex = lsatype & OSPF6_LSTYPE_FCODE_MASK;
        if (ltindex < OSPF6_LSTYPE_SIZE && ospf6_lsa_minlen[ltindex]
            && lsalen < ospf6_lsa_minlen[ltindex] + OSPF6_LSA_HEADER_SIZE) {
-               if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
-                                          RECV_HDR))
-                       zlog_debug("%s: undersized (%u B) LSA", __func__,
-                                  lsalen);
+               zlog_warn("%s: undersized (%u B) LSA", __func__, lsalen);
                return MSG_NG;
        }
        switch (lsatype) {
@@ -999,11 +1136,9 @@ static unsigned ospf6_lsa_examin(struct ospf6_lsa_header *lsah,
                   by N>=0 interface descriptions. */
                if ((lsalen - OSPF6_LSA_HEADER_SIZE - OSPF6_ROUTER_LSA_MIN_SIZE)
                    % OSPF6_ROUTER_LSDESC_FIX_SIZE) {
-                       if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
-                                                  RECV_HDR))
-                               zlog_debug(
-                                       "%s: interface description alignment error",
-                                       __func__);
+                       zlog_warn(
+                               "%s: Router LSA interface description alignment error",
+                               __func__);
                        return MSG_NG;
                }
                break;
@@ -1013,11 +1148,9 @@ static unsigned ospf6_lsa_examin(struct ospf6_lsa_header *lsah,
                if ((lsalen - OSPF6_LSA_HEADER_SIZE
                     - OSPF6_NETWORK_LSA_MIN_SIZE)
                    % OSPF6_NETWORK_LSDESC_FIX_SIZE) {
-                       if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
-                                                  RECV_HDR))
-                               zlog_debug(
-                                       "%s: router description alignment error",
-                                       __func__);
+                       zlog_warn(
+                               "%s: Network LSA router description alignment error",
+                               __func__);
                        return MSG_NG;
                }
                break;
@@ -1038,10 +1171,8 @@ static unsigned ospf6_lsa_examin(struct ospf6_lsa_header *lsah,
                /* RFC5340 A.4.6, fixed-size LSA. */
                if (lsalen
                    > OSPF6_LSA_HEADER_SIZE + OSPF6_INTER_ROUTER_LSA_FIX_SIZE) {
-                       if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
-                                                  RECV_HDR))
-                               zlog_debug("%s: oversized (%u B) LSA", __func__,
-                                          lsalen);
+                       zlog_warn("%s: Inter Router LSA oversized (%u B) LSA",
+                                 __func__, lsalen);
                        return MSG_NG;
                }
                break;
@@ -1067,10 +1198,9 @@ static unsigned ospf6_lsa_examin(struct ospf6_lsa_header *lsah,
                   IPv6
                   prefix before ospf6_prefix_examin() confirms its sizing. */
                if (exp_length + OSPF6_PREFIX_MIN_SIZE > lsalen) {
-                       if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
-                                                  RECV_HDR))
-                               zlog_debug("%s: undersized (%u B) LSA header",
-                                          __func__, lsalen);
+                       zlog_warn(
+                               "%s: AS External undersized (%u B) LSA header",
+                               __func__, lsalen);
                        return MSG_NG;
                }
                /* forwarding address */
@@ -1086,10 +1216,9 @@ static unsigned ospf6_lsa_examin(struct ospf6_lsa_header *lsah,
                   I.e.,
                   this check does not include any IPv6 prefix fields. */
                if (exp_length > lsalen) {
-                       if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
-                                                  RECV_HDR))
-                               zlog_debug("%s: undersized (%u B) LSA header",
-                                          __func__, lsalen);
+                       zlog_warn(
+                               "%s: AS External undersized (%u B) LSA header",
+                               __func__, lsalen);
                        return MSG_NG;
                }
                /* The last call completely covers the remainder (IPv6 prefix).
@@ -1155,34 +1284,26 @@ ospf6_lsaseq_examin(struct ospf6_lsa_header *lsah, /* start of buffered data */
        while (length) {
                uint16_t lsalen;
                if (length < OSPF6_LSA_HEADER_SIZE) {
-                       if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
-                                                  RECV_HDR))
-                               zlog_debug(
-                                       "%s: undersized (%zu B) trailing (#%u) LSA header",
-                                       __func__, length, counted_lsas);
+                       zlog_warn(
+                               "%s: undersized (%zu B) trailing (#%u) LSA header",
+                               __func__, length, counted_lsas);
                        return MSG_NG;
                }
                /* save on ntohs() calls here and in the LSA validator */
                lsalen = OSPF6_LSA_SIZE(lsah);
                if (lsalen < OSPF6_LSA_HEADER_SIZE) {
-                       if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
-                                                  RECV_HDR))
-                               zlog_debug(
-                                       "%s: malformed LSA header #%u, declared length is %u B",
-                                       __func__, counted_lsas, lsalen);
+                       zlog_warn(
+                               "%s: malformed LSA header #%u, declared length is %u B",
+                               __func__, counted_lsas, lsalen);
                        return MSG_NG;
                }
                if (headeronly) {
                        /* less checks here and in ospf6_lsa_examin() */
                        if (MSG_OK != ospf6_lsa_examin(lsah, lsalen, 1)) {
-                               if (IS_OSPF6_DEBUG_MESSAGE(
-                                           OSPF6_MESSAGE_TYPE_UNKNOWN,
-                                           RECV_HDR))
-                                       zlog_debug(
-                                               "%s: anomaly in header-only %s LSA #%u",
-                                               __func__,
-                                               ospf6_lstype_name(lsah->type),
-                                               counted_lsas);
+                               zlog_warn(
+                                       "%s: anomaly in header-only %s LSA #%u",
+                                       __func__, ospf6_lstype_name(lsah->type),
+                                       counted_lsas);
                                return MSG_NG;
                        }
                        lsah = (struct ospf6_lsa_header
@@ -1193,25 +1314,16 @@ ospf6_lsaseq_examin(struct ospf6_lsa_header *lsah, /* start of buffered data */
                        /* make sure the input buffer is deep enough before
                         * further checks */
                        if (lsalen > length) {
-                               if (IS_OSPF6_DEBUG_MESSAGE(
-                                           OSPF6_MESSAGE_TYPE_UNKNOWN,
-                                           RECV_HDR))
-                                       zlog_debug(
-                                               "%s: anomaly in %s LSA #%u: declared length is %u B, buffered length is %zu B",
-                                               __func__,
-                                               ospf6_lstype_name(lsah->type),
-                                               counted_lsas, lsalen, length);
+                               zlog_warn(
+                                       "%s: anomaly in %s LSA #%u: declared length is %u B, buffered length is %zu B",
+                                       __func__, ospf6_lstype_name(lsah->type),
+                                       counted_lsas, lsalen, length);
                                return MSG_NG;
                        }
                        if (MSG_OK != ospf6_lsa_examin(lsah, lsalen, 0)) {
-                               if (IS_OSPF6_DEBUG_MESSAGE(
-                                           OSPF6_MESSAGE_TYPE_UNKNOWN,
-                                           RECV_HDR))
-                                       zlog_debug(
-                                               "%s: anomaly in %s LSA #%u",
-                                               __func__,
-                                               ospf6_lstype_name(lsah->type),
-                                               counted_lsas);
+                               zlog_warn("%s: anomaly in %s LSA #%u", __func__,
+                                         ospf6_lstype_name(lsah->type),
+                                         counted_lsas);
                                return MSG_NG;
                        }
                        lsah = (struct ospf6_lsa_header *)((caddr_t)lsah
@@ -1222,11 +1334,8 @@ ospf6_lsaseq_examin(struct ospf6_lsa_header *lsah, /* start of buffered data */
        }
 
        if (declared_num_lsas && counted_lsas != declared_num_lsas) {
-               if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
-                                          RECV_HDR))
-                       zlog_debug(
-                               "%s: #LSAs declared (%u) does not match actual (%u)",
-                               __func__, declared_num_lsas, counted_lsas);
+               zlog_warn("%s: #LSAs declared (%u) does not match actual (%u)",
+                         __func__, declared_num_lsas, counted_lsas);
                return MSG_NG;
        }
        return MSG_OK;
@@ -1241,41 +1350,31 @@ static unsigned ospf6_packet_examin(struct ospf6_header *oh,
 
        /* length, 1st approximation */
        if (bytesonwire < OSPF6_HEADER_SIZE) {
-               if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
-                                          RECV_HDR))
-                       zlog_debug("%s: undersized (%u B) packet", __func__,
-                                  bytesonwire);
+               zlog_warn("%s: undersized (%u B) packet", __func__,
+                         bytesonwire);
                return MSG_NG;
        }
        /* Now it is safe to access header fields. */
        if (bytesonwire != ntohs(oh->length)) {
-               if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
-                                          RECV_HDR))
-                       zlog_debug(
-                               "%s: %s packet length error (%u real, %u declared)",
-                               __func__, lookup_msg(ospf6_message_type_str,
-                                                    oh->type, NULL),
-                               bytesonwire, ntohs(oh->length));
+               zlog_warn("%s: %s packet length error (%u real, %u declared)",
+                         __func__,
+                         lookup_msg(ospf6_message_type_str, oh->type, NULL),
+                         bytesonwire, ntohs(oh->length));
                return MSG_NG;
        }
        /* version check */
        if (oh->version != OSPFV3_VERSION) {
-               if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
-                                          RECV_HDR))
-                       zlog_debug("%s: invalid (%u) protocol version",
-                                  __func__, oh->version);
+               zlog_warn("%s: invalid (%u) protocol version", __func__,
+                         oh->version);
                return MSG_NG;
        }
        /* length, 2nd approximation */
        if (oh->type < OSPF6_MESSAGE_TYPE_ALL && ospf6_packet_minlen[oh->type]
            && bytesonwire
                       < OSPF6_HEADER_SIZE + ospf6_packet_minlen[oh->type]) {
-               if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
-                                          RECV_HDR))
-                       zlog_debug("%s: undersized (%u B) %s packet", __func__,
-                                  bytesonwire,
-                                  lookup_msg(ospf6_message_type_str, oh->type,
-                                             NULL));
+               zlog_warn("%s: undersized (%u B) %s packet", __func__,
+                         bytesonwire,
+                         lookup_msg(ospf6_message_type_str, oh->type, NULL));
                return MSG_NG;
        }
        /* type-specific deeper validation */
@@ -1288,11 +1387,8 @@ static unsigned ospf6_packet_examin(struct ospf6_header *oh,
                    == (bytesonwire - OSPF6_HEADER_SIZE - OSPF6_HELLO_MIN_SIZE)
                               % 4)
                        return MSG_OK;
-               if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
-                                          RECV_HDR))
-                       zlog_debug("%s: alignment error in %s packet", __func__,
-                                  lookup_msg(ospf6_message_type_str, oh->type,
-                                             NULL));
+               zlog_warn("%s: alignment error in %s packet", __func__,
+                         lookup_msg(ospf6_message_type_str, oh->type, NULL));
                return MSG_NG;
        case OSPF6_MESSAGE_TYPE_DBDESC:
                /* RFC5340 A.3.3, packet header + OSPF6_DB_DESC_MIN_SIZE bytes
@@ -1312,11 +1408,8 @@ static unsigned ospf6_packet_examin(struct ospf6_header *oh,
                    == (bytesonwire - OSPF6_HEADER_SIZE - OSPF6_LS_REQ_MIN_SIZE)
                               % OSPF6_LSREQ_LSDESC_FIX_SIZE)
                        return MSG_OK;
-               if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
-                                          RECV_HDR))
-                       zlog_debug("%s: alignment error in %s packet", __func__,
-                                  lookup_msg(ospf6_message_type_str, oh->type,
-                                             NULL));
+               zlog_warn("%s: alignment error in %s packet", __func__,
+                         lookup_msg(ospf6_message_type_str, oh->type, NULL));
                return MSG_NG;
        case OSPF6_MESSAGE_TYPE_LSUPDATE:
                /* RFC5340 A.3.5, packet header + OSPF6_LS_UPD_MIN_SIZE bytes
@@ -1341,16 +1434,12 @@ static unsigned ospf6_packet_examin(struct ospf6_header *oh,
                        1, 0);
                break;
        default:
-               if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
-                                          RECV_HDR))
-                       zlog_debug("%s: invalid (%u) message type", __func__,
-                                  oh->type);
+               zlog_warn("%s: invalid (%u) message type", __func__, oh->type);
                return MSG_NG;
        }
-       if (test != MSG_OK
-           && IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN, RECV_HDR))
-               zlog_debug("%s: anomaly in %s packet", __func__,
-                          lookup_msg(ospf6_message_type_str, oh->type, NULL));
+       if (test != MSG_OK)
+               zlog_warn("%s: anomaly in %s packet", __func__,
+                         lookup_msg(ospf6_message_type_str, oh->type, NULL));
        return test;
 }
 
@@ -1570,23 +1659,19 @@ void ospf6_message_terminate(void)
        iobuflen = 0;
 }
 
-int ospf6_receive(struct thread *thread)
+enum ospf6_read_return_enum {
+       OSPF6_READ_ERROR,
+       OSPF6_READ_CONTINUE,
+};
+
+static int ospf6_read_helper(int sockfd, struct ospf6 *ospf6)
 {
-       int sockfd;
-       unsigned int len;
+       int len;
        struct in6_addr src, dst;
        ifindex_t ifindex;
        struct iovec iovector[2];
        struct ospf6_interface *oi;
        struct ospf6_header *oh;
-       struct ospf6 *ospf6;
-
-       /* add next read thread */
-       ospf6 = THREAD_ARG(thread);
-       sockfd = THREAD_FD(thread);
-
-       thread_add_read(master, ospf6_receive, ospf6, ospf6->fd,
-                       &ospf6->t_ospf6_receive);
 
        /* initialize */
        memset(&src, 0, sizeof(src));
@@ -1600,9 +1685,12 @@ int ospf6_receive(struct thread *thread)
 
        /* receive message */
        len = ospf6_recvmsg(&src, &dst, &ifindex, iovector, sockfd);
-       if (len > iobuflen) {
+       if (len < 0)
+               return OSPF6_READ_ERROR;
+
+       if ((uint)len > iobuflen) {
                flog_err(EC_LIB_DEVELOPMENT, "Excess message read");
-               return 0;
+               return OSPF6_READ_ERROR;
        }
 
        oi = ospf6_interface_lookup_by_ifindex(ifindex, ospf6->vrf_id);
@@ -1611,19 +1699,19 @@ int ospf6_receive(struct thread *thread)
                if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
                                           RECV_HDR))
                        zlog_debug("Message received on disabled interface");
-               return 0;
+               return OSPF6_READ_CONTINUE;
        }
        if (CHECK_FLAG(oi->flag, OSPF6_INTERFACE_PASSIVE)) {
                if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_UNKNOWN,
                                           RECV_HDR))
                        zlog_debug("%s: Ignore message on passive interface %s",
                                   __func__, oi->interface->name);
-               return 0;
+               return OSPF6_READ_CONTINUE;
        }
 
        oh = (struct ospf6_header *)recvbuf;
        if (ospf6_rxpacket_examin(oi, oh, len) != MSG_OK)
-               return 0;
+               return OSPF6_READ_CONTINUE;
 
        /* Being here means, that no sizing/alignment issues were detected in
           the input packet. This renders the additional checks performed below
@@ -1684,91 +1772,243 @@ int ospf6_receive(struct thread *thread)
                assert(0);
        }
 
+       return OSPF6_READ_CONTINUE;
+}
+
+int ospf6_receive(struct thread *thread)
+{
+       int sockfd;
+       struct ospf6 *ospf6;
+       int count = 0;
+
+       /* add next read thread */
+       ospf6 = THREAD_ARG(thread);
+       sockfd = THREAD_FD(thread);
+
+       thread_add_read(master, ospf6_receive, ospf6, ospf6->fd,
+                       &ospf6->t_ospf6_receive);
+
+       while (count < ospf6->write_oi_count) {
+               count++;
+               switch (ospf6_read_helper(sockfd, ospf6)) {
+               case OSPF6_READ_ERROR:
+                       return 0;
+               case OSPF6_READ_CONTINUE:
+                       break;
+               }
+       }
+
        return 0;
 }
 
-static void ospf6_send(struct in6_addr *src, struct in6_addr *dst,
-                      struct ospf6_interface *oi, struct ospf6_header *oh)
+static void ospf6_make_header(uint8_t type, struct ospf6_interface *oi,
+                             struct stream *s)
 {
-       unsigned int len;
-       char srcname[64];
-       struct iovec iovector[2];
+       struct ospf6_header *oh;
 
-       /* initialize */
-       iovector[0].iov_base = (caddr_t)oh;
-       iovector[0].iov_len = ntohs(oh->length);
-       iovector[1].iov_base = NULL;
-       iovector[1].iov_len = 0;
+       oh = (struct ospf6_header *)STREAM_DATA(s);
+
+       oh->version = (uint8_t)OSPFV3_VERSION;
+       oh->type = type;
 
-       /* fill OSPF header */
-       oh->version = OSPFV3_VERSION;
-       /* message type must be set before */
-       /* message length must be set before */
        oh->router_id = oi->area->ospf6->router_id;
        oh->area_id = oi->area->area_id;
-       /* checksum is calculated by kernel */
        oh->instance_id = oi->instance_id;
        oh->reserved = 0;
+       stream_forward_endp(s, OSPF6_HEADER_SIZE);
+}
 
-       /* Log */
-       if (IS_OSPF6_DEBUG_MESSAGE(oh->type, SEND_HDR)) {
-               if (src)
-                       inet_ntop(AF_INET6, src, srcname, sizeof(srcname));
-               else
-                       memset(srcname, 0, sizeof(srcname));
-               zlog_debug("%s send on %s",
-                          lookup_msg(ospf6_message_type_str, oh->type, NULL),
-                          oi->interface->name);
-               zlog_debug("    src: %s", srcname);
-               zlog_debug("    dst: %pI6", dst);
+static void ospf6_fill_header(struct ospf6_interface *oi, struct stream *s,
+                             uint16_t length)
+{
+       struct ospf6_header *oh;
+
+       oh = (struct ospf6_header *)STREAM_DATA(s);
+
+       oh->length = htons(length);
+}
+
+static void ospf6_fill_lsupdate_header(struct stream *s, uint32_t lsa_num)
+{
+       struct ospf6_header *oh;
+       struct ospf6_lsupdate *lsu;
+
+       oh = (struct ospf6_header *)STREAM_DATA(s);
+
+       lsu = (struct ospf6_lsupdate *)((caddr_t)oh
+                                       + sizeof(struct ospf6_header));
+       lsu->lsa_number = htonl(lsa_num);
+}
+
+static uint32_t ospf6_packet_max(struct ospf6_interface *oi)
+{
+       assert(oi->ifmtu > sizeof(struct ip6_hdr));
+       return oi->ifmtu - (sizeof(struct ip6_hdr));
+}
+
+static uint16_t ospf6_make_hello(struct ospf6_interface *oi, struct stream *s)
+{
+       struct listnode *node, *nnode;
+       struct ospf6_neighbor *on;
+       uint16_t length = OSPF6_HELLO_MIN_SIZE;
+
+       stream_putl(s, oi->interface->ifindex);
+       stream_putc(s, oi->priority);
+       stream_putc(s, oi->area->options[0]);
+       stream_putc(s, oi->area->options[1]);
+       stream_putc(s, oi->area->options[2]);
+       stream_putw(s, oi->hello_interval);
+       stream_putw(s, oi->dead_interval);
+       stream_put_ipv4(s, oi->drouter);
+       stream_put_ipv4(s, oi->bdrouter);
+
+       for (ALL_LIST_ELEMENTS(oi->neighbor_list, node, nnode, on)) {
+               if (on->state < OSPF6_NEIGHBOR_INIT)
+                       continue;
+
+               if ((length + sizeof(uint32_t) + OSPF6_HEADER_SIZE)
+                   > ospf6_packet_max(oi)) {
+                       if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_HELLO,
+                                                  SEND))
+                               zlog_debug(
+                                       "sending Hello message: exceeds I/F MTU");
+                       break;
+               }
+
+               stream_put_ipv4(s, on->router_id);
+               length += sizeof(uint32_t);
+       }
+
+       return length;
+}
 
+static int ospf6_write(struct thread *thread)
+{
+       struct ospf6 *ospf6 = THREAD_ARG(thread);
+       struct ospf6_interface *oi;
+       struct ospf6_interface *last_serviced_oi = NULL;
+       struct ospf6_header *oh;
+       struct ospf6_packet *op;
+       struct listnode *node;
+       char srcname[64], dstname[64];
+       struct iovec iovector[2];
+       int pkt_count = 0;
+       int len;
+       int64_t latency = 0;
+       struct timeval timestamp;
+
+       if (ospf6->fd < 0) {
+               zlog_warn("ospf6_write failed to send, fd %d", ospf6->fd);
+               return -1;
+       }
+
+       node = listhead(ospf6->oi_write_q);
+       assert(node);
+       oi = listgetdata(node);
+
+       while ((pkt_count < ospf6->write_oi_count) && oi
+              && (last_serviced_oi != oi)) {
+
+               op = ospf6_fifo_head(oi->obuf);
+               assert(op);
+               assert(op->length >= OSPF6_HEADER_SIZE);
+
+               iovector[0].iov_base = (caddr_t)stream_pnt(op->s);
+               iovector[0].iov_len = op->length;
+               iovector[1].iov_base = NULL;
+               iovector[1].iov_len = 0;
+
+               oh = (struct ospf6_header *)STREAM_DATA(op->s);
+
+               len = ospf6_sendmsg(oi->linklocal_addr, &op->dst,
+                                   oi->interface->ifindex, iovector,
+                                   ospf6->fd);
+               if (len != op->length)
+                       flog_err(EC_LIB_DEVELOPMENT,
+                                "Could not send entire message");
+
+               if (IS_OSPF6_DEBUG_MESSAGE(oh->type, SEND)) {
+                       inet_ntop(AF_INET6, &op->dst, dstname, sizeof(dstname));
+                       inet_ntop(AF_INET6, oi->linklocal_addr, srcname,
+                                 sizeof(srcname));
+                       zlog_debug("%s send on %s",
+                                  lookup_msg(ospf6_message_type_str, oh->type,
+                                             NULL),
+                                  oi->interface->name);
+                       zlog_debug("    src: %s", srcname);
+                       zlog_debug("    dst: %s", dstname);
+               }
                switch (oh->type) {
                case OSPF6_MESSAGE_TYPE_HELLO:
-                       ospf6_hello_print(oh, OSPF6_ACTION_RECV);
+                       monotime(&timestamp);
+                       if (oi->hello_out)
+                               latency = monotime_since(&oi->last_hello, NULL)
+                                         - (oi->hello_interval * 1000000);
+
+                       /* log if latency exceeds the hello period */
+                       if (latency > (oi->hello_interval * 1000000))
+                               zlog_warn("%s hello TX high latency %" PRId64
+                                         "us.",
+                                         __func__, latency);
+                       oi->last_hello = timestamp;
+                       oi->hello_out++;
+                       ospf6_hello_print(oh, OSPF6_ACTION_SEND);
                        break;
                case OSPF6_MESSAGE_TYPE_DBDESC:
-                       ospf6_dbdesc_print(oh, OSPF6_ACTION_RECV);
+                       oi->db_desc_out++;
+                       ospf6_dbdesc_print(oh, OSPF6_ACTION_SEND);
                        break;
                case OSPF6_MESSAGE_TYPE_LSREQ:
-                       ospf6_lsreq_print(oh, OSPF6_ACTION_RECV);
+                       oi->ls_req_out++;
+                       ospf6_lsreq_print(oh, OSPF6_ACTION_SEND);
                        break;
                case OSPF6_MESSAGE_TYPE_LSUPDATE:
-                       ospf6_lsupdate_print(oh, OSPF6_ACTION_RECV);
+                       oi->ls_upd_out++;
+                       ospf6_lsupdate_print(oh, OSPF6_ACTION_SEND);
                        break;
                case OSPF6_MESSAGE_TYPE_LSACK:
-                       ospf6_lsack_print(oh, OSPF6_ACTION_RECV);
+                       oi->ls_ack_out++;
+                       ospf6_lsack_print(oh, OSPF6_ACTION_SEND);
                        break;
                default:
                        zlog_debug("Unknown message");
                        assert(0);
                        break;
                }
-       }
+               /* Now delete packet from queue. */
+               ospf6_packet_delete(oi);
+
+               /* Move this interface to the tail of write_q to
+                      serve everyone in a round robin fashion */
+               list_delete_node(ospf6->oi_write_q, node);
+               if (ospf6_fifo_head(oi->obuf) == NULL) {
+                       oi->on_write_q = 0;
+                       last_serviced_oi = NULL;
+                       oi = NULL;
+               } else {
+                       listnode_add(ospf6->oi_write_q, oi);
+               }
 
-       /* send message */
-       if (oi->area->ospf6->fd != -1) {
-               len = ospf6_sendmsg(src, dst, oi->interface->ifindex, iovector,
-                                   oi->area->ospf6->fd);
-               if (len != ntohs(oh->length))
-                       flog_err(EC_LIB_DEVELOPMENT,
-                                "Could not send entire message");
+               /* Setup to service from the head of the queue again */
+               if (!list_isempty(ospf6->oi_write_q)) {
+                       node = listhead(ospf6->oi_write_q);
+                       oi = listgetdata(node);
+               }
        }
-}
 
-static uint32_t ospf6_packet_max(struct ospf6_interface *oi)
-{
-       assert(oi->ifmtu > sizeof(struct ip6_hdr));
-       return oi->ifmtu - (sizeof(struct ip6_hdr));
+       /* If packets still remain in queue, call write thread. */
+       if (!list_isempty(ospf6->oi_write_q))
+               thread_add_write(master, ospf6_write, ospf6, ospf6->fd,
+                                &ospf6->t_write);
+
+       return 0;
 }
 
 int ospf6_hello_send(struct thread *thread)
 {
        struct ospf6_interface *oi;
-       struct ospf6_header *oh;
-       struct ospf6_hello *hello;
-       uint8_t *p;
-       struct listnode *node, *nnode;
-       struct ospf6_neighbor *on;
+       struct ospf6_packet *op;
+       uint16_t length = OSPF6_HEADER_SIZE;
 
        oi = (struct ospf6_interface *)THREAD_ARG(thread);
        oi->thread_send_hello = (struct thread *)NULL;
@@ -1780,88 +2020,44 @@ int ospf6_hello_send(struct thread *thread)
                return 0;
        }
 
-       if (iobuflen == 0) {
-               zlog_debug("Unable to send Hello on interface %s iobuflen is 0",
-                          oi->interface->name);
+       op = ospf6_packet_new(oi->ifmtu);
+
+       ospf6_make_header(OSPF6_MESSAGE_TYPE_HELLO, oi, op->s);
+
+       /* Prepare OSPF Hello body */
+       length += ospf6_make_hello(oi, op->s);
+       if (length == OSPF6_HEADER_SIZE) {
+               /* Hello overshooting MTU */
+               ospf6_packet_free(op);
                return 0;
        }
 
-       /* set next thread */
-       thread_add_timer(master, ospf6_hello_send, oi, oi->hello_interval,
-                        &oi->thread_send_hello);
+       /* Fill OSPF header. */
+       ospf6_fill_header(oi, op->s, length);
 
-       memset(sendbuf, 0, iobuflen);
-       oh = (struct ospf6_header *)sendbuf;
-       hello = (struct ospf6_hello *)((caddr_t)oh
-                                      + sizeof(struct ospf6_header));
+       /* Set packet length. */
+       op->length = length;
 
-       hello->interface_id = htonl(oi->interface->ifindex);
-       hello->priority = oi->priority;
-       hello->options[0] = oi->area->options[0];
-       hello->options[1] = oi->area->options[1];
-       hello->options[2] = oi->area->options[2];
-       hello->hello_interval = htons(oi->hello_interval);
-       hello->dead_interval = htons(oi->dead_interval);
-       hello->drouter = oi->drouter;
-       hello->bdrouter = oi->bdrouter;
+       op->dst = allspfrouters6;
 
-       p = (uint8_t *)((caddr_t)hello + sizeof(struct ospf6_hello));
+       /* Add packet to the top of the interface output queue, so that they
+        * can't get delayed by things like long queues of LS Update packets
+        */
+       ospf6_packet_add_top(oi, op);
 
-       for (ALL_LIST_ELEMENTS(oi->neighbor_list, node, nnode, on)) {
-               if (on->state < OSPF6_NEIGHBOR_INIT)
-                       continue;
-
-               if (p - sendbuf + sizeof(uint32_t) > ospf6_packet_max(oi)) {
-                       if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_HELLO,
-                                                  SEND_HDR))
-                               zlog_debug(
-                                       "sending Hello message: exceeds I/F MTU");
-                       break;
-               }
-
-               memcpy(p, &on->router_id, sizeof(uint32_t));
-               p += sizeof(uint32_t);
-       }
-
-       oh->type = OSPF6_MESSAGE_TYPE_HELLO;
-       oh->length = htons(p - sendbuf);
+       /* set next thread */
+       thread_add_timer(master, ospf6_hello_send, oi, oi->hello_interval,
+                        &oi->thread_send_hello);
 
-       oi->hello_out++;
+       OSPF6_MESSAGE_WRITE_ON(oi);
 
-       ospf6_send(oi->linklocal_addr, &allspfrouters6, oi, oh);
        return 0;
 }
 
-int ospf6_dbdesc_send(struct thread *thread)
+static uint16_t ospf6_make_dbdesc(struct ospf6_neighbor *on, struct stream *s)
 {
-       struct ospf6_neighbor *on;
-       struct ospf6_header *oh;
-       struct ospf6_dbdesc *dbdesc;
-       uint8_t *p;
+       uint16_t length = OSPF6_DB_DESC_MIN_SIZE;
        struct ospf6_lsa *lsa, *lsanext;
-       struct in6_addr *dst;
-
-       on = (struct ospf6_neighbor *)THREAD_ARG(thread);
-       on->thread_send_dbdesc = (struct thread *)NULL;
-
-       if (on->state < OSPF6_NEIGHBOR_EXSTART) {
-               if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_DBDESC, SEND_HDR))
-                       zlog_debug(
-                               "Quit to send DbDesc to neighbor %s state %s",
-                               on->name, ospf6_neighbor_state_str[on->state]);
-               return 0;
-       }
-
-       /* set next thread if master */
-       if (CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MSBIT))
-               thread_add_timer(master, ospf6_dbdesc_send, on,
-                                on->ospf6_if->rxmt_interval,
-                                &on->thread_send_dbdesc);
-
-       memset(sendbuf, 0, iobuflen);
-       oh = (struct ospf6_header *)sendbuf;
-       dbdesc = (struct ospf6_dbdesc *)((caddr_t)oh
-                                        + sizeof(struct ospf6_header));
 
        /* if this is initial one, initialize sequence number for DbDesc */
        if (CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_IBIT)
@@ -1869,45 +2065,79 @@ int ospf6_dbdesc_send(struct thread *thread)
                on->dbdesc_seqnum = monotime(NULL);
        }
 
-       dbdesc->options[0] = on->ospf6_if->area->options[0];
-       dbdesc->options[1] = on->ospf6_if->area->options[1];
-       dbdesc->options[2] = on->ospf6_if->area->options[2];
-       dbdesc->ifmtu = htons(on->ospf6_if->ifmtu);
-       dbdesc->bits = on->dbdesc_bits;
-       dbdesc->seqnum = htonl(on->dbdesc_seqnum);
+       /* reserved */
+       stream_putc(s, 0); /* reserved 1 */
+       stream_putc(s, on->ospf6_if->area->options[0]);
+       stream_putc(s, on->ospf6_if->area->options[1]);
+       stream_putc(s, on->ospf6_if->area->options[2]);
+       stream_putw(s, on->ospf6_if->ifmtu);
+       stream_putc(s, 0); /* reserved 2 */
+       stream_putc(s, on->dbdesc_bits);
+       stream_putl(s, on->dbdesc_seqnum);
 
        /* if this is not initial one, set LSA headers in dbdesc */
-       p = (uint8_t *)((caddr_t)dbdesc + sizeof(struct ospf6_dbdesc));
        if (!CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_IBIT)) {
                for (ALL_LSDB(on->dbdesc_list, lsa, lsanext)) {
                        ospf6_lsa_age_update_to_send(lsa,
                                                     on->ospf6_if->transdelay);
 
                        /* MTU check */
-                       if (p - sendbuf + sizeof(struct ospf6_lsa_header)
+                       if ((length + sizeof(struct ospf6_lsa_header)
+                            + OSPF6_HEADER_SIZE)
                            > ospf6_packet_max(on->ospf6_if)) {
                                ospf6_lsa_unlock(lsa);
                                if (lsanext)
                                        ospf6_lsa_unlock(lsanext);
                                break;
                        }
-                       memcpy(p, lsa->header, sizeof(struct ospf6_lsa_header));
-                       p += sizeof(struct ospf6_lsa_header);
+                       stream_put(s, lsa->header,
+                                  sizeof(struct ospf6_lsa_header));
+                       length += sizeof(struct ospf6_lsa_header);
                }
        }
+       return length;
+}
+
+int ospf6_dbdesc_send(struct thread *thread)
+{
+       struct ospf6_neighbor *on;
+       uint16_t length = OSPF6_HEADER_SIZE;
+       struct ospf6_packet *op;
+
+       on = (struct ospf6_neighbor *)THREAD_ARG(thread);
+       on->thread_send_dbdesc = (struct thread *)NULL;
+
+       if (on->state < OSPF6_NEIGHBOR_EXSTART) {
+               if (IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_DBDESC, SEND))
+                       zlog_debug(
+                               "Quit to send DbDesc to neighbor %s state %s",
+                               on->name, ospf6_neighbor_state_str[on->state]);
+               return 0;
+       }
+
+       /* set next thread if master */
+       if (CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MSBIT))
+               thread_add_timer(master, ospf6_dbdesc_send, on,
+                                on->ospf6_if->rxmt_interval,
+                                &on->thread_send_dbdesc);
+
+       op = ospf6_packet_new(on->ospf6_if->ifmtu);
+       ospf6_make_header(OSPF6_MESSAGE_TYPE_DBDESC, on->ospf6_if, op->s);
 
-       oh->type = OSPF6_MESSAGE_TYPE_DBDESC;
-       oh->length = htons(p - sendbuf);
+       length += ospf6_make_dbdesc(on, op->s);
+       ospf6_fill_header(on->ospf6_if, op->s, length);
 
+       /* Set packet length. */
+       op->length = length;
 
        if (on->ospf6_if->state == OSPF6_INTERFACE_POINTTOPOINT)
-               dst = &allspfrouters6;
+               op->dst = allspfrouters6;
        else
-               dst = &on->linklocal_addr;
+               op->dst = on->linklocal_addr;
 
-       on->ospf6_if->db_desc_out++;
+       ospf6_packet_add(on->ospf6_if, op);
 
-       ospf6_send(on->ospf6_if->linklocal_addr, dst, on->ospf6_if, oh);
+       OSPF6_MESSAGE_WRITE_ON(on->ospf6_if);
 
        return 0;
 }
@@ -1927,7 +2157,8 @@ int ospf6_dbdesc_send_newone(struct thread *thread)
        size = sizeof(struct ospf6_lsa_header) + sizeof(struct ospf6_dbdesc);
        for (ALL_LSDB(on->summary_list, lsa, lsanext)) {
                /* if stub area then don't advertise AS-External LSAs */
-               if (IS_AREA_STUB(on->ospf6_if->area)
+               if ((IS_AREA_STUB(on->ospf6_if->area)
+                    || IS_AREA_NSSA(on->ospf6_if->area))
                    && ntohs(lsa->header->type) == OSPF6_LSTYPE_AS_EXTERNAL) {
                        ospf6_lsdb_remove(lsa, on->summary_list);
                        continue;
@@ -1959,13 +2190,84 @@ int ospf6_dbdesc_send_newone(struct thread *thread)
        return 0;
 }
 
+static uint16_t ospf6_make_lsreq(struct ospf6_neighbor *on, struct stream *s)
+{
+       uint16_t length = 0;
+       struct ospf6_lsa *lsa, *lsanext, *last_req = NULL;
+
+       for (ALL_LSDB(on->request_list, lsa, lsanext)) {
+               if ((length + OSPF6_HEADER_SIZE)
+                   > ospf6_packet_max(on->ospf6_if)) {
+                       ospf6_lsa_unlock(lsa);
+                       if (lsanext)
+                               ospf6_lsa_unlock(lsanext);
+                       break;
+               }
+               stream_putw(s, 0); /* reserved */
+               stream_putw(s, ntohs(lsa->header->type));
+               stream_putl(s, ntohl(lsa->header->id));
+               stream_putl(s, ntohl(lsa->header->adv_router));
+               length += sizeof(struct ospf6_lsreq_entry);
+               last_req = lsa;
+       }
+
+       if (last_req != NULL) {
+               if (on->last_ls_req != NULL)
+                       on->last_ls_req = ospf6_lsa_unlock(on->last_ls_req);
+
+               ospf6_lsa_lock(last_req);
+               on->last_ls_req = last_req;
+       }
+
+       return length;
+}
+
+static uint16_t ospf6_make_lsack_neighbor(struct ospf6_neighbor *on,
+                                         struct ospf6_packet **op)
+{
+       uint16_t length = 0;
+       struct ospf6_lsa *lsa, *lsanext;
+       int lsa_cnt = 0;
+
+       for (ALL_LSDB(on->lsack_list, lsa, lsanext)) {
+               if ((length + sizeof(struct ospf6_lsa_header)
+                    + OSPF6_HEADER_SIZE)
+                   > ospf6_packet_max(on->ospf6_if)) {
+                       /* if we run out of packet size/space here,
+                          better to try again soon. */
+                       if (lsa_cnt) {
+                               ospf6_fill_header(on->ospf6_if, (*op)->s,
+                                                 length + OSPF6_HEADER_SIZE);
+
+                               (*op)->length = length + OSPF6_HEADER_SIZE;
+                               (*op)->dst = on->linklocal_addr;
+                               ospf6_packet_add(on->ospf6_if, *op);
+                               OSPF6_MESSAGE_WRITE_ON(on->ospf6_if);
+                               /* new packet */
+                               *op = ospf6_packet_new(on->ospf6_if->ifmtu);
+                               ospf6_make_header(OSPF6_MESSAGE_TYPE_LSACK,
+                                                 on->ospf6_if, (*op)->s);
+                               length = 0;
+                               lsa_cnt = 0;
+                       }
+               }
+               ospf6_lsa_age_update_to_send(lsa, on->ospf6_if->transdelay);
+               stream_put((*op)->s, lsa->header,
+                          sizeof(struct ospf6_lsa_header));
+               length += sizeof(struct ospf6_lsa_header);
+
+               assert(lsa->lock == 2);
+               ospf6_lsdb_remove(lsa, on->lsack_list);
+               lsa_cnt++;
+       }
+       return length;
+}
+
 int ospf6_lsreq_send(struct thread *thread)
 {
        struct ospf6_neighbor *on;
-       struct ospf6_header *oh;
-       struct ospf6_lsreq_entry *e;
-       uint8_t *p;
-       struct ospf6_lsa *lsa, *lsanext, *last_req;
+       struct ospf6_packet *op;
+       uint16_t length = OSPF6_HEADER_SIZE;
 
        on = (struct ospf6_neighbor *)THREAD_ARG(thread);
        on->thread_send_lsreq = (struct thread *)NULL;
@@ -1986,49 +2288,31 @@ int ospf6_lsreq_send(struct thread *thread)
                return 0;
        }
 
-       memset(sendbuf, 0, iobuflen);
-       oh = (struct ospf6_header *)sendbuf;
-       last_req = NULL;
-
-       /* set Request entries in lsreq */
-       p = (uint8_t *)((caddr_t)oh + sizeof(struct ospf6_header));
-       for (ALL_LSDB(on->request_list, lsa, lsanext)) {
-               /* MTU check */
-               if (p - sendbuf + sizeof(struct ospf6_lsreq_entry)
-                   > ospf6_packet_max(on->ospf6_if)) {
-                       ospf6_lsa_unlock(lsa);
-                       if (lsanext)
-                               ospf6_lsa_unlock(lsanext);
-                       break;
-               }
-
-               e = (struct ospf6_lsreq_entry *)p;
-               e->type = lsa->header->type;
-               e->id = lsa->header->id;
-               e->adv_router = lsa->header->adv_router;
-               p += sizeof(struct ospf6_lsreq_entry);
-               last_req = lsa;
-       }
+       op = ospf6_packet_new(on->ospf6_if->ifmtu);
+       ospf6_make_header(OSPF6_MESSAGE_TYPE_LSREQ, on->ospf6_if, op->s);
 
-       if (last_req != NULL) {
-               if (on->last_ls_req != NULL)
-                       on->last_ls_req = ospf6_lsa_unlock(on->last_ls_req);
+       length += ospf6_make_lsreq(on, op->s);
 
-               ospf6_lsa_lock(last_req);
-               on->last_ls_req = last_req;
+       if (length == OSPF6_HEADER_SIZE) {
+               /* Hello overshooting MTU */
+               ospf6_packet_free(op);
+               return 0;
        }
 
-       oh->type = OSPF6_MESSAGE_TYPE_LSREQ;
-       oh->length = htons(p - sendbuf);
+       /* Fill OSPF header. */
+       ospf6_fill_header(on->ospf6_if, op->s, length);
 
-       on->ospf6_if->ls_req_out++;
+       /* Set packet length */
+       op->length = length;
 
        if (on->ospf6_if->state == OSPF6_INTERFACE_POINTTOPOINT)
-               ospf6_send(on->ospf6_if->linklocal_addr, &allspfrouters6,
-                          on->ospf6_if, oh);
+               op->dst = allspfrouters6;
        else
-               ospf6_send(on->ospf6_if->linklocal_addr, &on->linklocal_addr,
-                          on->ospf6_if, oh);
+               op->dst = on->linklocal_addr;
+
+       ospf6_packet_add(on->ospf6_if, op);
+
+       OSPF6_MESSAGE_WRITE_ON(on->ospf6_if);
 
        /* set next thread */
        if (on->request_list->count != 0) {
@@ -2043,43 +2327,117 @@ int ospf6_lsreq_send(struct thread *thread)
 
 static void ospf6_send_lsupdate(struct ospf6_neighbor *on,
                                struct ospf6_interface *oi,
-                               struct ospf6_header *oh)
+                               struct ospf6_packet *op)
 {
 
        if (on) {
-               on->ospf6_if->ls_upd_out++;
 
                if ((on->ospf6_if->state == OSPF6_INTERFACE_POINTTOPOINT)
                    || (on->ospf6_if->state == OSPF6_INTERFACE_DR)
-                   || (on->ospf6_if->state == OSPF6_INTERFACE_BDR)) {
-                       ospf6_send(on->ospf6_if->linklocal_addr,
-                                  &allspfrouters6, on->ospf6_if, oh);
-               } else {
-                       ospf6_send(on->ospf6_if->linklocal_addr,
-                                  &on->linklocal_addr, on->ospf6_if, oh);
-               }
+                   || (on->ospf6_if->state == OSPF6_INTERFACE_BDR))
+                       op->dst = allspfrouters6;
+               else
+                       op->dst = on->linklocal_addr;
+               oi = on->ospf6_if;
        } else if (oi) {
-
-               oi->ls_upd_out++;
-
                if ((oi->state == OSPF6_INTERFACE_POINTTOPOINT)
                    || (oi->state == OSPF6_INTERFACE_DR)
-                   || (oi->state == OSPF6_INTERFACE_BDR)) {
-                       ospf6_send(oi->linklocal_addr, &allspfrouters6, oi, oh);
-               } else {
-                       ospf6_send(oi->linklocal_addr, &alldrouters6, oi, oh);
+                   || (oi->state == OSPF6_INTERFACE_BDR))
+                       op->dst = allspfrouters6;
+               else
+                       op->dst = alldrouters6;
+       }
+       if (oi) {
+               ospf6_packet_add(oi, op);
+               OSPF6_MESSAGE_WRITE_ON(oi);
+       }
+}
+
+static uint16_t ospf6_make_lsupdate_list(struct ospf6_neighbor *on,
+                                        struct ospf6_packet **op, int *lsa_cnt)
+{
+       uint16_t length = OSPF6_LS_UPD_MIN_SIZE;
+       struct ospf6_lsa *lsa, *lsanext;
+
+       /* skip over fixed header */
+       stream_forward_endp((*op)->s, OSPF6_LS_UPD_MIN_SIZE);
+
+       for (ALL_LSDB(on->lsupdate_list, lsa, lsanext)) {
+               if ((length + (unsigned int)OSPF6_LSA_SIZE(lsa->header)
+                    + OSPF6_HEADER_SIZE)
+                   > ospf6_packet_max(on->ospf6_if)) {
+                       ospf6_fill_header(on->ospf6_if, (*op)->s,
+                                         length + OSPF6_HEADER_SIZE);
+                       (*op)->length = length + OSPF6_HEADER_SIZE;
+                       ospf6_fill_lsupdate_header((*op)->s, *lsa_cnt);
+                       ospf6_send_lsupdate(on, NULL, *op);
+
+                       /* refresh packet */
+                       *op = ospf6_packet_new(on->ospf6_if->ifmtu);
+                       length = OSPF6_LS_UPD_MIN_SIZE;
+                       *lsa_cnt = 0;
+                       ospf6_make_header(OSPF6_MESSAGE_TYPE_LSUPDATE,
+                                         on->ospf6_if, (*op)->s);
+                       stream_forward_endp((*op)->s, OSPF6_LS_UPD_MIN_SIZE);
+               }
+               ospf6_lsa_age_update_to_send(lsa, on->ospf6_if->transdelay);
+               stream_put((*op)->s, lsa->header, OSPF6_LSA_SIZE(lsa->header));
+               (*lsa_cnt)++;
+               length += OSPF6_LSA_SIZE(lsa->header);
+               assert(lsa->lock == 2);
+               ospf6_lsdb_remove(lsa, on->lsupdate_list);
+       }
+       return length;
+}
+
+static uint16_t ospf6_make_ls_retrans_list(struct ospf6_neighbor *on,
+                                          struct ospf6_packet **op,
+                                          int *lsa_cnt)
+{
+       uint16_t length = OSPF6_LS_UPD_MIN_SIZE;
+       struct ospf6_lsa *lsa, *lsanext;
+
+       /* skip over fixed header */
+       stream_forward_endp((*op)->s, OSPF6_LS_UPD_MIN_SIZE);
+
+       for (ALL_LSDB(on->retrans_list, lsa, lsanext)) {
+               if ((length + (unsigned int)OSPF6_LSA_SIZE(lsa->header)
+                    + OSPF6_HEADER_SIZE)
+                   > ospf6_packet_max(on->ospf6_if)) {
+                       ospf6_fill_header(on->ospf6_if, (*op)->s,
+                                         length + OSPF6_HEADER_SIZE);
+                       (*op)->length = length + OSPF6_HEADER_SIZE;
+                       ospf6_fill_lsupdate_header((*op)->s, *lsa_cnt);
+                       if (on->ospf6_if->state == OSPF6_INTERFACE_POINTTOPOINT)
+                               (*op)->dst = allspfrouters6;
+                       else
+                               (*op)->dst = on->linklocal_addr;
+
+                       ospf6_packet_add(on->ospf6_if, *op);
+                       OSPF6_MESSAGE_WRITE_ON(on->ospf6_if);
+
+                       /* refresh packet */
+                       *op = ospf6_packet_new(on->ospf6_if->ifmtu);
+                       length = OSPF6_LS_UPD_MIN_SIZE;
+                       *lsa_cnt = 0;
+                       ospf6_make_header(OSPF6_MESSAGE_TYPE_LSUPDATE,
+                                         on->ospf6_if, (*op)->s);
+                       stream_forward_endp((*op)->s, OSPF6_LS_UPD_MIN_SIZE);
                }
+               ospf6_lsa_age_update_to_send(lsa, on->ospf6_if->transdelay);
+               stream_put((*op)->s, lsa->header, OSPF6_LSA_SIZE(lsa->header));
+               (*lsa_cnt)++;
+               length += OSPF6_LSA_SIZE(lsa->header);
        }
+       return length;
 }
 
 int ospf6_lsupdate_send_neighbor(struct thread *thread)
 {
        struct ospf6_neighbor *on;
-       struct ospf6_header *oh;
-       struct ospf6_lsupdate *lsupdate;
-       uint8_t *p;
-       int lsa_cnt;
-       struct ospf6_lsa *lsa, *lsanext;
+       struct ospf6_packet *op;
+       uint16_t length = OSPF6_HEADER_SIZE;
+       int lsa_cnt = 0;
 
        on = (struct ospf6_neighbor *)THREAD_ARG(thread);
        on->thread_send_lsupdate = (struct thread *)NULL;
@@ -2095,119 +2453,41 @@ int ospf6_lsupdate_send_neighbor(struct thread *thread)
                return 0;
        }
 
-       memset(sendbuf, 0, iobuflen);
-       oh = (struct ospf6_header *)sendbuf;
-       lsupdate = (struct ospf6_lsupdate *)((caddr_t)oh
-                                            + sizeof(struct ospf6_header));
-
-       p = (uint8_t *)((caddr_t)lsupdate + sizeof(struct ospf6_lsupdate));
-       lsa_cnt = 0;
-
-       /* lsupdate_list lists those LSA which doesn't need to be
-          retransmitted. remove those from the list */
-       for (ALL_LSDB(on->lsupdate_list, lsa, lsanext)) {
-               /* MTU check */
-               if ((p - sendbuf + (unsigned int)OSPF6_LSA_SIZE(lsa->header))
-                   > ospf6_packet_max(on->ospf6_if)) {
-                       if (lsa_cnt) {
-                               oh->type = OSPF6_MESSAGE_TYPE_LSUPDATE;
-                               oh->length = htons(p - sendbuf);
-                               lsupdate->lsa_number = htonl(lsa_cnt);
-
-                               ospf6_send_lsupdate(on, NULL, oh);
-
-                               memset(sendbuf, 0, iobuflen);
-                               oh = (struct ospf6_header *)sendbuf;
-                               lsupdate = (struct ospf6_lsupdate
-                                                   *)((caddr_t)oh
-                                                      + sizeof(struct
-                                                               ospf6_header));
-
-                               p = (uint8_t *)((caddr_t)lsupdate
-                                               + sizeof(struct
-                                                        ospf6_lsupdate));
-                               lsa_cnt = 0;
-                       }
-               }
-
-               ospf6_lsa_age_update_to_send(lsa, on->ospf6_if->transdelay);
-               memcpy(p, lsa->header, OSPF6_LSA_SIZE(lsa->header));
-               p += OSPF6_LSA_SIZE(lsa->header);
-               lsa_cnt++;
-
-               assert(lsa->lock == 2);
-               ospf6_lsdb_remove(lsa, on->lsupdate_list);
-       }
-
+       /* first do lsupdate_list */
+       op = ospf6_packet_new(on->ospf6_if->ifmtu);
+       ospf6_make_header(OSPF6_MESSAGE_TYPE_LSUPDATE, on->ospf6_if, op->s);
+       length += ospf6_make_lsupdate_list(on, &op, &lsa_cnt);
        if (lsa_cnt) {
-               oh->type = OSPF6_MESSAGE_TYPE_LSUPDATE;
-               oh->length = htons(p - sendbuf);
-               lsupdate->lsa_number = htonl(lsa_cnt);
-               ospf6_send_lsupdate(on, NULL, oh);
-       }
-
-       /* The addresses used for retransmissions are different from those sent
-          the
-          first time and so we need to separate them here.
-       */
-       memset(sendbuf, 0, iobuflen);
-       oh = (struct ospf6_header *)sendbuf;
-       lsupdate = (struct ospf6_lsupdate *)((caddr_t)oh
-                                            + sizeof(struct ospf6_header));
-       p = (uint8_t *)((caddr_t)lsupdate + sizeof(struct ospf6_lsupdate));
-       lsa_cnt = 0;
-
-       for (ALL_LSDB(on->retrans_list, lsa, lsanext)) {
-               /* MTU check */
-               if ((p - sendbuf + (unsigned int)OSPF6_LSA_SIZE(lsa->header))
-                   > ospf6_packet_max(on->ospf6_if)) {
-                       if (lsa_cnt) {
-                               oh->type = OSPF6_MESSAGE_TYPE_LSUPDATE;
-                               oh->length = htons(p - sendbuf);
-                               lsupdate->lsa_number = htonl(lsa_cnt);
-
-                               if (on->ospf6_if->state
-                                   == OSPF6_INTERFACE_POINTTOPOINT) {
-                                       ospf6_send(on->ospf6_if->linklocal_addr,
-                                                  &allspfrouters6,
-                                                  on->ospf6_if, oh);
-                               } else {
-                                       ospf6_send(on->ospf6_if->linklocal_addr,
-                                                  &on->linklocal_addr,
-                                                  on->ospf6_if, oh);
-                               }
-
-                               memset(sendbuf, 0, iobuflen);
-                               oh = (struct ospf6_header *)sendbuf;
-                               lsupdate = (struct ospf6_lsupdate
-                                                   *)((caddr_t)oh
-                                                      + sizeof(struct
-                                                               ospf6_header));
-                               p = (uint8_t *)((caddr_t)lsupdate
-                                               + sizeof(struct
-                                                        ospf6_lsupdate));
-                               lsa_cnt = 0;
-                       }
-               }
-
-               ospf6_lsa_age_update_to_send(lsa, on->ospf6_if->transdelay);
-               memcpy(p, lsa->header, OSPF6_LSA_SIZE(lsa->header));
-               p += OSPF6_LSA_SIZE(lsa->header);
-               lsa_cnt++;
-       }
-
+               /* Fill OSPF header. */
+               ospf6_fill_header(on->ospf6_if, op->s, length);
+               ospf6_fill_lsupdate_header(op->s, lsa_cnt);
+               op->length = length;
+               ospf6_send_lsupdate(on, NULL, op);
+
+               /* prepare new packet */
+               op = ospf6_packet_new(on->ospf6_if->ifmtu);
+               length = OSPF6_HEADER_SIZE;
+               lsa_cnt = 0;
+       } else {
+               stream_reset(op->s);
+               length = OSPF6_HEADER_SIZE;
+       }
+
+       ospf6_make_header(OSPF6_MESSAGE_TYPE_LSUPDATE, on->ospf6_if, op->s);
+       /* now do retransmit list */
+       length += ospf6_make_ls_retrans_list(on, &op, &lsa_cnt);
        if (lsa_cnt) {
-               oh->type = OSPF6_MESSAGE_TYPE_LSUPDATE;
-               oh->length = htons(p - sendbuf);
-               lsupdate->lsa_number = htonl(lsa_cnt);
-
+               ospf6_fill_header(on->ospf6_if, op->s, length);
+               ospf6_fill_lsupdate_header(op->s, lsa_cnt);
+               op->length = length;
                if (on->ospf6_if->state == OSPF6_INTERFACE_POINTTOPOINT)
-                       ospf6_send(on->ospf6_if->linklocal_addr,
-                                  &allspfrouters6, on->ospf6_if, oh);
+                       op->dst = allspfrouters6;
                else
-                       ospf6_send(on->ospf6_if->linklocal_addr,
-                                  &on->linklocal_addr, on->ospf6_if, oh);
-       }
+                       op->dst = on->linklocal_addr;
+               ospf6_packet_add(on->ospf6_if, op);
+               OSPF6_MESSAGE_WRITE_ON(on->ospf6_if);
+       } else
+               ospf6_packet_free(op);
 
        if (on->lsupdate_list->count != 0) {
                on->thread_send_lsupdate = NULL;
@@ -2225,44 +2505,78 @@ int ospf6_lsupdate_send_neighbor(struct thread *thread)
 int ospf6_lsupdate_send_neighbor_now(struct ospf6_neighbor *on,
                                     struct ospf6_lsa *lsa)
 {
-       struct ospf6_header *oh;
-       struct ospf6_lsupdate *lsupdate;
-       uint8_t *p;
-       int lsa_cnt = 0;
+       struct ospf6_packet *op;
+       uint16_t length = OSPF6_HEADER_SIZE;
 
-       memset(sendbuf, 0, iobuflen);
-       oh = (struct ospf6_header *)sendbuf;
-       lsupdate = (struct ospf6_lsupdate *)((caddr_t)oh
-                                            + sizeof(struct ospf6_header));
+       op = ospf6_packet_new(on->ospf6_if->ifmtu);
+       ospf6_make_header(OSPF6_MESSAGE_TYPE_LSUPDATE, on->ospf6_if, op->s);
 
-       p = (uint8_t *)((caddr_t)lsupdate + sizeof(struct ospf6_lsupdate));
+       /* skip over fixed header */
+       stream_forward_endp(op->s, OSPF6_LS_UPD_MIN_SIZE);
        ospf6_lsa_age_update_to_send(lsa, on->ospf6_if->transdelay);
-       memcpy(p, lsa->header, OSPF6_LSA_SIZE(lsa->header));
-       p += OSPF6_LSA_SIZE(lsa->header);
-       lsa_cnt++;
-
-       oh->type = OSPF6_MESSAGE_TYPE_LSUPDATE;
-       oh->length = htons(p - sendbuf);
-       lsupdate->lsa_number = htonl(lsa_cnt);
+       stream_put(op->s, lsa->header, OSPF6_LSA_SIZE(lsa->header));
+       length = OSPF6_HEADER_SIZE + OSPF6_LS_UPD_MIN_SIZE
+                + OSPF6_LSA_SIZE(lsa->header);
+       ospf6_fill_header(on->ospf6_if, op->s, length);
+       ospf6_fill_lsupdate_header(op->s, 1);
+       op->length = length;
 
        if (IS_OSPF6_DEBUG_FLOODING
            || IS_OSPF6_DEBUG_MESSAGE(OSPF6_MESSAGE_TYPE_LSUPDATE, SEND_HDR))
                zlog_debug("%s: Send lsupdate with lsa %s (age %u)", __func__,
                           lsa->name, ntohs(lsa->header->age));
 
-       ospf6_send_lsupdate(on, NULL, oh);
+       ospf6_send_lsupdate(on, NULL, op);
 
        return 0;
 }
 
+static uint16_t ospf6_make_lsupdate_interface(struct ospf6_interface *oi,
+                                             struct ospf6_packet **op,
+                                             int *lsa_cnt)
+{
+       uint16_t length = OSPF6_LS_UPD_MIN_SIZE;
+       struct ospf6_lsa *lsa, *lsanext;
+
+       /* skip over fixed header */
+       stream_forward_endp((*op)->s, OSPF6_LS_UPD_MIN_SIZE);
+
+       for (ALL_LSDB(oi->lsupdate_list, lsa, lsanext)) {
+               if (length + (unsigned int)OSPF6_LSA_SIZE(lsa->header)
+                           + OSPF6_HEADER_SIZE
+                   > ospf6_packet_max(oi)) {
+                       ospf6_fill_header(oi, (*op)->s,
+                                         length + OSPF6_HEADER_SIZE);
+                       (*op)->length = length + OSPF6_HEADER_SIZE;
+                       ospf6_fill_lsupdate_header((*op)->s, *lsa_cnt);
+                       ospf6_send_lsupdate(NULL, oi, *op);
+
+                       /* refresh packet */
+                       *op = ospf6_packet_new(oi->ifmtu);
+                       length = OSPF6_LS_UPD_MIN_SIZE;
+                       *lsa_cnt = 0;
+                       ospf6_make_header(OSPF6_MESSAGE_TYPE_LSUPDATE, oi,
+                                         (*op)->s);
+                       stream_forward_endp((*op)->s, OSPF6_LS_UPD_MIN_SIZE);
+               }
+
+               ospf6_lsa_age_update_to_send(lsa, oi->transdelay);
+               stream_put((*op)->s, lsa->header, OSPF6_LSA_SIZE(lsa->header));
+               (*lsa_cnt)++;
+               length += OSPF6_LSA_SIZE(lsa->header);
+
+               assert(lsa->lock == 2);
+               ospf6_lsdb_remove(lsa, oi->lsupdate_list);
+       }
+       return length;
+}
+
 int ospf6_lsupdate_send_interface(struct thread *thread)
 {
        struct ospf6_interface *oi;
-       struct ospf6_header *oh;
-       struct ospf6_lsupdate *lsupdate;
-       uint8_t *p;
-       int lsa_cnt;
-       struct ospf6_lsa *lsa, *lsanext;
+       struct ospf6_packet *op;
+       uint16_t length = OSPF6_HEADER_SIZE;
+       int lsa_cnt = 0;
 
        oi = (struct ospf6_interface *)THREAD_ARG(thread);
        oi->thread_send_lsupdate = (struct thread *)NULL;
@@ -2281,59 +2595,17 @@ int ospf6_lsupdate_send_interface(struct thread *thread)
        if (oi->lsupdate_list->count == 0)
                return 0;
 
-       memset(sendbuf, 0, iobuflen);
-       oh = (struct ospf6_header *)sendbuf;
-       lsupdate = (struct ospf6_lsupdate *)((caddr_t)oh
-                                            + sizeof(struct ospf6_header));
-
-       p = (uint8_t *)((caddr_t)lsupdate + sizeof(struct ospf6_lsupdate));
-       lsa_cnt = 0;
-
-       for (ALL_LSDB(oi->lsupdate_list, lsa, lsanext)) {
-               /* MTU check */
-               if ((p - sendbuf + ((unsigned int)OSPF6_LSA_SIZE(lsa->header)))
-                   > ospf6_packet_max(oi)) {
-                       if (lsa_cnt) {
-                               oh->type = OSPF6_MESSAGE_TYPE_LSUPDATE;
-                               oh->length = htons(p - sendbuf);
-                               lsupdate->lsa_number = htonl(lsa_cnt);
-
-                               ospf6_send_lsupdate(NULL, oi, oh);
-                               if (IS_OSPF6_DEBUG_MESSAGE(
-                                           OSPF6_MESSAGE_TYPE_LSUPDATE, SEND))
-                                       zlog_debug("%s: LSUpdate length %d",
-                                                  __func__, ntohs(oh->length));
-
-                               memset(sendbuf, 0, iobuflen);
-                               oh = (struct ospf6_header *)sendbuf;
-                               lsupdate = (struct ospf6_lsupdate
-                                                   *)((caddr_t)oh
-                                                      + sizeof(struct
-                                                               ospf6_header));
-
-                               p = (uint8_t *)((caddr_t)lsupdate
-                                               + sizeof(struct
-                                                        ospf6_lsupdate));
-                               lsa_cnt = 0;
-                       }
-               }
-
-               ospf6_lsa_age_update_to_send(lsa, oi->transdelay);
-               memcpy(p, lsa->header, OSPF6_LSA_SIZE(lsa->header));
-               p += OSPF6_LSA_SIZE(lsa->header);
-               lsa_cnt++;
-
-               assert(lsa->lock == 2);
-               ospf6_lsdb_remove(lsa, oi->lsupdate_list);
-       }
-
+       op = ospf6_packet_new(oi->ifmtu);
+       ospf6_make_header(OSPF6_MESSAGE_TYPE_LSUPDATE, oi, op->s);
+       length += ospf6_make_lsupdate_interface(oi, &op, &lsa_cnt);
        if (lsa_cnt) {
-               oh->type = OSPF6_MESSAGE_TYPE_LSUPDATE;
-               oh->length = htons(p - sendbuf);
-               lsupdate->lsa_number = htonl(lsa_cnt);
-
-               ospf6_send_lsupdate(NULL, oi, oh);
-       }
+               /* Fill OSPF header. */
+               ospf6_fill_header(oi, op->s, length);
+               ospf6_fill_lsupdate_header(op->s, lsa_cnt);
+               op->length = length;
+               ospf6_send_lsupdate(NULL, oi, op);
+       } else
+               ospf6_packet_free(op);
 
        if (oi->lsupdate_list->count > 0) {
                oi->thread_send_lsupdate = NULL;
@@ -2347,10 +2619,8 @@ int ospf6_lsupdate_send_interface(struct thread *thread)
 int ospf6_lsack_send_neighbor(struct thread *thread)
 {
        struct ospf6_neighbor *on;
-       struct ospf6_header *oh;
-       uint8_t *p;
-       struct ospf6_lsa *lsa, *lsanext;
-       int lsa_cnt = 0;
+       struct ospf6_packet *op;
+       uint16_t length = OSPF6_HEADER_SIZE;
 
        on = (struct ospf6_neighbor *)THREAD_ARG(thread);
        on->thread_send_lsack = (struct thread *)NULL;
@@ -2367,53 +2637,24 @@ int ospf6_lsack_send_neighbor(struct thread *thread)
        if (on->lsack_list->count == 0)
                return 0;
 
-       memset(sendbuf, 0, iobuflen);
-       oh = (struct ospf6_header *)sendbuf;
-
-       p = (uint8_t *)((caddr_t)oh + sizeof(struct ospf6_header));
-
-       for (ALL_LSDB(on->lsack_list, lsa, lsanext)) {
-               /* MTU check */
-               if (p - sendbuf + sizeof(struct ospf6_lsa_header)
-                   > ospf6_packet_max(on->ospf6_if)) {
-                       /* if we run out of packet size/space here,
-                          better to try again soon. */
-                       if (lsa_cnt) {
-                               oh->type = OSPF6_MESSAGE_TYPE_LSACK;
-                               oh->length = htons(p - sendbuf);
-
-                               on->ospf6_if->ls_ack_out++;
-
-                               ospf6_send(on->ospf6_if->linklocal_addr,
-                                          &on->linklocal_addr, on->ospf6_if,
-                                          oh);
-
-                               memset(sendbuf, 0, iobuflen);
-                               oh = (struct ospf6_header *)sendbuf;
-                               p = (uint8_t *)((caddr_t)oh
-                                               + sizeof(struct ospf6_header));
-                               lsa_cnt = 0;
-                       }
-               }
+       op = ospf6_packet_new(on->ospf6_if->ifmtu);
+       ospf6_make_header(OSPF6_MESSAGE_TYPE_LSACK, on->ospf6_if, op->s);
 
-               ospf6_lsa_age_update_to_send(lsa, on->ospf6_if->transdelay);
-               memcpy(p, lsa->header, sizeof(struct ospf6_lsa_header));
-               p += sizeof(struct ospf6_lsa_header);
+       length += ospf6_make_lsack_neighbor(on, &op);
 
-               assert(lsa->lock == 2);
-               ospf6_lsdb_remove(lsa, on->lsack_list);
-               lsa_cnt++;
+       if (length == OSPF6_HEADER_SIZE) {
+               ospf6_packet_free(op);
+               return 0;
        }
 
-       if (lsa_cnt) {
-               oh->type = OSPF6_MESSAGE_TYPE_LSACK;
-               oh->length = htons(p - sendbuf);
-
-               on->ospf6_if->ls_ack_out++;
+       /* Fill OSPF header. */
+       ospf6_fill_header(on->ospf6_if, op->s, length);
 
-               ospf6_send(on->ospf6_if->linklocal_addr, &on->linklocal_addr,
-                          on->ospf6_if, oh);
-       }
+       /* Set packet length, dst and queue to FIFO. */
+       op->length = length;
+       op->dst = on->linklocal_addr;
+       ospf6_packet_add(on->ospf6_if, op);
+       OSPF6_MESSAGE_WRITE_ON(on->ospf6_if);
 
        if (on->lsack_list->count > 0)
                thread_add_event(master, ospf6_lsack_send_neighbor, on, 0,
@@ -2422,13 +2663,42 @@ int ospf6_lsack_send_neighbor(struct thread *thread)
        return 0;
 }
 
+static uint16_t ospf6_make_lsack_interface(struct ospf6_interface *oi,
+                                          struct ospf6_packet *op)
+{
+       uint16_t length = 0;
+       struct ospf6_lsa *lsa, *lsanext;
+
+       for (ALL_LSDB(oi->lsack_list, lsa, lsanext)) {
+               if ((length + sizeof(struct ospf6_lsa_header)
+                    + OSPF6_HEADER_SIZE)
+                   > ospf6_packet_max(oi)) {
+                       /* if we run out of packet size/space here,
+                          better to try again soon. */
+                       THREAD_OFF(oi->thread_send_lsack);
+                       thread_add_event(master, ospf6_lsack_send_interface, oi,
+                                        0, &oi->thread_send_lsack);
+
+                       ospf6_lsa_unlock(lsa);
+                       if (lsanext)
+                               ospf6_lsa_unlock(lsanext);
+                       break;
+               }
+               ospf6_lsa_age_update_to_send(lsa, oi->transdelay);
+               stream_put(op->s, lsa->header, sizeof(struct ospf6_lsa_header));
+               length += sizeof(struct ospf6_lsa_header);
+
+               assert(lsa->lock == 2);
+               ospf6_lsdb_remove(lsa, oi->lsack_list);
+       }
+       return length;
+}
+
 int ospf6_lsack_send_interface(struct thread *thread)
 {
        struct ospf6_interface *oi;
-       struct ospf6_header *oh;
-       uint8_t *p;
-       struct ospf6_lsa *lsa, *lsanext;
-       int lsa_cnt = 0;
+       struct ospf6_packet *op;
+       uint16_t length = OSPF6_HEADER_SIZE;
 
        oi = (struct ospf6_interface *)THREAD_ARG(thread);
        oi->thread_send_lsack = (struct thread *)NULL;
@@ -2446,47 +2716,29 @@ int ospf6_lsack_send_interface(struct thread *thread)
        if (oi->lsack_list->count == 0)
                return 0;
 
-       memset(sendbuf, 0, iobuflen);
-       oh = (struct ospf6_header *)sendbuf;
-
-       p = (uint8_t *)((caddr_t)oh + sizeof(struct ospf6_header));
-
-       for (ALL_LSDB(oi->lsack_list, lsa, lsanext)) {
-               /* MTU check */
-               if (p - sendbuf + sizeof(struct ospf6_lsa_header)
-                   > ospf6_packet_max(oi)) {
-                       /* if we run out of packet size/space here,
-                          better to try again soon. */
-                       THREAD_OFF(oi->thread_send_lsack);
-                       thread_add_event(master, ospf6_lsack_send_interface, oi,
-                                        0, &oi->thread_send_lsack);
-
-                       ospf6_lsa_unlock(lsa);
-                       if (lsanext)
-                               ospf6_lsa_unlock(lsanext);
-                       break;
-               }
+       op = ospf6_packet_new(oi->ifmtu);
+       ospf6_make_header(OSPF6_MESSAGE_TYPE_LSACK, oi, op->s);
 
-               ospf6_lsa_age_update_to_send(lsa, oi->transdelay);
-               memcpy(p, lsa->header, sizeof(struct ospf6_lsa_header));
-               p += sizeof(struct ospf6_lsa_header);
+       length += ospf6_make_lsack_interface(oi, op);
 
-               assert(lsa->lock == 2);
-               ospf6_lsdb_remove(lsa, oi->lsack_list);
-               lsa_cnt++;
+       if (length == OSPF6_HEADER_SIZE) {
+               ospf6_packet_free(op);
+               return 0;
        }
+       /* Fill OSPF header. */
+       ospf6_fill_header(oi, op->s, length);
 
-       if (lsa_cnt) {
-               oh->type = OSPF6_MESSAGE_TYPE_LSACK;
-               oh->length = htons(p - sendbuf);
+       /* Set packet length, dst and queue to FIFO. */
+       op->length = length;
+       if ((oi->state == OSPF6_INTERFACE_POINTTOPOINT)
+           || (oi->state == OSPF6_INTERFACE_DR)
+           || (oi->state == OSPF6_INTERFACE_BDR))
+               op->dst = allspfrouters6;
+       else
+               op->dst = alldrouters6;
 
-               if ((oi->state == OSPF6_INTERFACE_POINTTOPOINT)
-                   || (oi->state == OSPF6_INTERFACE_DR)
-                   || (oi->state == OSPF6_INTERFACE_BDR))
-                       ospf6_send(oi->linklocal_addr, &allspfrouters6, oi, oh);
-               else
-                       ospf6_send(oi->linklocal_addr, &alldrouters6, oi, oh);
-       }
+       ospf6_packet_add(oi, op);
+       OSPF6_MESSAGE_WRITE_ON(oi);
 
        if (oi->lsack_list->count > 0)
                thread_add_event(master, ospf6_lsack_send_interface, oi, 0,
@@ -2495,7 +2747,6 @@ int ospf6_lsack_send_interface(struct thread *thread)
        return 0;
 }
 
-
 /* Commands */
 DEFUN(debug_ospf6_message, debug_ospf6_message_cmd,
       "debug ospf6 message <unknown|hello|dbdesc|lsreq|lsupdate|lsack|all> [<send|recv|send-hdr|recv-hdr>]",
index 7c108bd452ae7bc26a39191797e7ba60ba01dd4a..0cd10ef82519c34e837dbe3c7bc7429f0128f1a4 100644 (file)
@@ -63,6 +63,27 @@ extern unsigned char conf_debug_ospf6_message[];
 #define OSPF6_MESSAGE_TYPE_LSACK    0x5  /* Flooding acknowledgment */
 #define OSPF6_MESSAGE_TYPE_ALL      0x6  /* For debug option */
 
+struct ospf6_packet {
+       struct ospf6_packet *next;
+
+       /* Pointer to data stream. */
+       struct stream *s;
+
+       /* IP destination address. */
+       struct in6_addr dst;
+
+       /* OSPF6 packet length. */
+       uint16_t length;
+};
+
+/* OSPF packet queue structure. */
+struct ospf6_fifo {
+       unsigned long count;
+
+       struct ospf6_packet *head;
+       struct ospf6_packet *tail;
+};
+
 /* OSPFv3 packet header */
 #define OSPF6_HEADER_SIZE                     16U
 struct ospf6_header {
@@ -136,6 +157,10 @@ extern void ospf6_lsreq_print(struct ospf6_header *, int action);
 extern void ospf6_lsupdate_print(struct ospf6_header *, int action);
 extern void ospf6_lsack_print(struct ospf6_header *, int action);
 
+extern struct ospf6_fifo *ospf6_fifo_new(void);
+extern void ospf6_fifo_flush(struct ospf6_fifo *fifo);
+extern void ospf6_fifo_free(struct ospf6_fifo *fifo);
+
 extern int ospf6_iobuf_size(unsigned int size);
 extern void ospf6_message_terminate(void);
 extern int ospf6_receive(struct thread *thread);
index 9323da8be3ed94a7673469a654cc5ce083d98b21..8cf05183e15370cd78ce72723d9e3fb505f5589f 100644 (file)
@@ -145,6 +145,8 @@ void ospf6_neighbor_delete(struct ospf6_neighbor *on)
 
        THREAD_OFF(on->inactivity_timer);
 
+       THREAD_OFF(on->last_dbdesc_release_timer);
+
        THREAD_OFF(on->thread_send_dbdesc);
        THREAD_OFF(on->thread_send_lsreq);
        THREAD_OFF(on->thread_send_lsupdate);
@@ -350,6 +352,16 @@ int negotiation_done(struct thread *thread)
        return 0;
 }
 
+static int ospf6_neighbor_last_dbdesc_release(struct thread *thread)
+{
+       struct ospf6_neighbor *on = THREAD_ARG(thread);
+
+       assert(on);
+       memset(&on->dbdesc_last, 0, sizeof(struct ospf6_dbdesc));
+
+       return 0;
+}
+
 int exchange_done(struct thread *thread)
 {
        struct ospf6_neighbor *on;
@@ -366,10 +378,13 @@ int exchange_done(struct thread *thread)
        THREAD_OFF(on->thread_send_dbdesc);
        ospf6_lsdb_remove_all(on->dbdesc_list);
 
-       /* XXX
-         thread_add_timer (master, ospf6_neighbor_last_dbdesc_release, on,
-                           on->ospf6_if->dead_interval);
-       */
+       /* RFC 2328 (10.8): Release the last dbdesc after dead_interval */
+       if (!CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MSBIT)) {
+               THREAD_OFF(on->last_dbdesc_release_timer);
+               thread_add_timer(master, ospf6_neighbor_last_dbdesc_release, on,
+                                on->ospf6_if->dead_interval,
+                                &on->last_dbdesc_release_timer);
+       }
 
        if (on->request_list->count == 0)
                ospf6_neighbor_state_change(OSPF6_NEIGHBOR_FULL, on,
@@ -969,10 +984,9 @@ static void ospf6_neighbor_show_detail(struct vty *vty,
        }
 }
 
-static void ospf6_neighbor_show_detail_common(struct vty *vty, int argc,
-                                             struct cmd_token **argv,
-                                             struct ospf6 *ospf6, int idx_type,
-                                             int detail_idx, int json_idx)
+static void ospf6_neighbor_show_detail_common(struct vty *vty,
+                                             struct ospf6 *ospf6, bool uj,
+                                             bool detail, bool drchoice)
 {
        struct ospf6_neighbor *on;
        struct ospf6_interface *oi;
@@ -980,18 +994,15 @@ static void ospf6_neighbor_show_detail_common(struct vty *vty, int argc,
        struct listnode *i, *j, *k;
        json_object *json = NULL;
        json_object *json_array = NULL;
-       bool uj = use_json(argc, argv);
        void (*showfunc)(struct vty *, struct ospf6_neighbor *,
                         json_object *json, bool use_json);
 
-       showfunc = ospf6_neighbor_show;
-
-       if ((uj && argc == detail_idx) || (!uj && argc == json_idx)) {
-               if (!strncmp(argv[idx_type]->arg, "de", 2))
-                       showfunc = ospf6_neighbor_show_detail;
-               else if (!strncmp(argv[idx_type]->arg, "dr", 2))
-                       showfunc = ospf6_neighbor_show_drchoice;
-       }
+       if (detail)
+               showfunc = ospf6_neighbor_show_detail;
+       else if (drchoice)
+               showfunc = ospf6_neighbor_show_drchoice;
+       else
+               showfunc = ospf6_neighbor_show;
 
        if (uj) {
                json = json_object_new_object();
@@ -1036,28 +1047,28 @@ DEFUN(show_ipv6_ospf6_neighbor, show_ipv6_ospf6_neighbor_cmd,
       "Display details\n"
       "Display DR choices\n" JSON_STR)
 {
-       int idx_type = 4;
-       int detail_idx = 5;
-       int json_idx = 6;
        struct ospf6 *ospf6;
        struct listnode *node;
        const char *vrf_name = NULL;
        bool all_vrf = false;
        int idx_vrf = 0;
+       int idx_type = 4;
+       bool uj = use_json(argc, argv);
+       bool detail = false;
+       bool drchoice = false;
 
        OSPF6_CMD_CHECK_RUNNING();
        OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
-       if (idx_vrf > 0) {
-               idx_type += 2;
-               detail_idx += 2;
-               json_idx += 2;
-       }
+
+       if (argv_find(argv, argc, "detail", &idx_type))
+               detail = true;
+       else if (argv_find(argv, argc, "drchoice", &idx_type))
+               drchoice = true;
 
        for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) {
                if (all_vrf || strcmp(ospf6->name, vrf_name) == 0) {
-                       ospf6_neighbor_show_detail_common(vty, argc, argv,
-                                                         ospf6, idx_type,
-                                                         detail_idx, json_idx);
+                       ospf6_neighbor_show_detail_common(vty, ospf6, uj,
+                                                         detail, drchoice);
                        if (!all_vrf)
                                break;
                }
index 47f8c834e23dcca403da377d6478759f149e1574..729b1d2e85d2e9de7be35798d9c57d2d12a707ce 100644 (file)
@@ -47,6 +47,10 @@ struct ospf6_neighbor {
        uint32_t state_change;
        struct timeval last_changed;
 
+       /* last received hello */
+       struct timeval last_hello;
+       uint32_t hello_in;
+
        /* Neighbor Router ID */
        in_addr_t router_id;
 
@@ -89,6 +93,9 @@ struct ospf6_neighbor {
        /* Inactivity timer */
        struct thread *inactivity_timer;
 
+       /* Timer to release the last dbdesc packet */
+       struct thread *last_dbdesc_release_timer;
+
        /* Thread for sending message */
        struct thread *thread_send_dbdesc;
        struct thread *thread_send_lsreq;
index 76f98fecdd8e2deb4d520edd3ca6135cf4bbce10..5961cfe66adb74fc9693441c4977eec7817ac30d 100644 (file)
@@ -257,10 +257,13 @@ int ospf6_recvmsg(struct in6_addr *src, struct in6_addr *dst,
        rmsghdr.msg_control = (caddr_t)cmsgbuf;
        rmsghdr.msg_controllen = sizeof(cmsgbuf);
 
-       retval = recvmsg(ospf6_sock, &rmsghdr, 0);
-       if (retval < 0)
-               zlog_warn("recvmsg failed: %s", safe_strerror(errno));
-       else if (retval == iov_totallen(message))
+       retval = recvmsg(ospf6_sock, &rmsghdr, MSG_DONTWAIT);
+       if (retval < 0) {
+               if (errno != EAGAIN && errno != EWOULDBLOCK)
+                       zlog_warn("stream_recvmsg failed: %s",
+                                 safe_strerror(errno));
+               return retval;
+       } else if (retval == iov_totallen(message))
                zlog_warn("recvmsg read full buffer size: %d", retval);
 
        /* source address */
index 08d8be4445d5bf73805cfdb5b1ae522b2f023e23..3886a0d263261b6a45b3a2c44edb7c4caf8b257b 100644 (file)
@@ -36,4 +36,19 @@ extern int ospf6_recvmsg(struct in6_addr *src, struct in6_addr *dst,
                         ifindex_t *ifindex, struct iovec *message,
                         int ospf6_sock);
 
+#define OSPF6_MESSAGE_WRITE_ON(oi)                                             \
+       do {                                                                   \
+               bool list_was_empty =                                          \
+                       list_isempty(oi->area->ospf6->oi_write_q);             \
+               if ((oi)->on_write_q == 0) {                                   \
+                       listnode_add(oi->area->ospf6->oi_write_q, (oi));       \
+                       (oi)->on_write_q = 1;                                  \
+               }                                                              \
+               if (list_was_empty                                             \
+                   && !list_isempty(oi->area->ospf6->oi_write_q))             \
+                       thread_add_write(master, ospf6_write, oi->area->ospf6, \
+                                        oi->area->ospf6->fd,                  \
+                                        &oi->area->ospf6->t_write);           \
+       } while (0)
+
 #endif /* OSPF6_NETWORK_H */
diff --git a/ospf6d/ospf6_nssa.c b/ospf6d/ospf6_nssa.c
new file mode 100644 (file)
index 0000000..9f8cdf8
--- /dev/null
@@ -0,0 +1,1402 @@
+/*
+ * OSPFv3 Not So Stubby Area implementation.
+ *
+ * Copyright (C) 2021 Kaushik Nath
+ * Copyright (C) 2021 Soman K.S
+ *
+ * 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; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <zebra.h>
+#include "log.h"
+#include "prefix.h"
+#include "table.h"
+#include "vty.h"
+#include "linklist.h"
+#include "command.h"
+#include "thread.h"
+#include "plist.h"
+#include "filter.h"
+
+#include "ospf6_proto.h"
+#include "ospf6_route.h"
+#include "ospf6_lsa.h"
+#include "ospf6_route.h"
+#include "ospf6_lsdb.h"
+#include "ospf6_message.h"
+#include "ospf6_zebra.h"
+
+#include "ospf6_top.h"
+#include "ospf6_area.h"
+#include "ospf6_interface.h"
+#include "ospf6_neighbor.h"
+
+#include "ospf6_flood.h"
+#include "ospf6_intra.h"
+#include "ospf6_abr.h"
+#include "ospf6_asbr.h"
+#include "ospf6d.h"
+#include "ospf6_nssa.h"
+
+DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_LSA,         "OSPF6 LSA");
+unsigned char config_debug_ospf6_nssa = 0;
+/* Determine whether this router is elected translator or not for area */
+static int ospf6_abr_nssa_am_elected(struct ospf6_area *oa)
+{
+       struct ospf6_lsa *lsa;
+       struct ospf6_router_lsa *router_lsa;
+       in_addr_t *best = NULL;
+       uint16_t type;
+
+       type = htons(OSPF6_LSTYPE_ROUTER);
+
+       /* Verify all the router LSA to compare the router ID */
+       for (ALL_LSDB_TYPED(oa->lsdb, type, lsa)) {
+
+               router_lsa = (struct ospf6_router_lsa
+                                     *)((caddr_t)lsa->header
+                                        + sizeof(struct ospf6_lsa_header));
+
+               /* ignore non-ABR routers */
+               if (!CHECK_FLAG(router_lsa->bits, OSPF6_ROUTER_BIT_B))
+                       continue;
+
+               /* Router has Nt flag - always translate */
+               if (CHECK_FLAG(router_lsa->bits, OSPF6_ROUTER_BIT_NT)) {
+                       if (IS_OSPF6_DEBUG_NSSA)
+                               zlog_debug("%s: router %pI4 asserts Nt",
+                                          __func__, &lsa->header->id);
+                       return 1;
+               }
+
+               if (best == NULL)
+                       best = &lsa->header->adv_router;
+               else if (IPV4_ADDR_CMP(best, &lsa->header->adv_router) < 0)
+                       best = &lsa->header->adv_router;
+       }
+
+       if (best == NULL) {
+               if (IS_OSPF6_DEBUG_NSSA)
+                       zlog_debug("%s: best electable ABR not found",
+                                  __func__);
+               return 0;
+       }
+
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug("%s: best electable ABR is: %pI4", __func__, best);
+
+       if (IPV4_ADDR_CMP(best, &oa->ospf6->router_id) <= 0) {
+               if (IS_OSPF6_DEBUG_NSSA)
+                       zlog_debug("%s: elected ABR is: %pI4", __func__, best);
+               return 1;
+       } else {
+               if (IS_OSPF6_DEBUG_NSSA)
+                       zlog_debug("%s: not elected best %pI4, router ID %pI4",
+                                  __func__, best, &oa->ospf6->router_id);
+               return 0;
+       }
+}
+
+/* Flush the translated LSA when translation is disabled */
+static void ospf6_flush_translated_lsa(struct ospf6_area *area)
+{
+       uint16_t type;
+       struct ospf6_lsa *type7;
+       struct ospf6_lsa *type5;
+       struct ospf6 *ospf6 = area->ospf6;
+
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug("%s: start area %s", __func__, area->name);
+
+       type = htons(OSPF6_LSTYPE_TYPE_7);
+       for (ALL_LSDB_TYPED_ADVRTR(area->lsdb, type, ospf6->router_id, type7)) {
+               type5 = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL),
+                                         type7->external_lsa_id,
+                                         ospf6->router_id, ospf6->lsdb);
+               if (type5 && CHECK_FLAG(type5->flag, OSPF6_LSA_LOCAL_XLT))
+                       ospf6_lsa_premature_aging(type5);
+       }
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug("%s: finish area %s", __func__, area->name);
+}
+
+/* Check NSSA status for all nssa areas*/
+void ospf6_abr_nssa_check_status(struct ospf6 *ospf6)
+{
+       struct ospf6_area *area;
+       struct listnode *lnode, *nnode;
+
+       for (ALL_LIST_ELEMENTS(ospf6->area_list, lnode, nnode, area)) {
+               uint8_t old_state = area->NSSATranslatorState;
+
+               if (IS_OSPF6_DEBUG_NSSA)
+                       zlog_debug("%s: checking area %s flag %x", __func__,
+                                  area->name, area->flag);
+
+               if (!IS_AREA_NSSA(area))
+                       continue;
+
+               if (!CHECK_FLAG(area->ospf6->flag, OSPF6_FLAG_ABR)) {
+                       if (IS_OSPF6_DEBUG_NSSA)
+                               zlog_debug("%s: not ABR", __func__);
+                       area->NSSATranslatorState =
+                               OSPF6_NSSA_TRANSLATE_DISABLED;
+                       ospf6_flush_translated_lsa(area);
+               } else {
+                       /* Router is ABR */
+                       if (area->NSSATranslatorRole == OSPF6_NSSA_ROLE_ALWAYS)
+                               area->NSSATranslatorState =
+                                       OSPF6_NSSA_TRANSLATE_ENABLED;
+                       else {
+                               /* We are a candidate for Translation */
+                               if (ospf6_abr_nssa_am_elected(area) > 0) {
+                                       area->NSSATranslatorState =
+                                               OSPF6_NSSA_TRANSLATE_ENABLED;
+                                       if (IS_OSPF6_DEBUG_NSSA)
+                                               zlog_debug(
+                                                       "%s: elected translator",
+                                                       __func__);
+                               } else {
+                                       area->NSSATranslatorState =
+                                               OSPF6_NSSA_TRANSLATE_DISABLED;
+                                       ospf6_flush_translated_lsa(area);
+                                       if (IS_OSPF6_DEBUG_NSSA)
+                                               zlog_debug("%s: not elected",
+                                                          __func__);
+                               }
+                       }
+               }
+
+               /* RFC3101, 3.1:
+                * All NSSA border routers must set the E-bit in the Type-1
+                * router-LSAs of their directly attached non-stub areas, even
+                * when they are not translating.
+                */
+               if (old_state != area->NSSATranslatorState) {
+                       if (old_state == OSPF6_NSSA_TRANSLATE_DISABLED)
+                               ospf6_asbr_status_update(ospf6,
+                                                        ++ospf6->redist_count);
+                       else
+                               ospf6_asbr_status_update(ospf6,
+                                                        --ospf6->redist_count);
+               }
+       }
+}
+
+/* Mark the summary LSA's as unapproved, when ABR status changes.*/
+static void ospf6_abr_unapprove_summaries(struct ospf6 *ospf6)
+{
+       struct listnode *node, *nnode;
+       struct ospf6_area *area;
+       struct ospf6_lsa *lsa;
+       uint16_t type;
+
+       if (IS_OSPF6_DEBUG_ABR)
+               zlog_debug("%s : Start", __func__);
+
+       for (ALL_LIST_ELEMENTS(ospf6->area_list, node, nnode, area)) {
+               if (IS_OSPF6_DEBUG_ABR)
+                       zlog_debug("%s : considering area %pI4", __func__,
+                                  &area->area_id);
+               /* Inter area router LSA */
+               type = htons(OSPF6_LSTYPE_INTER_ROUTER);
+               for (ALL_LSDB_TYPED_ADVRTR(area->lsdb, type, ospf6->router_id,
+                                          lsa)) {
+                       if (IS_OSPF6_DEBUG_ABR)
+                               zlog_debug(
+                                       "%s : approved unset on summary link id %pI4",
+                                       __func__, &lsa->header->id);
+                       SET_FLAG(lsa->flag, OSPF6_LSA_UNAPPROVED);
+               }
+               /* Inter area prefix LSA */
+               type = htons(OSPF6_LSTYPE_INTER_PREFIX);
+               for (ALL_LSDB_TYPED_ADVRTR(area->lsdb, type, ospf6->router_id,
+                                          lsa)) {
+                       if (IS_OSPF6_DEBUG_ABR)
+                               zlog_debug(
+                                       "%s : approved unset on asbr-summary link id %pI4",
+                                       __func__, &lsa->header->id);
+                       SET_FLAG(lsa->flag, OSPF6_LSA_UNAPPROVED);
+               }
+       }
+
+       if (IS_OSPF6_DEBUG_ABR)
+               zlog_debug("%s : Stop", __func__);
+}
+
+/* Re-advertise inter-area router LSA's */
+void ospf6_asbr_prefix_readvertise(struct ospf6 *ospf6)
+{
+       struct ospf6_route *brouter;
+       struct listnode *node, *nnode;
+       struct ospf6_area *oa;
+
+       if (IS_OSPF6_DEBUG_ABR)
+               zlog_debug("Re-examining Inter-Router prefixes");
+
+
+       for (ALL_LIST_ELEMENTS(ospf6->area_list, node, nnode, oa)) {
+               for (brouter = ospf6_route_head(oa->ospf6->brouter_table);
+                    brouter; brouter = ospf6_route_next(brouter))
+                       ospf6_abr_originate_summary_to_area(brouter, oa);
+       }
+
+       if (IS_OSPF6_DEBUG_ABR)
+               zlog_debug("Finished re-examining Inter-Router prefixes");
+}
+
+/* Advertise prefixes configured using area <area-id> range command */
+static void ospf6_abr_announce_aggregates(struct ospf6 *ospf6)
+{
+       struct ospf6_area *area;
+       struct ospf6_route *range;
+       struct listnode *node, *nnode;
+
+       if (IS_OSPF6_DEBUG_ABR)
+               zlog_debug("ospf6_abr_announce_aggregates(): Start");
+
+       for (ALL_LIST_ELEMENTS(ospf6->area_list, node, nnode, area)) {
+               for (range = ospf6_route_head(area->range_table); range;
+                    range = ospf6_route_next(range))
+                       ospf6_abr_range_update(range, ospf6);
+       }
+
+       for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, area)) {
+               if (IS_OSPF6_DEBUG_ABR)
+                       zlog_debug(
+                               "ospf_abr_announce_aggregates(): looking at area %pI4",
+                               &area->area_id);
+       }
+
+       if (IS_OSPF6_DEBUG_ABR)
+               zlog_debug("ospf6_abr_announce_aggregates(): Stop");
+}
+
+/* Flush the summary LSA's which are not approved.*/
+void ospf6_abr_remove_unapproved_summaries(struct ospf6 *ospf6)
+{
+       struct listnode *node, *nnode;
+       struct ospf6_area *area;
+       struct ospf6_lsa *lsa;
+       uint16_t type;
+
+       if (IS_OSPF6_DEBUG_ABR)
+               zlog_debug("%s : Start", __func__);
+
+       for (ALL_LIST_ELEMENTS(ospf6->area_list, node, nnode, area)) {
+               if (IS_OSPF6_DEBUG_ABR)
+                       zlog_debug("%s : looking at area %pI4", __func__,
+                                  &area->area_id);
+
+               /* Inter area router LSA */
+               type = htons(OSPF6_LSTYPE_INTER_ROUTER);
+               for (ALL_LSDB_TYPED_ADVRTR(area->lsdb, type, ospf6->router_id,
+                                          lsa)) {
+                       if (CHECK_FLAG(lsa->flag, OSPF6_LSA_UNAPPROVED)) {
+                               lsa->header->age = htons(OSPF_LSA_MAXAGE);
+                               THREAD_OFF(lsa->refresh);
+                               thread_execute(master, ospf6_lsa_expire, lsa,
+                                              0);
+                       }
+               }
+
+               /* Inter area prefix LSA */
+               type = htons(OSPF6_LSTYPE_INTER_PREFIX);
+               for (ALL_LSDB_TYPED_ADVRTR(area->lsdb, type, ospf6->router_id,
+                                          lsa)) {
+                       if (CHECK_FLAG(lsa->flag, OSPF6_LSA_UNAPPROVED)) {
+                               lsa->header->age = htons(OSPF_LSA_MAXAGE);
+                               THREAD_OFF(lsa->refresh);
+                               thread_execute(master, ospf6_lsa_expire, lsa,
+                                              0);
+                       }
+               }
+       }
+
+       if (IS_OSPF6_DEBUG_ABR)
+               zlog_debug("%s : Stop", __func__);
+}
+
+/*
+ * This is the function taking care about ABR stuff, i.e.
+ * summary-LSA origination and flooding.
+ */
+static void ospf6_abr_task(struct ospf6 *ospf6)
+{
+       if (IS_OSPF6_DEBUG_ABR)
+               zlog_debug("%s : Start", __func__);
+
+       if (ospf6->route_table == NULL || ospf6->brouter_table == NULL) {
+               if (IS_OSPF6_DEBUG_ABR)
+                       zlog_debug("%s : Routing tables are not yet ready",
+                                  __func__);
+               return;
+       }
+
+       ospf6_abr_unapprove_summaries(ospf6);
+
+       if (IS_OSPF6_DEBUG_ABR)
+               zlog_debug("%s : prepare aggregates", __func__);
+
+       ospf6_abr_range_reset_cost(ospf6);
+
+       if (IS_OSPF6_ABR(ospf6)) {
+               if (IS_OSPF6_DEBUG_ABR)
+                       zlog_debug("%s : process network RT", __func__);
+               ospf6_abr_prefix_resummarize(ospf6);
+
+               if (IS_OSPF6_DEBUG_ABR)
+                       zlog_debug("%s : process router RT", __func__);
+               ospf6_asbr_prefix_readvertise(ospf6);
+
+               if (IS_OSPF6_DEBUG_ABR)
+                       zlog_debug("%s : announce aggregates", __func__);
+               ospf6_abr_announce_aggregates(ospf6);
+
+               if (IS_OSPF6_DEBUG_ABR)
+                       zlog_debug("%s : announce stub defaults", __func__);
+               ospf6_abr_defaults_to_stub(ospf6);
+       }
+
+       if (IS_OSPF6_DEBUG_ABR)
+               zlog_debug("%s : remove unapproved summaries", __func__);
+       ospf6_abr_remove_unapproved_summaries(ospf6);
+
+       if (IS_OSPF6_DEBUG_ABR)
+               zlog_debug("%s : Stop", __func__);
+}
+
+/* For NSSA Translations
+ * Mark the translated LSA's as unapproved. */
+static void ospf6_abr_unapprove_translates(struct ospf6 *ospf6)
+{
+       struct ospf6_lsa *lsa;
+       uint16_t type;
+       struct ospf6_area *oa;
+       struct listnode *node;
+
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug("ospf6_abr_unapprove_translates(): Start");
+
+       type = htons(OSPF6_LSTYPE_AS_EXTERNAL);
+       for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, oa)) {
+               for (ALL_LSDB_TYPED(oa->lsdb, type, lsa)) {
+                       if (CHECK_FLAG(lsa->flag, OSPF6_LSA_LOCAL_XLT)) {
+                               SET_FLAG(lsa->flag, OSPF6_LSA_UNAPPROVED);
+                               if (IS_OSPF6_DEBUG_NSSA)
+                                       zlog_debug(
+                                               "%s : approved unset on link id %pI4",
+                                               __func__, &lsa->header->id);
+                       }
+               }
+       }
+
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug("ospf6_abr_unapprove_translates(): Stop");
+}
+
+/* Generate the translated external lsa  from NSSA lsa */
+static struct ospf6_lsa *ospf6_lsa_translated_nssa_new(struct ospf6_area *area,
+                                                      struct ospf6_lsa *type7)
+{
+       char *buffer;
+       struct ospf6_lsa *lsa;
+       struct ospf6_as_external_lsa *ext, *extnew;
+       struct ospf6_lsa_header *lsa_header;
+       caddr_t old_ptr, new_ptr;
+       struct ospf6_as_external_lsa *nssa;
+       struct prefix prefix;
+       struct ospf6_route *match;
+       struct ospf6 *ospf6 = area->ospf6;
+       ptrdiff_t tag_offset = 0;
+       route_tag_t network_order;
+
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug("%s : Start", __func__);
+
+       if (area->NSSATranslatorState == OSPF6_NSSA_TRANSLATE_DISABLED) {
+               if (IS_OSPF6_DEBUG_NSSA)
+                       zlog_debug("%s: Translation disabled for area %s",
+                                  __func__, area->name);
+               return NULL;
+       }
+
+       buffer = XCALLOC(MTYPE_OSPF6_LSA, OSPF6_MAX_LSASIZE);
+       lsa_header = (struct ospf6_lsa_header *)buffer;
+       extnew = (struct ospf6_as_external_lsa
+                         *)((caddr_t)lsa_header
+                            + sizeof(struct ospf6_lsa_header));
+       ext = (struct ospf6_as_external_lsa
+                      *)((caddr_t)(type7->header)
+                         + sizeof(struct ospf6_lsa_header));
+       old_ptr =
+               (caddr_t)((caddr_t)ext + sizeof(struct ospf6_as_external_lsa));
+       new_ptr = (caddr_t)((caddr_t)extnew
+                           + sizeof(struct ospf6_as_external_lsa));
+
+       memcpy(extnew, ext, sizeof(struct ospf6_as_external_lsa));
+
+       /* find the translated Type-5 for this Type-7 */
+       nssa = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END(
+               type7->header);
+
+       prefix.family = AF_INET6;
+       prefix.prefixlen = nssa->prefix.prefix_length;
+       ospf6_prefix_in6_addr(&prefix.u.prefix6, nssa, &nssa->prefix);
+
+       /* Find the LSA from the external route */
+       match = ospf6_route_lookup(&prefix, area->route_table);
+       if (match == NULL) {
+               if (IS_OSPF6_DEBUG_NSSA)
+                       zlog_debug("%s : no matching route %pFX", __func__,
+                                  &prefix);
+               return NULL;
+       }
+
+       /* set Prefix */
+       memcpy(new_ptr, old_ptr, OSPF6_PREFIX_SPACE(ext->prefix.prefix_length));
+       ospf6_prefix_apply_mask(&extnew->prefix);
+       new_ptr += OSPF6_PREFIX_SPACE(extnew->prefix.prefix_length);
+
+       tag_offset =
+               sizeof(*ext) + OSPF6_PREFIX_SPACE(ext->prefix.prefix_length);
+
+       /* Forwarding address */
+       if (CHECK_FLAG(ext->bits_metric, OSPF6_ASBR_BIT_F)) {
+               memcpy(new_ptr, (caddr_t)ext + tag_offset,
+                      sizeof(struct in6_addr));
+               new_ptr += sizeof(struct in6_addr);
+               tag_offset += sizeof(struct in6_addr);
+       }
+       /* External Route Tag */
+       if (CHECK_FLAG(ext->bits_metric, OSPF6_ASBR_BIT_T)) {
+               memcpy(&network_order, (caddr_t)ext + tag_offset,
+                      sizeof(network_order));
+               network_order = htonl(network_order);
+               memcpy(new_ptr, &network_order, sizeof(network_order));
+               new_ptr += sizeof(network_order);
+       }
+
+       /* Fill LSA Header */
+       lsa_header->age = 0;
+       lsa_header->type = htons(OSPF6_LSTYPE_AS_EXTERNAL);
+       lsa_header->id = htonl(ospf6->external_id);
+       ospf6->external_id++;
+       lsa_header->adv_router = ospf6->router_id;
+       lsa_header->seqnum =
+               ospf6_new_ls_seqnum(lsa_header->type, lsa_header->id,
+                                   lsa_header->adv_router, ospf6->lsdb);
+       lsa_header->length = htons((caddr_t)new_ptr - (caddr_t)lsa_header);
+       type7->external_lsa_id = lsa_header->id;
+
+       /* LSA checksum */
+       ospf6_lsa_checksum(lsa_header);
+
+       /* create LSA */
+       lsa = ospf6_lsa_create(lsa_header);
+
+       SET_FLAG(lsa->flag, OSPF6_LSA_LOCAL_XLT);
+       UNSET_FLAG(lsa->flag, OSPF6_LSA_UNAPPROVED);
+
+       /* Originate */
+       ospf6_lsa_originate_process(lsa, ospf6);
+
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug("%s: Originated type5 LSA id %pI4", __func__,
+                          &lsa_header->id);
+       return lsa;
+}
+
+/* Delete LSA from retransmission list */
+static void ospf6_ls_retransmit_delete_nbr_as(struct ospf6 *ospf6,
+                                             struct ospf6_lsa *lsa)
+{
+       struct listnode *node, *nnode;
+       struct ospf6_area *area;
+
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug("%s : start lsa %s", __func__, lsa->name);
+
+       /*The function ospf6_flood_clear_area removes LSA from
+        * retransmit list.
+        */
+       for (ALL_LIST_ELEMENTS(ospf6->area_list, node, nnode, area))
+               ospf6_flood_clear_area(lsa, area);
+
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug("%s : finish  lsa %s", __func__, lsa->name);
+}
+
+/* Refresh translated  AS-external-LSA. */
+struct ospf6_lsa *ospf6_translated_nssa_refresh(struct ospf6_area *area,
+                                               struct ospf6_lsa *type7,
+                                               struct ospf6_lsa *type5)
+{
+       struct ospf6_lsa *new = NULL;
+       struct ospf6_as_external_lsa *ext_lsa;
+       struct prefix prefix;
+       struct ospf6 *ospf6 = area->ospf6;
+
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug("%s : start area %s", __func__, area->name);
+
+       /* Sanity checks. */
+       assert(type7);
+
+       /* Find the AS external LSA */
+       if (type5 == NULL) {
+               if (IS_OSPF6_DEBUG_NSSA)
+                       zlog_debug(
+                               "%s: No translated Type-5 found for Type-7 with Id %pI4",
+                               __func__, &type7->header->id);
+
+               /* find the translated Type-5 for this Type-7 */
+               ext_lsa = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END(
+                       type7->header);
+
+               prefix.family = AF_INET6;
+               prefix.prefixlen = ext_lsa->prefix.prefix_length;
+               ospf6_prefix_in6_addr(&prefix.u.prefix6, ext_lsa,
+                                     &ext_lsa->prefix);
+
+               /* Find the AS external LSA from Type-7 LSA */
+               if (IS_OSPF6_DEBUG_NSSA)
+                       zlog_debug("%s: try to find external LSA id %d",
+                                  __func__, type7->external_lsa_id);
+               type5 = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL),
+                                         type7->external_lsa_id,
+                                         ospf6->router_id, ospf6->lsdb);
+       }
+
+       if (type5) {
+               if (CHECK_FLAG(type5->flag, OSPF6_LSA_LOCAL_XLT)) {
+                       /* Delete LSA from neighbor retransmit-list. */
+                       ospf6_ls_retransmit_delete_nbr_as(ospf6, type5);
+
+                       /* Flush the LSA */
+                       ospf6_lsa_premature_aging(type5);
+               } else {
+                       if (IS_OSPF6_DEBUG_NSSA)
+                               zlog_debug("%s: Invalid translated LSA %s",
+                                          __func__, type5->name);
+                       return NULL;
+               }
+       }
+
+       /* create new translated LSA */
+       if (ospf6_lsa_age_current(type7) != OSPF_LSA_MAXAGE) {
+               if ((new = ospf6_lsa_translated_nssa_new(area, type7))
+                   == NULL) {
+                       if (IS_OSPF6_DEBUG_NSSA)
+                               zlog_debug(
+                                       "%s: Could not translate Type-7 for %pI4",
+                                       __func__, &type7->header->id);
+                       return NULL;
+               }
+       }
+
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug("%s: finish", __func__);
+
+       return new;
+}
+
+/* Originate Translated Type-5 for supplied Type-7 NSSA LSA */
+struct ospf6_lsa *ospf6_translated_nssa_originate(struct ospf6_area *oa,
+                                                 struct ospf6_lsa *type7)
+{
+       struct ospf6_lsa *new;
+
+       if (ntohs(type7->header->type) != OSPF6_LSTYPE_TYPE_7)
+               return NULL;
+
+       if ((new = ospf6_lsa_translated_nssa_new(oa, type7)) == NULL) {
+               if (IS_OSPF6_DEBUG_NSSA)
+                       zlog_debug(
+                               "%s : Could not translate Type-7, Id %pI4, to Type-5",
+                               __func__, &type7->header->id);
+               return NULL;
+       }
+
+       return new;
+}
+
+int ospf6_abr_translate_nssa(struct ospf6_area *area, struct ospf6_lsa *lsa)
+{
+       /* Incoming Type-7 or later aggregated Type-7
+        *
+        * LSA is skipped if P-bit is off.
+        * LSA is aggregated if within range.
+        *
+        * The Type-7 is translated, Installed/Approved as a Type-5 into
+        * global LSDB, then Flooded through AS
+        *
+        *  Later, any Unapproved Translated Type-5's are flushed/discarded
+        */
+
+       struct ospf6_lsa *old = NULL, *new = NULL;
+       struct ospf6_as_external_lsa *nssa_lsa;
+       struct prefix prefix;
+       struct ospf6_route *match;
+       struct ospf6 *ospf6;
+
+       ospf6 = area->ospf6;
+       nssa_lsa = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END(
+               lsa->header);
+
+       if (!CHECK_FLAG(nssa_lsa->prefix.prefix_options,
+                       OSPF6_PREFIX_OPTION_P)) {
+               if (IS_OSPF6_DEBUG_NSSA)
+                       zlog_debug(
+                               "%s : LSA Id %pI4, P-bit off, NO Translation",
+                               __func__, &lsa->header->id);
+               return 1;
+       }
+
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug(
+                       "%s : LSA Id %pI4 external ID %pI4, Translating type 7 to 5",
+                       __func__, &lsa->header->id, &lsa->external_lsa_id);
+
+       prefix.family = AF_INET6;
+       prefix.prefixlen = nssa_lsa->prefix.prefix_length;
+       ospf6_prefix_in6_addr(&prefix.u.prefix6, nssa_lsa, &nssa_lsa->prefix);
+
+       if (!CHECK_FLAG(nssa_lsa->bits_metric, OSPF6_ASBR_BIT_F)) {
+               if (IS_OSPF6_DEBUG_NSSA)
+                       zlog_debug(
+                               "%s : LSA Id %pI4, Forward address is 0, NO Translation",
+                               __func__, &lsa->header->id);
+               return 1;
+       }
+
+       /* Find the existing AS-External LSA for this prefix */
+       match = ospf6_route_lookup(&prefix, ospf6->external_table);
+       if (match) {
+               old = ospf6_lsdb_lookup(OSPF6_LSTYPE_AS_EXTERNAL,
+                                       match->path.origin.id, ospf6->router_id,
+                                       ospf6->lsdb);
+       }
+
+       /* Check Type 5 LSA using the matching external ID */
+       if (old == NULL) {
+               old = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL),
+                                       lsa->external_lsa_id, ospf6->router_id,
+                                       ospf6->lsdb);
+       }
+
+       if (old) {
+               /* Do not continue if type 5 LSA not approved */
+               if (CHECK_FLAG(old->flag, OSPF6_LSA_UNAPPROVED)) {
+                       if (IS_OSPF6_DEBUG_NSSA)
+                               zlog_debug(
+                                       "%s : LSA Id %pI4 type 5 is not approved",
+                                       __func__, &old->header->id);
+                       return 1;
+               }
+
+               if (IS_OSPF6_DEBUG_NSSA)
+                       zlog_debug(
+                               "%s : found old translated LSA Id %pI4, refreshing",
+                               __func__, &old->header->id);
+
+               /* refresh */
+               new = ospf6_translated_nssa_refresh(area, lsa, old);
+               if (!new) {
+                       if (IS_OSPF6_DEBUG_NSSA)
+                               zlog_debug(
+                                       "%s : could not refresh translated LSA Id %pI4",
+                                       __func__, &old->header->id);
+               }
+       } else {
+               /* no existing external route for this LSA Id
+                * originate translated LSA
+                */
+
+               if (ospf6_translated_nssa_originate(area, lsa) == NULL) {
+                       if (IS_OSPF6_DEBUG_NSSA)
+                               zlog_debug(
+                                       "%s : Could not translate Type-7 for %pI4 to Type-5",
+                                       __func__, &lsa->header->id);
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
+static void ospf6_abr_process_nssa_translates(struct ospf6 *ospf6)
+{
+       /* Scan through all NSSA_LSDB records for all areas;
+        * If P-bit is on, translate all Type-7's to 5's and aggregate or\
+        * flood install as approved in Type-5 LSDB with XLATE Flag on
+        * later, do same for all aggregates...  At end, DISCARD all
+        * remaining UNAPPROVED Type-5's (Aggregate is for future ) */
+
+       struct listnode *node;
+       struct ospf6_area *oa;
+       struct ospf6_lsa *lsa;
+       int type;
+
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug("%s : Start", __func__);
+
+       for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, oa)) {
+
+               /* skip if not translator */
+               if (oa->NSSATranslatorState == OSPF6_NSSA_TRANSLATE_DISABLED) {
+                       zlog_debug("%s area %pI4 NSSATranslatorState %d",
+                                  __func__, &oa->area_id,
+                                  oa->NSSATranslatorState);
+                       continue;
+               }
+
+               /* skip if not Nssa Area */
+               if (!IS_AREA_NSSA(oa)) {
+                       zlog_debug("%s area %pI4 Flag %x", __func__,
+                                  &oa->area_id, oa->flag);
+                       continue;
+               }
+
+               if (IS_OSPF6_DEBUG_NSSA)
+                       zlog_debug("%s : looking at area %pI4", __func__,
+                                  &oa->area_id);
+
+               type = htons(OSPF6_LSTYPE_TYPE_7);
+               for (ALL_LSDB_TYPED(oa->lsdb, type, lsa)) {
+                       zlog_debug("%s : lsa %s , id %pI4 , adv router %pI4",
+                                  lsa->name, __func__, &lsa->header->id,
+                                  &lsa->header->adv_router);
+                       ospf6_abr_translate_nssa(oa, lsa);
+               }
+       }
+
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug("%s : Stop", __func__);
+}
+
+/* Generate translated type-5 LSA from the configured area ranges*/
+static void ospf6_abr_translate_nssa_range(struct ospf6 *ospf6)
+{
+       struct listnode *node, *nnode;
+       struct ospf6_area *oa;
+       struct ospf6_route *range;
+       struct ospf6_lsa *lsa;
+
+       for (ALL_LIST_ELEMENTS(ospf6->area_list, node, nnode, oa)) {
+               for (range = ospf6_route_head(oa->range_table); range;
+                    range = ospf6_route_next(range)) {
+                       if (IS_OSPF6_DEBUG_NSSA)
+                               zlog_debug(
+                                       "Translating range %pFX of area %pI4",
+                                       &range->prefix, &oa->area_id);
+                       if (CHECK_FLAG(range->flag,
+                                      OSPF6_ROUTE_DO_NOT_ADVERTISE))
+                               continue;
+
+                       /* Find the NSSA LSA from the route */
+                       /* Generate and flood external LSA */
+                       lsa = ospf6_lsdb_lookup(OSPF6_LSTYPE_TYPE_7,
+                                               range->path.origin.id,
+                                               ospf6->router_id, oa->lsdb);
+                       if (lsa)
+                               ospf6_abr_translate_nssa(oa, lsa);
+               }
+       }
+}
+
+static void ospf6_abr_send_nssa_aggregates(struct ospf6 *ospf6)
+{
+       struct listnode *node;
+       struct ospf6_area *area;
+
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug("%s : Start", __func__);
+
+       for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, area)) {
+               if (area->NSSATranslatorState == OSPF6_NSSA_TRANSLATE_DISABLED)
+                       continue;
+
+               if (IS_OSPF6_DEBUG_NSSA)
+                       zlog_debug("%s : looking at area %pI4", __func__,
+                                  &area->area_id);
+
+               ospf6_abr_translate_nssa_range(ospf6);
+       }
+
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug("%s : Stop", __func__);
+}
+
+/*Flood max age LSA's for the unapproved LSA's */
+static int ospf6_abr_remove_unapproved_translates_apply(struct ospf6_lsa *lsa)
+{
+       if (CHECK_FLAG(lsa->flag, OSPF6_LSA_LOCAL_XLT)
+           && CHECK_FLAG(lsa->flag, OSPF6_LSA_UNAPPROVED)) {
+               zlog_debug("%s : removing unapproved translates, lsa : %s",
+                          __func__, lsa->name);
+
+               /* FLUSH THROUGHOUT AS */
+               ospf6_lsa_premature_aging(lsa);
+       }
+       return 0;
+}
+
+static void ospf6_abr_remove_unapproved_translates(struct ospf6 *ospf6)
+{
+       struct ospf6_lsa *lsa;
+       uint16_t type;
+
+       /* All AREA PROCESS should have APPROVED necessary LSAs */
+       /* Remove any left over and not APPROVED */
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug("ospf6_abr_remove_unapproved_translates(): Start");
+
+       type = htons(OSPF6_LSTYPE_AS_EXTERNAL);
+       for (ALL_LSDB_TYPED(ospf6->lsdb, type, lsa))
+               ospf6_abr_remove_unapproved_translates_apply(lsa);
+
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug("ospf_abr_remove_unapproved_translates(): Stop");
+}
+
+static void ospf6_abr_nssa_task(struct ospf6 *ospf6)
+{
+       /* called only if any_nssa */
+       struct ospf6_route *range;
+       struct ospf6_area *area;
+       struct listnode *node, *nnode;
+
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug("Check for NSSA-ABR Tasks():");
+
+       if (!IS_OSPF6_ABR(ospf6)) {
+               if (IS_OSPF6_DEBUG_NSSA)
+                       zlog_debug("%s  Not ABR", __func__);
+               return;
+       }
+
+       if (!ospf6->anyNSSA) {
+               if (IS_OSPF6_DEBUG_NSSA)
+                       zlog_debug("%s  Not NSSA", __func__);
+               return;
+       }
+
+       /* Each area must confirm TranslatorRole */
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug("ospf6_abr_nssa_task(): Start");
+
+       /* For all Global Entries flagged "local-translate", unset APPROVED */
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug("ospf6_abr_nssa_task(): unapprove translates");
+
+       ospf6_abr_unapprove_translates(ospf6);
+
+       /* RESET all Ranges in every Area, same as summaries */
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug("ospf6_abr_nssa_task(): NSSA initialize aggregates");
+       ospf6_abr_range_reset_cost(ospf6);
+
+       /* For all NSSAs, Type-7s, translate to 5's, INSTALL/FLOOD, or
+        *  Aggregate as Type-7
+        * Install or Approve in Type-5 Global LSDB
+        */
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug("ospf6_abr_nssa_task(): process translates");
+       ospf6_abr_process_nssa_translates(ospf6);
+
+       /* Translate/Send any "ranged" aggregates, and also 5-Install and
+        *  Approve
+        * Scan Type-7's for aggregates, translate to Type-5's,
+        *  Install/Flood/Approve
+        */
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug("ospf6_abr_nssa_task(): send NSSA aggregates");
+       ospf6_abr_send_nssa_aggregates(ospf6); /*TURNED OFF FOR NOW */
+
+       /* Flush any unapproved previous translates from Global Data Base */
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug(
+                       "ospf6_abr_nssa_task(): remove unapproved translates");
+       ospf6_abr_remove_unapproved_translates(ospf6);
+
+       for (ALL_LIST_ELEMENTS(ospf6->area_list, node, nnode, area)) {
+               for (range = ospf6_route_head(area->range_table); range;
+                    range = ospf6_route_next(range)) {
+                       if (CHECK_FLAG(range->flag,
+                                      OSPF6_ROUTE_DO_NOT_ADVERTISE))
+                               ospf6_zebra_delete_discard(range, ospf6);
+                       else
+                               ospf6_zebra_add_discard(range, ospf6);
+               }
+       }
+
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug("ospf6_abr_nssa_task(): Stop");
+}
+
+int ospf6_redistribute_check(struct ospf6 *ospf6, struct ospf6_route *route,
+                            int type)
+{
+       route_map_result_t ret;
+       struct prefix *prefix;
+       struct ospf6_redist *red;
+
+       if (!ospf6_zebra_is_redistribute(type, ospf6->vrf_id))
+               return 0;
+
+       prefix = &route->prefix;
+
+       red = ospf6_redist_lookup(ospf6, type, 0);
+       if (!red)
+               return 0;
+
+       /* Change to new redist structure */
+       if (ROUTEMAP_NAME(red)) {
+               if (ROUTEMAP(red) == NULL)
+                       ospf6_asbr_routemap_update(NULL);
+               if (ROUTEMAP(red) == NULL) {
+                       zlog_warn(
+                               "route-map \"%s\" not found, suppress redistributing",
+                               ROUTEMAP_NAME(red));
+                       return 0;
+               }
+       }
+
+       /*  Change to new redist structure */
+       if (ROUTEMAP(red)) {
+               ret = route_map_apply(ROUTEMAP(red), prefix, route);
+               if (ret == RMAP_DENYMATCH) {
+                       if (IS_OSPF6_DEBUG_ASBR)
+                               zlog_debug("Denied by route-map \"%s\"",
+                                          ROUTEMAP_NAME(red));
+                       return 0;
+               }
+       }
+
+       return 1;
+}
+
+static void ospf6_external_lsa_refresh_type(struct ospf6 *ospf6, uint8_t type,
+                                           unsigned short instance, int force)
+{
+       struct ospf6_route *route;
+       struct ospf6_external_info *info;
+       struct ospf6_lsa *lsa;
+
+       if (type == ZEBRA_ROUTE_MAX)
+               return;
+
+       for (route = ospf6_route_head(ospf6->external_table); route;
+            route = ospf6_route_next(route)) {
+               info = route->route_option;
+
+               /* Find the external LSA in the database */
+               if (!is_default_prefix(&route->prefix)) {
+                       lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL),
+                                               htonl(info->id),
+                                               ospf6->router_id, ospf6->lsdb);
+
+                       if (lsa) {
+                               THREAD_OFF(lsa->refresh);
+
+                               /* LSA is maxage,  immediate refresh */
+                               if (OSPF6_LSA_IS_MAXAGE(lsa))
+                                       ospf6_flood(NULL, lsa);
+                               else
+                                       thread_add_timer(master,
+                                                        ospf6_lsa_refresh, lsa,
+                                                        OSPF_LS_REFRESH_TIME,
+                                                        &lsa->refresh);
+                       } else {
+                               /* LSA not found in the database
+                                * Verify and originate  external LSA
+                                */
+                               if (ospf6_redistribute_check(ospf6, route,
+                                                            type))
+                                       ospf6_as_external_lsa_originate(route,
+                                                                       ospf6);
+                       }
+               }
+       }
+}
+
+/* Refresh default route */
+static void ospf6_external_lsa_refresh_default(struct ospf6 *ospf6)
+{
+       struct ospf6_route *route;
+       struct ospf6_external_info *info;
+       struct ospf6_lsa *lsa;
+
+       for (route = ospf6_route_head(ospf6->external_table); route;
+            route = ospf6_route_next(route)) {
+               if (is_default_prefix(&route->prefix)) {
+                       info = route->route_option;
+                       lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL),
+                                               htonl(info->id),
+                                               ospf6->router_id, ospf6->lsdb);
+
+                       if (lsa) {
+                               if (IS_OSPF6_DEBUG_NSSA)
+                                       zlog_debug(
+                                               "LSA[Type5:0.0.0.0]: Refresh AS-external-LSA %p",
+                                               (void *)lsa);
+                               if (OSPF6_LSA_IS_MAXAGE(lsa))
+                                       ospf6_flood(NULL, lsa);
+                               else
+                                       thread_add_timer(master,
+                                                        ospf6_lsa_refresh, lsa,
+                                                        OSPF_LS_REFRESH_TIME,
+                                                        &lsa->refresh);
+                       } else if (!lsa) {
+                               if (IS_OSPF6_DEBUG_NSSA)
+                                       zlog_debug(
+                                               "LSA[Type5:0.0.0.0]: Originate AS-external-LSA");
+                               ospf6_as_external_lsa_originate(route, ospf6);
+                       }
+               }
+       }
+}
+
+/* If there's redistribution configured, we need to refresh external
+ * LSAs in order to install Type-7 and flood to all NSSA Areas
+ */
+void ospf6_asbr_nssa_redist_task(struct ospf6 *ospf6)
+{
+       int type;
+       struct ospf6_redist *red;
+
+       for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
+               red = ospf6_redist_lookup(ospf6, type, 0);
+               if (!red)
+                       return;
+
+               ospf6_external_lsa_refresh_type(ospf6, type, red->instance,
+                                               LSA_REFRESH_IF_CHANGED);
+       }
+       ospf6_external_lsa_refresh_default(ospf6);
+}
+
+/* This function performs ABR related processing */
+static int ospf6_abr_task_timer(struct thread *thread)
+{
+       struct ospf6 *ospf6 = THREAD_ARG(thread);
+
+       ospf6->t_abr_task = NULL;
+
+       if (IS_OSPF6_DEBUG_ABR)
+               zlog_debug("Running ABR task on timer");
+
+       (void)ospf6_check_and_set_router_abr(ospf6);
+       ospf6_abr_nssa_check_status(ospf6);
+       ospf6_abr_task(ospf6);
+       /* if nssa-abr, then scan Type-7 LSDB */
+       ospf6_abr_nssa_task(ospf6);
+       ospf6_asbr_nssa_redist_task(ospf6);
+
+       return 0;
+}
+
+void ospf6_schedule_abr_task(struct ospf6 *ospf6)
+{
+       if (ospf6->t_abr_task) {
+               if (IS_OSPF6_DEBUG_ABR)
+                       zlog_debug("ABR task already scheduled");
+               return;
+       }
+
+       if (IS_OSPF6_DEBUG_ABR)
+               zlog_debug("Scheduling ABR task");
+
+       thread_add_timer(master, ospf6_abr_task_timer, ospf6,
+                        OSPF6_ABR_TASK_DELAY, &ospf6->t_abr_task);
+}
+
+/* Flush the NSSA LSAs from the area */
+static void ospf6_nssa_flush_area(struct ospf6_area *area)
+{
+       uint16_t type;
+       struct ospf6_lsa *lsa = NULL, *type5 = NULL;
+       struct ospf6 *ospf6 = area->ospf6;
+       const struct route_node *rt = NULL;
+
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug("%s: area %s", __func__, area->name);
+
+       /* Flush the NSSA LSA */
+       type = htons(OSPF6_LSTYPE_TYPE_7);
+       rt = ospf6_lsdb_head(area->lsdb_self, 0, type, ospf6->router_id, &lsa);
+       while (lsa) {
+               lsa->header->age = htons(OSPF_LSA_MAXAGE);
+               SET_FLAG(lsa->flag, OSPF6_LSA_FLUSH);
+               ospf6_flood(NULL, lsa);
+               /* Flush the translated LSA */
+               if (ospf6_check_and_set_router_abr(ospf6)) {
+                       type = htons(OSPF6_LSTYPE_AS_EXTERNAL);
+                       type5 = ospf6_lsdb_lookup(
+                               htons(type), lsa->external_lsa_id,
+                               ospf6->router_id, ospf6->lsdb);
+                       if (type5
+                           && CHECK_FLAG(type5->flag, OSPF6_LSA_LOCAL_XLT)) {
+                               type5->header->age = htons(OSPF_LSA_MAXAGE);
+                               SET_FLAG(type5->flag, OSPF6_LSA_FLUSH);
+                               ospf6_flood(NULL, type5);
+                       }
+               }
+               lsa = ospf6_lsdb_next(rt, lsa);
+       }
+}
+
+static void ospf6_area_nssa_update(struct ospf6_area *area)
+{
+       struct ospf6_route *route;
+
+       if (IS_AREA_NSSA(area)) {
+               if (!ospf6_check_and_set_router_abr(area->ospf6))
+                       OSPF6_OPT_CLEAR(area->options, OSPF6_OPT_E);
+               area->ospf6->anyNSSA++;
+               OSPF6_OPT_SET(area->options, OSPF6_OPT_N);
+               area->NSSATranslatorRole = OSPF6_NSSA_ROLE_CANDIDATE;
+       } else if (IS_AREA_ENABLED(area)) {
+               if (IS_OSPF6_DEBUG_ORIGINATE(ROUTER))
+                       zlog_debug("Normal area for if %s", area->name);
+               OSPF6_OPT_CLEAR(area->options, OSPF6_OPT_N);
+               if (ospf6_check_and_set_router_abr(area->ospf6))
+                       OSPF6_OPT_SET(area->options, OSPF6_OPT_E);
+               area->ospf6->anyNSSA--;
+               area->NSSATranslatorState = OSPF6_NSSA_TRANSLATE_DISABLED;
+       }
+
+       /* Refresh router LSA */
+       if (IS_AREA_NSSA(area)) {
+               OSPF6_ROUTER_LSA_SCHEDULE(area);
+
+               /* Check if router is ABR */
+               if (ospf6_check_and_set_router_abr(area->ospf6)) {
+                       if (IS_OSPF6_DEBUG_NSSA)
+                               zlog_debug("Router is ABR area %s", area->name);
+                       ospf6_schedule_abr_task(area->ospf6);
+               } else {
+                       /* Router is not ABR */
+                       if (IS_OSPF6_DEBUG_NSSA)
+                               zlog_debug("NSSA area %s", area->name);
+
+                       /* Originate NSSA LSA */
+                       for (route = ospf6_route_head(
+                                    area->ospf6->external_table);
+                            route; route = ospf6_route_next(route))
+                               ospf6_nssa_lsa_originate(route, area);
+               }
+       } else {
+               /* Disable NSSA */
+               if (IS_OSPF6_DEBUG_NSSA)
+                       zlog_debug("Normal area %s", area->name);
+               ospf6_nssa_flush_area(area);
+               ospf6_area_disable(area);
+               ospf6_area_delete(area);
+       }
+}
+
+int ospf6_area_nssa_set(struct ospf6 *ospf6, struct ospf6_area *area)
+{
+
+       if (!IS_AREA_NSSA(area)) {
+               SET_FLAG(area->flag, OSPF6_AREA_NSSA);
+               if (IS_OSPF6_DEBUG_NSSA)
+                       zlog_debug("area %s nssa set", area->name);
+               ospf6_area_nssa_update(area);
+       }
+
+       return 1;
+}
+
+int ospf6_area_nssa_unset(struct ospf6 *ospf6, struct ospf6_area *area)
+{
+       if (IS_AREA_NSSA(area)) {
+               UNSET_FLAG(area->flag, OSPF6_AREA_NSSA);
+               if (IS_OSPF6_DEBUG_NSSA)
+                       zlog_debug("area %s nssa reset", area->name);
+               ospf6_area_nssa_update(area);
+       }
+
+       return 1;
+}
+
+/* Find the NSSA forwarding address */
+static struct in6_addr *ospf6_get_nssa_fwd_addr(struct ospf6_area *oa)
+{
+       struct listnode *node, *nnode;
+       struct ospf6_interface *oi;
+
+       for (ALL_LIST_ELEMENTS(oa->if_list, node, nnode, oi)) {
+               if (if_is_operative(oi->interface))
+                       if (oi->area && IS_AREA_NSSA(oi->area))
+                               return ospf6_interface_get_global_address(
+                                       oi->interface);
+       }
+       return NULL;
+}
+
+void ospf6_nssa_lsa_originate(struct ospf6_route *route,
+                             struct ospf6_area *area)
+{
+       char buffer[OSPF6_MAX_LSASIZE];
+       struct ospf6_lsa_header *lsa_header;
+       struct ospf6_lsa *lsa;
+       struct ospf6_external_info *info = route->route_option;
+       struct in6_addr *fwd_addr;
+
+       struct ospf6_as_external_lsa *as_external_lsa;
+       char buf[PREFIX2STR_BUFFER];
+       caddr_t p;
+
+       if (IS_OSPF6_DEBUG_ASBR || IS_OSPF6_DEBUG_ORIGINATE(AS_EXTERNAL)) {
+               prefix2str(&route->prefix, buf, sizeof(buf));
+               zlog_debug("Originate AS-External-LSA for %s", buf);
+       }
+
+       /* prepare buffer */
+       memset(buffer, 0, sizeof(buffer));
+       lsa_header = (struct ospf6_lsa_header *)buffer;
+       as_external_lsa = (struct ospf6_as_external_lsa
+                                  *)((caddr_t)lsa_header
+                                     + sizeof(struct ospf6_lsa_header));
+       p = (caddr_t)((caddr_t)as_external_lsa
+                     + sizeof(struct ospf6_as_external_lsa));
+
+       /* Fill AS-External-LSA */
+       /* Metric type */
+       if (route->path.metric_type == OSPF6_PATH_TYPE_EXTERNAL2)
+               SET_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_E);
+       else
+               UNSET_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_E);
+
+       /* external route tag */
+       if (info->tag)
+               SET_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_T);
+       else
+               UNSET_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_T);
+
+       /* Set metric */
+       OSPF6_ASBR_METRIC_SET(as_external_lsa, route->path.cost);
+
+       /* prefixlen */
+       as_external_lsa->prefix.prefix_length = route->prefix.prefixlen;
+
+       /* PrefixOptions */
+       as_external_lsa->prefix.prefix_options = route->path.prefix_options;
+
+       /* Set the P bit */
+       as_external_lsa->prefix.prefix_options |= OSPF6_PREFIX_OPTION_P;
+
+       /* don't use refer LS-type */
+       as_external_lsa->prefix.prefix_refer_lstype = htons(0);
+
+       /* set Prefix */
+       memcpy(p, &route->prefix.u.prefix6,
+              OSPF6_PREFIX_SPACE(route->prefix.prefixlen));
+       ospf6_prefix_apply_mask(&as_external_lsa->prefix);
+       p += OSPF6_PREFIX_SPACE(route->prefix.prefixlen);
+
+       /* Forwarding address */
+       fwd_addr = ospf6_get_nssa_fwd_addr(area);
+       if (fwd_addr) {
+               memcpy(p, fwd_addr, sizeof(struct in6_addr));
+               p += sizeof(struct in6_addr);
+               SET_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_F);
+       } else
+               UNSET_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_F);
+
+       /* External Route Tag */
+       if (CHECK_FLAG(as_external_lsa->bits_metric, OSPF6_ASBR_BIT_T)) {
+               route_tag_t network_order = htonl(info->tag);
+
+               memcpy(p, &network_order, sizeof(network_order));
+               p += sizeof(network_order);
+       }
+
+       /* Fill LSA Header */
+       lsa_header->age = 0;
+       lsa_header->type = htons(OSPF6_LSTYPE_TYPE_7);
+       lsa_header->id = route->path.origin.id;
+       lsa_header->adv_router = area->ospf6->router_id;
+       lsa_header->seqnum =
+               ospf6_new_ls_seqnum(lsa_header->type, lsa_header->id,
+                                   lsa_header->adv_router, area->ospf6->lsdb);
+       lsa_header->length = htons((caddr_t)p - (caddr_t)lsa_header);
+
+       /* LSA checksum */
+       ospf6_lsa_checksum(lsa_header);
+       /* create LSA */
+       lsa = ospf6_lsa_create(lsa_header);
+
+       /* Originate */
+       ospf6_lsa_originate_area(lsa, area);
+}
+
+void ospf6_abr_check_translate_nssa(struct ospf6_area *area,
+                                   struct ospf6_lsa *lsa)
+{
+       struct ospf6_lsa *type5 = NULL;
+       struct ospf6 *ospf6 = area->ospf6;
+
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug("%s : start", __func__);
+
+       type5 = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL),
+                                 lsa->external_lsa_id, ospf6->router_id,
+                                 ospf6->lsdb);
+
+       if (ospf6_check_and_set_router_abr(ospf6) && (type5 == NULL)) {
+               if (IS_OSPF6_DEBUG_NSSA)
+                       zlog_debug("%s : Originating type5 LSA", __func__);
+               ospf6_lsa_translated_nssa_new(area, lsa);
+       }
+}
+
+DEFUN(debug_ospf6_nssa, debug_ospf6_nssa_cmd,
+      "debug ospf6 nssa",
+      DEBUG_STR
+      OSPF6_STR
+      "Debug OSPFv3 NSSA function\n")
+{
+       OSPF6_DEBUG_NSSA_ON();
+       return CMD_SUCCESS;
+}
+
+DEFUN(no_debug_ospf6_nssa, no_debug_ospf6_nssa_cmd,
+      "no debug ospf6 nssa",
+      NO_STR
+      DEBUG_STR
+      OSPF6_STR
+      "Debug OSPFv3 NSSA function\n")
+{
+       OSPF6_DEBUG_NSSA_OFF();
+       return CMD_SUCCESS;
+}
+
+void config_write_ospf6_debug_nssa(struct vty *vty)
+{
+       if (IS_OSPF6_DEBUG_NSSA)
+               vty_out(vty, "debug ospf6 nssa\n");
+}
+
+void install_element_ospf6_debug_nssa(void)
+{
+       install_element(ENABLE_NODE, &debug_ospf6_nssa_cmd);
+       install_element(ENABLE_NODE, &no_debug_ospf6_nssa_cmd);
+       install_element(CONFIG_NODE, &debug_ospf6_nssa_cmd);
+       install_element(CONFIG_NODE, &no_debug_ospf6_nssa_cmd);
+}
diff --git a/ospf6d/ospf6_nssa.h b/ospf6d/ospf6_nssa.h
new file mode 100644 (file)
index 0000000..a171d76
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * OSPFv3 Not So Stubby Area implementation.
+ *
+ * Copyright (C) 2021 Kaushik Nath
+ * Copyright (C) 2021 Soman K.S
+ *
+ * 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; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef OSPF6_NSSA_H
+#define OSPF6_NSSA_H
+
+#define OSPF6_OPTION_NP         0x08
+#define OSPF6_LS_INFINITY       0xffffff
+
+#define OSPF6_OPT_N             (1 << 3) /* Handling Type-7 LSA Capability */
+
+#define OSPF6_DEBUG_NSSA        0x09
+/* Debug option */
+extern unsigned char config_debug_ospf6_nssa;
+
+#define OSPF6_DEBUG_NSSA_ON() (config_debug_ospf6_nssa = 1)
+#define OSPF6_DEBUG_NSSA_OFF() (config_debug_ospf6_nssa = 0)
+#define IS_OSPF6_DEBUG_NSSA config_debug_ospf6_nssa
+
+#define CHECK_LSA_TYPE_1_TO_5_OR_7(type)                                       \
+       ((type == OSPF6_ROUTER_LSA_MIN_SIZE)                                   \
+        || (type == OSPF6_NETWORK_LSA_MIN_SIZE)                               \
+        || (type == OSPF6_LINK_LSA_MIN_SIZE)                                  \
+        || (type == OSPF6_INTRA_PREFIX_LSA_MIN_SIZE)                          \
+        || (type == OSPF6_AS_NSSA_LSA))
+
+#define OSPF6_LSA_APPROVED      0x08
+#define OSPF6_LSA_LOCAL_XLT     0x40
+
+#define OSPF6_ABR_TASK_DELAY    7
+
+int ospf6_area_nssa_no_summary_set(struct ospf6 *ospf6, struct in_addr area_id);
+int ospf6_area_nssa_unset(struct ospf6 *ospf6, struct ospf6_area *area);
+int ospf6_area_nssa_set(struct ospf6 *ospf6, struct ospf6_area *area);
+
+extern void ospf6_nssa_lsa_flush(struct ospf6 *ospf6, struct prefix_ipv6 *p);
+extern struct ospf6_lsa *ospf6_translated_nssa_refresh(struct ospf6_area *,
+                                                      struct ospf6_lsa *,
+                                                      struct ospf6_lsa *);
+extern struct ospf6_lsa *ospf6_translated_nssa_originate(struct ospf6_area *,
+                                                        struct ospf6_lsa *);
+
+extern void ospf6_asbr_nssa_redist_task(struct ospf6 *ospf6);
+
+extern void ospf6_schedule_abr_task(struct ospf6 *ospf6);
+void ospf6_asbr_prefix_readvertise(struct ospf6 *ospf6);
+extern void ospf6_nssa_lsa_originate(struct ospf6_route *route,
+                                    struct ospf6_area *area);
+extern void install_element_ospf6_debug_nssa(void);
+int ospf6_redistribute_check(struct ospf6 *ospf6, struct ospf6_route *route,
+                            int type);
+extern int ospf6_abr_translate_nssa(struct ospf6_area *area,
+                                   struct ospf6_lsa *lsa);
+extern void ospf6_abr_check_translate_nssa(struct ospf6_area *area,
+                                          struct ospf6_lsa *lsa);
+extern void ospf6_abr_nssa_check_status(struct ospf6 *ospf6);
+extern void config_write_ospf6_debug_nssa(struct vty *vty);
+#endif /* OSPF6_NSSA_H */
index da6b270e0174581ba3b2ffed49f13812f0cd3b72..b98dc38b728e26fca094bce5cd866b46cfa7e98a 100644 (file)
@@ -35,6 +35,8 @@
 #define OSPF6_ROUTER_BIT_V     (1 << 2)
 #define OSPF6_ROUTER_BIT_E     (1 << 1)
 #define OSPF6_ROUTER_BIT_B     (1 << 0)
+#define OSPF6_ROUTER_BIT_NT    (1 << 4)
+
 
 /* OSPF options */
 /* present in HELLO, DD, LSA */
index 908011c9469161db5aa5f5c7b1b0f13cab3b2015..0a026785f47ca689d842de4fbc4ac3181424ebb0 100644 (file)
@@ -688,6 +688,9 @@ struct ospf6_route *ospf6_route_add(struct ospf6_route *route,
                if (node->info == old) {
                        node->info = route;
                        SET_FLAG(route->flag, OSPF6_ROUTE_BEST);
+                       if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
+                               zlog_debug("%s:  replace old route %s",
+                                          __func__, buf);
                }
 
                if (old->prev)
@@ -745,12 +748,12 @@ struct ospf6_route *ospf6_route_add(struct ospf6_route *route,
                        UNSET_FLAG(next->flag, OSPF6_ROUTE_BEST);
                        SET_FLAG(route->flag, OSPF6_ROUTE_BEST);
                        if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
-                               zlog_info(
+                               zlog_debug(
                                        "%s %p: route add %p cost %u: replacing previous best: %p cost %u",
                                        ospf6_route_table_name(table),
                                        (void *)table, (void *)route,
-                                       route->path.cost,
-                                       (void *)next, next->path.cost);
+                                       route->path.cost, (void *)next,
+                                       next->path.cost);
                }
 
                route->installed = now;
@@ -876,6 +879,9 @@ void ospf6_route_remove(struct ospf6_route *route,
                if (route->next && route->next->rnode == node) {
                        node->info = route->next;
                        SET_FLAG(route->next->flag, OSPF6_ROUTE_BEST);
+                       if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
+                               zlog_debug("%s: remove route %s", __func__,
+                                          buf);
                } else {
                        node->info = NULL;
                        route->rnode = NULL;
index dcf76c7038e6d50e9d30556377fdf3b3d65f3318..92922567e833215d84bb16e371ac70b22aab41cd 100644 (file)
@@ -664,9 +664,10 @@ static uint8_t *ospfv3GeneralGroup(struct variable *v, oid *name,
                return SNMP_INTEGER(3);
        case OSPFv3AREABDRRTRSTATUS:
                if (ospf6)
-                       return SNMP_INTEGER(ospf6_is_router_abr(ospf6)
-                                                   ? SNMP_TRUE
-                                                   : SNMP_FALSE);
+                       return SNMP_INTEGER(
+                               ospf6_check_and_set_router_abr(ospf6)
+                                       ? SNMP_TRUE
+                                       : SNMP_FALSE);
                return SNMP_INTEGER(SNMP_FALSE);
        case OSPFv3ASBDRRTRSTATUS:
                if (ospf6)
index 7652d71c59d52ed52e7050dca9bc14a674cf254f..032484e28885aae9b6dadb19e109b73dee4c5aa3 100644 (file)
 #include "ospf6_area.h"
 #include "ospf6_proto.h"
 #include "ospf6_abr.h"
+#include "ospf6_asbr.h"
 #include "ospf6_spf.h"
 #include "ospf6_intra.h"
 #include "ospf6_interface.h"
 #include "ospf6d.h"
 #include "ospf6_abr.h"
+#include "ospf6_nssa.h"
 
 DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_VERTEX, "OSPF6 vertex");
 
@@ -282,9 +284,7 @@ static void ospf6_nexthop_calc(struct ospf6_vertex *w, struct ospf6_vertex *v,
 
        oi = ospf6_interface_lookup_by_ifindex(ifindex, ospf6->vrf_id);
        if (oi == NULL) {
-               if (IS_OSPF6_DEBUG_SPF(PROCESS))
-                       zlog_debug("Can't find interface in SPF: ifindex %d",
-                                  ifindex);
+               zlog_warn("Can't find interface in SPF: ifindex %d", ifindex);
                return;
        }
 
@@ -473,9 +473,7 @@ void ospf6_spf_calculation(uint32_t router_id,
        /* construct root vertex */
        lsa = ospf6_create_single_router_lsa(oa, oa->lsdb_self, router_id);
        if (lsa == NULL) {
-               if (IS_OSPF6_DEBUG_SPF(PROCESS))
-                       zlog_debug("%s: No router LSA for area %s", __func__,
-                                  oa->name);
+               zlog_warn("%s: No router LSA for area %s", __func__, oa->name);
                return;
        }
 
@@ -603,7 +601,7 @@ static int ospf6_spf_calculation_thread(struct thread *t)
        monotime(&start);
        ospf6->ts_spf = start;
 
-       if (ospf6_is_router_abr(ospf6))
+       if (ospf6_check_and_set_router_abr(ospf6))
                ospf6_abr_range_reset_cost(ospf6);
 
        for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, oa)) {
@@ -640,7 +638,10 @@ static int ospf6_spf_calculation_thread(struct thread *t)
                areas_processed++;
        }
 
-       if (ospf6_is_router_abr(ospf6))
+       /* External LSA calculation */
+       ospf6_ase_calculate_timer_add(ospf6);
+
+       if (ospf6_check_and_set_router_abr(ospf6))
                ospf6_abr_defaults_to_stub(ospf6);
 
        monotime(&end);
@@ -1105,3 +1106,162 @@ void ospf6_remove_temp_router_lsa(struct ospf6_area *area)
                ospf6_lsdb_remove(lsa, area->temp_router_lsa_lsdb);
        }
 }
+
+int ospf6_ase_calculate_route(struct ospf6 *ospf6, struct ospf6_lsa *lsa,
+                             struct ospf6_area *area)
+{
+       struct ospf6_route *route;
+       struct ospf6_as_external_lsa *external;
+       struct prefix prefix;
+       void (*hook_add)(struct ospf6_route *) = NULL;
+       void (*hook_remove)(struct ospf6_route *) = NULL;
+
+       assert(lsa);
+
+       if (IS_OSPF6_DEBUG_SPF(PROCESS))
+               zlog_debug("%s :  start", __func__);
+
+       if (ntohs(lsa->header->type) == OSPF6_LSTYPE_TYPE_7)
+               if (IS_OSPF6_DEBUG_SPF(PROCESS))
+                       zlog_debug("%s: Processing Type-7", __func__);
+
+       /* Stay away from any Local Translated Type-7 LSAs */
+       if (CHECK_FLAG(lsa->flag, OSPF6_LSA_LOCAL_XLT)) {
+               if (IS_OSPF6_DEBUG_SPF(PROCESS))
+                       zlog_debug("%s: Rejecting Local translated LSA",
+                                  __func__);
+               return 0;
+       }
+
+       external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END(
+               lsa->header);
+       prefix.family = AF_INET6;
+       prefix.prefixlen = external->prefix.prefix_length;
+       ospf6_prefix_in6_addr(&prefix.u.prefix6, external, &external->prefix);
+
+       if (ntohs(lsa->header->type) == OSPF6_LSTYPE_AS_EXTERNAL) {
+               hook_add = ospf6->route_table->hook_add;
+               hook_remove = ospf6->route_table->hook_remove;
+               ospf6->route_table->hook_add = NULL;
+               ospf6->route_table->hook_remove = NULL;
+
+               if (!OSPF6_LSA_IS_MAXAGE(lsa))
+                       ospf6_asbr_lsa_add(lsa);
+
+               ospf6->route_table->hook_add = hook_add;
+               ospf6->route_table->hook_remove = hook_remove;
+
+               route = ospf6_route_lookup(&prefix, ospf6->route_table);
+               if (route == NULL) {
+                       if (IS_OSPF6_DEBUG_SPF(PROCESS))
+                               zlog_debug("%s: no external route %pFX",
+                                          __func__, &prefix);
+                       return 0;
+               }
+
+               if (CHECK_FLAG(route->flag, OSPF6_ROUTE_REMOVE)
+                   && CHECK_FLAG(route->flag, OSPF6_ROUTE_ADD)) {
+                       UNSET_FLAG(route->flag, OSPF6_ROUTE_REMOVE);
+                       UNSET_FLAG(route->flag, OSPF6_ROUTE_ADD);
+               }
+
+               if (CHECK_FLAG(route->flag, OSPF6_ROUTE_REMOVE))
+                       ospf6_route_remove(route, ospf6->route_table);
+               else if (CHECK_FLAG(route->flag, OSPF6_ROUTE_ADD)
+                        || CHECK_FLAG(route->flag, OSPF6_ROUTE_CHANGE)) {
+                       if (hook_add) {
+                               if (IS_OSPF6_DEBUG_SPF(PROCESS))
+                                       zlog_debug(
+                                               "%s: add external route %pFX",
+                                               __func__, &prefix);
+                               (*hook_add)(route);
+                       }
+               }
+       } else if (ntohs(lsa->header->type) == OSPF6_LSTYPE_TYPE_7) {
+               hook_add = area->route_table->hook_add;
+               hook_remove = area->route_table->hook_remove;
+               area->route_table->hook_add = NULL;
+               area->route_table->hook_remove = NULL;
+
+               if (!OSPF6_LSA_IS_MAXAGE(lsa))
+                       ospf6_asbr_lsa_add(lsa);
+
+               area->route_table->hook_add = hook_add;
+               area->route_table->hook_remove = hook_remove;
+
+               route = ospf6_route_lookup(&prefix, area->route_table);
+               if (route == NULL) {
+                       if (IS_OSPF6_DEBUG_SPF(PROCESS))
+                               zlog_debug("%s: no route %pFX, area %s",
+                                          __func__, &prefix, area->name);
+                       return 0;
+               }
+
+               if (CHECK_FLAG(route->flag, OSPF6_ROUTE_REMOVE)
+                   && CHECK_FLAG(route->flag, OSPF6_ROUTE_ADD)) {
+                       UNSET_FLAG(route->flag, OSPF6_ROUTE_REMOVE);
+                       UNSET_FLAG(route->flag, OSPF6_ROUTE_ADD);
+               }
+
+               if (CHECK_FLAG(route->flag, OSPF6_ROUTE_REMOVE)) {
+                       if (IS_OSPF6_DEBUG_SPF(PROCESS))
+                               zlog_debug("%s : remove route %pFX, area %s",
+                                          __func__, &prefix, area->name);
+                       ospf6_route_remove(route, area->route_table);
+               } else if (CHECK_FLAG(route->flag, OSPF6_ROUTE_ADD)
+                          || CHECK_FLAG(route->flag, OSPF6_ROUTE_CHANGE)) {
+                       if (hook_add) {
+                               if (IS_OSPF6_DEBUG_SPF(PROCESS))
+                                       zlog_debug(
+                                               "%s: add nssa route %pFX, area %s",
+                                               __func__, &prefix, area->name);
+                               (*hook_add)(route);
+                       }
+                       ospf6_abr_check_translate_nssa(area, lsa);
+               }
+       }
+       return 0;
+}
+
+static int ospf6_ase_calculate_timer(struct thread *t)
+{
+       struct ospf6 *ospf6;
+       struct ospf6_lsa *lsa;
+       struct listnode *node, *nnode;
+       struct ospf6_area *area;
+       uint16_t type;
+
+       ospf6 = THREAD_ARG(t);
+       ospf6->t_ase_calc = NULL;
+
+       /* Calculate external route for each AS-external-LSA */
+       type = htons(OSPF6_LSTYPE_AS_EXTERNAL);
+       for (ALL_LSDB_TYPED(ospf6->lsdb, type, lsa))
+               ospf6_ase_calculate_route(ospf6, lsa, NULL);
+
+       /*  This version simple adds to the table all NSSA areas  */
+       if (ospf6->anyNSSA) {
+               for (ALL_LIST_ELEMENTS(ospf6->area_list, node, nnode, area)) {
+                       if (IS_OSPF6_DEBUG_SPF(PROCESS))
+                               zlog_debug("%s : looking at area %s", __func__,
+                                          area->name);
+
+                       if (IS_OSPF6_DEBUG_SPF(PROCESS)) {
+                               type = htons(OSPF6_LSTYPE_TYPE_7);
+                               for (ALL_LSDB_TYPED(area->lsdb, type, lsa))
+                                       ospf6_ase_calculate_route(ospf6, lsa,
+                                                                 area);
+                       }
+               }
+       }
+       return 0;
+}
+
+void ospf6_ase_calculate_timer_add(struct ospf6 *ospf6)
+{
+       if (ospf6 == NULL)
+               return;
+
+       thread_add_timer(master, ospf6_ase_calculate_timer, ospf6,
+                        OSPF6_ASE_CALC_INTERVAL, &ospf6->t_ase_calc);
+}
index 4660bfd05db9f391eae4b27dc2a7897a1da2f650..d6fbc5c13b74ed6201091ead73daa2fab9bc8e45 100644 (file)
@@ -35,6 +35,8 @@ extern unsigned char conf_debug_ospf6_spf;
 #define IS_OSPF6_DEBUG_SPF(level)                                              \
        (conf_debug_ospf6_spf & OSPF6_DEBUG_SPF_##level)
 
+#define OSPF6_ASE_CALC_INTERVAL 1
+
 PREDECL_SKIPLIST_NONUNIQ(vertex_pqueue);
 /* Transit Vertex */
 struct ospf6_vertex {
@@ -161,5 +163,7 @@ extern struct ospf6_lsa *ospf6_create_single_router_lsa(struct ospf6_area *area,
                                                        struct ospf6_lsdb *lsdb,
                                                        uint32_t adv_router);
 extern void ospf6_remove_temp_router_lsa(struct ospf6_area *area);
-
+extern void ospf6_ase_calculate_timer_add(struct ospf6 *ospf6);
+extern int ospf6_ase_calculate_route(struct ospf6 *ospf6, struct ospf6_lsa *lsa,
+                                    struct ospf6_area *area);
 #endif /* OSPF6_SPF_H */
index 42405ca35ea48fdeb6df88185bae163d87a7f4fa..6cea5032bdce2b9d726b66ded12cebbcad000455 100644 (file)
@@ -52,6 +52,7 @@
 #include "ospf6_spf.h"
 #include "ospf6d.h"
 #include "lib/json.h"
+#include "ospf6_nssa.h"
 
 DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_TOP, "OSPF6 top");
 
@@ -231,6 +232,8 @@ void ospf6_vrf_init(void)
 {
        vrf_init(ospf6_vrf_new, ospf6_vrf_enable, ospf6_vrf_disable,
                 ospf6_vrf_delete, ospf6_vrf_enable);
+
+       vrf_cmd_init(NULL, &ospf6d_privs);
 }
 
 static void ospf6_top_lsdb_hook_add(struct ospf6_lsa *lsa)
@@ -259,7 +262,22 @@ static void ospf6_top_lsdb_hook_remove(struct ospf6_lsa *lsa)
 
 static void ospf6_top_route_hook_add(struct ospf6_route *route)
 {
-       struct ospf6 *ospf6 = route->table->scope;
+       struct ospf6 *ospf6 = NULL;
+       struct ospf6_area *oa = NULL;
+
+       if (route->table->scope_type == OSPF6_SCOPE_TYPE_GLOBAL)
+               ospf6 = route->table->scope;
+       else if (route->table->scope_type == OSPF6_SCOPE_TYPE_AREA) {
+               oa = (struct ospf6_area *)route->table->scope;
+               ospf6 = oa->ospf6;
+       } else {
+               if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)
+                   || IS_OSPF6_DEBUG_BROUTER)
+                       zlog_debug(
+                               "%s: Route is not GLOBAL or scope is not of TYPE_AREA: %pFX",
+                               __func__, &route->prefix);
+               return;
+       }
 
        ospf6_abr_originate_summary(route, ospf6);
        ospf6_zebra_route_update_add(route, ospf6);
@@ -267,7 +285,22 @@ static void ospf6_top_route_hook_add(struct ospf6_route *route)
 
 static void ospf6_top_route_hook_remove(struct ospf6_route *route)
 {
-       struct ospf6 *ospf6 = route->table->scope;
+       struct ospf6 *ospf6 = NULL;
+       struct ospf6_area *oa = NULL;
+
+       if (route->table->scope_type == OSPF6_SCOPE_TYPE_GLOBAL)
+               ospf6 = route->table->scope;
+       else if (route->table->scope_type == OSPF6_SCOPE_TYPE_AREA) {
+               oa = (struct ospf6_area *)route->table->scope;
+               ospf6 = oa->ospf6;
+       } else {
+               if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)
+                   || IS_OSPF6_DEBUG_BROUTER)
+                       zlog_debug(
+                               "%s: Route is not GLOBAL or scope is not of TYPE_AREA: %pFX",
+                               __func__, &route->prefix);
+               return;
+       }
 
        route->flag |= OSPF6_ROUTE_REMOVE;
        ospf6_abr_originate_summary(route, ospf6);
@@ -375,6 +408,7 @@ static struct ospf6 *ospf6_create(const char *name)
 
        o->external_id_table = route_table_init();
 
+       o->write_oi_count = OSPF6_WRITE_INTERFACE_COUNT_DEFAULT;
        o->ref_bandwidth = OSPF6_REFERENCE_BANDWIDTH;
 
        o->distance_table = route_table_init();
@@ -382,6 +416,8 @@ static struct ospf6 *ospf6_create(const char *name)
 
        o->max_multipath = MULTIPATH_NUM;
 
+       o->oi_write_q = list_new();
+
        QOBJ_REG(o, ospf6);
 
        /* Make ospf protocol socket. */
@@ -393,6 +429,8 @@ static struct ospf6 *ospf6_create(const char *name)
 struct ospf6 *ospf6_instance_create(const char *name)
 {
        struct ospf6 *ospf6;
+       struct vrf *vrf;
+       struct interface *ifp;
 
        ospf6 = ospf6_create(name);
        if (DFLT_OSPF6_LOG_ADJACENCY_CHANGES)
@@ -400,6 +438,13 @@ struct ospf6 *ospf6_instance_create(const char *name)
        if (ospf6->router_id == 0)
                ospf6_router_id_update(ospf6);
        ospf6_add(ospf6);
+       if (ospf6->vrf_id != VRF_UNKNOWN) {
+               vrf = vrf_lookup_by_id(ospf6->vrf_id);
+               FOR_ALL_INTERFACES (vrf, ifp) {
+                       if (ifp->info)
+                               ospf6_interface_start(ifp->info);
+               }
+       }
        if (ospf6->fd < 0)
                return ospf6;
 
@@ -442,6 +487,7 @@ void ospf6_delete(struct ospf6 *o)
 
        ospf6_distance_reset(o);
        route_table_finish(o->distance_table);
+       list_delete(&o->oi_write_q);
 
        if (o->vrf_id != VRF_UNKNOWN) {
                vrf = vrf_lookup_by_id(o->vrf_id);
@@ -850,7 +896,7 @@ DEFUN (no_ospf6_distance_ospf6,
        return CMD_SUCCESS;
 }
 
-DEFUN (ospf6_interface_area,
+DEFUN_HIDDEN (ospf6_interface_area,
        ospf6_interface_area_cmd,
        "interface IFNAME area <A.B.C.D|(0-4294967295)>",
        "Enable routing on an IPv6 interface\n"
@@ -868,6 +914,13 @@ DEFUN (ospf6_interface_area,
        struct interface *ifp;
        vrf_id_t vrf_id = VRF_DEFAULT;
        int ipv6_count = 0;
+       uint32_t area_id;
+       int format;
+
+       vty_out(vty,
+               "This command is deprecated, because it is not VRF-aware.\n");
+       vty_out(vty,
+               "Please, use \"ipv6 ospf6 area\" on an interface instead.\n");
 
        if (ospf6->vrf_id != VRF_UNKNOWN)
                vrf_id = ospf6->vrf_id;
@@ -900,8 +953,17 @@ DEFUN (ospf6_interface_area,
                return CMD_WARNING_CONFIG_FAILED;
        }
 
-       /* parse Area-ID */
-       OSPF6_CMD_AREA_GET(argv[idx_ipv4]->arg, oa, ospf6);
+       if (str2area_id(argv[idx_ipv4]->arg, &area_id, &format)) {
+               vty_out(vty, "Malformed Area-ID: %s\n", argv[idx_ipv4]->arg);
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       oi->area_id = area_id;
+       oi->area_id_format = format;
+
+       oa = ospf6_area_lookup(area_id, ospf6);
+       if (oa == NULL)
+               oa = ospf6_area_create(area_id, ospf6, format);
 
        /* attach interface to area */
        listnode_add(oa->if_list, oi); /* sort ?? */
@@ -917,13 +979,15 @@ DEFUN (ospf6_interface_area,
        ospf6_interface_enable(oi);
 
        /* If the router is ABR, originate summary routes */
-       if (ospf6_is_router_abr(ospf6))
+       if (ospf6_check_and_set_router_abr(ospf6)) {
                ospf6_abr_enable_area(oa);
+               ospf6_schedule_abr_task(oa->ospf6);
+       }
 
        return CMD_SUCCESS;
 }
 
-DEFUN (no_ospf6_interface_area,
+DEFUN_HIDDEN (no_ospf6_interface_area,
        no_ospf6_interface_area_cmd,
        "no interface IFNAME area <A.B.C.D|(0-4294967295)>",
        NO_STR
@@ -943,6 +1007,11 @@ DEFUN (no_ospf6_interface_area,
        uint32_t area_id;
        vrf_id_t vrf_id = VRF_DEFAULT;
 
+       vty_out(vty,
+               "This command is deprecated, because it is not VRF-aware.\n");
+       vty_out(vty,
+               "Please, use \"no ipv6 ospf6 area\" on an interface instead.\n");
+
        if (ospf6->vrf_id != VRF_UNKNOWN)
                vrf_id = ospf6->vrf_id;
 
@@ -989,6 +1058,9 @@ DEFUN (no_ospf6_interface_area,
                ospf6_abr_disable_area(oa);
        }
 
+       oi->area_id = 0;
+       oi->area_id_format = OSPF6_AREA_FMT_UNSET;
+
        return CMD_SUCCESS;
 }
 
@@ -1566,9 +1638,6 @@ static int ospf6_distance_config_write(struct vty *vty, struct ospf6 *ospf6)
 /* OSPF configuration write function. */
 static int config_write_ospf6(struct vty *vty)
 {
-       struct listnode *j, *k;
-       struct ospf6_area *oa;
-       struct ospf6_interface *oi;
        struct ospf6 *ospf6;
        struct listnode *node, *nnode;
 
@@ -1602,6 +1671,11 @@ static int config_write_ospf6(struct vty *vty)
                        vty_out(vty, " auto-cost reference-bandwidth %d\n",
                                ospf6->ref_bandwidth);
 
+               if (ospf6->write_oi_count
+                   != OSPF6_WRITE_INTERFACE_COUNT_DEFAULT)
+                       vty_out(vty, " write-multiplier %d\n",
+                               ospf6->write_oi_count);
+
                /* LSA timers print. */
                if (ospf6->lsa_minarrival != OSPF_MIN_LS_ARRIVAL)
                        vty_out(vty, " timers lsa min-arrival %d\n",
@@ -1619,11 +1693,6 @@ static int config_write_ospf6(struct vty *vty)
                ospf6_distance_config_write(vty, ospf6);
                ospf6_distribute_config_write(vty, ospf6);
 
-               for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, j, oa)) {
-                       for (ALL_LIST_ELEMENTS_RO(oa->if_list, k, oi))
-                               vty_out(vty, " interface %s area %s\n",
-                                       oi->interface->name, oa->name);
-               }
                vty_out(vty, "!\n");
        }
        return 0;
index 238d6a40ce230c55cdb522703ca70a1094278500..5b739ac76b098bd0b8b9668a9eed2751775daaeb 100644 (file)
@@ -95,6 +95,8 @@ struct ospf6 {
        struct list *redist[ZEBRA_ROUTE_MAX + 1];
 
        uint8_t flag;
+#define OSPF6_FLAG_ABR          0x04
+#define OSPF6_FLAG_ASBR         0x08
 
        int redistribute; /* Num of redistributed protocols. */
 
@@ -126,7 +128,10 @@ struct ospf6 {
        struct thread *maxage_remover;
        struct thread *t_distribute_update; /* Distirbute update timer. */
        struct thread *t_ospf6_receive; /* OSPF6 receive timer */
+#define OSPF6_WRITE_INTERFACE_COUNT_DEFAULT 20
+       struct thread *t_write;
 
+       int write_oi_count; /* Num of packets sent per thread invocation */
        uint32_t ref_bandwidth;
 
        /* Distance parameters */
@@ -145,14 +150,18 @@ struct ospf6 {
         * to support ECMP.
         */
        uint16_t max_multipath;
+       /* Count of NSSA areas */
+       uint8_t anyNSSA;
+       struct thread *t_abr_task; /* ABR task timer. */
+       struct list *oi_write_q;
 
+       uint32_t redist_count;
        QOBJ_FIELDS;
 };
 DECLARE_QOBJ_TYPE(ospf6);
 
 #define OSPF6_DISABLED    0x01
 #define OSPF6_STUB_ROUTER 0x02
-#define OSPF6_FLAG_ASBR   0x04
 #define OSPF6_MAX_IF_ADDRS 100
 #define OSPF6_MAX_IF_ADDRS_JUMBO 200
 #define OSPF6_DEFAULT_MTU 1500
index da8c695f6502e0774b33f5cb3f4db24c99a1ef38..65f0aa664e786dd215fa35c365f2afd3edae052d 100644 (file)
@@ -46,6 +46,7 @@
 #include "ospf6d.h"
 #include "ospf6_bfd.h"
 #include "lib/json.h"
+#include "ospf6_nssa.h"
 
 DEFINE_MGROUP(OSPF6D, "ospf6d");
 
@@ -94,6 +95,7 @@ static int config_write_ospf6_debug(struct vty *vty)
        config_write_ospf6_debug_asbr(vty);
        config_write_ospf6_debug_abr(vty);
        config_write_ospf6_debug_flood(vty);
+       config_write_ospf6_debug_nssa(vty);
 
        return 0;
 }
@@ -153,6 +155,8 @@ static uint16_t parse_type_spec(int idx_lsa, int argc, struct cmd_token **argv)
                        type = htons(OSPF6_LSTYPE_INTER_PREFIX);
                else if (strmatch(argv[idx_lsa]->text, "link"))
                        type = htons(OSPF6_LSTYPE_LINK);
+               else if (strmatch(argv[idx_lsa]->text, "type-7"))
+                       type = htons(OSPF6_LSTYPE_TYPE_7);
        }
 
        return type;
@@ -1419,6 +1423,7 @@ void ospf6_init(struct thread_master *master)
        install_element_ospf6_debug_asbr();
        install_element_ospf6_debug_abr();
        install_element_ospf6_debug_flood();
+       install_element_ospf6_debug_nssa();
 
        install_element_ospf6_clear_interface();
 
index 00388afd38fdafedced8ebb9489e568be688a42b..2e1891be7189daa8955c3d588f746afeb160882e 100644 (file)
@@ -6,6 +6,7 @@ if OSPF6D
 noinst_LIBRARIES += ospf6d/libospf6.a
 sbin_PROGRAMS += ospf6d/ospf6d
 vtysh_scan += \
+       ospf6d/ospf6_nssa.c \
        ospf6d/ospf6_abr.c \
        ospf6d/ospf6_asbr.c \
        ospf6d/ospf6_area.c \
@@ -30,6 +31,7 @@ man8 += $(MANBUILD)/frr-ospf6d.8
 endif
 
 ospf6d_libospf6_a_SOURCES = \
+       ospf6d/ospf6_nssa.c \
        ospf6d/ospf6_abr.c \
        ospf6d/ospf6_area.c \
        ospf6d/ospf6_asbr.c \
@@ -53,6 +55,7 @@ ospf6d_libospf6_a_SOURCES = \
        # end
 
 noinst_HEADERS += \
+       ospf6d/ospf6_nssa.h \
        ospf6d/ospf6_abr.h \
        ospf6d/ospf6_area.h \
        ospf6d/ospf6_asbr.h \
index bda00e0c9e6481f9283386c812142bb76e875fb4..2fd195bb6d10461092720cc53f9a74b8dd894c04 100644 (file)
@@ -508,7 +508,6 @@ static void ospf_external_aggr_delete(struct ospf *ospf, struct route_node *rn)
 
        rn->info = NULL;
        route_unlock_node(rn);
-       route_unlock_node(rn);
 }
 
 struct ospf_external_aggr_rt *
@@ -1160,6 +1159,7 @@ int ospf_asbr_external_aggregator_unset(struct ospf *ospf,
        rn = route_node_lookup(ospf->rt_aggr_tbl, (struct prefix *)p);
        if (!rn)
                return OSPF_INVALID;
+       route_unlock_node(rn);
 
        aggr = rn->info;
 
@@ -1217,6 +1217,7 @@ int ospf_asbr_external_rt_advertise(struct ospf *ospf, struct prefix_ipv4 *p)
        rn = route_node_lookup(ospf->rt_aggr_tbl, (struct prefix *)p);
        if (!rn)
                return OSPF_INVALID;
+       route_unlock_node(rn);
 
        aggr = rn->info;
 
index 7eb587899b8d41691aeb6bb46edf9f065659b3fa..6c1ac6761af8f525bb9035015be23a2e37302251 100644 (file)
@@ -597,7 +597,7 @@ static int ospf_flood_through_interface(struct ospf_interface *oi,
                   Designated Router, chances are that all the neighbors have
                   received the LSA already. */
                if (NBR_IS_DR(inbr) || NBR_IS_BDR(inbr)) {
-                       if (IS_DEBUG_OSPF_NSSA)
+                       if (IS_DEBUG_OSPF(lsa, LSA_FLOODING))
                                zlog_debug("%s: DR/BDR NOT SEND to int %s (%s)",
                                           __func__, IF_NAME(oi),
                                           ospf_get_name(oi->ospf));
@@ -611,7 +611,7 @@ static int ospf_flood_through_interface(struct ospf_interface *oi,
                   end up retransmitting the updates. */
 
                if (oi->state == ISM_Backup) {
-                       if (IS_DEBUG_OSPF_NSSA)
+                       if (IS_DEBUG_OSPF(lsa, LSA_FLOODING))
                                zlog_debug(
                                        "%s: ISM_Backup NOT SEND to int %s (%s)",
                                        __func__, IF_NAME(oi),
@@ -626,8 +626,7 @@ static int ospf_flood_through_interface(struct ospf_interface *oi,
           (which       must be > 0) when it is copied into the outgoing Link
           State Update packet (until the LS age field reaches the maximum
           value of MaxAge). */
-       /* XXX HASSO: Is this IS_DEBUG_OSPF_NSSA really correct? */
-       if (IS_DEBUG_OSPF_NSSA)
+       if (IS_DEBUG_OSPF(lsa, LSA_FLOODING))
                zlog_debug("%s: DR/BDR sending upd to int %s (%s)", __func__,
                           IF_NAME(oi), ospf_get_name(oi->ospf));
 
index a25057a27f54514ea2a9fc0595d33e045a68bb3e..b32318b832a568eaee533640b21ed54c6d3b31cf 100644 (file)
@@ -52,7 +52,7 @@
 
 static const char * const ospf_exit_reason_desc[] = {
        "Unknown reason",
-       "Helper inprogress",
+       "Helper in progress",
        "Topology Change",
        "Grace timer expiry",
        "Successful graceful restart",
@@ -159,10 +159,8 @@ const char *ospf_rejected_reason2str(unsigned int reason)
  * Returns:
  *    Nothing
  */
-void ospf_gr_helper_init(struct ospf *ospf)
+void ospf_gr_helper_instance_init(struct ospf *ospf)
 {
-       int rc;
-
        if (IS_DEBUG_OSPF_GR_HELPER)
                zlog_debug("%s, GR Helper init.", __func__);
 
@@ -176,6 +174,37 @@ void ospf_gr_helper_init(struct ospf *ospf)
        ospf->enable_rtr_list =
                hash_create(ospf_enable_rtr_hash_key, ospf_enable_rtr_hash_cmp,
                            "OSPF enable router hash");
+}
+
+/*
+ * De-Initialize GR helper config data structures.
+ *
+ * OSPF
+ *    OSPF pointer
+ *
+ * Returns:
+ *    Nothing
+ */
+void ospf_gr_helper_instance_stop(struct ospf *ospf)
+{
+       if (IS_DEBUG_OSPF_GR_HELPER)
+               zlog_debug("%s, GR helper deinit.", __func__);
+
+       ospf_enable_rtr_hash_destroy(ospf);
+}
+
+/*
+ * Initialize GR helper config data structures.
+ *
+ * Returns:
+ *    Nothing
+ */
+void ospf_gr_helper_init(void)
+{
+       int rc;
+
+       if (IS_DEBUG_OSPF_GR_HELPER)
+               zlog_debug("%s, GR Helper init.", __func__);
 
        rc = ospf_register_opaque_functab(
                OSPF_OPAQUE_LINK_LSA, OPAQUE_TYPE_GRACE_LSA, NULL, NULL, NULL,
@@ -191,20 +220,15 @@ void ospf_gr_helper_init(struct ospf *ospf)
 /*
  * De-Initialize GR helper config data structures.
  *
- * OSPF
- *    OSPF pointer
- *
  * Returns:
  *    Nothing
  */
-void ospf_gr_helper_stop(struct ospf *ospf)
+void ospf_gr_helper_stop(void)
 {
 
        if (IS_DEBUG_OSPF_GR_HELPER)
                zlog_debug("%s, GR helper deinit.", __func__);
 
-       ospf_enable_rtr_hash_destroy(ospf);
-
        ospf_delete_opaque_functab(OSPF_OPAQUE_LINK_LSA, OPAQUE_TYPE_GRACE_LSA);
 }
 
@@ -342,7 +366,7 @@ static int ospf_handle_grace_timer_expiry(struct thread *thread)
  *    Grace LSA received from RESTARTER.
  *
  * nbr
- *    ospf neighbour which requets the router to act as
+ *    OSPF neighbour which requests the router to act as
  *    HELPER.
  *
  * Returns:
@@ -374,11 +398,11 @@ int ospf_process_grace_lsa(struct ospf *ospf, struct ospf_lsa *lsa,
 
        if (IS_DEBUG_OSPF_GR_HELPER)
                zlog_debug(
-                       "%s, Grace LSA received from %pI4, grace interval:%u, restartreason :%s",
+                       "%s, Grace LSA received from %pI4, grace interval:%u, restart reason:%s",
                        __func__, &restart_addr, grace_interval,
                        ospf_restart_reason2str(restart_reason));
 
-       /* Incase of broadcast links, if RESTARTER is DR_OTHER,
+       /* In case of broadcast links, if RESTARTER is DR_OTHER,
         * grace LSA might be received from DR, so need to get
         * actual neighbour info , here RESTARTER.
         */
@@ -441,7 +465,7 @@ int ospf_process_grace_lsa(struct ospf *ospf, struct ospf_lsa *lsa,
                return OSPF_GR_NOT_HELPER;
        }
 
-       /* Check the retranmission list of this
+       /* Check the retransmission list of this
         * neighbour, check any change in lsas.
         */
        if (ospf->strict_lsa_check && !ospf_ls_retransmit_isempty(restarter)
@@ -459,7 +483,7 @@ int ospf_process_grace_lsa(struct ospf *ospf, struct ospf_lsa *lsa,
        if (ntohs(lsa->data->ls_age) >= grace_interval) {
                if (IS_DEBUG_OSPF_GR_HELPER)
                        zlog_debug(
-                               "%s, Grace LSA age(%d) is more than the graceinterval(%d)",
+                               "%s, Grace LSA age(%d) is more than the grace interval(%d)",
                                __func__, lsa->data->ls_age, grace_interval);
                restarter->gr_helper_info.rejected_reason =
                        OSPF_HELPER_LSA_AGE_MORE;
@@ -508,7 +532,7 @@ int ospf_process_grace_lsa(struct ospf *ospf, struct ospf_lsa *lsa,
        restarter->gr_helper_info.gr_restart_reason = restart_reason;
        restarter->gr_helper_info.rejected_reason = OSPF_HELPER_REJECTED_NONE;
 
-       /* Incremnet the active restarer count */
+       /* Increment the active restarter count */
        ospf->active_restarter_cnt++;
 
        if (IS_DEBUG_OSPF_GR_HELPER)
@@ -528,7 +552,7 @@ int ospf_process_grace_lsa(struct ospf *ospf, struct ospf_lsa *lsa,
  * retransmission list.
  *
  * nbr
- *    ospf neighbor
+ *    OSPF neighbor
  *
  * Returns:
  *    TRUE  - if any change in the lsa.
@@ -579,7 +603,7 @@ static bool ospf_check_change_in_rxmt_list(struct ospf_neighbor *nbr)
  * ospf
  *    ospf pointer
  * lsa
- *    topo change occured due to this lsa type (1 to 5 and 7)
+ *    topo change occurred due to this lsa type (1 to 5 and 7)
  *
  * Returns:
  *    Nothing
@@ -593,7 +617,7 @@ void ospf_helper_handle_topo_chg(struct ospf *ospf, struct ospf_lsa *lsa)
                return;
 
        /* Topo change not required to be handled if strict
-        * LSA check is disbaled for this router.
+        * LSA check is disabled for this router.
         */
        if (!ospf->strict_lsa_check)
                return;
@@ -683,25 +707,26 @@ void ospf_gr_helper_exit(struct ospf_neighbor *nbr,
        ospf->active_restarter_cnt--;
 
        /* If the exit not triggered due to grace timer
-        * expairy , stop the grace timer.
+        * expiry, stop the grace timer.
         */
        if (reason != OSPF_GR_HELPER_GRACE_TIMEOUT)
                THREAD_OFF(nbr->gr_helper_info.t_grace_timer);
 
        /* check exit triggered due to successful completion
         * of graceful restart.
-        * If no, bringdown the neighbour.
+        * If no, bring down the neighbour.
         */
        if (reason != OSPF_GR_HELPER_COMPLETED) {
                if (IS_DEBUG_OSPF_GR_HELPER)
                        zlog_debug(
                                "%s, Failed GR exit, so bringing down the neighbour",
                                __func__);
-               OSPF_NSM_EVENT_EXECUTE(nbr, NSM_KillNbr);
+               OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_KillNbr);
        }
 
        /*Recalculate the DR for the network segment */
-       ospf_dr_election(oi);
+       if (oi->type == OSPF_IFTYPE_BROADCAST || oi->type == OSPF_IFTYPE_NBMA)
+               ospf_dr_election(oi);
 
        /* Originate a router LSA */
        ospf_router_lsa_update_area(oi->area);
@@ -712,7 +737,7 @@ void ospf_gr_helper_exit(struct ospf_neighbor *nbr,
 }
 
 /*
- * Process Maxage Grace LSA.
+ * Process MaxAge Grace LSA.
  * It is a indication for successful completion of GR.
  * If router acting as HELPER, It exits from helper role.
  *
@@ -723,7 +748,7 @@ void ospf_gr_helper_exit(struct ospf_neighbor *nbr,
  *    Grace LSA received from RESTARTER.
  *
  * nbr
- *    ospf neighbour which requets the router to act as
+ *    OSPF neighbour which requests the router to act as
  *    HELPER.
  *
  * Returns:
@@ -778,7 +803,7 @@ void ospf_process_maxage_grace_lsa(struct ospf *ospf, struct ospf_lsa *lsa,
  * Disable/Enable HELPER support on router level.
  *
  * ospf
- *    OSPFpointer.
+ *    OSPF pointer.
  *
  * status
  *    TRUE/FALSE
@@ -819,7 +844,7 @@ void ospf_gr_helper_support_set(struct ospf *ospf, bool support)
                                lookup.advRtrAddr.s_addr =
                                        nbr->router_id.s_addr;
                                /* check if helper support enabled for the
-                                * correspodning routerid.If enabled, dont
+                                * corresponding routerid.If enabled, dont
                                 * dont exit from helper role.
                                 */
                                if (hash_lookup(ospf->enable_rtr_list, &lookup))
@@ -995,72 +1020,115 @@ static void show_ospf_grace_lsa_info(struct vty *vty, struct ospf_lsa *lsa)
        lsah = (struct lsa_header *)lsa->data;
 
        if (lsa->size <= OSPF_LSA_HEADER_SIZE) {
-               vty_out(vty, "%% Invalid LSA length: %d\n", length);
+               if (vty)
+                       vty_out(vty, "%% Invalid LSA length: %d\n", length);
+               else
+                       zlog_debug("%% Invalid LSA length: %d", length);
                return;
        }
 
        length = lsa->size - OSPF_LSA_HEADER_SIZE;
 
-       vty_out(vty, "  TLV info:\n");
+       if (vty)
+               vty_out(vty, "  TLV info:\n");
+       else
+               zlog_debug("  TLV info:");
 
        for (tlvh = TLV_HDR_TOP(lsah); sum < length && tlvh;
             tlvh = TLV_HDR_NEXT(tlvh)) {
                /* Check TLV len */
                if (sum + TLV_SIZE(tlvh) > length) {
-                       vty_out(vty, "%% Invalid TLV length: %u\n",
-                               TLV_SIZE(tlvh));
+                       if (vty)
+                               vty_out(vty, "%% Invalid TLV length: %u\n",
+                                       TLV_SIZE(tlvh));
+                       else
+                               zlog_debug("%% Invalid TLV length: %u",
+                                          TLV_SIZE(tlvh));
                        return;
                }
 
                switch (ntohs(tlvh->type)) {
                case GRACE_PERIOD_TYPE:
-                       if (TLV_SIZE(tlvh) <
-                           sizeof(struct grace_tlv_graceperiod)) {
-                               vty_out(vty,
-                                       "%% Invalid grace TLV length %u\n",
-                                       TLV_SIZE(tlvh));
+                       if (TLV_SIZE(tlvh)
+                           < sizeof(struct grace_tlv_graceperiod)) {
+                               if (vty)
+                                       vty_out(vty,
+                                               "%% Invalid grace TLV length %u\n",
+                                               TLV_SIZE(tlvh));
+                               else
+                                       zlog_debug(
+                                               "%% Invalid grace TLV length %u",
+                                               TLV_SIZE(tlvh));
                                return;
                        }
 
                        gracePeriod = (struct grace_tlv_graceperiod *)tlvh;
                        sum += TLV_SIZE(tlvh);
 
-                       vty_out(vty, "   Grace period:%d\n",
-                               ntohl(gracePeriod->interval));
+                       if (vty)
+                               vty_out(vty, "   Grace period:%d\n",
+                                       ntohl(gracePeriod->interval));
+                       else
+                               zlog_debug("   Grace period:%d",
+                                          ntohl(gracePeriod->interval));
                        break;
                case RESTART_REASON_TYPE:
-                       if (TLV_SIZE(tlvh) <
-                           sizeof(struct grace_tlv_restart_reason)) {
-                               vty_out(vty,
-                                       "%% Invalid reason TLV length %u\n",
-                                       TLV_SIZE(tlvh));
+                       if (TLV_SIZE(tlvh)
+                           < sizeof(struct grace_tlv_restart_reason)) {
+                               if (vty)
+                                       vty_out(vty,
+                                               "%% Invalid reason TLV length %u\n",
+                                               TLV_SIZE(tlvh));
+                               else
+                                       zlog_debug(
+                                               "%% Invalid reason TLV length %u",
+                                               TLV_SIZE(tlvh));
                                return;
                        }
 
                        grReason = (struct grace_tlv_restart_reason *)tlvh;
                        sum += TLV_SIZE(tlvh);
 
-                       vty_out(vty, "   Restart reason:%s\n",
-                               ospf_restart_reason2str(grReason->reason));
+                       if (vty)
+                               vty_out(vty, "   Restart reason:%s\n",
+                                       ospf_restart_reason2str(
+                                               grReason->reason));
+                       else
+                               zlog_debug("   Restart reason:%s",
+                                          ospf_restart_reason2str(
+                                                  grReason->reason));
                        break;
                case RESTARTER_IP_ADDR_TYPE:
-                       if (TLV_SIZE(tlvh) <
-                           sizeof(struct grace_tlv_restart_addr)) {
-                               vty_out(vty,
-                                       "%% Invalid addr TLV length %u\n",
-                                       TLV_SIZE(tlvh));
+                       if (TLV_SIZE(tlvh)
+                           < sizeof(struct grace_tlv_restart_addr)) {
+                               if (vty)
+                                       vty_out(vty,
+                                               "%% Invalid addr TLV length %u\n",
+                                               TLV_SIZE(tlvh));
+                               else
+                                       zlog_debug(
+                                               "%% Invalid addr TLV length %u",
+                                               TLV_SIZE(tlvh));
                                return;
                        }
 
                        restartAddr = (struct grace_tlv_restart_addr *)tlvh;
                        sum += TLV_SIZE(tlvh);
 
-                       vty_out(vty, "   Restarter address:%pI4\n",
-                               &restartAddr->addr);
+                       if (vty)
+                               vty_out(vty, "   Restarter address:%pI4\n",
+                                       &restartAddr->addr);
+                       else
+                               zlog_debug("   Restarter address:%pI4",
+                                          &restartAddr->addr);
                        break;
                default:
-                       vty_out(vty, "   Unknown TLV type %d\n",
-                               ntohs(tlvh->type));
+                       if (vty)
+                               vty_out(vty, "   Unknown TLV type %d\n",
+                                       ntohs(tlvh->type));
+                       else
+                               zlog_debug("   Unknown TLV type %d",
+                                          ntohs(tlvh->type));
 
                        break;
                }
index c355bb4f3d65027c4552abc02d3b3359a20b108a..bd6d1d74622e41386ebd4d5ae319a51a24303adb 100644 (file)
@@ -156,8 +156,10 @@ const char *ospf_exit_reason2str(unsigned int reason);
 const char *ospf_restart_reason2str(unsigned int reason);
 const char *ospf_rejected_reason2str(unsigned int reason);
 
-extern void ospf_gr_helper_init(struct ospf *ospf);
-extern void ospf_gr_helper_stop(struct ospf *ospf);
+extern void ospf_gr_helper_instance_init(struct ospf *ospf);
+extern void ospf_gr_helper_instance_stop(struct ospf *ospf);
+extern void ospf_gr_helper_init(void);
+extern void ospf_gr_helper_stop(void);
 extern int ospf_process_grace_lsa(struct ospf *ospf, struct ospf_lsa *lsa,
                                  struct ospf_neighbor *nbr);
 extern void ospf_gr_helper_exit(struct ospf_neighbor *nbr,
index 72dc699bd989fd5ea5a47a6f4b35b35ec0e92e53..c850df55bb5892a4799f601d5bd619810ed22a1b 100644 (file)
@@ -2084,6 +2084,8 @@ void ospf_external_lsa_rid_change(struct ospf *ospf)
 {
        struct external_info *ei;
        struct ospf_external_aggr_rt *aggr;
+       struct ospf_lsa *lsa = NULL;
+       int force;
        int type;
 
        for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
@@ -2112,24 +2114,48 @@ void ospf_external_lsa_rid_change(struct ospf *ospf)
                                        continue;
 
                                if (is_prefix_default(
-                                               (struct prefix_ipv4 *)&ei->p))
+                                           (struct prefix_ipv4 *)&ei->p))
                                        continue;
 
-                               if (!ospf_redistribute_check(ospf, ei, NULL))
-                                       continue;
+                               lsa = ospf_external_info_find_lsa(ospf, &ei->p);
 
                                aggr = ospf_external_aggr_match(ospf, &ei->p);
                                if (aggr) {
+
+                                       if (!ospf_redistribute_check(ospf, ei,
+                                                                    NULL))
+                                               continue;
+
                                        if (IS_DEBUG_OSPF(lsa, EXTNL_LSA_AGGR))
                                                zlog_debug(
                                                        "Originate Summary LSA after reset/router-ID change");
+
                                        /* Here the LSA is originated as new */
                                        ospf_originate_summary_lsa(ospf, aggr,
                                                                   ei);
-                               } else if (!ospf_external_lsa_originate(ospf,
-                                                                       ei))
-                                       flog_warn(EC_OSPF_LSA_INSTALL_FAILURE,
-                                                 "LSA: AS-external-LSA was not originated.");
+                               } else if (lsa) {
+                                       /* LSA needs to be refreshed even if
+                                        * there is no change in the route
+                                        * params if the LSA is in maxage.
+                                        */
+                                       if (IS_LSA_MAXAGE(lsa))
+                                               force = LSA_REFRESH_FORCE;
+                                       else
+                                               force = LSA_REFRESH_IF_CHANGED;
+
+                                       ospf_external_lsa_refresh(ospf, lsa,
+                                                               ei, force, 0);
+                               } else {
+                                       if (!ospf_redistribute_check(ospf, ei,
+                                                                    NULL))
+                                               continue;
+
+                                       if (!ospf_external_lsa_originate(ospf,
+                                                                        NULL))
+                                               flog_warn(
+                                                       EC_OSPF_LSA_INSTALL_FAILURE,
+                                                       "LSA: AS-external-LSA was not originated.");
+                               }
                        }
                }
        }
@@ -2670,15 +2696,16 @@ struct ospf_lsa *ospf_lsa_install(struct ospf *ospf, struct ospf_interface *oi,
 
                        if (IS_DEBUG_OSPF(lsa, LSA_REFRESH)) {
                                zlog_debug(
-                                       "ospf_lsa_install() Premature Aging lsa 0x%p, seqnum 0x%x",
-                                       (void *)lsa,
+                                       "%s() Premature Aging lsa %p, seqnum 0x%x",
+                                       __func__, lsa,
                                        ntohl(lsa->data->ls_seqnum));
                                ospf_lsa_header_dump(lsa->data);
                        }
                } else {
                        if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) {
                                zlog_debug(
-                                       "ospf_lsa_install() got an lsa with seq 0x80000000 that was not self originated. Ignoring");
+                                       "%s() got an lsa with seq 0x80000000 that was not self originated. Ignoring",
+                                       __func__);
                                ospf_lsa_header_dump(lsa->data);
                        }
                        return old;
@@ -2764,9 +2791,8 @@ struct ospf_lsa *ospf_lsa_install(struct ospf *ospf, struct ospf_interface *oi,
         */
        if (IS_LSA_MAXAGE(new)) {
                if (IS_DEBUG_OSPF(lsa, LSA_INSTALL))
-                       zlog_debug("LSA[Type%d:%pI4]: Install LSA 0x%p, MaxAge",
-                                  new->data->type, &new->data->id,
-                                  (void *)lsa);
+                       zlog_debug("LSA[Type%d:%pI4]: Install LSA %p, MaxAge",
+                                  new->data->type, &new->data->id, lsa);
                ospf_lsa_maxage(ospf, lsa);
        }
 
@@ -2855,8 +2881,8 @@ static int ospf_maxage_lsa_remover(struct thread *thread)
                        if (CHECK_FLAG(lsa->flags, OSPF_LSA_PREMATURE_AGE)) {
                                if (IS_DEBUG_OSPF(lsa, LSA_FLOODING))
                                        zlog_debug(
-                                               "originating new lsa for lsa 0x%p",
-                                               (void *)lsa);
+                                               "originating new lsa for lsa %p",
+                                               lsa);
                                ospf_lsa_refresh(ospf, lsa);
                        }
 
index 91ba3044fe5fe018ed9bab7cc1586fbc942b4453..d94de129942f5c870dd9171b3a0fd3450a380fb6 100644 (file)
@@ -225,6 +225,7 @@ int main(int argc, char **argv)
 
        ospf_route_map_init();
        ospf_opaque_init();
+       ospf_gr_helper_init();
 
        /* OSPF errors init */
        ospf_error_init();
index a1b35b2fcd2bd912fc99fc16c3ef4d681373505f..8725497f2de9cd110cb8ba70667fc8fb79410f3e 100644 (file)
@@ -407,6 +407,9 @@ void ospf_renegotiate_optional_capabilities(struct ospf *top)
                }
        }
 
+       /* Refresh/Re-originate external LSAs (Type-7 and Type-5).*/
+       ospf_external_lsa_rid_change(top);
+
        return;
 }
 
index 42bf914f6755f3eed63de27858f5add4cf31a045..fac2f97141b5b78fcad95021316ee74bdceec060 100644 (file)
@@ -2119,15 +2119,12 @@ void ospf_opaque_lsa_flush_schedule(struct ospf_lsa *lsa0)
                goto out;
        }
 
+       /* This lsa will be flushed and removed eventually. */
+       ospf_lsa_flush(top, lsa);
+
        /* Dequeue listnode entry from the list. */
        listnode_delete(oipt->id_list, oipi);
 
-       /* Disassociate internal control information with the given lsa. */
-       free_opaque_info_per_id((void *)oipi);
-
-       /* Force given lsa's age to MaxAge. */
-       lsa->data->ls_age = htons(OSPF_LSA_MAXAGE);
-
        if (IS_DEBUG_OSPF_EVENT)
                zlog_debug(
                        "Schedule Type-%u Opaque-LSA to FLUSH: [opaque-type=%u, opaque-id=%x]",
@@ -2135,8 +2132,8 @@ void ospf_opaque_lsa_flush_schedule(struct ospf_lsa *lsa0)
                        GET_OPAQUE_TYPE(ntohl(lsa->data->id.s_addr)),
                        GET_OPAQUE_ID(ntohl(lsa->data->id.s_addr)));
 
-       /* This lsa will be flushed and removed eventually. */
-       ospf_lsa_flush(top, lsa);
+       /* Disassociate internal control information with the given lsa. */
+       free_opaque_info_per_id((void *)oipi);
 
 out:
        return;
index 2de6731758cd42315e41b2fa4bf145254cc8fd0f..580eee13cf0815117d1934f5f9030c7caddf25fd 100644 (file)
@@ -1862,9 +1862,9 @@ static void ospf_ls_upd(struct ospf *ospf, struct ip *iph,
                return;
        }
 
-       /* Get list of LSAs from Link State Update packet. - Also perorms Stages
-        * 1 (validate LSA checksum) and 2 (check for LSA consistent type)
-        * of section 13.
+       /* Get list of LSAs from Link State Update packet. - Also performs
+        * Stages 1 (validate LSA checksum) and 2 (check for LSA consistent
+        * type) of section 13.
         */
        lsas = ospf_ls_upd_list_lsa(nbr, s, oi, size);
 
@@ -1890,7 +1890,7 @@ static void ospf_ls_upd(struct ospf *ospf, struct ip *iph,
                struct ospf_lsa *ls_ret, *current;
                int ret = 1;
 
-               if (IS_DEBUG_OSPF_NSSA)
+               if (IS_DEBUG_OSPF(lsa, LSA))
                        zlog_debug("LSA Type-%d from %pI4, ID: %pI4, ADV: %pI4",
                                   lsa->data->type, &ospfh->router_id,
                                   &lsa->data->id, &lsa->data->adv_router);
index d3b114840ee2e38a1d0cb5ce43a6bd836cbc53c3..2525c1cf3ac2a9cf10628493517357022497f0b8 100644 (file)
@@ -71,19 +71,14 @@ static void ospf_route_map_update(const char *name)
                                        /* Keep old route-map. */
                                        struct route_map *old = ROUTEMAP(red);
 
-                                       if (!old) {
-                                               /* Route-map creation */
-                                               /* Update route-map. */
-                                               ROUTEMAP(red) =
-                                                       route_map_lookup_by_name(
-                                                               ROUTEMAP_NAME(red));
-
-                                                       route_map_counter_increment(
-                                                               ROUTEMAP(red));
-                                       } else {
-                                               /* Route-map deletion */
-                                               ROUTEMAP(red) = NULL;
-                                       }
+                                       ROUTEMAP(red) =
+                                               route_map_lookup_by_name(
+                                                       ROUTEMAP_NAME(red));
+
+                                       if (!old)
+                                               route_map_counter_increment(
+                                                       ROUTEMAP(red));
+
                                        /* No update for this distribute type.
                                         */
                                        if (old == NULL
index 3849d4b7eadd2d0f0bc5cf870ba6e74799bba600..43d6ff44ba0e6194ed8221cd9688cda6f2186f0d 100644 (file)
@@ -1889,19 +1889,19 @@ static int ospf_spf_calculate_schedule_worker(struct thread *thread)
 
        rbuf[0] = '\0';
        if (spf_reason_flags) {
-               if (spf_reason_flags & SPF_FLAG_ROUTER_LSA_INSTALL)
+               if (spf_reason_flags & (1 << SPF_FLAG_ROUTER_LSA_INSTALL))
                        strlcat(rbuf, "R, ", sizeof(rbuf));
-               if (spf_reason_flags & SPF_FLAG_NETWORK_LSA_INSTALL)
+               if (spf_reason_flags & (1 << SPF_FLAG_NETWORK_LSA_INSTALL))
                        strlcat(rbuf, "N, ", sizeof(rbuf));
-               if (spf_reason_flags & SPF_FLAG_SUMMARY_LSA_INSTALL)
+               if (spf_reason_flags & (1 << SPF_FLAG_SUMMARY_LSA_INSTALL))
                        strlcat(rbuf, "S, ", sizeof(rbuf));
-               if (spf_reason_flags & SPF_FLAG_ASBR_SUMMARY_LSA_INSTALL)
+               if (spf_reason_flags & (1 << SPF_FLAG_ASBR_SUMMARY_LSA_INSTALL))
                        strlcat(rbuf, "AS, ", sizeof(rbuf));
-               if (spf_reason_flags & SPF_FLAG_ABR_STATUS_CHANGE)
+               if (spf_reason_flags & (1 << SPF_FLAG_ABR_STATUS_CHANGE))
                        strlcat(rbuf, "ABR, ", sizeof(rbuf));
-               if (spf_reason_flags & SPF_FLAG_ASBR_STATUS_CHANGE)
+               if (spf_reason_flags & (1 << SPF_FLAG_ASBR_STATUS_CHANGE))
                        strlcat(rbuf, "ASBR, ", sizeof(rbuf));
-               if (spf_reason_flags & SPF_FLAG_MAXAGE)
+               if (spf_reason_flags & (1 << SPF_FLAG_MAXAGE))
                        strlcat(rbuf, "M, ", sizeof(rbuf));
 
                size_t rbuflen = strlen(rbuf);
index fb2d790532ba5fc35b60221c8989e1ba6ca849b7..54ce248d89efe5225ffc0ffb9ac7b37bcec52922 100644 (file)
@@ -362,88 +362,79 @@ DEFPY (no_ospf_router_id,
 }
 
 
-static void ospf_passive_interface_default(struct ospf *ospf, uint8_t newval)
+static void ospf_passive_interface_default_update(struct ospf *ospf,
+                                                 uint8_t newval)
 {
-       struct vrf *vrf = vrf_lookup_by_id(ospf->vrf_id);
        struct listnode *ln;
-       struct interface *ifp;
        struct ospf_interface *oi;
 
        ospf->passive_interface_default = newval;
 
-       FOR_ALL_INTERFACES (vrf, ifp) {
-               if (ifp && OSPF_IF_PARAM_CONFIGURED(IF_DEF_PARAMS(ifp),
-                                                   passive_interface))
-                       UNSET_IF_PARAM(IF_DEF_PARAMS(ifp), passive_interface);
-       }
-       for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, ln, oi)) {
-               if (OSPF_IF_PARAM_CONFIGURED(oi->params, passive_interface))
-                       UNSET_IF_PARAM(oi->params, passive_interface);
-               /* update multicast memberships */
+       /* update multicast memberships */
+       for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, ln, oi))
                ospf_if_set_multicast(oi);
-       }
 }
 
-static void ospf_passive_interface_update_addr(struct ospf *ospf,
-                                              struct interface *ifp,
-                                              struct ospf_if_params *params,
-                                              uint8_t value,
-                                              struct in_addr addr)
+static void ospf_passive_interface_update(struct interface *ifp)
 {
-       uint8_t dflt;
+       struct route_node *rn;
 
-       params->passive_interface = value;
-       if (params != IF_DEF_PARAMS(ifp)) {
-               if (OSPF_IF_PARAM_CONFIGURED(IF_DEF_PARAMS(ifp),
-                                            passive_interface))
-                       dflt = IF_DEF_PARAMS(ifp)->passive_interface;
-               else
-                       dflt = ospf->passive_interface_default;
+       /*
+        * XXX We should call ospf_if_set_multicast on exactly those
+        * interfaces for which the passive property changed.  It is too much
+        * work to determine this set, so we do this for every interface.
+        * This is safe and reasonable because ospf_if_set_multicast uses a
+        * record of joined groups to avoid systems calls if the desired
+        * memberships match the current memership.
+        */
 
-               if (value != dflt)
-                       SET_IF_PARAM(params, passive_interface);
-               else
-                       UNSET_IF_PARAM(params, passive_interface);
+       for (rn = route_top(IF_OIFS(ifp)); rn; rn = route_next(rn)) {
+               struct ospf_interface *oi = rn->info;
 
-               ospf_free_if_params(ifp, addr);
-               ospf_if_update_params(ifp, addr);
+               if (oi)
+                       ospf_if_set_multicast(oi);
        }
+
+       /*
+        * XXX It is not clear what state transitions the interface needs to
+        * undergo when going from active to passive and vice versa. Fixing
+        * this will require precise identification of interfaces having such a
+        * transition.
+        */
 }
 
-static void ospf_passive_interface_update(struct ospf *ospf,
-                                         struct interface *ifp,
-                                         struct ospf_if_params *params,
-                                         uint8_t value)
+DEFUN (ospf_passive_interface_default,
+       ospf_passive_interface_default_cmd,
+       "passive-interface default",
+       "Suppress routing updates on an interface\n"
+       "Suppress routing updates on interfaces by default\n")
 {
-       params->passive_interface = value;
-       if (params == IF_DEF_PARAMS(ifp)) {
-               if (value != ospf->passive_interface_default)
-                       SET_IF_PARAM(params, passive_interface);
-               else
-                       UNSET_IF_PARAM(params, passive_interface);
-       }
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
+
+       ospf_passive_interface_default_update(ospf, OSPF_IF_PASSIVE);
+
+       return CMD_SUCCESS;
 }
 
-DEFUN (ospf_passive_interface,
+DEFUN_HIDDEN (ospf_passive_interface_addr,
        ospf_passive_interface_addr_cmd,
-       "passive-interface <IFNAME [A.B.C.D]|default>",
+       "passive-interface IFNAME [A.B.C.D]",
        "Suppress routing updates on an interface\n"
        "Interface's name\n"
-       "IPv4 address\n"
-       "Suppress routing updates on interfaces by default\n")
+       "IPv4 address\n")
 {
        VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_ipv4 = 2;
        struct interface *ifp = NULL;
        struct in_addr addr = {.s_addr = INADDR_ANY};
-       int ret;
        struct ospf_if_params *params;
-       struct route_node *rn;
+       int ret;
+
+       vty_out(vty,
+               "This command is deprecated, because it is not VRF-aware.\n");
+       vty_out(vty,
+               "Please, use \"ip ospf passive\" on an interface instead.\n");
 
-       if (strmatch(argv[1]->text, "default")) {
-               ospf_passive_interface_default(ospf, OSPF_IF_PASSIVE);
-               return CMD_SUCCESS;
-       }
        if (ospf->vrf_id != VRF_UNKNOWN)
                ifp = if_get_by_name(argv[1]->arg, ospf->vrf_id);
 
@@ -452,8 +443,6 @@ DEFUN (ospf_passive_interface,
                return CMD_WARNING_CONFIG_FAILED;
        }
 
-       params = IF_DEF_PARAMS(ifp);
-
        if (argc == 3) {
                ret = inet_aton(argv[idx_ipv4]->arg, &addr);
                if (!ret) {
@@ -464,45 +453,39 @@ DEFUN (ospf_passive_interface,
 
                params = ospf_get_if_params(ifp, addr);
                ospf_if_update_params(ifp, addr);
-               ospf_passive_interface_update_addr(ospf, ifp, params,
-                                                  OSPF_IF_PASSIVE, addr);
+       } else {
+               params = IF_DEF_PARAMS(ifp);
        }
 
-       ospf_passive_interface_update(ospf, ifp, params, OSPF_IF_PASSIVE);
+       params->passive_interface = OSPF_IF_PASSIVE;
+       SET_IF_PARAM(params, passive_interface);
 
-       /* XXX We should call ospf_if_set_multicast on exactly those
-        * interfaces for which the passive property changed.  It is too much
-        * work to determine this set, so we do this for every interface.
-        * This is safe and reasonable because ospf_if_set_multicast uses a
-        * record of joined groups to avoid systems calls if the desired
-        * memberships match the current memership.
-        */
+       ospf_passive_interface_update(ifp);
 
-       for (rn = route_top(IF_OIFS(ifp)); rn; rn = route_next(rn)) {
-               struct ospf_interface *oi = rn->info;
+       return CMD_SUCCESS;
+}
 
-               if (oi && (OSPF_IF_PARAM(oi, passive_interface)
-                          == OSPF_IF_PASSIVE))
-                       ospf_if_set_multicast(oi);
-       }
-       /*
-        * XXX It is not clear what state transitions the interface needs to
-        * undergo when going from active to passive.  Fixing this will
-        * require precise identification of interfaces having such a
-        * transition.
-        */
+DEFUN (no_ospf_passive_interface_default,
+       no_ospf_passive_interface_default_cmd,
+       "no passive-interface default",
+       NO_STR
+       "Allow routing updates on an interface\n"
+       "Allow routing updates on interfaces by default\n")
+{
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
+
+       ospf_passive_interface_default_update(ospf, OSPF_IF_ACTIVE);
 
        return CMD_SUCCESS;
 }
 
-DEFUN (no_ospf_passive_interface,
+DEFUN_HIDDEN (no_ospf_passive_interface,
        no_ospf_passive_interface_addr_cmd,
-       "no passive-interface <IFNAME [A.B.C.D]|default>",
+       "no passive-interface IFNAME [A.B.C.D]",
        NO_STR
        "Allow routing updates on an interface\n"
        "Interface's name\n"
-       "IPv4 address\n"
-       "Allow routing updates on interfaces by default\n")
+       "IPv4 address\n")
 {
        VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        int idx_ipv4 = 3;
@@ -510,12 +493,11 @@ DEFUN (no_ospf_passive_interface,
        struct in_addr addr = {.s_addr = INADDR_ANY};
        struct ospf_if_params *params;
        int ret;
-       struct route_node *rn;
 
-       if (strmatch(argv[2]->text, "default")) {
-               ospf_passive_interface_default(ospf, OSPF_IF_ACTIVE);
-               return CMD_SUCCESS;
-       }
+       vty_out(vty,
+               "This command is deprecated, because it is not VRF-aware.\n");
+       vty_out(vty,
+               "Please, use \"no ip ospf passive\" on an interface instead.\n");
 
        if (ospf->vrf_id != VRF_UNKNOWN)
                ifp = if_get_by_name(argv[2]->arg, ospf->vrf_id);
@@ -525,8 +507,6 @@ DEFUN (no_ospf_passive_interface,
                return CMD_WARNING_CONFIG_FAILED;
        }
 
-       params = IF_DEF_PARAMS(ifp);
-
        if (argc == 4) {
                ret = inet_aton(argv[idx_ipv4]->arg, &addr);
                if (!ret) {
@@ -534,30 +514,22 @@ DEFUN (no_ospf_passive_interface,
                                "Please specify interface address by A.B.C.D\n");
                        return CMD_WARNING_CONFIG_FAILED;
                }
-
                params = ospf_lookup_if_params(ifp, addr);
                if (params == NULL)
                        return CMD_SUCCESS;
-               ospf_passive_interface_update_addr(ospf, ifp, params,
-                                                  OSPF_IF_ACTIVE, addr);
+       } else {
+               params = IF_DEF_PARAMS(ifp);
        }
-       ospf_passive_interface_update(ospf, ifp, params, OSPF_IF_ACTIVE);
 
-       /* XXX We should call ospf_if_set_multicast on exactly those
-        * interfaces for which the passive property changed.  It is too much
-        * work to determine this set, so we do this for every interface.
-        * This is safe and reasonable because ospf_if_set_multicast uses a
-        * record of joined groups to avoid systems calls if the desired
-        * memberships match the current memership.
-        */
-       for (rn = route_top(IF_OIFS(ifp)); rn; rn = route_next(rn)) {
-               struct ospf_interface *oi = rn->info;
-
-               if (oi
-                   && (OSPF_IF_PARAM(oi, passive_interface) == OSPF_IF_ACTIVE))
-                       ospf_if_set_multicast(oi);
+       params->passive_interface = OSPF_IF_ACTIVE;
+       UNSET_IF_PARAM(params, passive_interface);
+       if (params != IF_DEF_PARAMS(ifp)) {
+               ospf_free_if_params(ifp, addr);
+               ospf_if_update_params(ifp, addr);
        }
 
+       ospf_passive_interface_update(ifp);
+
        return CMD_SUCCESS;
 }
 
@@ -4435,21 +4407,27 @@ static void show_ip_ospf_neighbor_sub(struct vty *vty,
 
                                ospf_nbr_state_message(nbr, msgbuf, 16);
 
-                               long time_store;
-
-                               time_store =
-                                       monotime_until(
-                                               &nbr->t_inactivity->u.sands,
-                                               NULL)
-                                       / 1000LL;
-
                                json_object_int_add(json_neighbor, "priority",
                                                    nbr->priority);
                                json_object_string_add(json_neighbor, "state",
                                                       msgbuf);
-                               json_object_int_add(json_neighbor,
-                                                   "deadTimeMsecs",
-                                                   time_store);
+
+                               if (nbr->t_inactivity) {
+                                       long time_store;
+
+                                       time_store = monotime_until(
+                                                            &nbr->t_inactivity
+                                                                     ->u.sands,
+                                                            NULL)
+                                                    / 1000LL;
+                                       json_object_int_add(json_neighbor,
+                                                           "deadTimeMsecs",
+                                                           time_store);
+                               } else {
+                                       json_object_string_add(json_neighbor,
+                                                              "deadTimeMsecs",
+                                                              "inactive");
+                               }
                                json_object_string_add(
                                        json_neighbor, "address",
                                        inet_ntop(AF_INET, &nbr->src,
@@ -9094,6 +9072,82 @@ DEFUN (no_ip_ospf_area,
        return CMD_SUCCESS;
 }
 
+DEFUN (ip_ospf_passive,
+       ip_ospf_passive_cmd,
+       "ip ospf passive [A.B.C.D]",
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Suppress routing updates on an interface\n"
+       "Address of interface\n")
+{
+       VTY_DECLVAR_CONTEXT(interface, ifp);
+       int idx_ipv4 = 3;
+       struct in_addr addr;
+       struct ospf_if_params *params;
+       int ret;
+
+       if (argc == 4) {
+               ret = inet_aton(argv[idx_ipv4]->arg, &addr);
+               if (!ret) {
+                       vty_out(vty,
+                               "Please specify interface address by A.B.C.D\n");
+                       return CMD_WARNING_CONFIG_FAILED;
+               }
+               params = ospf_get_if_params(ifp, addr);
+               ospf_if_update_params(ifp, addr);
+       } else {
+               params = IF_DEF_PARAMS(ifp);
+       }
+
+       params->passive_interface = OSPF_IF_PASSIVE;
+       SET_IF_PARAM(params, passive_interface);
+
+       ospf_passive_interface_update(ifp);
+
+       return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_ospf_passive,
+       no_ip_ospf_passive_cmd,
+       "no ip ospf passive [A.B.C.D]",
+       NO_STR
+       "IP Information\n"
+       "OSPF interface commands\n"
+       "Enable routing updates on an interface\n"
+       "Address of interface\n")
+{
+       VTY_DECLVAR_CONTEXT(interface, ifp);
+       int idx_ipv4 = 4;
+       struct in_addr addr;
+       struct ospf_if_params *params;
+       int ret;
+
+       if (argc == 5) {
+               ret = inet_aton(argv[idx_ipv4]->arg, &addr);
+               if (!ret) {
+                       vty_out(vty,
+                               "Please specify interface address by A.B.C.D\n");
+                       return CMD_WARNING_CONFIG_FAILED;
+               }
+               params = ospf_lookup_if_params(ifp, addr);
+               if (params == NULL)
+                       return CMD_SUCCESS;
+       } else {
+               params = IF_DEF_PARAMS(ifp);
+       }
+
+       params->passive_interface = OSPF_IF_ACTIVE;
+       UNSET_IF_PARAM(params, passive_interface);
+       if (params != IF_DEF_PARAMS(ifp)) {
+               ospf_free_if_params(ifp, addr);
+               ospf_if_update_params(ifp, addr);
+       }
+
+       ospf_passive_interface_update(ifp);
+
+       return CMD_SUCCESS;
+}
+
 DEFUN (ospf_redistribute_source,
        ospf_redistribute_source_cmd,
        "redistribute " FRR_REDIST_STR_OSPFD " [{metric (0-16777214)|metric-type (1-2)|route-map WORD}]",
@@ -11865,6 +11919,14 @@ static int config_write_interface_one(struct vty *vty, struct vrf *vrf)
                                vty_out(vty, "\n");
                        }
 
+                       if (OSPF_IF_PARAM_CONFIGURED(params,
+                                                    passive_interface)) {
+                               vty_out(vty, " ip ospf passive");
+                               if (params != IF_DEF_PARAMS(ifp) && rn)
+                                       vty_out(vty, " %pI4", &rn->p.u.prefix4);
+                               vty_out(vty, "\n");
+                       }
+
                        /* LDP-Sync print */
                        if (params && params->ldp_sync_info)
                                ospf_ldp_sync_if_write_config(vty, params);
@@ -12312,10 +12374,6 @@ static int config_write_ospf_distance(struct vty *vty, struct ospf *ospf)
 
 static int ospf_config_write_one(struct vty *vty, struct ospf *ospf)
 {
-       struct vrf *vrf = vrf_lookup_by_id(ospf->vrf_id);
-       struct interface *ifp;
-       struct ospf_interface *oi;
-       struct listnode *node = NULL;
        int write = 0;
 
        /* `router ospf' print. */
@@ -12418,33 +12476,6 @@ static int ospf_config_write_one(struct vty *vty, struct ospf *ospf)
                        vty_out(vty, " no proactive-arp\n");
        }
 
-       FOR_ALL_INTERFACES (vrf, ifp)
-               if (OSPF_IF_PARAM_CONFIGURED(IF_DEF_PARAMS(ifp),
-                                            passive_interface)
-                   && IF_DEF_PARAMS(ifp)->passive_interface
-                              != ospf->passive_interface_default) {
-                       vty_out(vty, " %spassive-interface %s\n",
-                               IF_DEF_PARAMS(ifp)->passive_interface ? ""
-                                                                     : "no ",
-                               ifp->name);
-               }
-       for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi)) {
-               if (!OSPF_IF_PARAM_CONFIGURED(oi->params, passive_interface))
-                       continue;
-               if (OSPF_IF_PARAM_CONFIGURED(IF_DEF_PARAMS(oi->ifp),
-                                            passive_interface)) {
-                       if (oi->params->passive_interface
-                           == IF_DEF_PARAMS(oi->ifp)->passive_interface)
-                               continue;
-               } else if (oi->params->passive_interface
-                          == ospf->passive_interface_default)
-                       continue;
-
-               vty_out(vty, " %spassive-interface %s %pI4\n",
-                       oi->params->passive_interface ? "" : "no ",
-                       oi->ifp->name, &oi->address->u.prefix4);
-       }
-
        /* TI-LFA print. */
        if (ospf->ti_lfa_enabled) {
                if (ospf->ti_lfa_protection_type == OSPF_TI_LFA_NODE_PROTECTION)
@@ -12639,6 +12670,10 @@ static void ospf_vty_if_init(void)
        install_element(INTERFACE_NODE, &ip_ospf_area_cmd);
        install_element(INTERFACE_NODE, &no_ip_ospf_area_cmd);
 
+       /* "ip ospf passive" commands. */
+       install_element(INTERFACE_NODE, &ip_ospf_passive_cmd);
+       install_element(INTERFACE_NODE, &no_ip_ospf_passive_cmd);
+
        /* These commands are compatibitliy for previous version. */
        install_element(INTERFACE_NODE, &ospf_authentication_key_cmd);
        install_element(INTERFACE_NODE, &ospf_message_digest_key_cmd);
@@ -12798,7 +12833,9 @@ void ospf_vty_init(void)
        install_element(OSPF_NODE, &no_ospf_router_id_cmd);
 
        /* "passive-interface" commands. */
+       install_element(OSPF_NODE, &ospf_passive_interface_default_cmd);
        install_element(OSPF_NODE, &ospf_passive_interface_addr_cmd);
+       install_element(OSPF_NODE, &no_ospf_passive_interface_default_cmd);
        install_element(OSPF_NODE, &no_ospf_passive_interface_addr_cmd);
 
        /* "ospf abr-type" commands. */
@@ -12922,6 +12959,8 @@ void ospf_vty_init(void)
        install_element(OSPF_NODE, &ospf_max_multipath_cmd);
        install_element(OSPF_NODE, &no_ospf_max_multipath_cmd);
 
+       vrf_cmd_init(NULL, &ospfd_privs);
+
        /* Init interface related vty commands. */
        ospf_vty_if_init();
 
index 38c0ca2b67deff4e36ca238f0b5c99a434ca3179..e95ee55e68bdf8c8a4de4eb881f9eeb0ab3decee 100644 (file)
@@ -386,7 +386,7 @@ struct ospf *ospf_new_alloc(unsigned short instance, const char *name)
 
        new->proactive_arp = OSPF_PROACTIVE_ARP_DEFAULT;
 
-       ospf_gr_helper_init(new);
+       ospf_gr_helper_instance_init(new);
 
        ospf_asbr_external_aggregator_init(new);
 
@@ -651,6 +651,9 @@ void ospf_terminate(void)
        for (ALL_LIST_ELEMENTS(om->ospf, node, nnode, ospf))
                ospf_finish(ospf);
 
+       /* Cleanup GR */
+       ospf_gr_helper_stop();
+
        /* Cleanup route maps */
        route_map_finish();
 
@@ -692,7 +695,6 @@ static void ospf_finish_final(struct ospf *ospf)
        struct route_node *rn;
        struct ospf_nbr_nbma *nbr_nbma;
        struct ospf_lsa *lsa;
-       struct interface *ifp;
        struct ospf_interface *oi;
        struct ospf_area *area;
        struct ospf_vl_data *vl_data;
@@ -740,15 +742,6 @@ static void ospf_finish_final(struct ospf *ospf)
        if (ospf->vrf_id == VRF_DEFAULT)
                ospf_ldp_sync_gbl_exit(ospf, true);
 
-       /* Remove ospf interface config params: only passive-interface */
-       FOR_ALL_INTERFACES (vrf, ifp) {
-               struct ospf_if_params *params;
-
-               params = IF_DEF_PARAMS(ifp);
-               if (OSPF_IF_PARAM_CONFIGURED(params, passive_interface))
-                       UNSET_IF_PARAM(params, passive_interface);
-       }
-
        /* Reset interface. */
        for (ALL_LIST_ELEMENTS(ospf->oiflist, node, nnode, oi))
                ospf_if_free(oi);
@@ -825,8 +818,8 @@ static void ospf_finish_final(struct ospf *ospf)
                if ((lsa = rn->info) != NULL) {
                        ospf_lsa_unlock(&lsa);
                        rn->info = NULL;
+                       route_unlock_node(rn);
                }
-               route_unlock_node(rn);
        }
        route_table_finish(ospf->maxage_lsa);
 
@@ -900,7 +893,7 @@ static void ospf_finish_final(struct ospf *ospf)
        list_delete(&ospf->oi_write_q);
 
        /* Reset GR helper data structers */
-       ospf_gr_helper_stop(ospf);
+       ospf_gr_helper_instance_stop(ospf);
 
        close(ospf->fd);
        stream_free(ospf->ibuf);
index f8560a848c2c498c1b442733173b9840f8ef4bfe..112a3d5ee9e68e36c125648f50717d82bd54e849 100644 (file)
@@ -60,6 +60,12 @@ static struct log_ref ferr_path_warn[] = {
                .description = "The PCEP module failed to connected to configured PCE",
                .suggestion = "Check the connectivity between the PCC and the PCE"
        },
+       {
+               .code = EC_PATH_PCEP_PROTOCOL_ERROR,
+               .title = "PCEP protocol error",
+               .description = "The PCE did not respect the PCEP protocol",
+               .suggestion = "Open an Issue with all relevant log files"
+       },
        {
                .code = EC_PATH_PCEP_MISSING_SOURCE_ADDRESS,
                .title = "PCC connection error",
index 72e127f26b1564927b98fdd82e62a344ff2df6a6..5d05b6650b644d2b4155d9666a2a0c868ae06a34 100644 (file)
@@ -28,6 +28,7 @@ enum path_log_refs {
        EC_PATH_PCEP_PCC_FINI,
        EC_PATH_PCEP_PCC_CONF_UPDATE,
        EC_PATH_PCEP_LIB_CONNECT,
+       EC_PATH_PCEP_PROTOCOL_ERROR,
        EC_PATH_PCEP_MISSING_SOURCE_ADDRESS,
        EC_PATH_PCEP_RECOVERABLE_INTERNAL_ERROR,
        EC_PATH_PCEP_UNSUPPORTED_PCEP_FEATURE,
index 5b0f5b44e5c894312253e88267d7d01999ff60b1..e1fbb37f55c723bdfa298f7fab2bf7a409cb907d 100644 (file)
@@ -266,7 +266,7 @@ int pathd_srte_policy_create(struct nb_cb_create_args *args)
 
        color = yang_dnode_get_uint32(args->dnode, "./color");
        yang_dnode_get_ip(&endpoint, args->dnode, "./endpoint");
-       policy = srte_policy_add(color, &endpoint);
+       policy = srte_policy_add(color, &endpoint, SRTE_ORIGIN_LOCAL, NULL);
 
        nb_running_set_entry(args->dnode, policy);
        SET_FLAG(policy->flags, F_POLICY_NEW);
@@ -388,7 +388,8 @@ int pathd_srte_policy_candidate_path_create(struct nb_cb_create_args *args)
 
        policy = nb_running_get_entry(args->dnode, NULL, true);
        preference = yang_dnode_get_uint32(args->dnode, "./preference");
-       candidate = srte_candidate_add(policy, preference);
+       candidate =
+               srte_candidate_add(policy, preference, SRTE_ORIGIN_LOCAL, NULL);
        nb_running_set_entry(args->dnode, candidate);
        SET_FLAG(candidate->flags, F_CANDIDATE_NEW);
 
index ad24c2eb02b3aacdc33c8918866de6cd6d17ea9f..ce631eb7b040933484c13e0c0bfe4f0dfe3a88f3 100644 (file)
@@ -37,6 +37,7 @@
 #include "pathd/path_pcep_controller.h"
 #include "pathd/path_pcep_lib.h"
 #include "pathd/path_pcep_config.h"
+#include "pathd/path_pcep_debug.h"
 
 DEFINE_MTYPE(PATHD, PCEP, "PCEP module");
 
@@ -51,6 +52,7 @@ static int pcep_main_event_handler(enum pcep_main_event_type type, int pcc_id,
                                   void *payload);
 static int pcep_main_event_start_sync(int pcc_id);
 static int pcep_main_event_start_sync_cb(struct path *path, void *arg);
+static int pcep_main_event_initiate_candidate(struct path *path);
 static int pcep_main_event_update_candidate(struct path *path);
 static int pcep_main_event_remove_candidate_segments(const char *originator,
                                                     bool force);
@@ -64,6 +66,9 @@ static int pathd_candidate_removed_handler(struct srte_candidate *candidate);
 static struct path_metric *pcep_copy_metrics(struct path_metric *metric);
 static struct path_hop *pcep_copy_hops(struct path_hop *hop);
 
+/* Other static functions */
+static void notify_status(struct path *path, bool not_changed);
+
 /* Module Functions */
 static int pcep_module_finish(void);
 static int pcep_module_late_init(struct thread_master *tm);
@@ -165,6 +170,21 @@ void pcep_free_path(struct path *path)
        XFREE(MTYPE_PCEP, path);
 }
 
+/* ------------ Other Static Functions ------------ */
+
+void notify_status(struct path *path, bool not_changed)
+{
+       struct path *resp = NULL;
+
+       if ((resp = path_pcep_config_get_path(&path->nbkey))) {
+               resp->srp_id = path->srp_id;
+               flog_warn(EC_PATH_PCEP_RECOVERABLE_INTERNAL_ERROR,
+                         "(%s) Send report for candidate path %s", __func__,
+                         path->name);
+               pcep_ctrl_send_report(pcep_g->fpt, path->pcc_id, resp,
+                                     not_changed);
+       }
+}
 
 /* ------------ Main Thread Even Handler ------------ */
 
@@ -177,6 +197,11 @@ int pcep_main_event_handler(enum pcep_main_event_type type, int pcc_id,
        case PCEP_MAIN_EVENT_START_SYNC:
                ret = pcep_main_event_start_sync(pcc_id);
                break;
+       case PCEP_MAIN_EVENT_INITIATE_CANDIDATE:
+               assert(payload != NULL);
+               ret = pcep_main_event_initiate_candidate(
+                       (struct path *)payload);
+               break;
        case PCEP_MAIN_EVENT_UPDATE_CANDIDATE:
                assert(payload != NULL);
                ret = pcep_main_event_update_candidate((struct path *)payload);
@@ -209,19 +234,49 @@ int pcep_main_event_start_sync_cb(struct path *path, void *arg)
        return 1;
 }
 
+int pcep_main_event_initiate_candidate(struct path *path)
+{
+       int ret = 0;
+
+       ret = path_pcep_config_initiate_path(path);
+       if (path->do_remove) {
+               struct pcep_error *error;
+               error = XCALLOC(MTYPE_PCEP, sizeof(*error));
+               error->path = path;
+               error->error_type = PCEP_ERRT_INVALID_OPERATION;
+               switch (ret) {
+               case ERROR_19_1:
+                       error->error_value =
+                               PCEP_ERRV_LSP_UPDATE_FOR_NON_DELEGATED_LSP;
+                       break;
+               case ERROR_19_3:
+                       error->error_value =
+                               PCEP_ERRV_LSP_UPDATE_UNKNOWN_PLSP_ID;
+                       break;
+               case ERROR_19_9:
+                       error->error_value = PCEP_ERRV_LSP_NOT_PCE_INITIATED;
+                       break;
+               default:
+                       zlog_warn("(%s)PCE tried to REMOVE unknown error!",
+                                 __func__);
+                       XFREE(MTYPE_PCEP, error);
+                       pcep_free_path(path);
+                       return ret;
+                       break;
+               }
+               pcep_ctrl_send_error(pcep_g->fpt, path->pcc_id, error);
+       } else if (ret != PATH_NB_ERR && path->srp_id != 0)
+               notify_status(path, ret == PATH_NB_NO_CHANGE);
+       return ret;
+}
+
 int pcep_main_event_update_candidate(struct path *path)
 {
-       struct path *resp = NULL;
        int ret = 0;
 
        ret = path_pcep_config_update_path(path);
-       if (ret != PATH_NB_ERR && path->srp_id != 0) {
-               if ((resp = path_pcep_config_get_path(&path->nbkey))) {
-                       resp->srp_id = path->srp_id;
-                       pcep_ctrl_send_report(pcep_g->fpt, path->pcc_id, resp,
-                                             ret == PATH_NB_NO_CHANGE);
-               }
-       }
+       if (ret != PATH_NB_ERR && path->srp_id != 0)
+               notify_status(path, ret == PATH_NB_NO_CHANGE);
        return ret;
 }
 
index d0af674ff9036c3e2fe4153121d6c7b12e793b51..597a4b6c83f9609c8629492f10ef4405570c8945 100644 (file)
@@ -317,6 +317,16 @@ struct pcep_glob {
 
 extern struct pcep_glob *pcep_g;
 
+struct pcep_error {
+       struct path *path;
+       int error_type;
+       int error_value;
+       /* Rfc 8281 PcInitiated error on bad values */
+#define ERROR_19_1 1
+#define ERROR_19_3 2
+#define ERROR_19_9 3
+};
+
 /* Path Helper Functions */
 struct path *pcep_new_path(void);
 struct path_hop *pcep_new_hop(void);
index 609f0915598e1985e301237bf8e9c057be53ce7c..0349618304286d595d89a82d7502c2c413c94af9 100644 (file)
@@ -32,6 +32,8 @@
 #define MAX_FLOAT_LEN 22
 #define INETADDR4_MAXLEN 16
 #define INETADDR6_MAXLEN 40
+#define INITIATED_CANDIDATE_PREFERENCE 255
+#define INITIATED_POLICY_COLOR 1
 
 
 static void copy_candidate_objfun_info(struct srte_candidate *candidate,
@@ -147,7 +149,7 @@ struct path *candidate_to_path(struct srte_candidate *candidate)
                .plsp_id = 0,
                .name = name,
                .type = candidate->type,
-               .srp_id = 0,
+               .srp_id = policy->srp_id,
                .req_id = 0,
                .binding_sid = policy->binding_sid,
                .status = status,
@@ -276,6 +278,93 @@ path_pcep_config_list_path_hops(struct srte_segment_list *segment_list)
        return hop;
 }
 
+int path_pcep_config_initiate_path(struct path *path)
+{
+       struct srte_policy *policy;
+       struct srte_candidate *candidate;
+
+       if (path->do_remove) {
+               zlog_warn("PCE %s tried to REMOVE pce-initiate a path ",
+                         path->originator);
+               candidate = lookup_candidate(&path->nbkey);
+               if (candidate) {
+                       if (!path->is_delegated) {
+                               zlog_warn(
+                                       "(%s)PCE tried to REMOVE but it's not Delegated!",
+                                       __func__);
+                               return ERROR_19_1;
+                       }
+                       if (candidate->type != SRTE_CANDIDATE_TYPE_DYNAMIC) {
+                               zlog_warn(
+                                       "(%s)PCE tried to REMOVE but it's not PCE origin!",
+                                       __func__);
+                               return ERROR_19_9;
+                       }
+                       zlog_warn(
+                               "(%s)PCE tried to REMOVE found canidate!, let's remove",
+                               __func__);
+                       candidate->policy->srp_id = path->srp_id;
+                       SET_FLAG(candidate->policy->flags, F_POLICY_DELETED);
+                       SET_FLAG(candidate->flags, F_CANDIDATE_DELETED);
+               } else {
+                       zlog_warn("(%s)PCE tried to REMOVE not existing LSP!",
+                                 __func__);
+                       return ERROR_19_3;
+               }
+               srte_apply_changes();
+       } else {
+               assert(!IS_IPADDR_NONE(&path->nbkey.endpoint));
+
+               if (path->nbkey.preference == 0)
+                       path->nbkey.preference = INITIATED_CANDIDATE_PREFERENCE;
+
+               if (path->nbkey.color == 0)
+                       path->nbkey.color = INITIATED_POLICY_COLOR;
+
+               candidate = lookup_candidate(&path->nbkey);
+               if (!candidate) {
+                       policy = srte_policy_add(
+                               path->nbkey.color, &path->nbkey.endpoint,
+                               SRTE_ORIGIN_PCEP, path->originator);
+                       strlcpy(policy->name, path->name, sizeof(policy->name));
+                       policy->binding_sid = path->binding_sid;
+                       SET_FLAG(policy->flags, F_POLICY_NEW);
+                       candidate = srte_candidate_add(
+                               policy, path->nbkey.preference,
+                               SRTE_ORIGIN_PCEP, path->originator);
+                       strlcpy(candidate->name, path->name,
+                               sizeof(candidate->name));
+                       SET_FLAG(candidate->flags, F_CANDIDATE_NEW);
+               } else {
+                       policy = candidate->policy;
+                       if ((path->originator != candidate->originator)
+                           || (path->originator != policy->originator)) {
+                               /* There is already an initiated path from
+                                * another PCE, show a warning and regect the
+                                * initiated path */
+                               zlog_warn(
+                                       "PCE %s tried to initiate a path already initiated by PCE %s",
+                                       path->originator,
+                                       candidate->originator);
+                               return 1;
+                       }
+                       if ((policy->protocol_origin != SRTE_ORIGIN_PCEP)
+                           || (candidate->protocol_origin
+                               != SRTE_ORIGIN_PCEP)) {
+                               /* There is already an initiated path from
+                                * another PCE, show a warning and regect the
+                                * initiated path */
+                               zlog_warn(
+                                       "PCE %s tried to initiate a path created localy",
+                                       path->originator);
+                               return 1;
+                       }
+               }
+               return path_pcep_config_update_path(path);
+       }
+       return 0;
+}
+
 int path_pcep_config_update_path(struct path *path)
 {
        assert(path != NULL);
@@ -381,8 +470,12 @@ struct srte_candidate *lookup_candidate(struct lsp_nb_key *key)
 
 char *candidate_name(struct srte_candidate *candidate)
 {
-       return asprintfrr(MTYPE_PCEP, "%s-%s", candidate->policy->name,
-                         candidate->name);
+       if (candidate->protocol_origin == SRTE_ORIGIN_PCEP
+           || candidate->protocol_origin == SRTE_ORIGIN_BGP)
+               return asprintfrr(MTYPE_PCEP, "%s", candidate->policy->name);
+       else
+               return asprintfrr(MTYPE_PCEP, "%s-%s", candidate->policy->name,
+                                 candidate->name);
 }
 
 enum pcep_lsp_operational_status
index 223dd10c82097a6e00fb417b28c48946ab368a11..e56d497aa0259046bf76b35762eeca15597e9df3 100644 (file)
@@ -38,6 +38,7 @@ typedef int (*path_list_cb_t)(struct path *path, void *arg);
 void path_pcep_refine_path(struct path *path);
 struct path *path_pcep_config_get_path(struct lsp_nb_key *key);
 void path_pcep_config_list_path(path_list_cb_t cb, void *arg);
+int path_pcep_config_initiate_path(struct path *path);
 int path_pcep_config_update_path(struct path *path);
 struct path *candidate_to_path(struct srte_candidate *candidate);
 
index 528dcc3539923d7eb66de22a06091401fb314f41..449c40c16c23fad50f19b5dba189067e2abf3efb 100644 (file)
@@ -57,6 +57,7 @@ enum pcep_ctrl_event_type {
        EV_PCEPLIB_EVENT,
        EV_RESET_PCC_SESSION,
        EV_SEND_REPORT,
+       EV_SEND_ERROR,
        EV_PATH_REFINED
 };
 
@@ -328,6 +329,14 @@ int pcep_ctrl_send_report(struct frr_pthread *fpt, int pcc_id,
 }
 
 
+int pcep_ctrl_send_error(struct frr_pthread *fpt, int pcc_id,
+                        struct pcep_error *error)
+{
+       struct ctrl_state *ctrl_state = get_ctrl_state(fpt);
+       return send_to_thread(ctrl_state, pcc_id, EV_SEND_ERROR, 0, error);
+}
+
+
 /* ------------ Internal Functions Called from Main Thread ------------ */
 
 int pcep_ctrl_halt_cb(struct frr_pthread *fpt, void **res)
@@ -368,6 +377,13 @@ void pcep_thread_update_path(struct ctrl_state *ctrl_state, int pcc_id,
                     path);
 }
 
+void pcep_thread_initiate_path(struct ctrl_state *ctrl_state, int pcc_id,
+                              struct path *path)
+{
+       send_to_main(ctrl_state, pcc_id, PCEP_MAIN_EVENT_INITIATE_CANDIDATE,
+                    path);
+}
+
 void pcep_thread_remove_candidate_path_segments(struct ctrl_state *ctrl_state,
                                                struct pcc_state *pcc_state)
 {
@@ -743,6 +759,7 @@ int pcep_thread_event_handler(struct thread *thread)
        struct pcep_refine_path_event_data *refine_data = NULL;
 
        struct path *path_copy = NULL;
+       struct pcep_error *error = NULL;
 
        switch (type) {
        case EV_UPDATE_PCC_OPTS:
@@ -818,6 +835,13 @@ int pcep_thread_event_handler(struct thread *thread)
                refine_data = (struct pcep_refine_path_event_data *)payload;
                pcep_thread_path_refined_event(ctrl_state, refine_data);
                break;
+       case EV_SEND_ERROR:
+               assert(payload != NULL);
+               error = (struct pcep_error *)payload;
+               pcc_state = pcep_pcc_get_pcc_by_id(ctrl_state->pcc, pcc_id);
+               pcep_pcc_send_error(ctrl_state, pcc_state, error,
+                                   (bool)sub_type);
+               break;
        default:
                flog_warn(EC_PATH_PCEP_RECOVERABLE_INTERNAL_ERROR,
                          "Unexpected event received in controller thread: %u",
index 1b7c3a4c72a5d83b22c51aa3c87c597e72921c5f..f55cc0db72e635181541f44c92da6e2a2bddcfee 100644 (file)
@@ -27,6 +27,7 @@ struct pcc_state;
 enum pcep_main_event_type {
        PCEP_MAIN_EVENT_UNDEFINED = 0,
        PCEP_MAIN_EVENT_START_SYNC,
+       PCEP_MAIN_EVENT_INITIATE_CANDIDATE,
        PCEP_MAIN_EVENT_UPDATE_CANDIDATE,
        PCEP_MAIN_EVENT_REMOVE_CANDIDATE_LSP,
 };
@@ -137,10 +138,15 @@ struct pcep_pcc_info *pcep_ctrl_get_pcc_info(struct frr_pthread *fpt,
 int pcep_ctrl_send_report(struct frr_pthread *fpt, int pcc_id,
                          struct path *path, bool is_stable);
 
+int pcep_ctrl_send_error(struct frr_pthread *fpt, int pcc_id,
+                        struct pcep_error *error);
+
 /* Functions called from the controller thread */
 void pcep_thread_start_sync(struct ctrl_state *ctrl_state, int pcc_id);
 void pcep_thread_update_path(struct ctrl_state *ctrl_state, int pcc_id,
                             struct path *path);
+void pcep_thread_initiate_path(struct ctrl_state *ctrl_state, int pcc_id,
+                              struct path *path);
 void pcep_thread_cancel_timer(struct thread **thread);
 void pcep_thread_schedule_reconnect(struct ctrl_state *ctrl_state, int pcc_id,
                                    int retry_count, struct thread **thread);
index e14f6bc4a5703fb61a4f49c6656e8d714bf255ee..b0802ae6c3ecb0c19bb37675396a6f4477aea2db 100644 (file)
@@ -780,6 +780,10 @@ const char *pcep_tlv_type_name(enum pcep_object_tlv_types tlv_type)
        switch (tlv_type) {
        case PCEP_OBJ_TLV_TYPE_NO_PATH_VECTOR:
                return "NO_PATH_VECTOR";
+       case PCEP_OBJ_TLV_TYPE_OBJECTIVE_FUNCTION_LIST:
+               return "OBJECTIVE_FUNCTION_LIST";
+       case PCEP_OBJ_TLV_TYPE_VENDOR_INFO:
+               return "VENDOR_INFO";
        case PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY:
                return "STATEFUL_PCE_CAPABILITY";
        case PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME:
@@ -802,6 +806,18 @@ const char *pcep_tlv_type_name(enum pcep_object_tlv_types tlv_type)
                return "PATH_SETUP_TYPE";
        case PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE_CAPABILITY:
                return "PATH_SETUP_TYPE_CAPABILITY";
+       case PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_ID:
+               return "SRPOLICY_POL_ID";
+       case PCEP_OBJ_TLV_TYPE_SRPOLICY_POL_NAME:
+               return "SRPOLICY_POL_NAME";
+       case PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_ID:
+               return "SRPOLICY_CPATH_ID";
+       case PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_PREFERENCE:
+               return "SRPOLICY_CPATH_PREFERENCE";
+       case PCEP_OBJ_TLV_TYPE_UNKNOWN:
+               return "UNKNOWN";
+       case PCEP_OBJ_TLV_TYPE_ARBITRARY:
+               return "ARBITRARY";
        default:
                return "UNKNOWN";
        }
index e9d699de47137a906c95e7543da4ad2ba4a22ba0..9fc8c091f851edec90226f57b45925de841783fd 100644 (file)
@@ -35,6 +35,7 @@ DEFINE_MTYPE_STATIC(PATHD, PCEPLIB_MESSAGES, "PCEPlib PCEP Messages");
 #define DEFAULT_LSAP_SETUP_PRIO 4
 #define DEFAULT_LSAP_HOLDING_PRIO 4
 #define DEFAULT_LSAP_LOCAL_PRETECTION false
+#define MAX_PATH_NAME_SIZE 255
 
 /* pceplib logging callback */
 static int pceplib_logging_cb(int level, const char *fmt, va_list args);
@@ -76,8 +77,18 @@ static void pcep_lib_parse_srp(struct path *path, struct pcep_object_srp *srp);
 static void pcep_lib_parse_lsp(struct path *path, struct pcep_object_lsp *lsp);
 static void pcep_lib_parse_lspa(struct path *path,
                                struct pcep_object_lspa *lspa);
+static void pcep_lib_parse_lsp_symbolic_name(
+       struct path *path, struct pcep_object_tlv_symbolic_path_name *tlv);
 static void pcep_lib_parse_metric(struct path *path,
                                  struct pcep_object_metric *obj);
+static void
+pcep_lib_parse_endpoints_ipv4(struct path *path,
+                             struct pcep_object_endpoints_ipv4 *obj);
+static void
+pcep_lib_parse_endpoints_ipv6(struct path *path,
+                             struct pcep_object_endpoints_ipv6 *obj);
+static void pcep_lib_parse_vendor_info(struct path *path,
+                                      struct pcep_object_vendor_info *obj);
 static void pcep_lib_parse_ero(struct path *path, struct pcep_object_ro *ero);
 static struct path_hop *pcep_lib_parse_ero_sr(struct path_hop *next,
                                              struct pcep_ro_subobj_sr *sr);
@@ -160,7 +171,7 @@ pcep_lib_connect(struct ipaddr *src_addr, int src_port, struct ipaddr *dst_addr,
        }
 
        config->support_stateful_pce_lsp_update = true;
-       config->support_pce_lsp_instantiation = false;
+       config->support_pce_lsp_instantiation = pcep_options->pce_initiated;
        config->support_include_db_version = false;
        config->support_lsp_triggered_resync = false;
        config->support_lsp_delta_sync = false;
@@ -381,9 +392,25 @@ struct pcep_message *pcep_lib_format_request(struct pcep_caps *caps,
        }
 }
 
-struct pcep_message *pcep_lib_format_error(int error_type, int error_value)
+struct pcep_message *pcep_lib_format_error(int error_type, int error_value,
+                                          struct path *path)
 {
-       return pcep_msg_create_error(error_type, error_value);
+       double_linked_list *objs, *srp_tlvs;
+       struct pcep_object_srp *srp;
+       struct pcep_object_tlv_header *tlv;
+
+       if ((path == NULL) || (path->srp_id == 0))
+               return pcep_msg_create_error(error_type, error_value);
+
+       objs = dll_initialize();
+       srp_tlvs = dll_initialize();
+       tlv = (struct pcep_object_tlv_header *)pcep_tlv_create_path_setup_type(
+               SR_TE_PST);
+       dll_append(srp_tlvs, tlv);
+       srp = pcep_obj_create_srp(path->do_remove, path->srp_id, srp_tlvs);
+       dll_append(objs, srp);
+       return pcep_msg_create_error_with_objects(error_type, error_value,
+                                                 objs);
 }
 
 struct pcep_message *pcep_lib_format_request_cancelled(uint32_t reqid)
@@ -417,6 +444,9 @@ struct path *pcep_lib_parse_path(struct pcep_message *msg)
        struct pcep_object_metric *metric = NULL;
        struct pcep_object_bandwidth *bandwidth = NULL;
        struct pcep_object_objective_function *of = NULL;
+       struct pcep_object_endpoints_ipv4 *epv4 = NULL;
+       struct pcep_object_endpoints_ipv6 *epv6 = NULL;
+       struct pcep_object_vendor_info *vendor_info = NULL;
 
        path = pcep_new_path();
 
@@ -470,6 +500,21 @@ struct path *pcep_lib_parse_path(struct pcep_message *msg)
                        path->has_pce_objfun = true;
                        path->pce_objfun = of->of_code;
                        break;
+               case CLASS_TYPE(PCEP_OBJ_CLASS_ENDPOINTS,
+                               PCEP_OBJ_TYPE_ENDPOINT_IPV4):
+                       epv4 = (struct pcep_object_endpoints_ipv4 *)obj;
+                       pcep_lib_parse_endpoints_ipv4(path, epv4);
+                       break;
+               case CLASS_TYPE(PCEP_OBJ_CLASS_ENDPOINTS,
+                               PCEP_OBJ_TYPE_ENDPOINT_IPV6):
+                       epv6 = (struct pcep_object_endpoints_ipv6 *)obj;
+                       pcep_lib_parse_endpoints_ipv6(path, epv6);
+                       break;
+               case CLASS_TYPE(PCEP_OBJ_CLASS_VENDOR_INFO,
+                               PCEP_OBJ_TYPE_VENDOR_INFO):
+                       vendor_info = (struct pcep_object_vendor_info *)obj;
+                       pcep_lib_parse_vendor_info(path, vendor_info);
+                       break;
                default:
                        flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_OBJECT,
                                  "Unexpected PCEP object %s (%u) / %s (%u)",
@@ -632,7 +677,8 @@ double_linked_list *pcep_lib_format_path(struct pcep_caps *caps,
                tlv = (struct pcep_object_tlv_header *)
                        pcep_tlv_create_tlv_arbitrary(
                                binding_sid_lsp_tlv_data,
-                               sizeof(binding_sid_lsp_tlv_data), 65505);
+                               sizeof(binding_sid_lsp_tlv_data),
+                               PCEP_OBJ_TYPE_CISCO_BSID);
                assert(tlv != NULL);
                dll_append(lsp_tlvs, tlv);
        }
@@ -855,6 +901,12 @@ void pcep_lib_parse_rp(struct path *path, struct pcep_object_rp *rp)
        double_linked_list_node *node;
        struct pcep_object_tlv_header *tlv;
 
+       if (tlvs == NULL) {
+               flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV,
+                         "Unexpected Empty RP's TLV plsp-id:(%d)",
+                         path ? (int32_t)path->plsp_id : -1);
+               return;
+       }
        /* We ignore the other flags and priority for now */
        path->req_id = rp->request_id;
        path->has_pce_objfun = false;
@@ -884,6 +936,12 @@ void pcep_lib_parse_srp(struct path *path, struct pcep_object_srp *srp)
        path->do_remove = srp->flag_lsp_remove;
        path->srp_id = srp->srp_id_number;
 
+       if (tlvs == NULL) {
+               flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV,
+                         "Unexpected Empty SRP's TLV plsp-id:(%d)",
+                         path ? (int32_t)path->plsp_id : -1);
+               return;
+       }
        for (node = tlvs->head; node != NULL; node = node->next_node) {
                tlv = (struct pcep_object_tlv_header *)node->data;
                switch (tlv->type) {
@@ -904,6 +962,8 @@ void pcep_lib_parse_lsp(struct path *path, struct pcep_object_lsp *lsp)
        double_linked_list *tlvs = lsp->header.tlv_list;
        double_linked_list_node *node;
        struct pcep_object_tlv_header *tlv;
+       struct pcep_object_tlv_symbolic_path_name *name;
+       struct pcep_object_tlv_arbitrary *arb_tlv;
 
        path->plsp_id = lsp->plsp_id;
        path->status = lsp->operational_status;
@@ -913,12 +973,27 @@ void pcep_lib_parse_lsp(struct path *path, struct pcep_object_lsp *lsp)
        path->is_synching = lsp->flag_s;
        path->is_delegated = lsp->flag_d;
 
-       if (tlvs == NULL)
+       if (tlvs == NULL) {
+               flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV,
+                         "Unexpected Empty LSP's TLV plsp-id:(%d)",
+                         path ? (int32_t)path->plsp_id : -1);
                return;
+       }
 
        for (node = tlvs->head; node != NULL; node = node->next_node) {
                tlv = (struct pcep_object_tlv_header *)node->data;
                switch (tlv->type) {
+               case PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME:
+                       name = (struct pcep_object_tlv_symbolic_path_name *)tlv;
+                       pcep_lib_parse_lsp_symbolic_name(path, name);
+                       break;
+               case PCEP_OBJ_TYPE_CISCO_BSID:
+                       arb_tlv = (struct pcep_object_tlv_arbitrary *)tlv;
+                       memcpy(&path->binding_sid, arb_tlv->data + 2,
+                              sizeof(path->binding_sid));
+                       path->binding_sid = ntohl(path->binding_sid);
+                       path->binding_sid = (path->binding_sid >> 12);
+                       break;
                default:
                        flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV,
                                  "Unexpected LSP TLV %s (%u)",
@@ -928,6 +1003,16 @@ void pcep_lib_parse_lsp(struct path *path, struct pcep_object_lsp *lsp)
        }
 }
 
+void pcep_lib_parse_lsp_symbolic_name(
+       struct path *path, struct pcep_object_tlv_symbolic_path_name *tlv)
+{
+       uint16_t size = tlv->symbolic_path_name_length;
+       assert(path->name == NULL);
+       size = size > MAX_PATH_NAME_SIZE ? MAX_PATH_NAME_SIZE : size;
+       path->name = XCALLOC(MTYPE_PCEP, size);
+       strlcpy((char *)path->name, tlv->symbolic_path_name, size + 1);
+}
+
 void pcep_lib_parse_lspa(struct path *path, struct pcep_object_lspa *lspa)
 {
        path->has_affinity_filters = true;
@@ -952,6 +1037,34 @@ void pcep_lib_parse_metric(struct path *path, struct pcep_object_metric *obj)
        path->first_metric = metric;
 }
 
+void pcep_lib_parse_endpoints_ipv4(struct path *path,
+                                  struct pcep_object_endpoints_ipv4 *obj)
+{
+       SET_IPADDR_V4(&path->pcc_addr);
+       path->pcc_addr.ipaddr_v4 = obj->src_ipv4;
+       SET_IPADDR_V4(&path->nbkey.endpoint);
+       path->nbkey.endpoint.ipaddr_v4 = obj->dst_ipv4;
+}
+
+void pcep_lib_parse_endpoints_ipv6(struct path *path,
+                                  struct pcep_object_endpoints_ipv6 *obj)
+{
+       SET_IPADDR_V6(&path->pcc_addr);
+       path->pcc_addr.ipaddr_v6 = obj->src_ipv6;
+       SET_IPADDR_V6(&path->nbkey.endpoint);
+       path->nbkey.endpoint.ipaddr_v6 = obj->dst_ipv6;
+}
+
+void pcep_lib_parse_vendor_info(struct path *path,
+                               struct pcep_object_vendor_info *obj)
+{
+       if (obj->enterprise_number == ENTERPRISE_NUMBER_CISCO
+           && obj->enterprise_specific_info == ENTERPRISE_COLOR_CISCO)
+               path->nbkey.color = obj->enterprise_specific_info1;
+       else
+               path->nbkey.color = 0;
+}
+
 void pcep_lib_parse_ero(struct path *path, struct pcep_object_ro *ero)
 {
        struct path_hop *hop = NULL;
@@ -959,6 +1072,12 @@ void pcep_lib_parse_ero(struct path *path, struct pcep_object_ro *ero)
        double_linked_list_node *node;
        struct pcep_object_ro_subobj *obj;
 
+       if (objs == NULL) {
+               flog_warn(EC_PATH_PCEP_UNEXPECTED_PCEP_TLV,
+                         "Unexpected Empty ERO's sub_obj plsp-id:(%d)",
+                         path ? (int32_t)path->plsp_id : -1);
+               return;
+       }
        for (node = objs->tail; node != NULL; node = node->prev_node) {
                obj = (struct pcep_object_ro_subobj *)node->data;
                switch (obj->ro_subobj_type) {
index 3f34edcb3fbc7df051a1f736b19519b7becf81a4..524f385d140da3a652d3455dce60e42f843de29d 100644 (file)
@@ -37,7 +37,8 @@ struct pcep_message *pcep_lib_format_request(struct pcep_caps *caps,
                                             struct path *path);
 struct pcep_message *pcep_lib_format_request_cancelled(uint32_t reqid);
 
-struct pcep_message *pcep_lib_format_error(int error_type, int error_value);
+struct pcep_message *pcep_lib_format_error(int error_type, int error_value,
+                                          struct path *path);
 struct path *pcep_lib_parse_path(struct pcep_message *msg);
 void pcep_lib_parse_capabilities(struct pcep_message *msg,
                                 struct pcep_caps *caps);
index 779c400b8650ee2f554f19f4926926167fd0fb0d..81a338ac633bd11262422cf5189f69ba73114208 100644 (file)
@@ -93,7 +93,8 @@ static void send_pcep_message(struct pcc_state *pcc_state,
                              struct pcep_message *msg);
 static void send_pcep_error(struct pcc_state *pcc_state,
                            enum pcep_error_type error_type,
-                           enum pcep_error_value error_value);
+                           enum pcep_error_value error_value,
+                           struct path *trigger_path);
 static void send_report(struct pcc_state *pcc_state, struct path *path);
 static void send_comp_request(struct ctrl_state *ctrl_state,
                              struct pcc_state *pcc_state,
@@ -541,8 +542,8 @@ void pcep_pcc_send_report(struct ctrl_state *ctrl_state,
                return;
        }
 
-       PCEP_DEBUG("%s Send report for candidate path %s", pcc_state->tag,
-                  path->name);
+       PCEP_DEBUG("(%s)%s Send report for candidate path %s", __func__,
+                  pcc_state->tag, path->name);
 
        /* ODL and Cisco requires the first reported
         * LSP to have a DOWN status, the later status changes
@@ -555,6 +556,8 @@ void pcep_pcc_send_report(struct ctrl_state *ctrl_state,
        /* If no update is expected and the real status wasn't down, we need to
         * send a second report with the real status */
        if (is_stable && (real_status != PCEP_LSP_OPERATIONAL_DOWN)) {
+               PCEP_DEBUG("(%s)%s Send report for candidate path (!DOWN) %s",
+                          __func__, pcc_state->tag, path->name);
                path->srp_id = 0;
                path->status = real_status;
                send_report(pcc_state, path);
@@ -564,6 +567,19 @@ void pcep_pcc_send_report(struct ctrl_state *ctrl_state,
 }
 
 
+void pcep_pcc_send_error(struct ctrl_state *ctrl_state,
+                        struct pcc_state *pcc_state, struct pcep_error *error,
+                        bool sub_type)
+{
+
+       PCEP_DEBUG("(%s) Send error after PcInitiated ", __func__);
+
+
+       send_pcep_error(pcc_state, error->error_type, error->error_value,
+                       error->path);
+       pcep_free_path(error->path);
+       XFREE(MTYPE_PCEP, error);
+}
 /* ------------ Timeout handler ------------ */
 
 void pcep_pcc_timeout_handler(struct ctrl_state *ctrl_state,
@@ -651,6 +667,9 @@ void pcep_pcc_pathd_event_handler(struct ctrl_state *ctrl_state,
                PCEP_DEBUG("%s Candidate path %s removed", pcc_state->tag,
                           path->name);
                path->was_removed = true;
+               /* Removed as response to a PcInitiated 'R'emove*/
+               /* RFC 8281 #5.4 LSP Deletion*/
+               path->do_remove = path->was_removed;
                if (pcc_state->caps.is_stateful)
                        send_report(pcc_state, path);
                return;
@@ -1203,14 +1222,113 @@ void handle_pcep_lsp_initiate(struct ctrl_state *ctrl_state,
                              struct pcc_state *pcc_state,
                              struct pcep_message *msg)
 {
-       PCEP_DEBUG("%s Received LSP initiate, not supported yet",
-                  pcc_state->tag);
+       char err[MAX_ERROR_MSG_SIZE] = "";
+       struct path *path;
+
+       path = pcep_lib_parse_path(msg);
+
+       if (!pcc_state->pce_opts->config_opts.pce_initiated) {
+               /* PCE Initiated is not enabled */
+               flog_warn(EC_PATH_PCEP_UNSUPPORTED_PCEP_FEATURE,
+                         "Not allowed PCE initiated path received: %s",
+                         format_pcep_message(msg));
+               send_pcep_error(pcc_state, PCEP_ERRT_LSP_INSTANTIATE_ERROR,
+                               PCEP_ERRV_UNACCEPTABLE_INSTANTIATE_ERROR, path);
+               return;
+       }
 
-       /* TODO when we support both PCC and PCE initiated sessions,
-        *      we should first check the session type before
-        *      rejecting this message. */
-       send_pcep_error(pcc_state, PCEP_ERRT_INVALID_OPERATION,
-                       PCEP_ERRV_LSP_NOT_PCE_INITIATED);
+       if (path->do_remove) {
+               // lookup in nbkey sequential as no endpoint
+               struct nbkey_map_data *key;
+               char endpoint[46];
+
+               frr_each (nbkey_map, &pcc_state->nbkey_map, key) {
+                       ipaddr2str(&key->nbkey.endpoint, endpoint,
+                                  sizeof(endpoint));
+                       flog_warn(
+                               EC_PATH_PCEP_UNSUPPORTED_PCEP_FEATURE,
+                               "FOR_EACH nbkey [color (%d) endpoint (%s)] path [plsp_id (%d)] ",
+                               key->nbkey.color, endpoint, path->plsp_id);
+                       if (path->plsp_id == key->plspid) {
+                               flog_warn(
+                                       EC_PATH_PCEP_UNSUPPORTED_PCEP_FEATURE,
+                                       "FOR_EACH MATCH nbkey [color (%d) endpoint (%s)] path [plsp_id (%d)] ",
+                                       key->nbkey.color, endpoint,
+                                       path->plsp_id);
+                               path->nbkey = key->nbkey;
+                               break;
+                       }
+               }
+       } else {
+               if (path->first_hop == NULL /*ero sets first_hop*/) {
+                       /* If the PCC receives a PCInitiate message without an
+                        * ERO and the R flag in the SRP object != zero, then it
+                        * MUST send a PCErr message with Error-type=6
+                        * (Mandatory Object missing) and Error-value=9 (ERO
+                        * object missing). */
+                       flog_warn(EC_PATH_PCEP_UNSUPPORTED_PCEP_FEATURE,
+                                 "ERO object missing or incomplete : %s",
+                                 format_pcep_message(msg));
+                       send_pcep_error(pcc_state,
+                                       PCEP_ERRT_LSP_INSTANTIATE_ERROR,
+                                       PCEP_ERRV_INTERNAL_ERROR, path);
+                       return;
+               }
+
+               if (path->plsp_id != 0) {
+                       /* If the PCC receives a PCInitiate message with a
+                        * non-zero PLSP-ID and the R flag in the SRP object set
+                        * to zero, then it MUST send a PCErr message with
+                        * Error-type=19 (Invalid Operation) and Error-value=8
+                        * (Non-zero PLSP-ID in the LSP Initiate Request) */
+                       flog_warn(
+                               EC_PATH_PCEP_PROTOCOL_ERROR,
+                               "PCE initiated path with non-zero PLSP ID: %s",
+                               format_pcep_message(msg));
+                       send_pcep_error(pcc_state, PCEP_ERRT_INVALID_OPERATION,
+                                       PCEP_ERRV_LSP_INIT_NON_ZERO_PLSP_ID,
+                                       path);
+                       return;
+               }
+
+               if (path->name == NULL) {
+                       /* If the PCC receives a PCInitiate message without a
+                        * SYMBOLIC-PATH-NAME TLV, then it MUST send a PCErr
+                        * message with Error-type=10 (Reception of an invalid
+                        * object) and Error-value=8 (SYMBOLIC-PATH-NAME TLV
+                        * missing) */
+                       flog_warn(
+                               EC_PATH_PCEP_PROTOCOL_ERROR,
+                               "PCE initiated path without symbolic name: %s",
+                               format_pcep_message(msg));
+                       send_pcep_error(
+                               pcc_state, PCEP_ERRT_RECEPTION_OF_INV_OBJECT,
+                               PCEP_ERRV_SYMBOLIC_PATH_NAME_TLV_MISSING, path);
+                       return;
+               }
+       }
+
+       /* TODO: If there is a conflict with the symbolic path name of an
+        * existing LSP, the PCC MUST send a PCErr message with Error-type=23
+        * (Bad Parameter value) and Error-value=1 (SYMBOLIC-PATH-NAME in
+        * use) */
+
+       specialize_incoming_path(pcc_state, path);
+       /* TODO: Validate the PCC address received from the PCE is valid */
+       PCEP_DEBUG("%s Received LSP initiate", pcc_state->tag);
+       PCEP_DEBUG_PATH("%s", format_path(path));
+
+       if (validate_incoming_path(pcc_state, path, err, sizeof(err))) {
+               pcep_thread_initiate_path(ctrl_state, pcc_state->id, path);
+       } else {
+               /* FIXME: Monitor the amount of errors from the PCE and
+                * possibly disconnect and blacklist */
+               flog_warn(EC_PATH_PCEP_UNSUPPORTED_PCEP_FEATURE,
+                         "Unsupported PCEP protocol feature: %s", err);
+               pcep_free_path(path);
+               send_pcep_error(pcc_state, PCEP_ERRT_INVALID_OPERATION,
+                               PCEP_ERRV_LSP_NOT_PCE_INITIATED, path);
+       }
 }
 
 void handle_pcep_comp_reply(struct ctrl_state *ctrl_state,
@@ -1232,7 +1350,7 @@ void handle_pcep_comp_reply(struct ctrl_state *ctrl_state,
                        pcc_state->tag, path->req_id);
                PCEP_DEBUG_PATH("%s", format_path(path));
                send_pcep_error(pcc_state, PCEP_ERRT_UNKNOWN_REQ_REF,
-                               PCEP_ERRV_UNASSIGNED);
+                               PCEP_ERRV_UNASSIGNED, NULL);
                return;
        }
 
@@ -1447,13 +1565,14 @@ void send_pcep_message(struct pcc_state *pcc_state, struct pcep_message *msg)
 
 void send_pcep_error(struct pcc_state *pcc_state,
                     enum pcep_error_type error_type,
-                    enum pcep_error_value error_value)
+                    enum pcep_error_value error_value,
+                    struct path *trigger_path)
 {
        struct pcep_message *msg;
        PCEP_DEBUG("%s Sending PCEP error type %s (%d) value %s (%d)",
                   pcc_state->tag, pcep_error_type_name(error_type), error_type,
                   pcep_error_value_name(error_type, error_value), error_value);
-       msg = pcep_lib_format_error(error_type, error_value);
+       msg = pcep_lib_format_error(error_type, error_value, trigger_path);
        send_pcep_message(pcc_state, msg);
 }
 
@@ -1504,7 +1623,8 @@ void specialize_outgoing_path(struct pcc_state *pcc_state, struct path *path)
 /* Updates the path for the PCC */
 void specialize_incoming_path(struct pcc_state *pcc_state, struct path *path)
 {
-       set_pcc_address(pcc_state, &path->nbkey, &path->pcc_addr);
+       if (IS_IPADDR_NONE(&path->pcc_addr))
+               set_pcc_address(pcc_state, &path->nbkey, &path->pcc_addr);
        path->sender = pcc_state->pce_opts->addr;
        path->pcc_id = pcc_state->id;
        path->update_origin = SRTE_ORIGIN_PCEP;
@@ -1538,7 +1658,7 @@ bool validate_incoming_path(struct pcc_state *pcc_state, struct path *path,
        }
 
        if (err_type != 0) {
-               send_pcep_error(pcc_state, err_type, err_value);
+               send_pcep_error(pcc_state, err_type, err_value, NULL);
                return false;
        }
 
@@ -1564,7 +1684,6 @@ void send_comp_request(struct ctrl_state *ctrl_state,
        if (!pcc_state->is_best) {
                return;
        }
-       /* TODO: Add a timer to retry the computation request ? */
 
        specialize_outgoing_path(pcc_state, req->path);
 
@@ -1579,10 +1698,7 @@ void send_comp_request(struct ctrl_state *ctrl_state,
        send_pcep_message(pcc_state, msg);
        req->was_sent = true;
 
-       /* TODO: Enable this back when the pcep config changes are merged back
-        */
-       // timeout = pcc_state->pce_opts->config_opts.pcep_request_time_seconds;
-       timeout = 30;
+       timeout = pcc_state->pce_opts->config_opts.pcep_request_time_seconds;
        pcep_thread_schedule_timeout(ctrl_state, pcc_state->id,
                                     TO_COMPUTATION_REQUEST, timeout,
                                     (void *)req, &req->t_retry);
@@ -1641,7 +1757,6 @@ void set_pcc_address(struct pcc_state *pcc_state, struct lsp_nb_key *nbkey,
        }
 }
 
-
 /* ------------ Data Structure Helper Functions ------------ */
 
 void lookup_plspid(struct pcc_state *pcc_state, struct path *path)
index ceac6f32781013c169103a3bcb3cc63bf0678b96..9e712baf16a5ad94b163a9fc02dc468729eaeea9 100644 (file)
@@ -125,6 +125,9 @@ void pcep_pcc_sync_done(struct ctrl_state *ctrl_state,
 void pcep_pcc_send_report(struct ctrl_state *ctrl_state,
                          struct pcc_state *pcc_state, struct path *path,
                          bool is_stable);
+void pcep_pcc_send_error(struct ctrl_state *ctrl_state,
+                        struct pcc_state *pcc_state, struct pcep_error *path,
+                        bool is_stable);
 int pcep_pcc_multi_pce_sync_path(struct ctrl_state *ctrl_state, int pcc_id,
                                 struct pcc_state **pcc_state_list);
 int pcep_pcc_multi_pce_remove_pcc(struct ctrl_state *ctrl_state,
index 9dc3a41638effe16ed7024fadbaec04f8da3da3f..022813a497164aa1a2831bcc48ce38ec1184a52a 100644 (file)
@@ -294,7 +294,9 @@ void srte_segment_set_local_modification(struct srte_segment_list *s_list,
  * @param endpoint The IP address of the policy endpoint
  * @return The created policy
  */
-struct srte_policy *srte_policy_add(uint32_t color, struct ipaddr *endpoint)
+struct srte_policy *srte_policy_add(uint32_t color, struct ipaddr *endpoint,
+                                   enum srte_protocol_origin origin,
+                                   const char *originator)
 {
        struct srte_policy *policy;
 
@@ -302,6 +304,11 @@ struct srte_policy *srte_policy_add(uint32_t color, struct ipaddr *endpoint)
        policy->color = color;
        policy->endpoint = *endpoint;
        policy->binding_sid = MPLS_LABEL_NONE;
+       policy->protocol_origin = origin;
+       if (originator != NULL)
+               strlcpy(policy->originator, originator,
+                       sizeof(policy->originator));
+
        RB_INIT(srte_candidate_head, &policy->candidate_paths);
        RB_INSERT(srte_policy_head, &srte_policies, policy);
 
@@ -646,7 +653,9 @@ void srte_policy_apply_changes(struct srte_policy *policy)
  * @return The added candidate path
  */
 struct srte_candidate *srte_candidate_add(struct srte_policy *policy,
-                                         uint32_t preference)
+                                         uint32_t preference,
+                                         enum srte_protocol_origin origin,
+                                         const char *originator)
 {
        struct srte_candidate *candidate;
        struct srte_lsp *lsp;
@@ -657,8 +666,18 @@ struct srte_candidate *srte_candidate_add(struct srte_policy *policy,
        candidate->preference = preference;
        candidate->policy = policy;
        candidate->type = SRTE_CANDIDATE_TYPE_UNDEFINED;
-       candidate->discriminator = frr_weak_random();
+       candidate->discriminator = rand();
+       candidate->protocol_origin = origin;
+       if (originator != NULL) {
+               strlcpy(candidate->originator, originator,
+                       sizeof(candidate->originator));
+               lsp->protocol_origin = origin;
+       }
 
+       if (candidate->protocol_origin == SRTE_ORIGIN_PCEP
+           || candidate->protocol_origin == SRTE_ORIGIN_BGP) {
+               candidate->type = SRTE_CANDIDATE_TYPE_DYNAMIC;
+       }
        lsp->candidate = candidate;
        candidate->lsp = lsp;
 
index 7d38272e856d6c623c5e359b10dfb99a7820bfb8..f790a0e3c909e908dbb2ba056830e9c811a5e6ac 100644 (file)
@@ -339,6 +339,12 @@ struct srte_policy {
        /* Binding SID */
        mpls_label_t binding_sid;
 
+       /* The Protocol-Origin. */
+       enum srte_protocol_origin protocol_origin;
+
+       /* The Originator */
+       char originator[64];
+
        /* Operational Status of the policy */
        enum srte_policy_status status;
 
@@ -352,6 +358,8 @@ struct srte_policy {
 #define F_POLICY_NEW 0x0002
 #define F_POLICY_MODIFIED 0x0004
 #define F_POLICY_DELETED 0x0008
+       /* SRP id for PcInitiated support */
+       int srp_id;
 };
 RB_HEAD(srte_policy_head, srte_policy);
 RB_PROTOTYPE(srte_policy_head, srte_policy, entry, srte_policy_compare)
@@ -385,7 +393,9 @@ int srte_segment_entry_set_nai(struct srte_segment_entry *segment,
 void srte_segment_set_local_modification(struct srte_segment_list *s_list,
                                         struct srte_segment_entry *s_entry,
                                         uint32_t ted_sid);
-struct srte_policy *srte_policy_add(uint32_t color, struct ipaddr *endpoint);
+struct srte_policy *srte_policy_add(uint32_t color, struct ipaddr *endpoint,
+                                   enum srte_protocol_origin origin,
+                                   const char *originator);
 void srte_policy_del(struct srte_policy *policy);
 struct srte_policy *srte_policy_find(uint32_t color, struct ipaddr *endpoint);
 int srte_policy_update_ted_sid(void);
@@ -395,7 +405,9 @@ void srte_apply_changes(void);
 void srte_clean_zebra(void);
 void srte_policy_apply_changes(struct srte_policy *policy);
 struct srte_candidate *srte_candidate_add(struct srte_policy *policy,
-                                         uint32_t preference);
+                                         uint32_t preference,
+                                         enum srte_protocol_origin origin,
+                                         const char *originator);
 void srte_candidate_del(struct srte_candidate *candidate);
 void srte_candidate_set_bandwidth(struct srte_candidate *candidate,
                                  float bandwidth, bool required);
index 1badaf95bddf0a8bd25d71304fab4a89819e3b04..786155903460deb6ea9db6e495863dd6bf4f9c41 100644 (file)
@@ -119,6 +119,7 @@ struct quagga_signal_t pbr_signals[] = {
 static const struct frr_yang_module_info *const pbrd_yang_modules[] = {
        &frr_filter_info,
        &frr_interface_info,
+       &frr_vrf_info,
 };
 
 FRR_DAEMON_INFO(pbrd, PBR, .vty_port = PBR_VTY_PORT,
index 216834fe0c60c6b84ccdc044b6e3c52eb870eb18..3d56fc3daa14ee09d89cc853b20b0e700a4becb3 100644 (file)
@@ -1143,10 +1143,14 @@ static const struct cmd_variable_handler pbr_map_name[] = {
        }
 };
 
+extern struct zebra_privs_t pbr_privs;
+
 void pbr_vty_init(void)
 {
        cmd_variable_handler_register(pbr_map_name);
 
+       vrf_cmd_init(NULL, &pbr_privs);
+
        install_node(&interface_node);
        if_cmd_init();
 
index 959a6f8cf6cb51609bcbcd5f0d4441981f7b239f..f26618e2917df8e9e349a5fc11bba877267a0ffb 100644 (file)
@@ -385,11 +385,16 @@ struct pcep_object_lsp {
        bool flag_c;
 };
 
+#define ENTERPRISE_NUMBER_CISCO 9
+#define ENTERPRISE_COLOR_CISCO 65540
 /* RFC 7470 */
 struct pcep_object_vendor_info {
        struct pcep_object_header header;
        uint32_t enterprise_number;
        uint32_t enterprise_specific_info;
+       uint32_t enterprise_specific_info1; /* cisco sends color for PcInit */
+       uint32_t enterprise_specific_info2;
+       uint32_t enterprise_specific_info3;
 };
 
 /* RFC 8282 */
index 9ab96f7bcec04b3ee9271709ef6865067bd2ce3c..69420f8e7abc08bf20c012855dfc4f43f9e576d5 100644 (file)
@@ -1339,8 +1339,15 @@ pcep_decode_obj_vendor_info(struct pcep_object_header *hdr,
        struct pcep_object_vendor_info *obj =
                (struct pcep_object_vendor_info *)common_object_create(
                        hdr, sizeof(struct pcep_object_vendor_info));
+
        obj->enterprise_number = ntohl(*((uint32_t *)(obj_buf)));
        obj->enterprise_specific_info = ntohl(*((uint32_t *)(obj_buf + 4)));
+       if (obj->enterprise_number == ENTERPRISE_NUMBER_CISCO
+           && obj->enterprise_specific_info == ENTERPRISE_COLOR_CISCO)
+               obj->enterprise_specific_info1 =
+                       ntohl(*((uint32_t *)(obj_buf + 8)));
+       else
+               obj->enterprise_specific_info1 = 0;
 
        return (struct pcep_object_header *)obj;
 }
index 5197201e40724a16f64eb082f69eeadf672e1ee3..6dd2b5655268c7be2ece34756c16a9ddc6ae52fb 100644 (file)
@@ -53,16 +53,16 @@ extern "C" {
  * https://www.iana.org/assignments/pcep/pcep.xhtml */
 enum pcep_object_tlv_types {
        PCEP_OBJ_TLV_TYPE_NO_PATH_VECTOR = 1,
-       PCEP_OBJ_TLV_TYPE_OBJECTIVE_FUNCTION_LIST = 4,  /* RFC 5541 */
+       PCEP_OBJ_TLV_TYPE_OBJECTIVE_FUNCTION_LIST = 4,  /* RFC 5541 */
        PCEP_OBJ_TLV_TYPE_VENDOR_INFO = 7,              /* RFC 7470 */
        PCEP_OBJ_TLV_TYPE_STATEFUL_PCE_CAPABILITY = 16, /* RFC 8231 */
-       PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME = 17,      /* RFC 8232 */
-       PCEP_OBJ_TLV_TYPE_IPV4_LSP_IDENTIFIERS = 18,    /* RFC 8231 */
-       PCEP_OBJ_TLV_TYPE_IPV6_LSP_IDENTIFIERS = 19,    /* RFC 8231 */
+       PCEP_OBJ_TLV_TYPE_SYMBOLIC_PATH_NAME = 17,      /* RFC 8232 */
+       PCEP_OBJ_TLV_TYPE_IPV4_LSP_IDENTIFIERS = 18,    /* RFC 8231 */
+       PCEP_OBJ_TLV_TYPE_IPV6_LSP_IDENTIFIERS = 19,    /* RFC 8231 */
        PCEP_OBJ_TLV_TYPE_LSP_ERROR_CODE = 20,          /* RFC 8232 */
        PCEP_OBJ_TLV_TYPE_RSVP_ERROR_SPEC = 21,         /* RFC 8232 */
        PCEP_OBJ_TLV_TYPE_LSP_DB_VERSION = 23,          /* RFC 8232 */
-       PCEP_OBJ_TLV_TYPE_SPEAKER_ENTITY_ID = 24,       /* RFC 8232 */
+       PCEP_OBJ_TLV_TYPE_SPEAKER_ENTITY_ID = 24,       /* RFC 8232 */
        PCEP_OBJ_TLV_TYPE_SR_PCE_CAPABILITY =
                26, /* draft-ietf-pce-segment-routing-16 */
        PCEP_OBJ_TLV_TYPE_PATH_SETUP_TYPE = 28, /* RFC 8408 */
@@ -77,10 +77,12 @@ enum pcep_object_tlv_types {
        PCEP_OBJ_TLV_TYPE_SRPOLICY_CPATH_PREFERENCE =
                63, /*TDB5 draft-barth-pce-segment-routing-policy-cp-04 */
        PCEP_OBJ_TLV_TYPE_UNKNOWN = 128,
-       PCEP_OBJ_TLV_TYPE_ARBITRARY =
-               65533 /* Max IANA To write arbitrary data */
+       PCEP_OBJ_TYPE_CISCO_BSID = 65505,
+       /* Max IANA To write arbitrary data */
+       PCEP_OBJ_TLV_TYPE_ARBITRARY = 65533
 };
 
+
 struct pcep_object_tlv_header {
        enum pcep_object_tlv_types type;
        /* Pointer into encoded_message field from the pcep_message */
index 37f3353f76cf3a4012f994510605020859bd8658..d59c97c9daca39d3af2710f521512edd935d1b9c 100644 (file)
@@ -838,7 +838,15 @@ struct pcep_object_tlv_header *pcep_decode_tlv(const uint8_t *tlv_buf)
                return NULL;
        }
 
-       tlv_decoder_funcptr tlv_decoder = tlv_decoders[tlv_hdr.type];
+       tlv_decoder_funcptr tlv_decoder = NULL;
+       if (tlv_hdr.type == PCEP_OBJ_TYPE_CISCO_BSID) {
+               pcep_log(LOG_INFO,
+                        "%s: Cisco BSID TLV decoder found for TLV type [%d]",
+                        __func__, tlv_hdr.type);
+               tlv_decoder = tlv_decoders[PCEP_OBJ_TLV_TYPE_ARBITRARY];
+       } else {
+               tlv_decoder = tlv_decoders[tlv_hdr.type];
+       }
        if (tlv_decoder == NULL) {
                pcep_log(LOG_INFO, "%s: No TLV decoder found for TLV type [%d]",
                         __func__, tlv_hdr.type);
index 5a7644b21a42b52ba7f91dc5faa0dd77fbdd3e0b..e25ddb21799a089a49c812451badfa1bff7a7bff 100644 (file)
@@ -809,8 +809,8 @@ void test_pcep_msg_read_pcep_report_cisco_pcc()
        CU_ASSERT_EQUAL(lsp->header.object_type, PCEP_OBJ_TYPE_LSP);
        CU_ASSERT_EQUAL(lsp->header.encoded_object_length, 60);
        CU_ASSERT_PTR_NOT_NULL(lsp->header.tlv_list);
-       /* The TLV with ID 65505 is not recognized, and its not in the list */
-       CU_ASSERT_EQUAL(lsp->header.tlv_list->num_entries, 2);
+       /* The TLV with ID 65505 is now recognized, and its in the list */
+       CU_ASSERT_EQUAL(lsp->header.tlv_list->num_entries, 3);
        CU_ASSERT_EQUAL(lsp->plsp_id, 524303);
        CU_ASSERT_EQUAL(lsp->operational_status, PCEP_LSP_OPERATIONAL_DOWN);
        CU_ASSERT_TRUE(lsp->flag_a);
index f6072b1771bbbe58bdac5b7a4c54b292525a19e5..b3d44446521bf8384a51ef15bd8852e2072a4677 100644 (file)
@@ -3853,6 +3853,54 @@ static const char *pim_cli_get_vrf_name(struct vty *vty)
        return yang_dnode_get_string(vrf_node, "./name");
 }
 
+/**
+ * Compatibility function to keep the legacy mesh group CLI behavior:
+ * Delete group when there are no more configurations in it.
+ *
+ * NOTE:
+ * Don't forget to call `nb_cli_apply_changes` after this.
+ */
+static void pim_cli_legacy_mesh_group_behavior(struct vty *vty,
+                                              const char *gname)
+{
+       const char *vrfname;
+       char xpath_value[XPATH_MAXLEN];
+       char xpath_member_value[XPATH_MAXLEN];
+       const struct lyd_node *member_dnode;
+
+       vrfname = pim_cli_get_vrf_name(vty);
+       if (vrfname == NULL)
+               return;
+
+       /* Get mesh group base XPath. */
+       snprintf(xpath_value, sizeof(xpath_value),
+                FRR_PIM_AF_XPATH "/msdp-mesh-groups[name='%s']",
+                "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname);
+       /* Group must exists, otherwise just quit. */
+       if (!yang_dnode_exists(vty->candidate_config->dnode, xpath_value))
+               return;
+
+       /* Group members check: */
+       strlcpy(xpath_member_value, xpath_value, sizeof(xpath_member_value));
+       strlcat(xpath_member_value, "/members", sizeof(xpath_member_value));
+       if (yang_dnode_exists(vty->candidate_config->dnode,
+                             xpath_member_value)) {
+               member_dnode = yang_dnode_get(vty->candidate_config->dnode,
+                                             xpath_member_value);
+               if (!yang_is_last_list_dnode(member_dnode))
+                       return;
+       }
+
+       /* Source address check: */
+       strlcpy(xpath_member_value, xpath_value, sizeof(xpath_member_value));
+       strlcat(xpath_member_value, "/source", sizeof(xpath_member_value));
+       if (yang_dnode_exists(vty->candidate_config->dnode, xpath_member_value))
+               return;
+
+       /* No configurations found: delete it. */
+       nb_cli_enqueue_change(vty, xpath_value, NB_OP_DESTROY, NULL);
+}
+
 DEFUN (clear_ip_interfaces,
        clear_ip_interfaces_cmd,
        "clear ip interfaces [vrf NAME]",
@@ -9685,305 +9733,199 @@ DEFUN (no_ip_msdp_peer,
        return nb_cli_apply_changes(vty, NULL);
 }
 
-DEFUN (ip_msdp_mesh_group_member,
-       ip_msdp_mesh_group_member_cmd,
-       "ip msdp mesh-group WORD member A.B.C.D",
-       IP_STR
-       CFG_MSDP_STR
-       "Configure MSDP mesh-group\n"
-       "mesh group name\n"
-       "mesh group member\n"
-       "peer ip address\n")
+DEFPY(ip_msdp_mesh_group_member,
+      ip_msdp_mesh_group_member_cmd,
+      "ip msdp mesh-group WORD$gname member A.B.C.D$maddr",
+      IP_STR
+      CFG_MSDP_STR
+      "Configure MSDP mesh-group\n"
+      "Mesh group name\n"
+      "Mesh group member\n"
+      "Peer IP address\n")
 {
        const char *vrfname;
-       char msdp_mesh_group_name_xpath[XPATH_MAXLEN];
-       char msdp_mesh_group_member_xpath[XPATH_MAXLEN];
+       char xpath_value[XPATH_MAXLEN];
 
        vrfname = pim_cli_get_vrf_name(vty);
        if (vrfname == NULL)
                return CMD_WARNING_CONFIG_FAILED;
 
-       snprintf(msdp_mesh_group_name_xpath, sizeof(msdp_mesh_group_name_xpath),
-                FRR_PIM_AF_XPATH,
-                "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
-       strlcat(msdp_mesh_group_name_xpath, "/msdp-mesh-group/mesh-group-name",
-               sizeof(msdp_mesh_group_name_xpath));
-       snprintf(msdp_mesh_group_member_xpath,
-                sizeof(msdp_mesh_group_member_xpath),
-                FRR_PIM_AF_XPATH,
-                "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
-       strlcat(msdp_mesh_group_member_xpath, "/msdp-mesh-group/member-ip",
-               sizeof(msdp_mesh_group_member_xpath));
+       /* Create mesh group. */
+       snprintf(xpath_value, sizeof(xpath_value),
+                FRR_PIM_AF_XPATH "/msdp-mesh-groups[name='%s']",
+                "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname);
+       nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL);
 
-       nb_cli_enqueue_change(vty, msdp_mesh_group_name_xpath, NB_OP_MODIFY,
-                             argv[3]->arg);
-       nb_cli_enqueue_change(vty, msdp_mesh_group_member_xpath, NB_OP_CREATE,
-                             argv[5]->arg);
+       /* Create mesh group member. */
+       strlcat(xpath_value, "/members[address='", sizeof(xpath_value));
+       strlcat(xpath_value, maddr_str, sizeof(xpath_value));
+       strlcat(xpath_value, "']", sizeof(xpath_value));
+       nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL);
 
        return nb_cli_apply_changes(vty, NULL);
 }
 
-DEFUN (no_ip_msdp_mesh_group_member,
-       no_ip_msdp_mesh_group_member_cmd,
-       "no ip msdp mesh-group WORD member A.B.C.D",
-       NO_STR
-       IP_STR
-       CFG_MSDP_STR
-       "Delete MSDP mesh-group member\n"
-       "mesh group name\n"
-       "mesh group member\n"
-       "peer ip address\n")
+DEFPY(no_ip_msdp_mesh_group_member,
+      no_ip_msdp_mesh_group_member_cmd,
+      "no ip msdp mesh-group WORD$gname member A.B.C.D$maddr",
+      NO_STR
+      IP_STR
+      CFG_MSDP_STR
+      "Delete MSDP mesh-group member\n"
+      "Mesh group name\n"
+      "Mesh group member\n"
+      "Peer IP address\n")
 {
        const char *vrfname;
-       char pim_af_xpath[XPATH_MAXLEN];
-       char mesh_group_xpath[XPATH_MAXLEN + 32];
-       char group_member_list_xpath[XPATH_MAXLEN + 64];
-       char group_member_xpath[XPATH_MAXLEN + 128];
-       char source_xpath[XPATH_MAXLEN + 64];
-       char mesh_group_name_xpath[XPATH_MAXLEN + 64];
-       const char *mesh_group_name;
-       const struct lyd_node *member_dnode;
+       char xpath_value[XPATH_MAXLEN];
+       char xpath_member_value[XPATH_MAXLEN];
 
        vrfname = pim_cli_get_vrf_name(vty);
        if (vrfname == NULL)
                return CMD_WARNING_CONFIG_FAILED;
 
-       snprintf(pim_af_xpath, sizeof(pim_af_xpath), FRR_PIM_AF_XPATH,
-                "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
+       /* Get mesh group base XPath. */
+       snprintf(xpath_value, sizeof(xpath_value),
+                FRR_PIM_AF_XPATH "/msdp-mesh-groups[name='%s']",
+                "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname);
 
-       snprintf(mesh_group_xpath, sizeof(mesh_group_xpath),
-                "%s/msdp-mesh-group", pim_af_xpath);
-
-       snprintf(group_member_list_xpath, sizeof(group_member_list_xpath),
-                "%s/msdp-mesh-group/member-ip", pim_af_xpath);
-
-       snprintf(group_member_xpath, sizeof(group_member_xpath), "%s[.='%s']",
-                group_member_list_xpath, argv[6]->arg);
-
-       snprintf(source_xpath, sizeof(source_xpath),
-                "%s/msdp-mesh-group/source-ip", pim_af_xpath);
-
-       snprintf(mesh_group_name_xpath, sizeof(mesh_group_name_xpath),
-                "%s/msdp-mesh-group/mesh-group-name", pim_af_xpath);
-
-       if (yang_dnode_exists(running_config->dnode, mesh_group_name_xpath)
-           == true) {
-               mesh_group_name = yang_dnode_get_string(running_config->dnode,
-                                                       mesh_group_name_xpath);
-               if (strcmp(mesh_group_name, argv[4]->arg)) {
-                       vty_out(vty, "%% mesh-group does not exist\n");
-                       return CMD_WARNING_CONFIG_FAILED;
-               }
+       if (!yang_dnode_exists(vty->candidate_config->dnode, xpath_value)) {
+               vty_out(vty, "%% mesh-group does not exist\n");
+               return CMD_WARNING_CONFIG_FAILED;
        }
 
-       if (yang_dnode_exists(vty->candidate_config->dnode,
-                             group_member_xpath)) {
-               if (!yang_dnode_exists(vty->candidate_config->dnode,
-                                      source_xpath)) {
-                       member_dnode = yang_dnode_get(
-                               vty->candidate_config->dnode,
-                               group_member_xpath);
-                       if (yang_is_last_list_dnode(member_dnode)) {
-                               nb_cli_enqueue_change(vty, mesh_group_xpath,
-                                                     NB_OP_DESTROY, NULL);
-                               return nb_cli_apply_changes(vty, NULL);
-                       }
-                       nb_cli_enqueue_change(vty, group_member_list_xpath,
-                                             NB_OP_DESTROY, argv[6]->arg);
-                       return nb_cli_apply_changes(vty, NULL);
-               }
-               nb_cli_enqueue_change(vty, group_member_list_xpath,
-                                     NB_OP_DESTROY, argv[6]->arg);
-               return nb_cli_apply_changes(vty, NULL);
+       /* Remove mesh group member. */
+       strlcpy(xpath_member_value, xpath_value, sizeof(xpath_member_value));
+       strlcat(xpath_member_value, "/members[address='",
+               sizeof(xpath_member_value));
+       strlcat(xpath_member_value, maddr_str, sizeof(xpath_member_value));
+       strlcat(xpath_member_value, "']", sizeof(xpath_member_value));
+       if (!yang_dnode_exists(vty->candidate_config->dnode,
+                              xpath_member_value)) {
+               vty_out(vty, "%% mesh-group member does not exist\n");
+               return CMD_WARNING_CONFIG_FAILED;
        }
 
-       vty_out(vty, "%% mesh-group member does not exist\n");
+       nb_cli_enqueue_change(vty, xpath_value, NB_OP_DESTROY, NULL);
 
-       return CMD_SUCCESS;
+       /*
+        * If this is the last member, then we must remove the group altogether
+        * to not break legacy CLI behaviour.
+        */
+       pim_cli_legacy_mesh_group_behavior(vty, gname);
+
+       return nb_cli_apply_changes(vty, NULL);
 }
 
-DEFUN (ip_msdp_mesh_group_source,
-       ip_msdp_mesh_group_source_cmd,
-       "ip msdp mesh-group WORD source A.B.C.D",
-       IP_STR
-       CFG_MSDP_STR
-       "Configure MSDP mesh-group\n"
-       "mesh group name\n"
-       "mesh group local address\n"
-       "source ip address for the TCP connection\n")
+DEFPY(ip_msdp_mesh_group_source,
+      ip_msdp_mesh_group_source_cmd,
+      "ip msdp mesh-group WORD$gname source A.B.C.D$saddr",
+      IP_STR
+      CFG_MSDP_STR
+      "Configure MSDP mesh-group\n"
+      "Mesh group name\n"
+      "Mesh group local address\n"
+      "Source IP address for the TCP connection\n")
 {
        const char *vrfname;
-       char msdp_mesh_source_ip_xpath[XPATH_MAXLEN];
-       char msdp_mesh_group_name_xpath[XPATH_MAXLEN];
+       char xpath_value[XPATH_MAXLEN];
 
        vrfname = pim_cli_get_vrf_name(vty);
        if (vrfname == NULL)
                return CMD_WARNING_CONFIG_FAILED;
 
-       snprintf(msdp_mesh_group_name_xpath, sizeof(msdp_mesh_group_name_xpath),
-                FRR_PIM_AF_XPATH,
-                "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
-       strlcat(msdp_mesh_group_name_xpath, "/msdp-mesh-group/mesh-group-name",
-               sizeof(msdp_mesh_group_name_xpath));
-
-       snprintf(msdp_mesh_source_ip_xpath, sizeof(msdp_mesh_source_ip_xpath),
-                FRR_PIM_AF_XPATH,
-                "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
-       strlcat(msdp_mesh_source_ip_xpath, "/msdp-mesh-group/source-ip",
-               sizeof(msdp_mesh_source_ip_xpath));
+       /* Create mesh group. */
+       snprintf(xpath_value, sizeof(xpath_value),
+                FRR_PIM_AF_XPATH "/msdp-mesh-groups[name='%s']",
+                "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname);
+       nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL);
 
-       nb_cli_enqueue_change(vty, msdp_mesh_group_name_xpath, NB_OP_MODIFY,
-                             argv[3]->arg);
-       nb_cli_enqueue_change(vty, msdp_mesh_source_ip_xpath, NB_OP_MODIFY,
-                             argv[5]->arg);
+       /* Create mesh group member. */
+       strlcat(xpath_value, "/source", sizeof(xpath_value));
+       nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, saddr_str);
 
        return nb_cli_apply_changes(vty, NULL);
 }
 
-DEFUN (no_ip_msdp_mesh_group_source,
-       no_ip_msdp_mesh_group_source_cmd,
-       "no ip msdp mesh-group WORD source [A.B.C.D]",
-       NO_STR
-       IP_STR
-       CFG_MSDP_STR
-       "Delete MSDP mesh-group source\n"
-       "mesh group name\n"
-       "mesh group source\n"
-       "mesh group local address\n")
+DEFPY(no_ip_msdp_mesh_group_source,
+      no_ip_msdp_mesh_group_source_cmd,
+      "no ip msdp mesh-group WORD$gname source [A.B.C.D]",
+      NO_STR
+      IP_STR
+      CFG_MSDP_STR
+      "Delete MSDP mesh-group source\n"
+      "Mesh group name\n"
+      "Mesh group source\n"
+      "Mesh group local address\n")
 {
        const char *vrfname;
-       char msdp_mesh_xpath[XPATH_MAXLEN];
-       char source_xpath[XPATH_MAXLEN];
-       char group_member_xpath[XPATH_MAXLEN];
-       char mesh_group_name_xpath[XPATH_MAXLEN];
-       const char *mesh_group_name;
+       char xpath_value[XPATH_MAXLEN];
 
        vrfname = pim_cli_get_vrf_name(vty);
        if (vrfname == NULL)
                return CMD_WARNING_CONFIG_FAILED;
 
-       snprintf(msdp_mesh_xpath, sizeof(msdp_mesh_xpath),
-                FRR_PIM_AF_XPATH,
-                "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
-       strlcat(msdp_mesh_xpath, "/msdp-mesh-group", sizeof(msdp_mesh_xpath));
+       /* Get mesh group base XPath. */
+       snprintf(xpath_value, sizeof(xpath_value),
+                FRR_PIM_AF_XPATH "/msdp-mesh-groups[name='%s']",
+                "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname);
+       nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL);
 
-       snprintf(source_xpath, sizeof(source_xpath),
-                FRR_PIM_AF_XPATH,
-                "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
-       strlcat(source_xpath, "/msdp-mesh-group/source-ip",
-               sizeof(source_xpath));
+       /* Create mesh group member. */
+       strlcat(xpath_value, "/source", sizeof(xpath_value));
+       nb_cli_enqueue_change(vty, xpath_value, NB_OP_DESTROY, NULL);
 
-       snprintf(group_member_xpath,
-                sizeof(group_member_xpath),
-                FRR_PIM_AF_XPATH,
-                "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
-       strlcat(group_member_xpath, "/msdp-mesh-group/member-ip",
-               sizeof(group_member_xpath));
+       /*
+        * If this is the last member, then we must remove the group altogether
+        * to not break legacy CLI behaviour.
+        */
+       pim_cli_legacy_mesh_group_behavior(vty, gname);
 
-       snprintf(mesh_group_name_xpath, sizeof(mesh_group_name_xpath),
-                FRR_PIM_AF_XPATH,
-                "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
-       strlcat(mesh_group_name_xpath, "/msdp-mesh-group/mesh-group-name",
-               sizeof(mesh_group_name_xpath));
-
-       if (yang_dnode_exists(running_config->dnode, mesh_group_name_xpath)
-           == true) {
-               mesh_group_name = yang_dnode_get_string(running_config->dnode,
-                                                       mesh_group_name_xpath);
-               if (strcmp(mesh_group_name, argv[4]->arg)) {
-                       vty_out(vty, "%% mesh-group does not exist\n");
-                       return CMD_WARNING_CONFIG_FAILED;
-               }
-       }
-
-       if (!yang_dnode_exists(vty->candidate_config->dnode,
-                              group_member_xpath)) {
-               nb_cli_enqueue_change(vty, msdp_mesh_xpath, NB_OP_DESTROY,
-                                     NULL);
-               return nb_cli_apply_changes(vty, NULL);
-       }
-       nb_cli_enqueue_change(vty, source_xpath, NB_OP_DESTROY, NULL);
        return nb_cli_apply_changes(vty, NULL);
 }
 
-DEFUN (no_ip_msdp_mesh_group,
-       no_ip_msdp_mesh_group_cmd,
-       "no ip msdp mesh-group [WORD]",
-       NO_STR
-       IP_STR
-       CFG_MSDP_STR
-       "Delete MSDP mesh-group\n"
-       "mesh group name")
+DEFPY(no_ip_msdp_mesh_group,
+      no_ip_msdp_mesh_group_cmd,
+      "no ip msdp mesh-group WORD$gname",
+      NO_STR
+      IP_STR
+      CFG_MSDP_STR
+      "Delete MSDP mesh-group\n"
+      "Mesh group name")
 {
        const char *vrfname;
-       const char *mesh_group_name;
-       char xpath[XPATH_MAXLEN];
-       char msdp_mesh_xpath[XPATH_MAXLEN];
+       char xpath_value[XPATH_MAXLEN];
 
        vrfname = pim_cli_get_vrf_name(vty);
        if (vrfname == NULL)
                return CMD_WARNING_CONFIG_FAILED;
 
-       if (argc == 5) {
-               snprintf(xpath, sizeof(xpath), FRR_PIM_AF_XPATH, "frr-pim:pimd",
-                        "pim", vrfname, "frr-routing:ipv4");
-               strlcat(xpath, "/msdp-mesh-group/mesh-group-name",
-                       sizeof(xpath));
-
-               if (yang_dnode_exists(running_config->dnode, xpath) == true) {
-                       mesh_group_name =
-                               yang_dnode_get_string(running_config->dnode,
-                                                     xpath);
-
-                       if (strcmp(mesh_group_name, argv[4]->arg)) {
-                               vty_out(vty, "%% mesh-group does not exist\n");
-                               return CMD_WARNING_CONFIG_FAILED;
-                       }
-               }
-       }
-
-       snprintf(msdp_mesh_xpath, sizeof(msdp_mesh_xpath),
-                FRR_PIM_AF_XPATH,
-                "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
-       strlcat(msdp_mesh_xpath, "/msdp-mesh-group", sizeof(msdp_mesh_xpath));
+       /* Get mesh group base XPath. */
+       snprintf(xpath_value, sizeof(xpath_value),
+                FRR_PIM_AF_XPATH "/msdp-mesh-groups[name='%s']",
+                "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname);
+       if (!yang_dnode_exists(vty->candidate_config->dnode, xpath_value))
+               return CMD_SUCCESS;
 
-       nb_cli_enqueue_change(vty, msdp_mesh_xpath, NB_OP_DESTROY, NULL);
+       nb_cli_enqueue_change(vty, xpath_value, NB_OP_DESTROY, NULL);
        return nb_cli_apply_changes(vty, NULL);
 }
 
-static void print_empty_json_obj(struct vty *vty)
-{
-       json_object *json;
-       json = json_object_new_object();
-       vty_out(vty, "%s\n",
-               json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY));
-       json_object_free(json);
-}
-
-static void ip_msdp_show_mesh_group(struct pim_instance *pim, struct vty *vty,
-                                   bool uj)
+static void ip_msdp_show_mesh_group(struct vty *vty, struct pim_msdp_mg *mg,
+                                   struct json_object *json)
 {
        struct listnode *mbrnode;
        struct pim_msdp_mg_mbr *mbr;
-       struct pim_msdp_mg *mg = pim->msdp.mg;
        char mbr_str[INET_ADDRSTRLEN];
        char src_str[INET_ADDRSTRLEN];
        char state_str[PIM_MSDP_STATE_STRLEN];
        enum pim_msdp_peer_state state;
-       json_object *json = NULL;
        json_object *json_mg_row = NULL;
        json_object *json_members = NULL;
        json_object *json_row = NULL;
 
-       if (!mg) {
-               if (uj)
-                       print_empty_json_obj(vty);
-               return;
-       }
-
        pim_inet4_dump("<source?>", mg->src_ip, src_str, sizeof(src_str));
-       if (uj) {
-               json = json_object_new_object();
+       if (json) {
                /* currently there is only one mesh group but we should still
                 * make
                 * it a dict with mg-name as key */
@@ -10005,7 +9947,7 @@ static void ip_msdp_show_mesh_group(struct pim_instance *pim, struct vty *vty,
                        state = PIM_MSDP_DISABLED;
                }
                pim_msdp_state_dump(state, state_str, sizeof(state_str));
-               if (uj) {
+               if (json) {
                        json_row = json_object_new_object();
                        json_object_string_add(json_row, "member", mbr_str);
                        json_object_string_add(json_row, "state", state_str);
@@ -10020,12 +9962,8 @@ static void ip_msdp_show_mesh_group(struct pim_instance *pim, struct vty *vty,
                }
        }
 
-       if (uj) {
+       if (json)
                json_object_object_add(json, mg->mesh_group_name, json_mg_row);
-               vty_out(vty, "%s\n", json_object_to_json_string_ext(
-                               json, JSON_C_TO_STRING_PRETTY));
-               json_object_free(json);
-       }
 }
 
 DEFUN (show_ip_msdp_mesh_group,
@@ -10040,12 +9978,34 @@ DEFUN (show_ip_msdp_mesh_group,
 {
        bool uj = use_json(argc, argv);
        int idx = 2;
+       struct pim_msdp_mg *mg;
        struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+       struct pim_instance *pim = vrf->info;
+       struct json_object *json = NULL;
 
        if (!vrf)
                return CMD_WARNING;
 
-       ip_msdp_show_mesh_group(vrf->info, vty, uj);
+       /* Quick case: list is empty. */
+       if (SLIST_EMPTY(&pim->msdp.mglist)) {
+               if (uj)
+                       vty_out(vty, "{}\n");
+
+               return CMD_SUCCESS;
+       }
+
+       if (uj)
+               json = json_object_new_object();
+
+       SLIST_FOREACH (mg, &pim->msdp.mglist, mg_entry)
+               ip_msdp_show_mesh_group(vty, mg, json);
+
+       if (uj) {
+               vty_out(vty, "%s\n",
+                       json_object_to_json_string_ext(
+                               json, JSON_C_TO_STRING_PRETTY));
+               json_object_free(json);
+       }
 
        return CMD_SUCCESS;
 }
@@ -10061,23 +10021,32 @@ DEFUN (show_ip_msdp_mesh_group_vrf_all,
        JSON_STR)
 {
        bool uj = use_json(argc, argv);
+       struct json_object *json = NULL, *vrf_json = NULL;
+       struct pim_instance *pim;
+       struct pim_msdp_mg *mg;
        struct vrf *vrf;
-       bool first = true;
 
        if (uj)
-               vty_out(vty, "{ ");
+               json = json_object_new_object();
+
        RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
                if (uj) {
-                       if (!first)
-                               vty_out(vty, ", ");
-                       vty_out(vty, " \"%s\": ", vrf->name);
-                       first = false;
+                       vrf_json = json_object_new_object();
+                       json_object_object_add(json, vrf->name, vrf_json);
                } else
                        vty_out(vty, "VRF: %s\n", vrf->name);
-               ip_msdp_show_mesh_group(vrf->info, vty, uj);
+
+               pim = vrf->info;
+               SLIST_FOREACH (mg, &pim->msdp.mglist, mg_entry)
+                       ip_msdp_show_mesh_group(vty, mg, vrf_json);
+       }
+
+       if (uj) {
+               vty_out(vty, "%s\n",
+                       json_object_to_json_string_ext(
+                               json, JSON_C_TO_STRING_PRETTY));
+               json_object_free(json);
        }
-       if (uj)
-               vty_out(vty, "}\n");
 
        return CMD_SUCCESS;
 }
index 9cf73c38c3aba6570cdb1d69fb0a58ec3955e954..095c6de549a120c4dbd77eabab3860f3a91c6a98 100644 (file)
@@ -58,8 +58,6 @@ static void pim_msdp_sa_deref(struct pim_msdp_sa *sa,
                              enum pim_msdp_sa_flags flags);
 static int pim_msdp_mg_mbr_comp(const void *p1, const void *p2);
 static void pim_msdp_mg_mbr_free(struct pim_msdp_mg_mbr *mbr);
-static void pim_msdp_mg_mbr_do_del(struct pim_msdp_mg *mg,
-                                  struct pim_msdp_mg_mbr *mbr);
 
 /************************ SA cache management ******************************/
 static void pim_msdp_sa_timer_expiry_log(struct pim_msdp_sa *sa,
@@ -1252,27 +1250,33 @@ static int pim_msdp_peer_comp(const void *p1, const void *p2)
 }
 
 /************************** Mesh group management **************************/
-static void pim_msdp_mg_free(struct pim_instance *pim)
+void pim_msdp_mg_free(struct pim_instance *pim, struct pim_msdp_mg **mgp)
 {
-       struct pim_msdp_mg *mg = pim->msdp.mg;
+       struct pim_msdp_mg_mbr *mbr;
+       struct listnode *n, *nn;
 
-       /* If the mesh-group has valid member or src_ip don't delete it */
-       if (!mg || mg->mbr_cnt || (mg->src_ip.s_addr != INADDR_ANY)) {
+       if (*mgp == NULL)
                return;
-       }
+
+       /* SIP is being removed - tear down all active peer sessions */
+       for (ALL_LIST_ELEMENTS((*mgp)->mbr_list, n, nn, mbr))
+               pim_msdp_mg_mbr_del((*mgp), mbr);
 
        if (PIM_DEBUG_MSDP_EVENTS) {
-               zlog_debug("MSDP mesh-group %s deleted", mg->mesh_group_name);
+               zlog_debug("MSDP mesh-group %s deleted",
+                          (*mgp)->mesh_group_name);
        }
-       XFREE(MTYPE_PIM_MSDP_MG_NAME, mg->mesh_group_name);
 
-       if (mg->mbr_list)
-               list_delete(&mg->mbr_list);
+       XFREE(MTYPE_PIM_MSDP_MG_NAME, (*mgp)->mesh_group_name);
+
+       if ((*mgp)->mbr_list)
+               list_delete(&(*mgp)->mbr_list);
 
-       XFREE(MTYPE_PIM_MSDP_MG, pim->msdp.mg);
+       XFREE(MTYPE_PIM_MSDP_MG, (*mgp));
 }
 
-static struct pim_msdp_mg *pim_msdp_mg_new(const char *mesh_group_name)
+struct pim_msdp_mg *pim_msdp_mg_new(struct pim_instance *pim,
+                                   const char *mesh_group_name)
 {
        struct pim_msdp_mg *mg;
 
@@ -1286,52 +1290,10 @@ static struct pim_msdp_mg *pim_msdp_mg_new(const char *mesh_group_name)
        if (PIM_DEBUG_MSDP_EVENTS) {
                zlog_debug("MSDP mesh-group %s created", mg->mesh_group_name);
        }
-       return mg;
-}
-
-enum pim_msdp_err pim_msdp_mg_del(struct pim_instance *pim,
-                                 const char *mesh_group_name)
-{
-       struct pim_msdp_mg *mg = pim->msdp.mg;
-       struct pim_msdp_mg_mbr *mbr;
-
-       if (!mg
-           || (mesh_group_name
-               && strcmp(mg->mesh_group_name, mesh_group_name))) {
-               return PIM_MSDP_ERR_NO_MG;
-       }
-
-       /* delete all the mesh-group members */
-       while (!list_isempty(mg->mbr_list)) {
-               mbr = listnode_head(mg->mbr_list);
-               pim_msdp_mg_mbr_do_del(mg, mbr);
-       }
-
-       /* clear src ip */
-       mg->src_ip.s_addr = INADDR_ANY;
-
-       /* free up the mesh-group */
-       pim_msdp_mg_free(pim);
-       return PIM_MSDP_ERR_NONE;
-}
-
-static enum pim_msdp_err pim_msdp_mg_add(struct pim_instance *pim,
-                                        const char *mesh_group_name)
-{
-       if (pim->msdp.mg) {
-               if (!strcmp(pim->msdp.mg->mesh_group_name, mesh_group_name)) {
-                       return PIM_MSDP_ERR_NONE;
-               }
-               /* currently only one mesh-group can exist at a time */
-               return PIM_MSDP_ERR_MAX_MESH_GROUPS;
-       }
 
-       pim->msdp.mg = pim_msdp_mg_new(mesh_group_name);
-       if (!pim->msdp.mg) {
-               return PIM_MSDP_ERR_OOM;
-       }
+       SLIST_INSERT_HEAD(&pim->msdp.mglist, mg, mg_entry);
 
-       return PIM_MSDP_ERR_NONE;
+       return mg;
 }
 
 static int pim_msdp_mg_mbr_comp(const void *p1, const void *p2)
@@ -1353,66 +1315,7 @@ static void pim_msdp_mg_mbr_free(struct pim_msdp_mg_mbr *mbr)
        XFREE(MTYPE_PIM_MSDP_MG_MBR, mbr);
 }
 
-static struct pim_msdp_mg_mbr *pim_msdp_mg_mbr_find(struct pim_instance *pim,
-                                                   struct in_addr mbr_ip)
-{
-       struct pim_msdp_mg_mbr *mbr;
-       struct listnode *mbr_node;
-
-       if (!pim->msdp.mg) {
-               return NULL;
-       }
-       /* we can move this to a hash but considering that number of peers in
-        * a mesh-group that seems like bit of an overkill */
-       for (ALL_LIST_ELEMENTS_RO(pim->msdp.mg->mbr_list, mbr_node, mbr)) {
-               if (mbr->mbr_ip.s_addr == mbr_ip.s_addr) {
-                       return mbr;
-               }
-       }
-       return mbr;
-}
-
-enum pim_msdp_err pim_msdp_mg_mbr_add(struct pim_instance *pim,
-                                     const char *mesh_group_name,
-                                     struct in_addr mbr_ip)
-{
-       int rc;
-       struct pim_msdp_mg_mbr *mbr;
-       struct pim_msdp_mg *mg;
-
-       rc = pim_msdp_mg_add(pim, mesh_group_name);
-       if (rc != PIM_MSDP_ERR_NONE) {
-               return rc;
-       }
-
-       mg = pim->msdp.mg;
-       mbr = pim_msdp_mg_mbr_find(pim, mbr_ip);
-       if (mbr) {
-               return PIM_MSDP_ERR_MG_MBR_EXISTS;
-       }
-
-       mbr = XCALLOC(MTYPE_PIM_MSDP_MG_MBR, sizeof(*mbr));
-       mbr->mbr_ip = mbr_ip;
-       listnode_add_sort(mg->mbr_list, mbr);
-
-       /* if valid SIP has been configured add peer session */
-       if (mg->src_ip.s_addr != INADDR_ANY) {
-               pim_msdp_peer_add(pim, mbr_ip, mg->src_ip, mesh_group_name,
-                                 &mbr->mp);
-       }
-
-       if (PIM_DEBUG_MSDP_EVENTS) {
-               char ip_str[INET_ADDRSTRLEN];
-               pim_inet4_dump("<mbr?>", mbr->mbr_ip, ip_str, sizeof(ip_str));
-               zlog_debug("MSDP mesh-group %s mbr %s created",
-                          mg->mesh_group_name, ip_str);
-       }
-       ++mg->mbr_cnt;
-       return PIM_MSDP_ERR_NONE;
-}
-
-static void pim_msdp_mg_mbr_do_del(struct pim_msdp_mg *mg,
-                                  struct pim_msdp_mg_mbr *mbr)
+void pim_msdp_mg_mbr_del(struct pim_msdp_mg *mg, struct pim_msdp_mg_mbr *mbr)
 {
        /* Delete active peer session if any */
        if (mbr->mp) {
@@ -1432,34 +1335,10 @@ static void pim_msdp_mg_mbr_do_del(struct pim_msdp_mg *mg,
        }
 }
 
-enum pim_msdp_err pim_msdp_mg_mbr_del(struct pim_instance *pim,
-                                     const char *mesh_group_name,
-                                     struct in_addr mbr_ip)
-{
-       struct pim_msdp_mg_mbr *mbr;
-       struct pim_msdp_mg *mg = pim->msdp.mg;
-
-       if (!mg || strcmp(mg->mesh_group_name, mesh_group_name)) {
-               return PIM_MSDP_ERR_NO_MG;
-       }
-
-       mbr = pim_msdp_mg_mbr_find(pim, mbr_ip);
-       if (!mbr) {
-               return PIM_MSDP_ERR_NO_MG_MBR;
-       }
-
-       pim_msdp_mg_mbr_do_del(mg, mbr);
-       /* if there are no references to the mg free it */
-       pim_msdp_mg_free(pim);
-
-       return PIM_MSDP_ERR_NONE;
-}
-
-static void pim_msdp_mg_src_do_del(struct pim_instance *pim)
+static void pim_msdp_src_del(struct pim_msdp_mg *mg)
 {
        struct pim_msdp_mg_mbr *mbr;
        struct listnode *mbr_node;
-       struct pim_msdp_mg *mg = pim->msdp.mg;
 
        /* SIP is being removed - tear down all active peer sessions */
        for (ALL_LIST_ELEMENTS_RO(mg->mbr_list, mbr_node, mbr)) {
@@ -1474,91 +1353,38 @@ static void pim_msdp_mg_src_do_del(struct pim_instance *pim)
        }
 }
 
-enum pim_msdp_err pim_msdp_mg_src_del(struct pim_instance *pim,
-                                     const char *mesh_group_name)
-{
-       struct pim_msdp_mg *mg = pim->msdp.mg;
-
-       if (!mg || strcmp(mg->mesh_group_name, mesh_group_name)) {
-               return PIM_MSDP_ERR_NO_MG;
-       }
-
-       if (mg->src_ip.s_addr != INADDR_ANY) {
-               mg->src_ip.s_addr = INADDR_ANY;
-               pim_msdp_mg_src_do_del(pim);
-               /* if there are no references to the mg free it */
-               pim_msdp_mg_free(pim);
-       }
-       return PIM_MSDP_ERR_NONE;
-}
-
-enum pim_msdp_err pim_msdp_mg_src_add(struct pim_instance *pim,
-                                     const char *mesh_group_name,
-                                     struct in_addr src_ip)
-{
-       int rc;
-       struct pim_msdp_mg_mbr *mbr;
-       struct listnode *mbr_node;
-       struct pim_msdp_mg *mg;
-
-       if (src_ip.s_addr == INADDR_ANY) {
-               pim_msdp_mg_src_del(pim, mesh_group_name);
-               return PIM_MSDP_ERR_NONE;
-       }
-
-       rc = pim_msdp_mg_add(pim, mesh_group_name);
-       if (rc != PIM_MSDP_ERR_NONE) {
-               return rc;
-       }
-
-       mg = pim->msdp.mg;
-       if (mg->src_ip.s_addr != INADDR_ANY) {
-               pim_msdp_mg_src_do_del(pim);
-       }
-       mg->src_ip = src_ip;
-
-       for (ALL_LIST_ELEMENTS_RO(mg->mbr_list, mbr_node, mbr)) {
-               pim_msdp_peer_add(pim, mbr->mbr_ip, mg->src_ip, mesh_group_name,
-                                 &mbr->mp);
-       }
-
-       if (PIM_DEBUG_MSDP_EVENTS) {
-               char ip_str[INET_ADDRSTRLEN];
-               pim_inet4_dump("<src?>", mg->src_ip, ip_str, sizeof(ip_str));
-               zlog_debug("MSDP mesh-group %s src %s set", mg->mesh_group_name,
-                          ip_str);
-       }
-       return PIM_MSDP_ERR_NONE;
-}
-
 /*********************** MSDP feature APIs *********************************/
 int pim_msdp_config_write(struct pim_instance *pim, struct vty *vty,
                          const char *spaces)
 {
+       struct pim_msdp_mg *mg;
        struct listnode *mbrnode;
        struct pim_msdp_mg_mbr *mbr;
-       struct pim_msdp_mg *mg = pim->msdp.mg;
        char mbr_str[INET_ADDRSTRLEN];
        char src_str[INET_ADDRSTRLEN];
        int count = 0;
 
-       if (!mg) {
+       if (SLIST_EMPTY(&pim->msdp.mglist))
                return count;
-       }
 
-       if (mg->src_ip.s_addr != INADDR_ANY) {
-               pim_inet4_dump("<src?>", mg->src_ip, src_str, sizeof(src_str));
-               vty_out(vty, "%sip msdp mesh-group %s source %s\n", spaces,
-                       mg->mesh_group_name, src_str);
-               ++count;
-       }
+       SLIST_FOREACH (mg, &pim->msdp.mglist, mg_entry) {
+               if (mg->src_ip.s_addr != INADDR_ANY) {
+                       pim_inet4_dump("<src?>", mg->src_ip, src_str,
+                                      sizeof(src_str));
+                       vty_out(vty, "%sip msdp mesh-group %s source %s\n",
+                               spaces, mg->mesh_group_name, src_str);
+                       ++count;
+               }
 
-       for (ALL_LIST_ELEMENTS_RO(mg->mbr_list, mbrnode, mbr)) {
-               pim_inet4_dump("<mbr?>", mbr->mbr_ip, mbr_str, sizeof(mbr_str));
-               vty_out(vty, "%sip msdp mesh-group %s member %s\n", spaces,
-                       mg->mesh_group_name, mbr_str);
-               ++count;
+               for (ALL_LIST_ELEMENTS_RO(mg->mbr_list, mbrnode, mbr)) {
+                       pim_inet4_dump("<mbr?>", mbr->mbr_ip, mbr_str,
+                                      sizeof(mbr_str));
+                       vty_out(vty, "%sip msdp mesh-group %s member %s\n",
+                               spaces, mg->mesh_group_name, mbr_str);
+                       ++count;
+               }
        }
+
        return count;
 }
 
@@ -1623,11 +1449,13 @@ void pim_msdp_init(struct pim_instance *pim, struct thread_master *master)
 /* counterpart to MSDP init; XXX: unused currently */
 void pim_msdp_exit(struct pim_instance *pim)
 {
-       pim_msdp_sa_adv_timer_setup(pim, false);
+       struct pim_msdp_mg *mg;
 
-       /* XXX: stop listener and delete all peer sessions */
+       pim_msdp_sa_adv_timer_setup(pim, false);
 
-       pim_msdp_mg_free(pim);
+       /* Stop listener and delete all peer sessions */
+       while ((mg = SLIST_FIRST(&pim->msdp.mglist)) != NULL)
+               pim_msdp_mg_free(pim, &mg);
 
        if (pim->msdp.peer_hash) {
                hash_clean(pim->msdp.peer_hash, NULL);
@@ -1653,3 +1481,57 @@ void pim_msdp_exit(struct pim_instance *pim)
                stream_free(pim->msdp.work_obuf);
        pim->msdp.work_obuf = NULL;
 }
+
+void pim_msdp_mg_src_add(struct pim_instance *pim, struct pim_msdp_mg *mg,
+                        struct in_addr *ai)
+{
+       struct pim_msdp_mg_mbr *mbr;
+       struct listnode *mbr_node;
+
+       /* Stop all connections and remove data structures. */
+       pim_msdp_src_del(mg);
+
+       /* Set new address. */
+       mg->src_ip = *ai;
+
+       /* No new address, disable everyone. */
+       if (ai->s_addr == INADDR_ANY) {
+               if (PIM_DEBUG_MSDP_EVENTS)
+                       zlog_debug("MSDP mesh-group %s src unset",
+                                  mg->mesh_group_name);
+               return;
+       }
+
+       /* Create data structures and start TCP connection. */
+       for (ALL_LIST_ELEMENTS_RO(mg->mbr_list, mbr_node, mbr))
+               pim_msdp_peer_add(pim, mbr->mbr_ip, mg->src_ip,
+                                 mg->mesh_group_name, &mbr->mp);
+
+       if (PIM_DEBUG_MSDP_EVENTS)
+               zlog_debug("MSDP mesh-group %s src %pI4 set",
+                          mg->mesh_group_name, &mg->src_ip);
+}
+
+struct pim_msdp_mg_mbr *pim_msdp_mg_mbr_add(struct pim_instance *pim,
+                                           struct pim_msdp_mg *mg,
+                                           struct in_addr *ia)
+{
+       struct pim_msdp_mg_mbr *mbr;
+
+       mbr = XCALLOC(MTYPE_PIM_MSDP_MG_MBR, sizeof(*mbr));
+       mbr->mbr_ip = *ia;
+       listnode_add_sort(mg->mbr_list, mbr);
+
+       /* if valid SIP has been configured add peer session */
+       if (mg->src_ip.s_addr != INADDR_ANY)
+               pim_msdp_peer_add(pim, mbr->mbr_ip, mg->src_ip,
+                                 mg->mesh_group_name, &mbr->mp);
+
+       if (PIM_DEBUG_MSDP_EVENTS)
+               zlog_debug("MSDP mesh-group %s mbr %pI4 created",
+                          mg->mesh_group_name, &mbr->mbr_ip);
+
+       ++mg->mbr_cnt;
+
+       return mbr;
+}
index 4d01880fbfc46cfe6e7b4ba67ca353352a525b81..bb7ee01ad819a1a0fb0d33c3f3f8833fee3b2e4f 100644 (file)
@@ -19,6 +19,8 @@
 #ifndef PIM_MSDP_H
 #define PIM_MSDP_H
 
+#include "lib/openbsd-queue.h"
+
 enum pim_msdp_peer_state {
        PIM_MSDP_DISABLED,
        PIM_MSDP_INACTIVE,
@@ -160,8 +162,13 @@ struct pim_msdp_mg {
        struct in_addr src_ip;
        uint32_t mbr_cnt;
        struct list *mbr_list;
+
+       /** Belongs to PIM instance list. */
+       SLIST_ENTRY(pim_msdp_mg) mg_entry;
 };
 
+SLIST_HEAD(pim_mesh_group_list, pim_msdp_mg);
+
 enum pim_msdp_flags {
        PIM_MSDPF_NONE = 0,
        PIM_MSDPF_ENABLE = (1 << 0),
@@ -196,8 +203,8 @@ struct pim_msdp {
 
        struct in_addr originator_id;
 
-       /* currently only one mesh-group is supported - so just stash it here */
-       struct pim_msdp_mg *mg;
+       /** List of mesh groups. */
+       struct pim_mesh_group_list mglist;
 };
 
 #define PIM_MSDP_PEER_READ_ON(mp)                                              \
@@ -246,17 +253,39 @@ bool pim_msdp_peer_rpf_check(struct pim_msdp_peer *mp, struct in_addr rp);
 void pim_msdp_up_join_state_changed(struct pim_instance *pim,
                                    struct pim_upstream *xg_up);
 void pim_msdp_up_del(struct pim_instance *pim, struct prefix_sg *sg);
-enum pim_msdp_err pim_msdp_mg_mbr_add(struct pim_instance *pim,
-                                     const char *mesh_group_name,
-                                     struct in_addr mbr_ip);
-enum pim_msdp_err pim_msdp_mg_mbr_del(struct pim_instance *pim,
-                                     const char *mesh_group_name,
-                                     struct in_addr mbr_ip);
-enum pim_msdp_err pim_msdp_mg_src_del(struct pim_instance *pim,
-                                     const char *mesh_group_name);
-enum pim_msdp_err pim_msdp_mg_src_add(struct pim_instance *pim,
-                                     const char *mesh_group_name,
-                                     struct in_addr src_ip);
 enum pim_msdp_err pim_msdp_mg_del(struct pim_instance *pim,
                                  const char *mesh_group_name);
+
+/**
+ * Allocates a new mesh group data structure under PIM instance.
+ */
+struct pim_msdp_mg *pim_msdp_mg_new(struct pim_instance *pim,
+                                   const char *mesh_group_name);
+/**
+ * Deallocates mesh group data structure under PIM instance.
+ */
+void pim_msdp_mg_free(struct pim_instance *pim, struct pim_msdp_mg **mgp);
+
+/**
+ * Change the source address of a mesh group peers. It will do the following:
+ * - Close all peers TCP connections
+ * - Recreate peers data structure
+ * - Start TCP connections with new local address.
+ */
+void pim_msdp_mg_src_add(struct pim_instance *pim, struct pim_msdp_mg *mg,
+                        struct in_addr *ai);
+
+/**
+ * Add new peer to mesh group and starts the connection if source address is
+ * configured.
+ */
+struct pim_msdp_mg_mbr *pim_msdp_mg_mbr_add(struct pim_instance *pim,
+                                           struct pim_msdp_mg *mg,
+                                           struct in_addr *ia);
+
+/**
+ * Stops the connection and removes the peer data structures.
+ */
+void pim_msdp_mg_mbr_del(struct pim_msdp_mg *mg, struct pim_msdp_mg_mbr *mbr);
+
 #endif
index 37c539883d643c7a25d755f441462f47d0a3f675..ea53f1ef1212c874e55ef6b41bc8862536843150 100644 (file)
@@ -118,31 +118,24 @@ const struct frr_yang_module_info frr_pim_info = {
                        }
                },
                {
-                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-group",
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-groups",
                        .cbs = {
-                               .create = routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_create,
-                               .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_destroy,
+                               .create = pim_msdp_mesh_group_create,
+                               .destroy = pim_msdp_mesh_group_destroy,
                        }
                },
                {
-                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-group/mesh-group-name",
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-groups/source",
                        .cbs = {
-                               .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_mesh_group_name_modify,
-                               .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_mesh_group_name_destroy,
+                               .modify = pim_msdp_mesh_group_source_modify,
+                               .destroy = pim_msdp_mesh_group_source_destroy,
                        }
                },
                {
-                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-group/member-ip",
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-groups/members",
                        .cbs = {
-                               .create = routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_member_ip_create,
-                               .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_member_ip_destroy,
-                       }
-               },
-               {
-                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-group/source-ip",
-                       .cbs = {
-                               .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_source_ip_modify,
-                               .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_source_ip_destroy,
+                               .create = pim_msdp_mesh_group_members_create,
+                               .destroy = pim_msdp_mesh_group_members_destroy,
                        }
                },
                {
index 440384e45ccd583b6a7d02c1a287a395786cec69..1959b403ff6545b624d602c7cbdbb3d9b61855e2 100644 (file)
@@ -60,22 +60,12 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ss
        struct nb_cb_create_args *args);
 int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ssm_pingd_source_ip_destroy(
        struct nb_cb_destroy_args *args);
-int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_create(
-       struct nb_cb_create_args *args);
-int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_destroy(
-       struct nb_cb_destroy_args *args);
-int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_mesh_group_name_modify(
-       struct nb_cb_modify_args *args);
-int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_mesh_group_name_destroy(
-       struct nb_cb_destroy_args *args);
-int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_member_ip_create(
-       struct nb_cb_create_args *args);
-int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_member_ip_destroy(
-       struct nb_cb_destroy_args *args);
-int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_source_ip_modify(
-       struct nb_cb_modify_args *args);
-int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_source_ip_destroy(
-       struct nb_cb_destroy_args *args);
+int pim_msdp_mesh_group_create(struct nb_cb_create_args *args);
+int pim_msdp_mesh_group_destroy(struct nb_cb_destroy_args *args);
+int pim_msdp_mesh_group_members_create(struct nb_cb_create_args *args);
+int pim_msdp_mesh_group_members_destroy(struct nb_cb_destroy_args *args);
+int pim_msdp_mesh_group_source_modify(struct nb_cb_modify_args *args);
+int pim_msdp_mesh_group_source_destroy(struct nb_cb_destroy_args *args);
 int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_create(
        struct nb_cb_create_args *args);
 int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_destroy(
index 11e8da3b87a4f46f0ed5c830061d96eb7be75b4f..b70656ea7b81f8d2d394e5cec09f94592e531af0 100644 (file)
@@ -243,147 +243,6 @@ static int pim_ssm_cmd_worker(struct pim_instance *pim, const char *plist,
        return ret;
 }
 
-static int ip_no_msdp_mesh_group_cmd_worker(struct pim_instance *pim,
-               const char *mg,
-               char *errmsg, size_t errmsg_len)
-{
-       enum pim_msdp_err result;
-
-       result = pim_msdp_mg_del(pim, mg);
-
-       switch (result) {
-       case PIM_MSDP_ERR_NONE:
-               break;
-       case PIM_MSDP_ERR_NO_MG:
-               snprintf(errmsg, errmsg_len,
-                        "%% mesh-group does not exist");
-               break;
-       default:
-               snprintf(errmsg, errmsg_len,
-                        "mesh-group source del failed");
-       }
-
-       return result ? NB_ERR : NB_OK;
-}
-
-static int ip_msdp_mesh_group_member_cmd_worker(struct pim_instance *pim,
-               const char *mg,
-               struct in_addr mbr_ip,
-               char *errmsg, size_t errmsg_len)
-{
-       enum pim_msdp_err result;
-       int ret = NB_OK;
-
-       result = pim_msdp_mg_mbr_add(pim, mg, mbr_ip);
-
-       switch (result) {
-       case PIM_MSDP_ERR_NONE:
-               break;
-       case PIM_MSDP_ERR_OOM:
-               ret = NB_ERR;
-               snprintf(errmsg, errmsg_len,
-                        "%% Out of memory");
-               break;
-       case PIM_MSDP_ERR_MG_MBR_EXISTS:
-               ret = NB_ERR;
-               snprintf(errmsg, errmsg_len,
-                        "%% mesh-group member exists");
-               break;
-       case PIM_MSDP_ERR_MAX_MESH_GROUPS:
-               ret = NB_ERR;
-               snprintf(errmsg, errmsg_len,
-                        "%% Only one mesh-group allowed currently");
-               break;
-       default:
-               ret = NB_ERR;
-               snprintf(errmsg, errmsg_len,
-                        "%% member add failed");
-       }
-
-       return ret;
-}
-
-static int ip_no_msdp_mesh_group_member_cmd_worker(struct pim_instance *pim,
-               const char *mg,
-               struct in_addr mbr_ip,
-               char *errmsg,
-               size_t errmsg_len)
-{
-       enum pim_msdp_err result;
-
-       result = pim_msdp_mg_mbr_del(pim, mg, mbr_ip);
-
-       switch (result) {
-       case PIM_MSDP_ERR_NONE:
-               break;
-       case PIM_MSDP_ERR_NO_MG:
-               snprintf(errmsg, errmsg_len,
-                        "%% mesh-group does not exist");
-               break;
-       case PIM_MSDP_ERR_NO_MG_MBR:
-               snprintf(errmsg, errmsg_len,
-                        "%% mesh-group member does not exist");
-               break;
-       default:
-               snprintf(errmsg, errmsg_len,
-                        "%% mesh-group member del failed");
-       }
-
-       return result ? NB_ERR : NB_OK;
-}
-
-static int ip_msdp_mesh_group_source_cmd_worker(struct pim_instance *pim,
-               const char *mg,
-               struct in_addr src_ip,
-               char *errmsg, size_t errmsg_len)
-{
-       enum pim_msdp_err result;
-
-       result = pim_msdp_mg_src_add(pim, mg, src_ip);
-
-       switch (result) {
-       case PIM_MSDP_ERR_NONE:
-               break;
-       case PIM_MSDP_ERR_OOM:
-               snprintf(errmsg, errmsg_len,
-                        "%% Out of memory");
-               break;
-       case PIM_MSDP_ERR_MAX_MESH_GROUPS:
-               snprintf(errmsg, errmsg_len,
-                        "%% Only one mesh-group allowed currently");
-               break;
-       default:
-               snprintf(errmsg, errmsg_len,
-                        "%% source add failed");
-       }
-
-       return result ? NB_ERR : NB_OK;
-}
-
-static int ip_no_msdp_mesh_group_source_cmd_worker(struct pim_instance *pim,
-               const char *mg,
-               char *errmsg,
-               size_t errmsg_len)
-{
-       enum pim_msdp_err result;
-
-       result = pim_msdp_mg_src_del(pim, mg);
-
-       switch (result) {
-       case PIM_MSDP_ERR_NONE:
-               break;
-       case PIM_MSDP_ERR_NO_MG:
-               snprintf(errmsg, errmsg_len,
-                        "%% mesh-group does not exist");
-               break;
-       default:
-               snprintf(errmsg, errmsg_len,
-                        "%% mesh-group source del failed");
-       }
-
-       return result ? NB_ERR : NB_OK;
-}
-
 static int ip_msdp_peer_cmd_worker(struct pim_instance *pim,
                struct in_addr peer_addr,
                struct in_addr local_addr,
@@ -1146,29 +1005,13 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ss
 }
 
 /*
- * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-group
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-groups
  */
-int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_create(
-       struct nb_cb_create_args *args)
-{
-       switch (args->event) {
-       case NB_EV_VALIDATE:
-       case NB_EV_PREPARE:
-       case NB_EV_ABORT:
-       case NB_EV_APPLY:
-               break;
-       }
-
-       return NB_OK;
-}
-
-int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_destroy(
-       struct nb_cb_destroy_args *args)
+int pim_msdp_mesh_group_create(struct nb_cb_create_args *args)
 {
+       struct pim_msdp_mg *mg;
        struct vrf *vrf;
-       struct pim_instance *pim;
-       const char *mesh_group_name;
-       int result;
 
        switch (args->event) {
        case NB_EV_VALIDATE:
@@ -1177,67 +1020,29 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ms
                break;
        case NB_EV_APPLY:
                vrf = nb_running_get_entry(args->dnode, NULL, true);
-               pim = vrf->info;
-               mesh_group_name = yang_dnode_get_string(args->dnode, "mesh-group-name");
-
-               result = ip_no_msdp_mesh_group_cmd_worker(pim, mesh_group_name,
-                               args->errmsg,
-                               args->errmsg_len);
-
-               if (result != PIM_MSDP_ERR_NONE)
-                       return NB_ERR_INCONSISTENCY;
-
+               mg = pim_msdp_mg_new(vrf->info, yang_dnode_get_string(
+                                                       args->dnode, "./name"));
+               nb_running_set_entry(args->dnode, mg);
                break;
        }
 
        return NB_OK;
 }
 
-/*
- * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-group/mesh-group-name
- */
-int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_mesh_group_name_modify(
-       struct nb_cb_modify_args *args)
+int pim_msdp_mesh_group_destroy(struct nb_cb_destroy_args *args)
 {
-       const char *mesh_group_name;
-       const char *mesh_group_name_old;
-       char xpath[XPATH_MAXLEN];
+       struct pim_msdp_mg *mg;
+       struct vrf *vrf;
 
        switch (args->event) {
        case NB_EV_VALIDATE:
-               mesh_group_name = yang_dnode_get_string(args->dnode, ".");
-               yang_dnode_get_path(args->dnode, xpath, sizeof(xpath));
-
-               if (yang_dnode_exists(running_config->dnode, xpath) == false)
-                       break;
-
-               mesh_group_name_old = yang_dnode_get_string(
-                                       running_config->dnode,
-                                       xpath);
-               if (strcmp(mesh_group_name, mesh_group_name_old)) {
-                       /* currently only one mesh-group can exist at a time */
-                       snprintf(args->errmsg, args->errmsg_len,
-                                "Only one mesh-group allowed currently");
-                       return NB_ERR_VALIDATION;
-               }
-               break;
        case NB_EV_PREPARE:
        case NB_EV_ABORT:
-       case NB_EV_APPLY:
                break;
-       }
-
-       return NB_OK;
-}
-
-int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_mesh_group_name_destroy(
-       struct nb_cb_destroy_args *args)
-{
-       switch (args->event) {
-       case NB_EV_VALIDATE:
-       case NB_EV_PREPARE:
-       case NB_EV_ABORT:
        case NB_EV_APPLY:
+               mg = nb_running_unset_entry(args->dnode);
+               vrf = nb_running_get_entry(args->dnode, NULL, true);
+               pim_msdp_mg_free(vrf->info, &mg);
                break;
        }
 
@@ -1245,16 +1050,15 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ms
 }
 
 /*
- * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-group/member-ip
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-groups/source
  */
-int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_member_ip_create(
-       struct nb_cb_create_args *args)
+int pim_msdp_mesh_group_source_modify(struct nb_cb_modify_args *args)
 {
+       const struct lyd_node *vrf_dnode;
+       struct pim_msdp_mg *mg;
        struct vrf *vrf;
-       struct pim_instance *pim;
-       const char *mesh_group_name;
-       struct ipaddr mbr_ip;
-       enum pim_msdp_err result;
+       struct ipaddr ip;
 
        switch (args->event) {
        case NB_EV_VALIDATE:
@@ -1262,33 +1066,24 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ms
        case NB_EV_ABORT:
                break;
        case NB_EV_APPLY:
-               vrf = nb_running_get_entry(args->dnode, NULL, true);
-               pim = vrf->info;
-               mesh_group_name = yang_dnode_get_string(args->dnode,
-                               "../mesh-group-name");
-               yang_dnode_get_ip(&mbr_ip, args->dnode, NULL);
-
-               result = ip_msdp_mesh_group_member_cmd_worker(
-                               pim, mesh_group_name, mbr_ip.ip._v4_addr,
-                               args->errmsg, args->errmsg_len);
-
-               if (result != PIM_MSDP_ERR_NONE)
-                       return NB_ERR_INCONSISTENCY;
+               mg = nb_running_get_entry(args->dnode, NULL, true);
+               vrf_dnode =
+                       yang_dnode_get_parent(args->dnode, "address-family");
+               vrf = nb_running_get_entry(vrf_dnode, "../../", true);
+               yang_dnode_get_ip(&ip, args->dnode, NULL);
 
+               pim_msdp_mg_src_add(vrf->info, mg, &ip.ip._v4_addr);
                break;
        }
-
        return NB_OK;
 }
 
-int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_member_ip_destroy(
-       struct nb_cb_destroy_args *args)
+int pim_msdp_mesh_group_source_destroy(struct nb_cb_destroy_args *args)
 {
+       const struct lyd_node *vrf_dnode;
+       struct pim_msdp_mg *mg;
        struct vrf *vrf;
-       struct pim_instance *pim;
-       const char *mesh_group_name;
-       struct ipaddr mbr_ip;
-       enum pim_msdp_err result;
+       struct in_addr addr;
 
        switch (args->event) {
        case NB_EV_VALIDATE:
@@ -1296,36 +1091,30 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ms
        case NB_EV_ABORT:
                break;
        case NB_EV_APPLY:
-               vrf = nb_running_get_entry(args->dnode, NULL, true);
-               pim = vrf->info;
-               mesh_group_name = yang_dnode_get_string(args->dnode,
-                               "../mesh-group-name");
-               yang_dnode_get_ip(&mbr_ip, args->dnode, NULL);
-
-               result = ip_no_msdp_mesh_group_member_cmd_worker(
-                               pim, mesh_group_name, mbr_ip.ip._v4_addr,
-                               args->errmsg, args->errmsg_len);
-
-               if (result != PIM_MSDP_ERR_NONE)
-                       return NB_ERR_INCONSISTENCY;
+               mg = nb_running_get_entry(args->dnode, NULL, true);
+               vrf_dnode =
+                       yang_dnode_get_parent(args->dnode, "address-family");
+               vrf = nb_running_get_entry(vrf_dnode, "../../", true);
 
+               addr.s_addr = INADDR_ANY;
+               pim_msdp_mg_src_add(vrf->info, mg, &addr);
                break;
        }
-
        return NB_OK;
 }
 
+
 /*
- * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-group/source-ip
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-groups/members
  */
-int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_source_ip_modify(
-       struct nb_cb_modify_args *args)
+int pim_msdp_mesh_group_members_create(struct nb_cb_create_args *args)
 {
+       const struct lyd_node *vrf_dnode;
+       struct pim_msdp_mg_mbr *mbr;
+       struct pim_msdp_mg *mg;
        struct vrf *vrf;
-       struct pim_instance *pim;
-       const char *mesh_group_name;
-       struct ipaddr src_ip;
-       enum pim_msdp_err result;
+       struct ipaddr ip;
 
        switch (args->event) {
        case NB_EV_VALIDATE:
@@ -1333,31 +1122,24 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ms
        case NB_EV_ABORT:
                break;
        case NB_EV_APPLY:
-               vrf = nb_running_get_entry(args->dnode, NULL, true);
-               pim = vrf->info;
-               mesh_group_name = yang_dnode_get_string(args->dnode,
-                               "../mesh-group-name");
-               yang_dnode_get_ip(&src_ip, args->dnode, NULL);
-
-               result = ip_msdp_mesh_group_source_cmd_worker(
-                               pim, mesh_group_name, src_ip.ip._v4_addr,
-                               args->errmsg, args->errmsg_len);
-
-               if (result != PIM_MSDP_ERR_NONE)
-                       return NB_ERR_INCONSISTENCY;
+               mg = nb_running_get_entry(args->dnode, NULL, true);
+               vrf_dnode =
+                       yang_dnode_get_parent(args->dnode, "address-family");
+               vrf = nb_running_get_entry(vrf_dnode, "../../", true);
+               yang_dnode_get_ip(&ip, args->dnode, "address");
 
+               mbr = pim_msdp_mg_mbr_add(vrf->info, mg, &ip.ip._v4_addr);
+               nb_running_set_entry(args->dnode, mbr);
                break;
        }
+
        return NB_OK;
 }
 
-int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_source_ip_destroy(
-       struct nb_cb_destroy_args *args)
+int pim_msdp_mesh_group_members_destroy(struct nb_cb_destroy_args *args)
 {
-       struct vrf *vrf;
-       struct pim_instance *pim;
-       const char *mesh_group_name;
-       enum pim_msdp_err result;
+       struct pim_msdp_mg_mbr *mbr;
+       struct pim_msdp_mg *mg;
 
        switch (args->event) {
        case NB_EV_VALIDATE:
@@ -1365,20 +1147,13 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ms
        case NB_EV_ABORT:
                break;
        case NB_EV_APPLY:
-               vrf = nb_running_get_entry(args->dnode, NULL, true);
-               pim = vrf->info;
-               mesh_group_name = yang_dnode_get_string(args->dnode,
-                               "../mesh-group-name");
-
-               result = ip_no_msdp_mesh_group_source_cmd_worker(
-                               pim, mesh_group_name, args->errmsg,
-                               args->errmsg_len);
-
-               if (result != PIM_MSDP_ERR_NONE)
-                       return NB_ERR_INCONSISTENCY;
+               mbr = nb_running_get_entry(args->dnode, NULL, true);
+               mg = nb_running_get_entry(args->dnode, "../", true);
 
+               pim_msdp_mg_mbr_del(mg, mbr);
                break;
        }
+
        return NB_OK;
 }
 
index c6c82fb65ac1dfca3a115392103a855f4803cb5c..7d940efd9c615ea19c355f44b1966913c0885231 100644 (file)
@@ -3690,6 +3690,8 @@ void rip_vrf_init(void)
 {
        vrf_init(rip_vrf_new, rip_vrf_enable, rip_vrf_disable, rip_vrf_delete,
                 rip_vrf_enable);
+
+       vrf_cmd_init(NULL, &ripd_privs);
 }
 
 void rip_vrf_terminate(void)
index 3b8d2076f347d2473e323c32072d3d1354b53f91..a0ea18f3e9b801195b869bb3bc0ba4b83ad96d93 100644 (file)
@@ -2691,6 +2691,8 @@ void ripng_vrf_init(void)
 {
        vrf_init(ripng_vrf_new, ripng_vrf_enable, ripng_vrf_disable,
                 ripng_vrf_delete, ripng_vrf_enable);
+
+       vrf_cmd_init(NULL, &ripngd_privs);
 }
 
 void ripng_vrf_terminate(void)
index 3a96339f47d8e977d62b47a1a4356c9460493bfe..ee9f7b053737ab82e165bbf5453f2fdd906848c2 100644 (file)
 #ifndef _STATIC_DEBUG_H
 #define _STATIC_DEBUG_H
 
-
 #include <zebra.h>
 
 #include "lib/debug.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /* staticd debugging records */
 extern struct debug static_dbg_events;
 extern struct debug static_dbg_route;
@@ -70,5 +73,8 @@ int static_debug_status_write(struct vty *vty);
  */
 void static_debug_set(int vtynode, bool onoff, bool events, bool route);
 
+#ifdef __cplusplus
+}
+#endif
 
 #endif /* _STATIC_DEBUG_H */
index 0313ae1c3af7dc8c637200ff595776f95908b9d4..5c3030fcfa5d4bd848971991dff6293121cdc63c 100644 (file)
 #ifndef _FRR_STATIC_NB_H_
 #define _FRR_STATIC_NB_H_
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 extern const struct frr_yang_module_info frr_staticd_info;
 
 /* Mandatory callbacks. */
@@ -181,4 +185,8 @@ int routing_control_plane_protocols_name_validate(
        FRR_S_ROUTE_SRC_INFO_KEY_NO_DISTANCE_XPATH                             \
        FRR_STATIC_ROUTE_NH_KEY_XPATH
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif
index 9139c367d18d17225edc0e23549b0e7b9c6b6d72..08dba2ebb53f8d04422196ea6225a83ec82f6524 100644 (file)
 #ifndef __STATIC_NHT_H__
 #define __STATIC_NHT_H__
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /*
  * When we get notification that nexthop tracking has an answer for
  * us call this function to find the nexthop we are tracking so it
@@ -53,4 +57,9 @@ extern void static_nht_mark_state(struct prefix *sp, vrf_id_t vrf_id,
  */
 extern void static_get_nh_str(struct static_nexthop *nh, char *nexthop,
                              size_t size);
+
+#ifdef __cplusplus
+}
+#endif
+
 #endif
index f64a40329d466c8424fd0503a729e9976f49ca4d..1269621cc9dbf05bb4a93217223d5684e9b11812 100644 (file)
 #include "table.h"
 #include "memory.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 DECLARE_MGROUP(STATIC);
 
 /* Static route label information */
@@ -216,4 +220,9 @@ extern void zebra_stable_node_cleanup(struct route_table *table,
  */
 extern void static_get_nh_str(struct static_nexthop *nh, char *nexthop,
                              size_t size);
+
+#ifdef __cplusplus
+}
+#endif
+
 #endif
index 3977899054a061d0a6d114f1232d60a5dc170f7e..be311af8c44263ddd1c9be04bb3c8d833b8329f0 100644 (file)
 #ifndef __STATIC_VRF_H__
 #define __STATIC_VRF_H__
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 struct static_vrf {
        struct vrf *vrf;
 
@@ -43,4 +47,8 @@ struct route_table *static_vrf_static_table(afi_t afi, safi_t safi,
                                            struct static_vrf *svrf);
 extern void static_vrf_terminate(void);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif
index 7ffc8d9c98b3756b3bc1d5897f5690a74bdce4d3..01577685e5e07b74c9c564326660c162e863728f 100644 (file)
 #ifndef __STATIC_VTY_H__
 #define __STATIC_VTY_H__
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 int static_config(struct vty *vty, struct static_vrf *svrf,
                  afi_t afi, safi_t safi, const char *cmd);
 
 void static_vty_init(void);
+
+#ifdef __cplusplus
+}
+#endif
+
 #endif
index 19c578c60e2edcf37ad75a6d614643a0c298a367..40275908f7fb0f0537d61e08d48e9a9e3d3b55ff 100644 (file)
@@ -529,6 +529,16 @@ void static_zebra_init(void)
                                      "Static Nexthop Tracking hash");
 }
 
+/* static_zebra_stop used by tests/lib/test_grpc.cpp */
+void static_zebra_stop(void)
+{
+       if (!zclient)
+               return;
+       zclient_stop(zclient);
+       zclient_free(zclient);
+       zclient = NULL;
+}
+
 void static_zebra_vrf_register(struct vrf *vrf)
 {
        if (vrf->vrf_id == VRF_DEFAULT)
index 9f93f3ee631084d7b4c83b48d2f5ff69198e935f..ca6308559e2e88b34b6de7893059f3d78092a571 100644 (file)
 #ifndef __STATIC_ZEBRA_H__
 #define __STATIC_ZEBRA_H__
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 extern struct thread_master *master;
 
 extern void static_zebra_nht_register(struct route_node *rn,
@@ -28,9 +32,15 @@ extern void static_zebra_route_add(struct route_node *rn,
                                   struct static_path *pn, safi_t safi,
                                   bool install);
 extern void static_zebra_init(void);
+/* static_zebra_stop used by tests/lib/test_grpc.cpp */
+extern void static_zebra_stop(void);
 extern void static_zebra_vrf_register(struct vrf *vrf);
 extern void static_zebra_vrf_unregister(struct vrf *vrf);
 extern int static_zebra_nh_update(struct route_node *rn,
                                  struct static_nexthop *nh);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif
index 5b2028ffd409600a284f97bbf8f5e5060a808190..ade3573535617a40b709282b9118ab4eb35c338e 100644 (file)
@@ -309,7 +309,8 @@ static int topology_load_node(const struct isis_topology *topology,
 {
        int ret;
 
-       isis_dynhn_insert(tnode->sysid, tnode->hostname, tnode->level);
+       isis_dynhn_insert(area->isis, tnode->sysid, tnode->hostname,
+                         tnode->level);
 
        for (int level = IS_LEVEL_1; level <= IS_LEVEL_2; level++) {
                if ((tnode->level & level) == 0)
index b89a5a008ee7cbf1030d7fae3d0389c07bc47e44..a30f33ccade1797d4f347023f1387674747785f1 100644 (file)
@@ -269,7 +269,7 @@ static int test_run(struct vty *vty, const struct isis_topology *topology,
                if (sysid2buff(fail_id, fail_sysid_str) == 0) {
                        struct isis_dynhn *dynhn;
 
-                       dynhn = dynhn_find_by_name(fail_sysid_str);
+                       dynhn = dynhn_find_by_name(area->isis, fail_sysid_str);
                        if (dynhn == NULL) {
                                vty_out(vty, "Invalid system id %s\n",
                                        fail_sysid_str);
@@ -339,9 +339,6 @@ static int test_run(struct vty *vty, const struct isis_topology *topology,
        /* Cleanup IS-IS area. */
        isis_area_destroy(area);
 
-       /* Cleanup hostnames. */
-       dyn_cache_cleanup_all();
-
        return CMD_SUCCESS;
 }
 
diff --git a/tests/lib/test_grpc.cpp b/tests/lib/test_grpc.cpp
new file mode 100644 (file)
index 0000000..4917968
--- /dev/null
@@ -0,0 +1,979 @@
+/*
+ * May 16 2021, Christian Hopps <chopps@labn.net>
+ *
+ * Copyright (c) 2021, LabN Consulting, L.L.C
+ *
+ * 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 <time.h>
+#include <unistd.h>
+#include <zebra.h>
+
+#include "filter.h"
+#include "frr_pthread.h"
+#include "libfrr.h"
+#include "routing_nb.h"
+#include "northbound_cli.h"
+#include "thread.h"
+#include "vrf.h"
+#include "vty.h"
+
+#include "staticd/static_debug.h"
+#include "staticd/static_nb.h"
+#include "staticd/static_vrf.h"
+#include "staticd/static_vty.h"
+#include "staticd/static_zebra.h"
+
+// GRPC C++ includes
+#include <string>
+#include <sstream>
+#include <grpc/grpc.h>
+#include <grpcpp/channel.h>
+#include <grpcpp/client_context.h>
+#include <grpcpp/create_channel.h>
+#include <grpcpp/security/credentials.h>
+#include "grpc/frr-northbound.grpc.pb.h"
+
+DEFINE_HOOK(frr_late_init, (struct thread_master * tm), (tm));
+DEFINE_KOOH(frr_fini, (), ());
+
+struct vty *vty;
+
+bool mpls_enabled;
+struct thread_master *master;
+struct zebra_privs_t static_privs = {0};
+struct frrmod_runtime *grpc_module;
+char binpath[2 * MAXPATHLEN + 1];
+
+extern const char *json_expect1;
+extern const char *json_expect2;
+extern const char *json_expect3;
+extern const char *json_loadconf1;
+
+int test_dbg = 1;
+
+void inline test_debug(const std::string &s)
+{
+       if (test_dbg)
+               std::cout << s << std::endl;
+}
+
+// static struct option_chain modules[] = {{ .arg = "grpc:50051" }]
+// static struct option_chain **modnext = modules->next;
+
+static const struct frr_yang_module_info *const staticd_yang_modules[] = {
+       &frr_interface_info, &frr_filter_info, &frr_routing_info,
+       &frr_staticd_info,   &frr_vrf_info,
+};
+
+static int grpc_thread_stop(struct thread *thread);
+
+static void static_startup(void)
+{
+       // struct frrmod_runtime module;
+       // static struct option_chain *oc;
+       char moderr[256] = {};
+       cmd_init(1);
+
+       zlog_aux_init("NONE: ", LOG_DEBUG);
+       zprivs_preinit(&static_privs);
+       zprivs_init(&static_privs);
+
+       /* Load the server side module -- check libtool path first */
+       std::string modpath = std::string(binpath) + std::string("../../../lib/.libs");
+       grpc_module = frrmod_load("grpc:50051", modpath.c_str(), moderr, sizeof(moderr));
+       if (!grpc_module) {
+               modpath = std::string(binpath) +  std::string("../../lib");
+               grpc_module = frrmod_load("grpc:50051", modpath.c_str(), moderr,
+                                         sizeof(moderr));
+       }
+       if (!grpc_module) {
+               std::cout << "Failed to load grpc module:" << moderr
+                         << std::endl;
+               exit(1);
+       }
+
+       static_debug_init();
+
+       master = thread_master_create(NULL);
+       nb_init(master, staticd_yang_modules, array_size(staticd_yang_modules),
+               false);
+
+       static_zebra_init();
+       vty_init(master, true);
+       static_vrf_init();
+       static_vty_init();
+
+       hook_register(routing_conf_event,
+                     routing_control_plane_protocols_name_validate);
+
+       routing_control_plane_protocols_register_vrf_dependency();
+
+       // Add a route
+       vty = vty_new();
+       vty->type = vty::VTY_TERM;
+       vty_config_enter(vty, true, false);
+
+       auto ret = cmd_execute(vty, "ip route 11.0.0.0/8 Null0", NULL, 0);
+       assert(!ret);
+
+       ret = cmd_execute(vty, "end", NULL, 0);
+       assert(!ret);
+
+       nb_cli_pending_commit_check(vty);
+
+       frr_pthread_init();
+
+       // frr_config_fork();
+       hook_call(frr_late_init, master);
+}
+
+static void static_shutdown(void)
+{
+       hook_call(frr_fini);
+       vty_close(vty);
+       vrf_terminate();
+       vty_terminate();
+       cmd_terminate();
+       nb_terminate();
+       yang_terminate();
+       thread_master_free(master);
+       master = NULL;
+}
+
+using frr::Northbound;
+using grpc::Channel;
+using grpc::ClientAsyncResponseReader;
+using grpc::ClientContext;
+using grpc::CompletionQueue;
+using grpc::Status;
+
+class NorthboundClient
+{
+      public:
+       NorthboundClient(std::shared_ptr<Channel> channel)
+           : stub_(frr::Northbound::NewStub(channel))
+       {
+       }
+
+       void Commit(uint32_t candidate_id)
+       {
+               frr::CommitRequest request;
+               frr::CommitResponse reply;
+               ClientContext context;
+               Status status;
+
+               request.set_candidate_id(candidate_id);
+
+               request.set_phase(frr::CommitRequest::ALL);
+               status = stub_->Commit(&context, request, &reply);
+               _throw_if_not_ok(status);
+#if 0
+               request.set_phase(frr::CommitRequest::VALIDATE);
+               status = stub_->Commit(&context, request, &reply);
+               _throw_if_not_ok(status);
+
+               request.set_phase(frr::CommitRequest::PREPARE);
+               status = stub_->Commit(&context, request, &reply);
+               _throw_if_not_ok(status);
+
+               request.set_phase(frr::CommitRequest::APPLY);
+               status = stub_->Commit(&context, request, &reply);
+               _throw_if_not_ok(status);
+#endif
+       }
+
+       uint32_t CreateCandidate()
+       {
+               frr::CreateCandidateRequest request;
+               frr::CreateCandidateResponse reply;
+               ClientContext context;
+               Status status;
+
+               status = stub_->CreateCandidate(&context, request, &reply);
+               _throw_if_not_ok(status);
+               return reply.candidate_id();
+       }
+
+       void DeleteCandidate(uint32_t candidate_id)
+       {
+               frr::DeleteCandidateRequest request;
+               frr::DeleteCandidateResponse reply;
+               ClientContext context;
+               Status status;
+
+               request.set_candidate_id(candidate_id);
+               status = stub_->DeleteCandidate(&context, request, &reply);
+               _throw_if_not_ok(status);
+       }
+
+       void EditCandidate(uint32_t candidate_id, const std::string &path,
+                          const std::string &value)
+       {
+               frr::EditCandidateRequest request;
+               frr::EditCandidateResponse reply;
+               ClientContext context;
+
+               request.set_candidate_id(candidate_id);
+               frr::PathValue *pv = request.add_update();
+               pv->set_path(path);
+               pv->set_value(value);
+
+               Status status = stub_->EditCandidate(&context, request, &reply);
+               _throw_if_not_ok(status);
+       }
+
+       std::string Get(const std::string &path,
+                       frr::GetRequest::DataType dtype, frr::Encoding enc,
+                       bool with_defaults)
+       {
+               frr::GetRequest request;
+               frr::GetResponse reply;
+               ClientContext context;
+               std::ostringstream ss;
+
+               request.set_type(dtype);
+               request.set_encoding(enc);
+               request.set_with_defaults(with_defaults);
+               request.add_path(path);
+
+               auto stream = stub_->Get(&context, request);
+               while (stream->Read(&reply)) {
+                       ss << reply.data().data() << std::endl;
+               }
+               auto status = stream->Finish();
+               _throw_if_not_ok(status);
+               return ss.str();
+       }
+
+       std::string GetCapabilities()
+       {
+               frr::GetCapabilitiesRequest request;
+               frr::GetCapabilitiesResponse reply;
+               ClientContext context;
+
+               Status status =
+                       stub_->GetCapabilities(&context, request, &reply);
+               _throw_if_not_ok(status);
+
+               std::ostringstream ss;
+               ss << "Capabilities:" << std::endl
+                  << "\tVersion: " << reply.frr_version() << std::endl
+                  << "\tRollback Support: " << reply.rollback_support()
+                  << std::endl
+                  << "\tSupported Modules:";
+
+               for (int i = 0; i < reply.supported_modules_size(); i++) {
+                       auto sm = reply.supported_modules(i);
+                       ss << std::endl
+                          << "\t\tName: \"" << sm.name()
+                          << "\" Revision: " << sm.revision() << " Org: \""
+                          << sm.organization() << "\"";
+               }
+
+               ss << std::endl << "\tSupported Encodings:";
+
+               for (int i = 0; i < reply.supported_encodings_size(); i++) {
+                       auto se = reply.supported_encodings(i);
+                       auto desc =
+                               google::protobuf::GetEnumDescriptor<decltype(
+                                       se)>();
+                       ss << std::endl
+                          << "\t\t" << desc->FindValueByNumber(se)->name();
+               }
+
+               ss << std::endl;
+
+               return ss.str();
+       }
+
+       void LoadToCandidate(uint32_t candidate_id, bool is_replace,
+                            bool is_json, const std::string &data)
+       {
+               frr::LoadToCandidateRequest request;
+               frr::LoadToCandidateResponse reply;
+               frr::DataTree *dt = new frr::DataTree;
+               ClientContext context;
+
+               request.set_candidate_id(candidate_id);
+               request.set_type(is_replace
+                                        ? frr::LoadToCandidateRequest::REPLACE
+                                        : frr::LoadToCandidateRequest::MERGE);
+               dt->set_encoding(is_json ? frr::JSON : frr::XML);
+               dt->set_data(data);
+               request.set_allocated_config(dt);
+
+               Status status =
+                       stub_->LoadToCandidate(&context, request, &reply);
+               _throw_if_not_ok(status);
+       }
+
+       std::string ListTransactions()
+       {
+               frr::ListTransactionsRequest request;
+               frr::ListTransactionsResponse reply;
+               ClientContext context;
+               std::ostringstream ss;
+
+               auto stream = stub_->ListTransactions(&context, request);
+
+               while (stream->Read(&reply)) {
+                       ss << "Tx ID: " << reply.id()
+                          << " client: " << reply.client()
+                          << " date: " << reply.date()
+                          << " comment: " << reply.comment() << std::endl;
+               }
+
+               auto status = stream->Finish();
+               _throw_if_not_ok(status);
+               return ss.str();
+       }
+
+      private:
+       std::unique_ptr<frr::Northbound::Stub> stub_;
+
+       void _throw_if_not_ok(Status &status)
+       {
+               if (!status.ok())
+                       throw std::runtime_error(
+                               std::to_string(status.error_code()) + ": "
+                               + status.error_message());
+       }
+};
+
+
+bool stop = false;
+
+int grpc_client_test_stop(struct frr_pthread *fpt, void **result)
+{
+       test_debug("client: STOP pthread");
+
+       assert(fpt->running);
+       atomic_store_explicit(&fpt->running, false, memory_order_relaxed);
+
+       test_debug("client: joining pthread");
+       pthread_join(fpt->thread, result);
+
+       test_debug("client: joined pthread");
+       return 0;
+}
+
+int find_first_diff(const std::string &s1, const std::string &s2)
+{
+       int s1len = s1.length();
+       int s2len = s2.length();
+       int mlen = std::min(s1len, s2len);
+
+       for (int i = 0; i < mlen; i++)
+               if (s1[i] != s2[i])
+                       return i;
+       return s1len == s2len ? -1 : mlen;
+}
+
+void assert_no_diff(const std::string &s1, const std::string &s2)
+{
+       int pos = find_first_diff(s1, s2);
+       if (pos == -1)
+               return;
+       std::cout << "not ok" << std::endl;
+       std::cout << "Same: " << s1.substr(0, pos) << std::endl;
+       std::cout << "Diff s1: " << s1.substr(pos) << std::endl;
+       std::cout << "Diff s2: " << s2.substr(pos) << std::endl;
+       assert(false);
+}
+
+void assert_config_same(NorthboundClient &client, const std::string &compare)
+{
+       std::string confs = client.Get("/frr-routing:routing",
+                                      frr::GetRequest::ALL, frr::JSON, true);
+       assert_no_diff(confs, compare);
+       std::cout << "ok" << std::endl;
+}
+
+void grpc_client_run_test(void)
+{
+       NorthboundClient client(grpc::CreateChannel(
+               "localhost:50051", grpc::InsecureChannelCredentials()));
+
+       std::string reply = client.GetCapabilities();
+
+       uint32_t cid;
+       cid = client.CreateCandidate();
+       std::cout << "CreateCandidate -> " << cid << std::endl;
+       assert(cid == 1);
+       client.DeleteCandidate(cid);
+       std::cout << "DeleteCandidate(" << cid << ")" << std::endl;
+       cid = client.CreateCandidate();
+       assert(cid == 2);
+       std::cout << "CreateCandidate -> " << cid << std::endl;
+
+       /*
+        * Get initial configuration
+        */
+       std::cout << "Comparing initial config...";
+       assert_config_same(client, json_expect1);
+
+       /*
+        * Add config using EditCandidate
+        */
+
+       char xpath_buf[1024];
+       strlcpy(xpath_buf,
+               "/frr-routing:routing/control-plane-protocols/"
+               "control-plane-protocol[type='frr-staticd:staticd']"
+               "[name='staticd'][vrf='default']/frr-staticd:staticd/route-list",
+               sizeof(xpath_buf));
+       int slen = strlen(xpath_buf);
+       for (int i = 0; i < 4; i++) {
+               snprintf(xpath_buf + slen, sizeof(xpath_buf) - slen,
+                        "[prefix='13.0.%d.0/24']"
+                        "[afi-safi='frr-routing:ipv4-unicast']/"
+                        "path-list[table-id='0'][distance='1']/"
+                        "frr-nexthops/nexthop[nh-type='blackhole']"
+                        "[vrf='default'][gateway=''][interface='(null)']",
+                        i);
+               client.EditCandidate(cid, xpath_buf, "");
+       }
+       client.Commit(cid);
+       std::cout << "Comparing EditCandidate config...";
+       assert_config_same(client, json_expect2);
+
+       client.DeleteCandidate(cid);
+       std::cout << "DeleteCandidate(" << cid << ")" << std::endl;
+
+       /*
+        * Add config using LoadToCandidate
+        */
+
+       cid = client.CreateCandidate();
+       std::cout << "CreateCandidate -> " << cid << std::endl;
+
+       client.LoadToCandidate(cid, false, true, json_loadconf1);
+       client.Commit(cid);
+
+       std::cout << "Comparing LoadToCandidate config...";
+       assert_config_same(client, json_expect3);
+
+       client.DeleteCandidate(cid);
+       std::cout << "DeleteCandidate(" << cid << ")" << std::endl;
+
+       std::string ltxreply = client.ListTransactions();
+       // std::cout << "client: pthread received: " << ltxreply << std::endl;
+}
+
+void *grpc_client_test_start(void *arg)
+{
+       struct frr_pthread *fpt = (struct frr_pthread *)arg;
+       fpt->master->owner = pthread_self();
+       frr_pthread_set_name(fpt);
+       frr_pthread_notify_running(fpt);
+
+       try {
+               grpc_client_run_test();
+               std::cout << "TEST PASSED" << std::endl;
+       } catch (std::exception &e) {
+               std::cout << "Exception in test: " << e.what() << std::endl;
+       }
+
+       // Signal FRR event loop to stop
+       test_debug("client: pthread: adding event to stop us");
+       thread_add_event(master, grpc_thread_stop, NULL, 0, NULL);
+
+       test_debug("client: pthread: DONE (returning)");
+
+       return NULL;
+}
+
+static int grpc_thread_start(struct thread *thread)
+{
+       struct frr_pthread_attr client = {
+               .start = grpc_client_test_start,
+               .stop = grpc_client_test_stop,
+       };
+
+       auto pth = frr_pthread_new(&client, "GRPC Client thread", "grpc");
+       frr_pthread_run(pth, NULL);
+       frr_pthread_wait_running(pth);
+
+       return 0;
+}
+
+static int grpc_thread_stop(struct thread *thread)
+{
+       std::cout << __func__ << ": frr_pthread_stop_all" << std::endl;
+       frr_pthread_stop_all();
+       std::cout << __func__ << ": static_shutdown" << std::endl;
+       static_shutdown();
+       std::cout << __func__ << ": exit cleanly" << std::endl;
+       exit(0);
+}
+
+/*
+ * return abs path to this binary with trailing `/`. Does not parse path
+ * environment to find in path, which should not matter for unit testing.
+ */
+static int get_binpath(const char *argv0, char cwd[2 * MAXPATHLEN + 1])
+{
+       const char *rch;
+       if (argv0[0] == '/') {
+               *cwd = 0;
+               rch = strrchr(argv0, '/');
+               strlcpy(cwd, argv0, MIN(rch - argv0 + 2, 2 * MAXPATHLEN + 1));
+               return 0;
+       }
+       if (!(rch = strrchr(argv0, '/'))) {
+               /* Does not handle using PATH, shouldn't matter for test */
+               errno = EINVAL;
+               return -1;
+       }
+       if (!getcwd(cwd, MAXPATHLEN))
+               return -1;
+       int len = strlen(cwd);
+       cwd[len++] = '/';
+       strlcpy(cwd + len, argv0, MIN(rch - argv0 + 2, 2 * MAXPATHLEN + 1));
+       return 0;
+}
+
+int main(int argc, char **argv)
+{
+       assert(argc >= 1);
+       if (get_binpath(argv[0], binpath) < 0)
+               exit(1);
+
+       static_startup();
+
+       thread_add_event(master, grpc_thread_start, NULL, 0, NULL);
+
+       /* Event Loop */
+       struct thread thread;
+       while (thread_fetch(master, &thread))
+               thread_call(&thread);
+       return 0;
+}
+
+// clang-format off
+
+const char *json_expect1 = R"NONCE({
+  "frr-routing:routing": {
+    "control-plane-protocols": {
+      "control-plane-protocol": [
+        {
+          "type": "frr-staticd:staticd",
+          "name": "staticd",
+          "vrf": "default",
+          "frr-staticd:staticd": {
+            "route-list": [
+              {
+                "prefix": "11.0.0.0/8",
+                "afi-safi": "frr-routing:ipv4-unicast",
+                "path-list": [
+                  {
+                    "table-id": 0,
+                    "distance": 1,
+                    "tag": 0,
+                    "frr-nexthops": {
+                      "nexthop": [
+                        {
+                          "nh-type": "blackhole",
+                          "vrf": "default",
+                          "gateway": "",
+                          "interface": "(null)",
+                          "bh-type": "null",
+                          "onlink": false
+                        }
+                      ]
+                    }
+                  }
+                ]
+              }
+            ]
+          }
+        }
+      ]
+    }
+  },
+  "frr-vrf:lib": {
+    "vrf": [
+      {
+        "name": "default",
+        "state": {
+          "active": false
+        }
+      }
+    ]
+  }
+}
+
+)NONCE";
+
+const char *json_loadconf1 = R"NONCE(
+{
+  "frr-routing:routing": {
+    "control-plane-protocols": {
+      "control-plane-protocol": [
+        {
+          "type": "frr-staticd:staticd",
+          "name": "staticd",
+          "vrf": "default",
+          "frr-staticd:staticd": {
+            "route-list": [
+              {
+                "prefix": "10.0.0.0/13",
+                "afi-safi": "frr-routing:ipv4-unicast",
+                "path-list": [
+                  {
+                    "table-id": 0,
+                    "distance": 1,
+                    "frr-nexthops": {
+                      "nexthop": [
+                        {
+                          "nh-type": "blackhole",
+                          "vrf": "default",
+                          "gateway": "",
+                          "interface": "(null)"
+                        }
+                      ]
+                    }
+                  }
+                ]
+              }
+            ]
+          }
+        }
+      ]
+    }
+  },
+  "frr-vrf:lib": {
+    "vrf": [
+      {
+        "name": "default"
+      }
+    ]
+  }
+})NONCE";
+
+const char *json_expect2 = R"NONCE({
+  "frr-routing:routing": {
+    "control-plane-protocols": {
+      "control-plane-protocol": [
+        {
+          "type": "frr-staticd:staticd",
+          "name": "staticd",
+          "vrf": "default",
+          "frr-staticd:staticd": {
+            "route-list": [
+              {
+                "prefix": "11.0.0.0/8",
+                "afi-safi": "frr-routing:ipv4-unicast",
+                "path-list": [
+                  {
+                    "table-id": 0,
+                    "distance": 1,
+                    "tag": 0,
+                    "frr-nexthops": {
+                      "nexthop": [
+                        {
+                          "nh-type": "blackhole",
+                          "vrf": "default",
+                          "gateway": "",
+                          "interface": "(null)",
+                          "bh-type": "null",
+                          "onlink": false
+                        }
+                      ]
+                    }
+                  }
+                ]
+              },
+              {
+                "prefix": "13.0.0.0/24",
+                "afi-safi": "frr-routing:ipv4-unicast",
+                "path-list": [
+                  {
+                    "table-id": 0,
+                    "distance": 1,
+                    "tag": 0,
+                    "frr-nexthops": {
+                      "nexthop": [
+                        {
+                          "nh-type": "blackhole",
+                          "vrf": "default",
+                          "gateway": "",
+                          "interface": "(null)",
+                          "bh-type": "null",
+                          "onlink": false
+                        }
+                      ]
+                    }
+                  }
+                ]
+              },
+              {
+                "prefix": "13.0.1.0/24",
+                "afi-safi": "frr-routing:ipv4-unicast",
+                "path-list": [
+                  {
+                    "table-id": 0,
+                    "distance": 1,
+                    "tag": 0,
+                    "frr-nexthops": {
+                      "nexthop": [
+                        {
+                          "nh-type": "blackhole",
+                          "vrf": "default",
+                          "gateway": "",
+                          "interface": "(null)",
+                          "bh-type": "null",
+                          "onlink": false
+                        }
+                      ]
+                    }
+                  }
+                ]
+              },
+              {
+                "prefix": "13.0.2.0/24",
+                "afi-safi": "frr-routing:ipv4-unicast",
+                "path-list": [
+                  {
+                    "table-id": 0,
+                    "distance": 1,
+                    "tag": 0,
+                    "frr-nexthops": {
+                      "nexthop": [
+                        {
+                          "nh-type": "blackhole",
+                          "vrf": "default",
+                          "gateway": "",
+                          "interface": "(null)",
+                          "bh-type": "null",
+                          "onlink": false
+                        }
+                      ]
+                    }
+                  }
+                ]
+              },
+              {
+                "prefix": "13.0.3.0/24",
+                "afi-safi": "frr-routing:ipv4-unicast",
+                "path-list": [
+                  {
+                    "table-id": 0,
+                    "distance": 1,
+                    "tag": 0,
+                    "frr-nexthops": {
+                      "nexthop": [
+                        {
+                          "nh-type": "blackhole",
+                          "vrf": "default",
+                          "gateway": "",
+                          "interface": "(null)",
+                          "bh-type": "null",
+                          "onlink": false
+                        }
+                      ]
+                    }
+                  }
+                ]
+              }
+            ]
+          }
+        }
+      ]
+    }
+  },
+  "frr-vrf:lib": {
+    "vrf": [
+      {
+        "name": "default",
+        "state": {
+          "active": false
+        }
+      }
+    ]
+  }
+}
+
+)NONCE";
+
+const char *json_expect3 = R"NONCE({
+  "frr-routing:routing": {
+    "control-plane-protocols": {
+      "control-plane-protocol": [
+        {
+          "type": "frr-staticd:staticd",
+          "name": "staticd",
+          "vrf": "default",
+          "frr-staticd:staticd": {
+            "route-list": [
+              {
+                "prefix": "11.0.0.0/8",
+                "afi-safi": "frr-routing:ipv4-unicast",
+                "path-list": [
+                  {
+                    "table-id": 0,
+                    "distance": 1,
+                    "tag": 0,
+                    "frr-nexthops": {
+                      "nexthop": [
+                        {
+                          "nh-type": "blackhole",
+                          "vrf": "default",
+                          "gateway": "",
+                          "interface": "(null)",
+                          "bh-type": "null",
+                          "onlink": false
+                        }
+                      ]
+                    }
+                  }
+                ]
+              },
+              {
+                "prefix": "13.0.0.0/24",
+                "afi-safi": "frr-routing:ipv4-unicast",
+                "path-list": [
+                  {
+                    "table-id": 0,
+                    "distance": 1,
+                    "tag": 0,
+                    "frr-nexthops": {
+                      "nexthop": [
+                        {
+                          "nh-type": "blackhole",
+                          "vrf": "default",
+                          "gateway": "",
+                          "interface": "(null)",
+                          "bh-type": "null",
+                          "onlink": false
+                        }
+                      ]
+                    }
+                  }
+                ]
+              },
+              {
+                "prefix": "13.0.1.0/24",
+                "afi-safi": "frr-routing:ipv4-unicast",
+                "path-list": [
+                  {
+                    "table-id": 0,
+                    "distance": 1,
+                    "tag": 0,
+                    "frr-nexthops": {
+                      "nexthop": [
+                        {
+                          "nh-type": "blackhole",
+                          "vrf": "default",
+                          "gateway": "",
+                          "interface": "(null)",
+                          "bh-type": "null",
+                          "onlink": false
+                        }
+                      ]
+                    }
+                  }
+                ]
+              },
+              {
+                "prefix": "13.0.2.0/24",
+                "afi-safi": "frr-routing:ipv4-unicast",
+                "path-list": [
+                  {
+                    "table-id": 0,
+                    "distance": 1,
+                    "tag": 0,
+                    "frr-nexthops": {
+                      "nexthop": [
+                        {
+                          "nh-type": "blackhole",
+                          "vrf": "default",
+                          "gateway": "",
+                          "interface": "(null)",
+                          "bh-type": "null",
+                          "onlink": false
+                        }
+                      ]
+                    }
+                  }
+                ]
+              },
+              {
+                "prefix": "13.0.3.0/24",
+                "afi-safi": "frr-routing:ipv4-unicast",
+                "path-list": [
+                  {
+                    "table-id": 0,
+                    "distance": 1,
+                    "tag": 0,
+                    "frr-nexthops": {
+                      "nexthop": [
+                        {
+                          "nh-type": "blackhole",
+                          "vrf": "default",
+                          "gateway": "",
+                          "interface": "(null)",
+                          "bh-type": "null",
+                          "onlink": false
+                        }
+                      ]
+                    }
+                  }
+                ]
+              },
+              {
+                "prefix": "10.0.0.0/13",
+                "afi-safi": "frr-routing:ipv4-unicast",
+                "path-list": [
+                  {
+                    "table-id": 0,
+                    "distance": 1,
+                    "tag": 0,
+                    "frr-nexthops": {
+                      "nexthop": [
+                        {
+                          "nh-type": "blackhole",
+                          "vrf": "default",
+                          "gateway": "",
+                          "interface": "(null)",
+                          "bh-type": "null",
+                          "onlink": false
+                        }
+                      ]
+                    }
+                  }
+                ]
+              }
+            ]
+          }
+        }
+      ]
+    }
+  },
+  "frr-vrf:lib": {
+    "vrf": [
+      {
+        "name": "default",
+        "state": {
+          "active": false
+        }
+      }
+    ]
+  }
+}
+
+)NONCE";
diff --git a/tests/lib/test_grpc.py b/tests/lib/test_grpc.py
new file mode 100644 (file)
index 0000000..06ae6c0
--- /dev/null
@@ -0,0 +1,23 @@
+import inspect
+import os
+import subprocess
+import pytest
+import frrtest
+
+class TestGRPC(object):
+    program = "./test_grpc"
+
+    @pytest.mark.skipif(
+        'S["GRPC_TRUE"]=""\n' not in open("../config.status").readlines(),
+        reason="GRPC not enabled",
+    )
+    def test_exits_cleanly(self):
+        basedir = os.path.dirname(inspect.getsourcefile(type(self)))
+        program = os.path.join(basedir, self.program)
+        proc = subprocess.Popen(
+            [frrtest.binpath(program)], stdin=subprocess.PIPE, stdout=subprocess.PIPE
+        )
+        output, _ = proc.communicate()
+        self.exitcode = proc.wait()
+        if self.exitcode != 0:
+            raise frrtest.TestExitNonzero(self)
index 39966997745e80bbd8092aab63f16bf28ec966c9..ca477851e393199b82fc163b0cf12a303efa0143 100644 (file)
@@ -106,6 +106,12 @@ check_PROGRAMS = \
        $(TESTS_ZEBRA) \
        # end
 
+if GRPC
+check_PROGRAMS += \
+       tests/lib/test_grpc \
+       #end
+endif
+
 if ZEROMQ
 check_PROGRAMS += \
        tests/lib/test_zmq \
@@ -156,9 +162,19 @@ TESTS_CFLAGS = \
        # end
 # note no -Werror
 
+TESTS_CXXFLAGS = \
+       $(AC_CXXFLAGS) \
+       $(LIBYANG_CFLAGS) \
+       $(SAN_FLAGS) \
+       # end
+# note no -Werror
+
 ALL_TESTS_LDADD = lib/libfrr.la $(LIBCAP)
 BGP_TEST_LDADD = bgpd/libbgp.a $(RFPLDADD) $(ALL_TESTS_LDADD) $(LIBYANG_LIBS) -lm
 ISISD_TEST_LDADD = isisd/libisis.a $(ALL_TESTS_LDADD)
+if GRPC
+GRPC_TESTS_LDADD = staticd/libstatic.a grpc/libfrrgrpc_pb.la -lgrpc++ -lprotobuf $(ALL_TESTS_LDADD) $(LIBYANG_LIBS) -lm
+endif
 OSPFD_TEST_LDADD = ospfd/libfrrospf.a $(ALL_TESTS_LDADD)
 OSPF6_TEST_LDADD = ospf6d/libospf6.a $(ALL_TESTS_LDADD)
 ZEBRA_TEST_LDADD = zebra/label_manager.o $(ALL_TESTS_LDADD)
@@ -251,6 +267,12 @@ tests_lib_northbound_test_oper_data_CPPFLAGS = $(TESTS_CPPFLAGS)
 tests_lib_northbound_test_oper_data_LDADD = $(ALL_TESTS_LDADD)
 tests_lib_northbound_test_oper_data_SOURCES = tests/lib/northbound/test_oper_data.c
 nodist_tests_lib_northbound_test_oper_data_SOURCES = yang/frr-test-module.yang.c
+if GRPC
+tests_lib_test_grpc_CXXFLAGS = $(WERROR) $(TESTS_CXXFLAGS)
+tests_lib_test_grpc_CPPFLAGS = $(TESTS_CPPFLAGS)
+tests_lib_test_grpc_LDADD = $(GRPC_TESTS_LDADD)
+tests_lib_test_grpc_SOURCES = tests/lib/test_grpc.cpp
+endif
 tests_lib_test_assert_CFLAGS = $(TESTS_CFLAGS)
 tests_lib_test_assert_CPPFLAGS = $(TESTS_CPPFLAGS)
 tests_lib_test_assert_LDADD = $(ALL_TESTS_LDADD)
index 597e2306965ac7e0a41eeb0acc118dd0db7abfc4..2d75428f1af6e8fc6d7024dfef50a0f6ca3c56fa 100644 (file)
@@ -906,17 +906,25 @@ def test_bgp_summary():
             # Read expected result from file
             expected_original = open(refTableFile).read().rstrip()
 
-            for filter in ["", "remote-as internal", "remote-as external",
+            for arguments in ["", "remote-as internal", "remote-as external",
                            "remote-as 100", "remote-as 123",
                            "neighbor 192.168.7.10", "neighbor 192.168.7.10",
                            "neighbor fc00:0:0:8::1000",
-                           "neighbor 10.0.0.1"]:
+                           "neighbor 10.0.0.1",
+                           "terse",
+                           "remote-as internal terse",
+                           "remote-as external terse",
+                           "remote-as 100 terse", "remote-as 123 terse",
+                           "neighbor 192.168.7.10 terse", "neighbor 192.168.7.10 terse",
+                           "neighbor fc00:0:0:8::1000 terse",
+                           "neighbor 10.0.0.1 terse"]:
                 # Actual output from router
                 actual = (
                     net["r%s" % i]
-                    .cmd('vtysh -c "show ip bgp summary ' + filter + '" 2> /dev/null')
+                    .cmd('vtysh -c "show ip bgp summary ' + arguments + '" 2> /dev/null')
                     .rstrip()
                 )
+
                 # Mask out "using XXiXX bytes" portion. They are random...
                 actual = re.sub(r"using [0-9]+ bytes", "using XXXX bytes", actual)
                 # Mask out "using XiXXX KiB" portion. They are random...
@@ -928,48 +936,55 @@ def test_bgp_summary():
                 actual = re.sub(r"Total number.*", "", actual)
                 actual = re.sub(r"Displayed.*", "", actual)
                 # Remove IPv4 Unicast Summary (Title only)
-                actual = re.sub(r"IPv4 Unicast Summary:", "", actual)
+                actual = re.sub(r"IPv4 Unicast Summary \(VRF default\):", "", actual)
                 # Remove IPv4 Multicast Summary (all of it)
-                actual = re.sub(r"IPv4 Multicast Summary:", "", actual)
+                actual = re.sub(r"IPv4 Multicast Summary \(VRF default\):", "", actual)
                 actual = re.sub(r"No IPv4 Multicast neighbor is configured", "", actual)
                 # Remove IPv4 VPN Summary (all of it)
-                actual = re.sub(r"IPv4 VPN Summary:", "", actual)
+                actual = re.sub(r"IPv4 VPN Summary \(VRF default\):", "", actual)
                 actual = re.sub(r"No IPv4 VPN neighbor is configured", "", actual)
                 # Remove IPv4 Encap Summary (all of it)
-                actual = re.sub(r"IPv4 Encap Summary:", "", actual)
+                actual = re.sub(r"IPv4 Encap Summary \(VRF default\):", "", actual)
                 actual = re.sub(r"No IPv4 Encap neighbor is configured", "", actual)
                 # Remove Unknown Summary (all of it)
-                actual = re.sub(r"Unknown Summary:", "", actual)
+                actual = re.sub(r"Unknown Summary \(VRF default\):", "", actual)
                 actual = re.sub(r"No Unknown neighbor is configured", "", actual)
 
-                actual = re.sub(r"IPv4 labeled-unicast Summary:", "", actual)
+                actual = re.sub(r"IPv4 labeled-unicast Summary \(VRF default\):", "", actual)
                 actual = re.sub(
                     r"No IPv4 labeled-unicast neighbor is configured", "", actual
                 )
 
                 expected = expected_original
-                # apply filters on expected output
-                if "internal" in filter or "remote-as 100" in filter:
+                # apply argumentss on expected output
+                if "internal" in arguments or "remote-as 100" in arguments:
                     expected = re.sub(r".+\s+200\s+.+", "", expected)
-                elif "external" in filter:
+                elif "external" in arguments:
                     expected = re.sub(r".+\s+100\s+.+Active.+", "", expected)
-                elif "remote-as 123" in filter:
+                elif "remote-as 123" in arguments:
                     expected = re.sub(
                         r"(192.168.7.(1|2)0|fc00:0:0:8::(1|2)000).+Active.+",
                         "", expected
                     )
-                elif "192.168.7.10" in filter:
+                    expected = re.sub(r"\nNeighbor.+Desc", "", expected)
+                    expected = expected + "% No matching neighbor\n"
+                elif "192.168.7.10" in arguments:
                     expected = re.sub(
                         r"(192.168.7.20|fc00:0:0:8::(1|2)000).+Active.+",
                         "", expected
                     )
-                elif "fc00:0:0:8::1000" in filter:
+                elif "fc00:0:0:8::1000" in arguments:
                     expected = re.sub(
                         r"(192.168.7.(1|2)0|fc00:0:0:8::2000).+Active.+",
                         "", expected
                     )
-                elif "10.0.0.1" in filter:
-                    expected = "No such neighbor in this view/vrf"
+                elif "10.0.0.1" in arguments:
+                    expected = "No such neighbor in VRF default"
+
+                if "terse" in arguments:
+                    expected = re.sub(r"BGP table version .+", "", expected)
+                    expected = re.sub(r"RIB entries .+", "", expected)
+                    expected = re.sub(r"Peers [0-9]+, using .+", "", expected)
 
                 # Strip empty lines
                 actual = actual.lstrip().rstrip()
@@ -978,13 +993,17 @@ def test_bgp_summary():
                 expected = re.sub(r"\n+", "\n", expected)
 
                 # reapply initial formatting
-                actual = re.sub(r"KiB of memory\n", "KiB of memory\n\n", actual)
-                expected = re.sub(r"KiB of memory\n", "KiB of memory\n\n", expected)
+                if "terse" in arguments:
+                    actual = re.sub(r" vrf-id 0\n", " vrf-id 0\n\n", actual)
+                    expected = re.sub(r" vrf-id 0\n", " vrf-id 0\n\n", expected)
+                else:
+                    actual = re.sub(r"KiB of memory\n", "KiB of memory\n\n", actual)
+                    expected = re.sub(r"KiB of memory\n", "KiB of memory\n\n", expected)
 
                 # realign expected neighbor columns if needed
                 try:
-                    idx_actual = re.search(r"\n(Neighbor\s+V\s+)", actual).group(1).find("V")
-                    idx_expected = re.search(r"\n(Neighbor\s+V\s+)", expected).group(1).find("V")
+                    idx_actual = re.search(r"(Neighbor\s+V\s+)", actual).group(1).find("V")
+                    idx_expected = re.search(r"(Neighbor\s+V\s+)", expected).group(1).find("V")
                     idx_diff = idx_expected - idx_actual
                     if idx_diff > 0:
                         # Neighbor        V         AS MsgRcvd MsgSent   TblVer  InQ OutQ  Up/Down State/PfxRcd
@@ -1002,8 +1021,8 @@ def test_bgp_summary():
                 diff = topotest.get_textdiff(
                     actual,
                     expected,
-                    title1="actual SHOW IP BGP SUMMARY " + filter.upper() ,
-                    title2="expected SHOW IP BGP SUMMARY " + filter.upper(),
+                    title1="actual SHOW IP BGP SUMMARY " + arguments.upper() ,
+                    title2="expected SHOW IP BGP SUMMARY " + arguments.upper(),
                 )
 
                 # Empty string if it matches, otherwise diff contains unified diff
@@ -1020,13 +1039,6 @@ def test_bgp_summary():
                     diff,
                 )
 
-                # Actual output from router
-                actual = (
-                    net["r%s" % i]
-                    .cmd('vtysh -c "show ip bgp summary" 2> /dev/null')
-                    .rstrip()
-                )
-
     # Make sure that all daemons are running
     for i in range(1, 2):
         fatal_error = net["r%s" % i].checkRouterRunning()
@@ -1074,22 +1086,22 @@ def test_bgp_ipv6_summary():
             actual = re.sub(r"Total number.*", "", actual)
             actual = re.sub(r"Displayed.*", "", actual)
             # Remove IPv4 Unicast Summary (Title only)
-            actual = re.sub(r"IPv6 Unicast Summary:", "", actual)
+            actual = re.sub(r"IPv6 Unicast Summary \(VRF default\):", "", actual)
             # Remove IPv4 Multicast Summary (all of it)
-            actual = re.sub(r"IPv6 Multicast Summary:", "", actual)
+            actual = re.sub(r"IPv6 Multicast Summary \(VRF default\):", "", actual)
             actual = re.sub(r"No IPv6 Multicast neighbor is configured", "", actual)
             # Remove IPv4 VPN Summary (all of it)
-            actual = re.sub(r"IPv6 VPN Summary:", "", actual)
+            actual = re.sub(r"IPv6 VPN Summary \(VRF default\):", "", actual)
             actual = re.sub(r"No IPv6 VPN neighbor is configured", "", actual)
             # Remove IPv4 Encap Summary (all of it)
-            actual = re.sub(r"IPv6 Encap Summary:", "", actual)
+            actual = re.sub(r"IPv6 Encap Summary \(VRF default\):", "", actual)
             actual = re.sub(r"No IPv6 Encap neighbor is configured", "", actual)
             # Remove Unknown Summary (all of it)
-            actual = re.sub(r"Unknown Summary:", "", actual)
+            actual = re.sub(r"Unknown Summary \(VRF default\):", "", actual)
             actual = re.sub(r"No Unknown neighbor is configured", "", actual)
 
             # Remove Labeled Unicast Summary (all of it)
-            actual = re.sub(r"IPv6 labeled-unicast Summary:", "", actual)
+            actual = re.sub(r"IPv6 labeled-unicast Summary \(VRF default\):", "", actual)
             actual = re.sub(
                 r"No IPv6 labeled-unicast neighbor is configured", "", actual
             )
index c828575c8489824e01c5d34f5df8ab941f835dec..eb571d5d1cd324eb4e4a251fe01f7b86a660c29d 100644 (file)
@@ -35,7 +35,7 @@
     {
       "distance": 110,
       "protocol": "ospf6",
-      "metric": 10,
+      "metric": 20,
       "selected": true,
       "installed": true,
       "prefix": "2001:db8:1::/64",
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vni_routes_base.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vni_routes_base.json
new file mode 100644 (file)
index 0000000..2eeebad
--- /dev/null
@@ -0,0 +1,192 @@
+{
+  "[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]":{
+    "prefix":"[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]",
+    "prefixLen":320,
+    "paths":[
+      [
+        {
+          "valid":true,
+          "bestpath":true,
+          "pathFrom":"external",
+          "routeType":2,
+          "ethTag":0,
+          "macLen":48,
+          "mac":"1a:2b:3c:4d:5e:61",
+          "weight":32768,
+          "peerId":"(unspec)",
+          "path":"",
+          "origin":"IGP",
+          "extendedCommunity":{
+            "string":"ET:8 RT:101:100"
+          },
+          "nexthops":[
+            {
+              "ip":"10.100.0.1",
+              "afi":"ipv4",
+              "used":true
+            }
+          ]
+        }
+      ]
+    ]
+  },
+  "[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]:[32]:[50.0.1.11]":{
+    "prefix":"[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]:[32]:[50.0.1.11]",
+    "prefixLen":320,
+    "paths":[
+      [
+        {
+          "valid":true,
+          "bestpath":true,
+          "pathFrom":"external",
+          "routeType":2,
+          "ethTag":0,
+          "macLen":48,
+          "mac":"1a:2b:3c:4d:5e:61",
+          "ipLen":32,
+          "ip":"50.0.1.11",
+          "weight":32768,
+          "peerId":"(unspec)",
+          "path":"",
+          "origin":"IGP",
+          "extendedCommunity":{
+            "string":"ET:8 RT:101:100"
+          },
+          "nexthops":[
+            {
+              "ip":"10.100.0.1",
+              "afi":"ipv4",
+              "used":true
+            }
+          ]
+        }
+      ]
+    ]
+  },
+  "[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]:[128]:[50:0:1::11]":{
+    "prefix":"[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]:[128]:[50:0:1::11]",
+    "prefixLen":320,
+    "paths":[
+      [
+        {
+          "valid":true,
+          "bestpath":true,
+          "pathFrom":"external",
+          "routeType":2,
+          "ethTag":0,
+          "macLen":48,
+          "mac":"1a:2b:3c:4d:5e:61",
+          "ipLen":128,
+          "ip":"50:0:1::11",
+          "weight":32768,
+          "peerId":"(unspec)",
+          "path":"",
+          "origin":"IGP",
+          "extendedCommunity":{
+            "string":"ET:8 RT:101:100"
+          },
+          "nexthops":[
+            {
+              "ip":"10.100.0.1",
+              "afi":"ipv4",
+              "used":true
+            }
+          ]
+        }
+      ]
+    ]
+  },
+  "[2]:[0]:[48]:[1a:2b:3c:4d:5e:62]":{
+    "prefix":"[2]:[0]:[48]:[1a:2b:3c:4d:5e:62]",
+    "prefixLen":320,
+    "paths":[
+      [
+        {
+          "valid":true,
+          "bestpath":true,
+          "pathFrom":"external",
+          "routeType":2,
+          "ethTag":0,
+          "macLen":48,
+          "mac":"1a:2b:3c:4d:5e:62",
+          "weight":0,
+          "peerId":"10.0.1.2",
+          "path":"102",
+          "origin":"IGP",
+          "extendedCommunity":{
+            "string":"RT:102:100 ET:8"
+          },
+          "nexthops":[
+            {
+              "ip":"10.100.0.2",
+              "afi":"ipv4",
+              "used":true
+            }
+          ]
+        }
+      ]
+    ]
+  },
+  "[3]:[0]:[32]:[10.100.0.1]":{
+    "prefix":"[3]:[0]:[32]:[10.100.0.1]",
+    "prefixLen":320,
+    "paths":[
+      [
+        {
+          "valid":true,
+          "bestpath":true,
+          "pathFrom":"external",
+          "routeType":3,
+          "ethTag":0,
+          "ipLen":32,
+          "ip":"10.100.0.1",
+          "weight":32768,
+          "peerId":"(unspec)",
+          "path":"",
+          "origin":"IGP",
+          "extendedCommunity":{
+            "string":"ET:8 RT:101:100"
+          },
+          "nexthops":[
+            {
+              "ip":"10.100.0.1",
+              "afi":"ipv4",
+              "used":true
+            }
+          ]
+        }
+      ]
+    ]
+  },
+  "[3]:[0]:[32]:[10.100.0.2]":{
+    "prefix":"[3]:[0]:[32]:[10.100.0.2]",
+    "prefixLen":320,
+    "paths":[
+      [
+        {
+          "valid":true,
+          "bestpath":true,
+          "pathFrom":"external",
+          "routeType":3,
+          "ethTag":0,
+          "ipLen":32,
+          "ip":"10.100.0.2",
+          "weight":0,
+          "peerId":"10.0.1.2",
+          "path":"102",
+          "origin":"IGP",
+          "extendedCommunity":{
+            "string":"RT:102:100 ET:8"
+          },
+          "nexthops":[
+            {
+              "ip":"10.100.0.2",
+              "afi":"ipv4",
+              "used":true
+            }
+          ]
+        }
+      ]
+    ]
+  }
+}
\ No newline at end of file
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vni_routes_no_rt2.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vni_routes_no_rt2.json
new file mode 100644 (file)
index 0000000..419bcc3
--- /dev/null
@@ -0,0 +1,8 @@
+{
+  "[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]": null,
+  "[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]:[32]:[50.0.1.11]": null,
+  "[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]:[128]:[50:0:1::11]": null,
+  "[2]:[0]:[48]:[1a:2b:3c:4d:5e:62]": null,
+  "[3]:[0]:[32]:[10.100.0.1]": null,
+  "[3]:[0]:[32]:[10.100.0.2]": null
+}
\ No newline at end of file
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vni_routes_no_rt5.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vni_routes_no_rt5.json
new file mode 100644 (file)
index 0000000..2eeebad
--- /dev/null
@@ -0,0 +1,192 @@
+{
+  "[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]":{
+    "prefix":"[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]",
+    "prefixLen":320,
+    "paths":[
+      [
+        {
+          "valid":true,
+          "bestpath":true,
+          "pathFrom":"external",
+          "routeType":2,
+          "ethTag":0,
+          "macLen":48,
+          "mac":"1a:2b:3c:4d:5e:61",
+          "weight":32768,
+          "peerId":"(unspec)",
+          "path":"",
+          "origin":"IGP",
+          "extendedCommunity":{
+            "string":"ET:8 RT:101:100"
+          },
+          "nexthops":[
+            {
+              "ip":"10.100.0.1",
+              "afi":"ipv4",
+              "used":true
+            }
+          ]
+        }
+      ]
+    ]
+  },
+  "[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]:[32]:[50.0.1.11]":{
+    "prefix":"[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]:[32]:[50.0.1.11]",
+    "prefixLen":320,
+    "paths":[
+      [
+        {
+          "valid":true,
+          "bestpath":true,
+          "pathFrom":"external",
+          "routeType":2,
+          "ethTag":0,
+          "macLen":48,
+          "mac":"1a:2b:3c:4d:5e:61",
+          "ipLen":32,
+          "ip":"50.0.1.11",
+          "weight":32768,
+          "peerId":"(unspec)",
+          "path":"",
+          "origin":"IGP",
+          "extendedCommunity":{
+            "string":"ET:8 RT:101:100"
+          },
+          "nexthops":[
+            {
+              "ip":"10.100.0.1",
+              "afi":"ipv4",
+              "used":true
+            }
+          ]
+        }
+      ]
+    ]
+  },
+  "[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]:[128]:[50:0:1::11]":{
+    "prefix":"[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]:[128]:[50:0:1::11]",
+    "prefixLen":320,
+    "paths":[
+      [
+        {
+          "valid":true,
+          "bestpath":true,
+          "pathFrom":"external",
+          "routeType":2,
+          "ethTag":0,
+          "macLen":48,
+          "mac":"1a:2b:3c:4d:5e:61",
+          "ipLen":128,
+          "ip":"50:0:1::11",
+          "weight":32768,
+          "peerId":"(unspec)",
+          "path":"",
+          "origin":"IGP",
+          "extendedCommunity":{
+            "string":"ET:8 RT:101:100"
+          },
+          "nexthops":[
+            {
+              "ip":"10.100.0.1",
+              "afi":"ipv4",
+              "used":true
+            }
+          ]
+        }
+      ]
+    ]
+  },
+  "[2]:[0]:[48]:[1a:2b:3c:4d:5e:62]":{
+    "prefix":"[2]:[0]:[48]:[1a:2b:3c:4d:5e:62]",
+    "prefixLen":320,
+    "paths":[
+      [
+        {
+          "valid":true,
+          "bestpath":true,
+          "pathFrom":"external",
+          "routeType":2,
+          "ethTag":0,
+          "macLen":48,
+          "mac":"1a:2b:3c:4d:5e:62",
+          "weight":0,
+          "peerId":"10.0.1.2",
+          "path":"102",
+          "origin":"IGP",
+          "extendedCommunity":{
+            "string":"RT:102:100 ET:8"
+          },
+          "nexthops":[
+            {
+              "ip":"10.100.0.2",
+              "afi":"ipv4",
+              "used":true
+            }
+          ]
+        }
+      ]
+    ]
+  },
+  "[3]:[0]:[32]:[10.100.0.1]":{
+    "prefix":"[3]:[0]:[32]:[10.100.0.1]",
+    "prefixLen":320,
+    "paths":[
+      [
+        {
+          "valid":true,
+          "bestpath":true,
+          "pathFrom":"external",
+          "routeType":3,
+          "ethTag":0,
+          "ipLen":32,
+          "ip":"10.100.0.1",
+          "weight":32768,
+          "peerId":"(unspec)",
+          "path":"",
+          "origin":"IGP",
+          "extendedCommunity":{
+            "string":"ET:8 RT:101:100"
+          },
+          "nexthops":[
+            {
+              "ip":"10.100.0.1",
+              "afi":"ipv4",
+              "used":true
+            }
+          ]
+        }
+      ]
+    ]
+  },
+  "[3]:[0]:[32]:[10.100.0.2]":{
+    "prefix":"[3]:[0]:[32]:[10.100.0.2]",
+    "prefixLen":320,
+    "paths":[
+      [
+        {
+          "valid":true,
+          "bestpath":true,
+          "pathFrom":"external",
+          "routeType":3,
+          "ethTag":0,
+          "ipLen":32,
+          "ip":"10.100.0.2",
+          "weight":0,
+          "peerId":"10.0.1.2",
+          "path":"102",
+          "origin":"IGP",
+          "extendedCommunity":{
+            "string":"RT:102:100 ET:8"
+          },
+          "nexthops":[
+            {
+              "ip":"10.100.0.2",
+              "afi":"ipv4",
+              "used":true
+            }
+          ]
+        }
+      ]
+    ]
+  }
+}
\ No newline at end of file
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vrf_ipv4_base.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vrf_ipv4_base.json
new file mode 100644 (file)
index 0000000..833f986
--- /dev/null
@@ -0,0 +1,27 @@
+{
+ "vrfName": "vrf-blue",
+ "routerId": "10.100.0.1",
+ "defaultLocPrf": 100,
+ "localAS": 101,
+ "routes": { "100.0.0.21/32": [
+  {
+    "valid":true,
+    "bestpath":true,
+    "pathFrom":"external",
+    "prefix":"100.0.0.21",
+    "prefixLen":32,
+    "network":"100.0.0.21\/32",
+    "metric":0,
+    "weight":0,
+    "peerId":"50.0.1.11",
+    "path":"111",
+    "origin":"IGP",
+    "nexthops":[
+      {
+        "ip":"50.0.1.11",
+        "afi":"ipv4",
+        "used":true
+      }
+    ]
+  }
+] }  }
\ No newline at end of file
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vrf_ipv4_no_rt2.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vrf_ipv4_no_rt2.json
new file mode 100644 (file)
index 0000000..833f986
--- /dev/null
@@ -0,0 +1,27 @@
+{
+ "vrfName": "vrf-blue",
+ "routerId": "10.100.0.1",
+ "defaultLocPrf": 100,
+ "localAS": 101,
+ "routes": { "100.0.0.21/32": [
+  {
+    "valid":true,
+    "bestpath":true,
+    "pathFrom":"external",
+    "prefix":"100.0.0.21",
+    "prefixLen":32,
+    "network":"100.0.0.21\/32",
+    "metric":0,
+    "weight":0,
+    "peerId":"50.0.1.11",
+    "path":"111",
+    "origin":"IGP",
+    "nexthops":[
+      {
+        "ip":"50.0.1.11",
+        "afi":"ipv4",
+        "used":true
+      }
+    ]
+  }
+] }  }
\ No newline at end of file
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vrf_ipv4_no_rt5.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vrf_ipv4_no_rt5.json
new file mode 100644 (file)
index 0000000..4a292bd
--- /dev/null
@@ -0,0 +1,6 @@
+{
+ "vrfName": "vrf-blue",
+ "routerId": "10.100.0.1",
+ "defaultLocPrf": 100,
+ "localAS": 101,
+ "routes": { "100.0.0.21/32": null }  }
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vrf_ipv6_base.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vrf_ipv6_base.json
new file mode 100644 (file)
index 0000000..3dc3fcf
--- /dev/null
@@ -0,0 +1,27 @@
+{
+ "vrfName": "vrf-blue",
+ "routerId": "10.100.0.1",
+ "defaultLocPrf": 100,
+ "localAS": 101,
+ "routes": { "100::21/128": [
+  {
+    "valid":true,
+    "bestpath":true,
+    "pathFrom":"external",
+    "prefix":"100::21",
+    "prefixLen":128,
+    "network":"100::21\/128",
+    "metric":0,
+    "weight":0,
+    "peerId":"50:0:1::11",
+    "path":"111",
+    "origin":"IGP",
+    "nexthops":[
+      {
+        "ip":"50:0:1::11",
+        "afi":"ipv6",
+        "scope":"global"
+      }
+    ]
+  }
+] }  }
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vrf_ipv6_no_rt2.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vrf_ipv6_no_rt2.json
new file mode 100644 (file)
index 0000000..3dc3fcf
--- /dev/null
@@ -0,0 +1,27 @@
+{
+ "vrfName": "vrf-blue",
+ "routerId": "10.100.0.1",
+ "defaultLocPrf": 100,
+ "localAS": 101,
+ "routes": { "100::21/128": [
+  {
+    "valid":true,
+    "bestpath":true,
+    "pathFrom":"external",
+    "prefix":"100::21",
+    "prefixLen":128,
+    "network":"100::21\/128",
+    "metric":0,
+    "weight":0,
+    "peerId":"50:0:1::11",
+    "path":"111",
+    "origin":"IGP",
+    "nexthops":[
+      {
+        "ip":"50:0:1::11",
+        "afi":"ipv6",
+        "scope":"global"
+      }
+    ]
+  }
+] }  }
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vrf_ipv6_no_rt5.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgp_vrf_ipv6_no_rt5.json
new file mode 100644 (file)
index 0000000..6c11d89
--- /dev/null
@@ -0,0 +1,6 @@
+{
+ "vrfName": "vrf-blue",
+ "routerId": "10.100.0.1",
+ "defaultLocPrf": 100,
+ "localAS": 101,
+ "routes": { "100::21/128": null }  }
\ No newline at end of file
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgpd.conf b/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/bgpd.conf
new file mode 100644 (file)
index 0000000..63aa99a
--- /dev/null
@@ -0,0 +1,30 @@
+router bgp 101
+ bgp router-id 10.100.0.1
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+ neighbor 10.0.1.2 remote-as 102
+ !
+ address-family l2vpn evpn
+  neighbor 10.0.1.2 activate
+  advertise-all-vni
+ exit-address-family
+!
+router bgp 101 vrf vrf-blue
+ bgp router-id 10.100.0.1
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+ neighbor 50.0.1.11 remote-as 111
+ neighbor 50:0:1::11 remote-as 111
+ !
+ address-family ipv4 unicast
+  no neighbor 50:0:1::11 activate
+ exit-address-family
+ !
+ address-family ipv6 unicast
+  neighbor 50:0:1::11 activate
+ exit-address-family
+ !
+ address-family l2vpn evpn
+  advertise ipv4 unicast gateway-ip
+  advertise ipv6 unicast gateway-ip
+ exit-address-family
\ No newline at end of file
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/zebra.conf b/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/zebra.conf
new file mode 100644 (file)
index 0000000..99a2e89
--- /dev/null
@@ -0,0 +1,14 @@
+!
+log file zebra.log
+!
+ip route 10.100.0.2/32 10.0.1.2
+!
+vrf vrf-blue
+ vni 1000 prefix-routes-only
+ exit-vrf
+!
+interface lo
+ ip address 10.100.0.1/32
+interface PE1-eth0
+ ip address 10.0.1.1/24
+!
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/zebra_vrf_ipv4_base.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/zebra_vrf_ipv4_base.json
new file mode 100644 (file)
index 0000000..2dcf35d
--- /dev/null
@@ -0,0 +1,56 @@
+{
+  "50.0.1.0\/24":[
+    {
+      "prefix":"50.0.1.0\/24",
+      "protocol":"connected",
+      "vrfName":"vrf-blue",
+      "selected":true,
+      "destSelected":true,
+      "distance":0,
+      "metric":0,
+      "installed":true,
+      "table":10,
+      "internalStatus":16,
+      "internalFlags":8,
+      "internalNextHopNum":1,
+      "internalNextHopActiveNum":1,
+      "nexthops":[
+        {
+          "flags":3,
+          "fib":true,
+          "directlyConnected":true,
+          "interfaceName":"br100",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "100.0.0.21\/32":[
+    {
+      "prefix":"100.0.0.21\/32",
+      "protocol":"bgp",
+      "vrfName":"vrf-blue",
+      "selected":true,
+      "destSelected":true,
+      "distance":20,
+      "metric":0,
+      "installed":true,
+      "table":10,
+      "internalStatus":16,
+      "internalFlags":8,
+      "internalNextHopNum":1,
+      "internalNextHopActiveNum":1,
+      "nexthops":[
+        {
+          "flags":3,
+          "fib":true,
+          "ip":"50.0.1.11",
+          "afi":"ipv4",
+          "interfaceName":"br100",
+          "active":true,
+          "weight":1
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/zebra_vrf_ipv4_no_rt2.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/zebra_vrf_ipv4_no_rt2.json
new file mode 100644 (file)
index 0000000..2dcf35d
--- /dev/null
@@ -0,0 +1,56 @@
+{
+  "50.0.1.0\/24":[
+    {
+      "prefix":"50.0.1.0\/24",
+      "protocol":"connected",
+      "vrfName":"vrf-blue",
+      "selected":true,
+      "destSelected":true,
+      "distance":0,
+      "metric":0,
+      "installed":true,
+      "table":10,
+      "internalStatus":16,
+      "internalFlags":8,
+      "internalNextHopNum":1,
+      "internalNextHopActiveNum":1,
+      "nexthops":[
+        {
+          "flags":3,
+          "fib":true,
+          "directlyConnected":true,
+          "interfaceName":"br100",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "100.0.0.21\/32":[
+    {
+      "prefix":"100.0.0.21\/32",
+      "protocol":"bgp",
+      "vrfName":"vrf-blue",
+      "selected":true,
+      "destSelected":true,
+      "distance":20,
+      "metric":0,
+      "installed":true,
+      "table":10,
+      "internalStatus":16,
+      "internalFlags":8,
+      "internalNextHopNum":1,
+      "internalNextHopActiveNum":1,
+      "nexthops":[
+        {
+          "flags":3,
+          "fib":true,
+          "ip":"50.0.1.11",
+          "afi":"ipv4",
+          "interfaceName":"br100",
+          "active":true,
+          "weight":1
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/zebra_vrf_ipv4_no_rt5.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/zebra_vrf_ipv4_no_rt5.json
new file mode 100644 (file)
index 0000000..9c3091d
--- /dev/null
@@ -0,0 +1,29 @@
+{
+  "50.0.1.0\/24":[
+    {
+      "prefix":"50.0.1.0\/24",
+      "protocol":"connected",
+      "vrfName":"vrf-blue",
+      "selected":true,
+      "destSelected":true,
+      "distance":0,
+      "metric":0,
+      "installed":true,
+      "table":10,
+      "internalStatus":16,
+      "internalFlags":8,
+      "internalNextHopNum":1,
+      "internalNextHopActiveNum":1,
+      "nexthops":[
+        {
+          "flags":3,
+          "fib":true,
+          "directlyConnected":true,
+          "interfaceName":"br100",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "100.0.0.21\/32": null
+}
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/zebra_vrf_ipv6_base.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/zebra_vrf_ipv6_base.json
new file mode 100644 (file)
index 0000000..229c927
--- /dev/null
@@ -0,0 +1,55 @@
+{
+  "50:0:1::\/48":[
+    {
+      "prefix":"50:0:1::\/48",
+      "protocol":"connected",
+      "vrfName":"vrf-blue",
+      "selected":true,
+      "destSelected":true,
+      "distance":0,
+      "metric":0,
+      "installed":true,
+      "table":10,
+      "internalStatus":16,
+      "internalFlags":8,
+      "internalNextHopNum":1,
+      "internalNextHopActiveNum":1,
+      "nexthops":[
+        {
+          "flags":3,
+          "fib":true,
+          "directlyConnected":true,
+          "interfaceName":"br100",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "100::21\/128":[
+    {
+      "prefix":"100::21\/128",
+      "protocol":"bgp",
+      "vrfName":"vrf-blue",
+      "selected":true,
+      "destSelected":true,
+      "distance":20,
+      "metric":0,
+      "installed":true,
+      "table":10,
+      "internalStatus":16,
+      "internalFlags":8,
+      "internalNextHopNum":1,
+      "internalNextHopActiveNum":1,
+      "nexthops":[
+        {
+          "flags":3,
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"br100",
+          "active":true,
+          "weight":1
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/zebra_vrf_ipv6_no_rt2.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/zebra_vrf_ipv6_no_rt2.json
new file mode 100644 (file)
index 0000000..229c927
--- /dev/null
@@ -0,0 +1,55 @@
+{
+  "50:0:1::\/48":[
+    {
+      "prefix":"50:0:1::\/48",
+      "protocol":"connected",
+      "vrfName":"vrf-blue",
+      "selected":true,
+      "destSelected":true,
+      "distance":0,
+      "metric":0,
+      "installed":true,
+      "table":10,
+      "internalStatus":16,
+      "internalFlags":8,
+      "internalNextHopNum":1,
+      "internalNextHopActiveNum":1,
+      "nexthops":[
+        {
+          "flags":3,
+          "fib":true,
+          "directlyConnected":true,
+          "interfaceName":"br100",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "100::21\/128":[
+    {
+      "prefix":"100::21\/128",
+      "protocol":"bgp",
+      "vrfName":"vrf-blue",
+      "selected":true,
+      "destSelected":true,
+      "distance":20,
+      "metric":0,
+      "installed":true,
+      "table":10,
+      "internalStatus":16,
+      "internalFlags":8,
+      "internalNextHopNum":1,
+      "internalNextHopActiveNum":1,
+      "nexthops":[
+        {
+          "flags":3,
+          "fib":true,
+          "afi":"ipv6",
+          "interfaceName":"br100",
+          "active":true,
+          "weight":1
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/zebra_vrf_ipv6_no_rt5.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE1/zebra_vrf_ipv6_no_rt5.json
new file mode 100644 (file)
index 0000000..94f82e6
--- /dev/null
@@ -0,0 +1,29 @@
+{
+  "50:0:1::\/48":[
+    {
+      "prefix":"50:0:1::\/48",
+      "protocol":"connected",
+      "vrfName":"vrf-blue",
+      "selected":true,
+      "destSelected":true,
+      "distance":0,
+      "metric":0,
+      "installed":true,
+      "table":10,
+      "internalStatus":16,
+      "internalFlags":8,
+      "internalNextHopNum":1,
+      "internalNextHopActiveNum":1,
+      "nexthops":[
+        {
+          "flags":3,
+          "fib":true,
+          "directlyConnected":true,
+          "interfaceName":"br100",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "100::21\/128": null
+}
\ No newline at end of file
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vni_routes_base.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vni_routes_base.json
new file mode 100644 (file)
index 0000000..7b8d38e
--- /dev/null
@@ -0,0 +1,192 @@
+{
+  "[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]":{
+    "prefix":"[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]",
+    "prefixLen":320,
+    "paths":[
+      [
+        {
+          "valid":true,
+          "bestpath":true,
+          "pathFrom":"external",
+          "routeType":2,
+          "ethTag":0,
+          "macLen":48,
+          "mac":"1a:2b:3c:4d:5e:61",
+          "weight":0,
+          "peerId":"10.0.1.1",
+          "path":"101",
+          "origin":"IGP",
+          "extendedCommunity":{
+            "string":"RT:101:100 ET:8"
+          },
+          "nexthops":[
+            {
+              "ip":"10.100.0.1",
+              "afi":"ipv4",
+              "used":true
+            }
+          ]
+        }
+      ]
+    ]
+  },
+  "[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]:[32]:[50.0.1.11]":{
+    "prefix":"[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]:[32]:[50.0.1.11]",
+    "prefixLen":320,
+    "paths":[
+      [
+        {
+          "valid":true,
+          "bestpath":true,
+          "pathFrom":"external",
+          "routeType":2,
+          "ethTag":0,
+          "macLen":48,
+          "mac":"1a:2b:3c:4d:5e:61",
+          "ipLen":32,
+          "ip":"50.0.1.11",
+          "weight":0,
+          "peerId":"10.0.1.1",
+          "path":"101",
+          "origin":"IGP",
+          "extendedCommunity":{
+            "string":"RT:101:100 ET:8"
+          },
+          "nexthops":[
+            {
+              "ip":"10.100.0.1",
+              "afi":"ipv4",
+              "used":true
+            }
+          ]
+        }
+      ]
+    ]
+  },
+  "[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]:[128]:[50:0:1::11]":{
+    "prefix":"[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]:[128]:[50:0:1::11]",
+    "prefixLen":320,
+    "paths":[
+      [
+        {
+          "valid":true,
+          "bestpath":true,
+          "pathFrom":"external",
+          "routeType":2,
+          "ethTag":0,
+          "macLen":48,
+          "mac":"1a:2b:3c:4d:5e:61",
+          "ipLen":128,
+          "ip":"50:0:1::11",
+          "weight":0,
+          "peerId":"10.0.1.1",
+          "path":"101",
+          "origin":"IGP",
+          "extendedCommunity":{
+            "string":"RT:101:100 ET:8"
+          },
+          "nexthops":[
+            {
+              "ip":"10.100.0.1",
+              "afi":"ipv4",
+              "used":true
+            }
+          ]
+        }
+      ]
+    ]
+  },
+  "[2]:[0]:[48]:[1a:2b:3c:4d:5e:62]":{
+    "prefix":"[2]:[0]:[48]:[1a:2b:3c:4d:5e:62]",
+    "prefixLen":320,
+    "paths":[
+      [
+        {
+          "valid":true,
+          "bestpath":true,
+          "pathFrom":"external",
+          "routeType":2,
+          "ethTag":0,
+          "macLen":48,
+          "mac":"1a:2b:3c:4d:5e:62",
+          "weight":32768,
+          "peerId":"(unspec)",
+          "path":"",
+          "origin":"IGP",
+          "extendedCommunity":{
+            "string":"ET:8 RT:102:100"
+          },
+          "nexthops":[
+            {
+              "ip":"10.100.0.2",
+              "afi":"ipv4",
+              "used":true
+            }
+          ]
+        }
+      ]
+    ]
+  },
+  "[3]:[0]:[32]:[10.100.0.1]":{
+    "prefix":"[3]:[0]:[32]:[10.100.0.1]",
+    "prefixLen":320,
+    "paths":[
+      [
+        {
+          "valid":true,
+          "bestpath":true,
+          "pathFrom":"external",
+          "routeType":3,
+          "ethTag":0,
+          "ipLen":32,
+          "ip":"10.100.0.1",
+          "weight":0,
+          "peerId":"10.0.1.1",
+          "path":"101",
+          "origin":"IGP",
+          "extendedCommunity":{
+            "string":"RT:101:100 ET:8"
+          },
+          "nexthops":[
+            {
+              "ip":"10.100.0.1",
+              "afi":"ipv4",
+              "used":true
+            }
+          ]
+        }
+      ]
+    ]
+  },
+  "[3]:[0]:[32]:[10.100.0.2]":{
+    "prefix":"[3]:[0]:[32]:[10.100.0.2]",
+    "prefixLen":320,
+    "paths":[
+      [
+        {
+          "valid":true,
+          "bestpath":true,
+          "pathFrom":"external",
+          "routeType":3,
+          "ethTag":0,
+          "ipLen":32,
+          "ip":"10.100.0.2",
+          "weight":32768,
+          "peerId":"(unspec)",
+          "path":"",
+          "origin":"IGP",
+          "extendedCommunity":{
+            "string":"ET:8 RT:102:100"
+          },
+          "nexthops":[
+            {
+              "ip":"10.100.0.2",
+              "afi":"ipv4",
+              "used":true
+            }
+          ]
+        }
+      ]
+    ]
+  }
+}
\ No newline at end of file
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vni_routes_no_rt2.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vni_routes_no_rt2.json
new file mode 100644 (file)
index 0000000..6273b3e
--- /dev/null
@@ -0,0 +1,68 @@
+{
+  "[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]": null,
+  "[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]:[32]:[50.0.1.11]": null,
+  "[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]:[128]:[50:0:1::11]": null,
+  "[2]:[0]:[48]:[1a:2b:3c:4d:5e:62]":{
+    "prefix":"[2]:[0]:[48]:[1a:2b:3c:4d:5e:62]",
+    "prefixLen":320,
+    "paths":[
+      [
+        {
+          "valid":true,
+          "bestpath":true,
+          "pathFrom":"external",
+          "routeType":2,
+          "ethTag":0,
+          "macLen":48,
+          "mac":"1a:2b:3c:4d:5e:62",
+          "weight":32768,
+          "peerId":"(unspec)",
+          "path":"",
+          "origin":"IGP",
+          "extendedCommunity":{
+            "string":"ET:8 RT:102:100"
+          },
+          "nexthops":[
+            {
+              "ip":"10.100.0.2",
+              "afi":"ipv4",
+              "used":true
+            }
+          ]
+        }
+      ]
+    ]
+  },
+  "[3]:[0]:[32]:[10.100.0.1]": null,
+  "[3]:[0]:[32]:[10.100.0.2]":{
+    "prefix":"[3]:[0]:[32]:[10.100.0.2]",
+    "prefixLen":320,
+    "paths":[
+      [
+        {
+          "valid":true,
+          "bestpath":true,
+          "pathFrom":"external",
+          "routeType":3,
+          "ethTag":0,
+          "ipLen":32,
+          "ip":"10.100.0.2",
+          "weight":32768,
+          "peerId":"(unspec)",
+          "path":"",
+          "origin":"IGP",
+          "extendedCommunity":{
+            "string":"ET:8 RT:102:100"
+          },
+          "nexthops":[
+            {
+              "ip":"10.100.0.2",
+              "afi":"ipv4",
+              "used":true
+            }
+          ]
+        }
+      ]
+    ]
+  }
+}
\ No newline at end of file
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vni_routes_no_rt5.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vni_routes_no_rt5.json
new file mode 100644 (file)
index 0000000..7b8d38e
--- /dev/null
@@ -0,0 +1,192 @@
+{
+  "[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]":{
+    "prefix":"[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]",
+    "prefixLen":320,
+    "paths":[
+      [
+        {
+          "valid":true,
+          "bestpath":true,
+          "pathFrom":"external",
+          "routeType":2,
+          "ethTag":0,
+          "macLen":48,
+          "mac":"1a:2b:3c:4d:5e:61",
+          "weight":0,
+          "peerId":"10.0.1.1",
+          "path":"101",
+          "origin":"IGP",
+          "extendedCommunity":{
+            "string":"RT:101:100 ET:8"
+          },
+          "nexthops":[
+            {
+              "ip":"10.100.0.1",
+              "afi":"ipv4",
+              "used":true
+            }
+          ]
+        }
+      ]
+    ]
+  },
+  "[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]:[32]:[50.0.1.11]":{
+    "prefix":"[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]:[32]:[50.0.1.11]",
+    "prefixLen":320,
+    "paths":[
+      [
+        {
+          "valid":true,
+          "bestpath":true,
+          "pathFrom":"external",
+          "routeType":2,
+          "ethTag":0,
+          "macLen":48,
+          "mac":"1a:2b:3c:4d:5e:61",
+          "ipLen":32,
+          "ip":"50.0.1.11",
+          "weight":0,
+          "peerId":"10.0.1.1",
+          "path":"101",
+          "origin":"IGP",
+          "extendedCommunity":{
+            "string":"RT:101:100 ET:8"
+          },
+          "nexthops":[
+            {
+              "ip":"10.100.0.1",
+              "afi":"ipv4",
+              "used":true
+            }
+          ]
+        }
+      ]
+    ]
+  },
+  "[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]:[128]:[50:0:1::11]":{
+    "prefix":"[2]:[0]:[48]:[1a:2b:3c:4d:5e:61]:[128]:[50:0:1::11]",
+    "prefixLen":320,
+    "paths":[
+      [
+        {
+          "valid":true,
+          "bestpath":true,
+          "pathFrom":"external",
+          "routeType":2,
+          "ethTag":0,
+          "macLen":48,
+          "mac":"1a:2b:3c:4d:5e:61",
+          "ipLen":128,
+          "ip":"50:0:1::11",
+          "weight":0,
+          "peerId":"10.0.1.1",
+          "path":"101",
+          "origin":"IGP",
+          "extendedCommunity":{
+            "string":"RT:101:100 ET:8"
+          },
+          "nexthops":[
+            {
+              "ip":"10.100.0.1",
+              "afi":"ipv4",
+              "used":true
+            }
+          ]
+        }
+      ]
+    ]
+  },
+  "[2]:[0]:[48]:[1a:2b:3c:4d:5e:62]":{
+    "prefix":"[2]:[0]:[48]:[1a:2b:3c:4d:5e:62]",
+    "prefixLen":320,
+    "paths":[
+      [
+        {
+          "valid":true,
+          "bestpath":true,
+          "pathFrom":"external",
+          "routeType":2,
+          "ethTag":0,
+          "macLen":48,
+          "mac":"1a:2b:3c:4d:5e:62",
+          "weight":32768,
+          "peerId":"(unspec)",
+          "path":"",
+          "origin":"IGP",
+          "extendedCommunity":{
+            "string":"ET:8 RT:102:100"
+          },
+          "nexthops":[
+            {
+              "ip":"10.100.0.2",
+              "afi":"ipv4",
+              "used":true
+            }
+          ]
+        }
+      ]
+    ]
+  },
+  "[3]:[0]:[32]:[10.100.0.1]":{
+    "prefix":"[3]:[0]:[32]:[10.100.0.1]",
+    "prefixLen":320,
+    "paths":[
+      [
+        {
+          "valid":true,
+          "bestpath":true,
+          "pathFrom":"external",
+          "routeType":3,
+          "ethTag":0,
+          "ipLen":32,
+          "ip":"10.100.0.1",
+          "weight":0,
+          "peerId":"10.0.1.1",
+          "path":"101",
+          "origin":"IGP",
+          "extendedCommunity":{
+            "string":"RT:101:100 ET:8"
+          },
+          "nexthops":[
+            {
+              "ip":"10.100.0.1",
+              "afi":"ipv4",
+              "used":true
+            }
+          ]
+        }
+      ]
+    ]
+  },
+  "[3]:[0]:[32]:[10.100.0.2]":{
+    "prefix":"[3]:[0]:[32]:[10.100.0.2]",
+    "prefixLen":320,
+    "paths":[
+      [
+        {
+          "valid":true,
+          "bestpath":true,
+          "pathFrom":"external",
+          "routeType":3,
+          "ethTag":0,
+          "ipLen":32,
+          "ip":"10.100.0.2",
+          "weight":32768,
+          "peerId":"(unspec)",
+          "path":"",
+          "origin":"IGP",
+          "extendedCommunity":{
+            "string":"ET:8 RT:102:100"
+          },
+          "nexthops":[
+            {
+              "ip":"10.100.0.2",
+              "afi":"ipv4",
+              "used":true
+            }
+          ]
+        }
+      ]
+    ]
+  }
+}
\ No newline at end of file
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vrf_ipv4_base.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vrf_ipv4_base.json
new file mode 100644 (file)
index 0000000..c03d701
--- /dev/null
@@ -0,0 +1,27 @@
+{
+ "vrfName": "vrf-blue",
+ "routerId": "10.100.0.2",
+ "defaultLocPrf": 100,
+ "localAS": 101,
+ "routes": { "100.0.0.21/32": [
+  {
+    "valid":true,
+    "bestpath":true,
+    "pathFrom":"external",
+    "prefix":"100.0.0.21",
+    "prefixLen":32,
+    "network":"100.0.0.21\/32",
+    "metric":0,
+    "weight":0,
+    "peerId":"10.0.1.1",
+    "path":"101 111",
+    "origin":"IGP",
+    "nexthops":[
+      {
+        "ip":"50.0.1.11",
+        "afi":"ipv4",
+        "used":true
+      }
+    ]
+  }
+] }  }
\ No newline at end of file
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vrf_ipv4_no_rt2.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vrf_ipv4_no_rt2.json
new file mode 100644 (file)
index 0000000..7f1b8d2
--- /dev/null
@@ -0,0 +1,27 @@
+{
+ "vrfName": "vrf-blue",
+ "routerId": "10.100.0.2",
+ "defaultLocPrf": 100,
+ "localAS": 101,
+ "routes": { "100.0.0.21/32": [
+  {
+    "valid":null,
+    "bestpath":null,
+    "pathFrom":"external",
+    "prefix":"100.0.0.21",
+    "prefixLen":32,
+    "network":"100.0.0.21\/32",
+    "metric":0,
+    "weight":0,
+    "peerId":"10.0.1.1",
+    "path":"101 111",
+    "origin":"IGP",
+    "nexthops":[
+      {
+        "ip":"50.0.1.11",
+        "afi":"ipv4",
+        "used":true
+      }
+    ]
+  }
+] }  }
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vrf_ipv4_no_rt5.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vrf_ipv4_no_rt5.json
new file mode 100644 (file)
index 0000000..52e4311
--- /dev/null
@@ -0,0 +1,6 @@
+{
+ "vrfName": "vrf-blue",
+ "routerId": "10.100.0.2",
+ "defaultLocPrf": 100,
+ "localAS": 101,
+ "routes": { "100.0.0.21/32": null }  }
\ No newline at end of file
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vrf_ipv6_base.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vrf_ipv6_base.json
new file mode 100644 (file)
index 0000000..1d90c9c
--- /dev/null
@@ -0,0 +1,28 @@
+{
+ "vrfName": "vrf-blue",
+ "routerId": "10.100.0.2",
+ "defaultLocPrf": 100,
+ "localAS": 101,
+ "routes": { "100::21/128": [
+  {
+    "valid":true,
+    "bestpath":true,
+    "pathFrom":"external",
+    "prefix":"100::21",
+    "prefixLen":128,
+    "network":"100::21\/128",
+    "metric":0,
+    "weight":0,
+    "peerId":"10.0.1.1",
+    "path":"101 111",
+    "origin":"IGP",
+    "nexthops":[
+      {
+        "ip":"50:0:1::11",
+        "afi":"ipv6",
+        "scope":"global",
+        "used":true
+      }
+    ]
+  }
+] }  }
\ No newline at end of file
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vrf_ipv6_no_rt2.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vrf_ipv6_no_rt2.json
new file mode 100644 (file)
index 0000000..a0e63c6
--- /dev/null
@@ -0,0 +1,28 @@
+{
+ "vrfName": "vrf-blue",
+ "routerId": "10.100.0.2",
+ "defaultLocPrf": 100,
+ "localAS": 101,
+ "routes": { "100::21/128": [
+  {
+    "valid":null,
+    "bestpath":null,
+    "pathFrom":"external",
+    "prefix":"100::21",
+    "prefixLen":128,
+    "network":"100::21\/128",
+    "metric":0,
+    "weight":0,
+    "peerId":"10.0.1.1",
+    "path":"101 111",
+    "origin":"IGP",
+    "nexthops":[
+      {
+        "ip":"50:0:1::11",
+        "afi":"ipv6",
+        "scope":"global",
+        "used":true
+      }
+    ]
+  }
+] }  }
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vrf_ipv6_no_rt5.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgp_vrf_ipv6_no_rt5.json
new file mode 100644 (file)
index 0000000..789fe69
--- /dev/null
@@ -0,0 +1,6 @@
+{
+ "vrfName": "vrf-blue",
+ "routerId": "10.100.0.2",
+ "defaultLocPrf": 100,
+ "localAS": 101,
+ "routes": { "100::21/128": null }  }
\ No newline at end of file
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgpd.conf b/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/bgpd.conf
new file mode 100644 (file)
index 0000000..59fee15
--- /dev/null
@@ -0,0 +1,14 @@
+router bgp 102
+ bgp router-id 10.100.0.2
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+ neighbor 10.0.1.1 remote-as 101
+ !
+ address-family l2vpn evpn
+  neighbor 10.0.1.1 activate
+  advertise-all-vni
+  enable-resolve-overlay-index
+ exit-address-family
+!
+router bgp 101 vrf vrf-blue
+ bgp router-id 10.100.0.2
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/zebra.conf b/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/zebra.conf
new file mode 100644 (file)
index 0000000..b78cdcc
--- /dev/null
@@ -0,0 +1,14 @@
+!
+log file zebra.log
+!
+ip route 10.100.0.1/32 10.0.1.1
+!
+vrf vrf-blue
+ vni 1000 prefix-routes-only
+ exit-vrf
+!
+interface lo
+ ip address 10.100.0.2/32
+interface  PE2-eth0
+ ip address 10.0.1.2/24
+!
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/zebra_vrf_ipv4_base.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/zebra_vrf_ipv4_base.json
new file mode 100644 (file)
index 0000000..b3a3640
--- /dev/null
@@ -0,0 +1,56 @@
+{
+  "50.0.1.0\/24":[
+    {
+      "prefix":"50.0.1.0\/24",
+      "protocol":"connected",
+      "vrfName":"vrf-blue",
+      "selected":true,
+      "destSelected":true,
+      "distance":0,
+      "metric":0,
+      "installed":true,
+      "table":10,
+      "internalStatus":16,
+      "internalFlags":8,
+      "internalNextHopNum":1,
+      "internalNextHopActiveNum":1,
+      "nexthops":[
+        {
+          "flags":3,
+          "fib":true,
+          "directlyConnected":true,
+          "interfaceName":"br100",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "100.0.0.21\/32":[
+    {
+      "prefix":"100.0.0.21\/32",
+      "protocol":"bgp",
+      "vrfName":"vrf-blue",
+      "selected":true,
+      "destSelected":true,
+      "distance":20,
+      "metric":0,
+      "installed":true,
+      "table":10,
+      "internalStatus":16,
+      "internalFlags":40,
+      "internalNextHopNum":1,
+      "internalNextHopActiveNum":1,
+      "nexthops":[
+        {
+          "flags":3,
+          "fib":true,
+          "ip":"50.0.1.11",
+          "afi":"ipv4",
+          "interfaceName":"br100",
+          "active":true,
+          "weight":1
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/zebra_vrf_ipv4_no_rt2.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/zebra_vrf_ipv4_no_rt2.json
new file mode 100644 (file)
index 0000000..996fe52
--- /dev/null
@@ -0,0 +1,29 @@
+{
+  "50.0.1.0\/24":[
+    {
+      "prefix":"50.0.1.0\/24",
+      "protocol":"connected",
+      "vrfName":"vrf-blue",
+      "selected":true,
+      "destSelected":true,
+      "distance":0,
+      "metric":0,
+      "installed":true,
+      "table":10,
+      "internalStatus":16,
+      "internalFlags":8,
+      "internalNextHopNum":1,
+      "internalNextHopActiveNum":1,
+      "nexthops":[
+        {
+          "flags":3,
+          "fib":true,
+          "directlyConnected":true,
+          "interfaceName":"br100",
+          "active":true
+        }
+      ]
+    }
+  ],
+   "100.0.0.21\/32": null
+}
\ No newline at end of file
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/zebra_vrf_ipv4_no_rt5.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/zebra_vrf_ipv4_no_rt5.json
new file mode 100644 (file)
index 0000000..996fe52
--- /dev/null
@@ -0,0 +1,29 @@
+{
+  "50.0.1.0\/24":[
+    {
+      "prefix":"50.0.1.0\/24",
+      "protocol":"connected",
+      "vrfName":"vrf-blue",
+      "selected":true,
+      "destSelected":true,
+      "distance":0,
+      "metric":0,
+      "installed":true,
+      "table":10,
+      "internalStatus":16,
+      "internalFlags":8,
+      "internalNextHopNum":1,
+      "internalNextHopActiveNum":1,
+      "nexthops":[
+        {
+          "flags":3,
+          "fib":true,
+          "directlyConnected":true,
+          "interfaceName":"br100",
+          "active":true
+        }
+      ]
+    }
+  ],
+   "100.0.0.21\/32": null
+}
\ No newline at end of file
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/zebra_vrf_ipv6_base.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/zebra_vrf_ipv6_base.json
new file mode 100644 (file)
index 0000000..d5be22a
--- /dev/null
@@ -0,0 +1,56 @@
+{
+  "50:0:1::\/48":[
+    {
+      "prefix":"50:0:1::\/48",
+      "protocol":"connected",
+      "vrfName":"vrf-blue",
+      "selected":true,
+      "destSelected":true,
+      "distance":0,
+      "metric":0,
+      "installed":true,
+      "table":10,
+      "internalStatus":16,
+      "internalFlags":8,
+      "internalNextHopNum":1,
+      "internalNextHopActiveNum":1,
+      "nexthops":[
+        {
+          "flags":3,
+          "fib":true,
+          "directlyConnected":true,
+          "interfaceName":"br100",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "100::21\/128":[
+    {
+      "prefix":"100::21\/128",
+      "protocol":"bgp",
+      "vrfName":"vrf-blue",
+      "selected":true,
+      "destSelected":true,
+      "distance":20,
+      "metric":0,
+      "installed":true,
+      "table":10,
+      "internalStatus":16,
+      "internalFlags":40,
+      "internalNextHopNum":1,
+      "internalNextHopActiveNum":1,
+      "nexthops":[
+        {
+          "flags":3,
+          "fib":true,
+          "ip":"50:0:1::11",
+          "afi":"ipv6",
+          "interfaceName":"br100",
+          "active":true,
+          "weight":1
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/zebra_vrf_ipv6_no_rt2.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/zebra_vrf_ipv6_no_rt2.json
new file mode 100644 (file)
index 0000000..94f82e6
--- /dev/null
@@ -0,0 +1,29 @@
+{
+  "50:0:1::\/48":[
+    {
+      "prefix":"50:0:1::\/48",
+      "protocol":"connected",
+      "vrfName":"vrf-blue",
+      "selected":true,
+      "destSelected":true,
+      "distance":0,
+      "metric":0,
+      "installed":true,
+      "table":10,
+      "internalStatus":16,
+      "internalFlags":8,
+      "internalNextHopNum":1,
+      "internalNextHopActiveNum":1,
+      "nexthops":[
+        {
+          "flags":3,
+          "fib":true,
+          "directlyConnected":true,
+          "interfaceName":"br100",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "100::21\/128": null
+}
\ No newline at end of file
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/zebra_vrf_ipv6_no_rt5.json b/tests/topotests/bgp-evpn-overlay-index-gateway/PE2/zebra_vrf_ipv6_no_rt5.json
new file mode 100644 (file)
index 0000000..94f82e6
--- /dev/null
@@ -0,0 +1,29 @@
+{
+  "50:0:1::\/48":[
+    {
+      "prefix":"50:0:1::\/48",
+      "protocol":"connected",
+      "vrfName":"vrf-blue",
+      "selected":true,
+      "destSelected":true,
+      "distance":0,
+      "metric":0,
+      "installed":true,
+      "table":10,
+      "internalStatus":16,
+      "internalFlags":8,
+      "internalNextHopNum":1,
+      "internalNextHopActiveNum":1,
+      "nexthops":[
+        {
+          "flags":3,
+          "fib":true,
+          "directlyConnected":true,
+          "interfaceName":"br100",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "100::21\/128": null
+}
\ No newline at end of file
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/__init__.py b/tests/topotests/bgp-evpn-overlay-index-gateway/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/host1/bgpd.conf b/tests/topotests/bgp-evpn-overlay-index-gateway/host1/bgpd.conf
new file mode 100644 (file)
index 0000000..7608ec9
--- /dev/null
@@ -0,0 +1,18 @@
+router bgp 111
+ bgp router-id 10.100.0.11
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+ neighbor 50.0.1.1 remote-as 101
+ neighbor 50:0:1::1 remote-as 101
+ !
+ address-family ipv4 unicast
+  network 100.0.0.21/32
+  no neighbor 50:0:1::1 activate
+ exit-address-family
+ !
+ address-family ipv6 unicast
+  network 100::21/128
+  neighbor 50:0:1::1 activate
+ exit-address-family
+
+
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/host1/zebra.conf b/tests/topotests/bgp-evpn-overlay-index-gateway/host1/zebra.conf
new file mode 100644 (file)
index 0000000..c8c832e
--- /dev/null
@@ -0,0 +1,4 @@
+!
+int host1-eth0
+ ip address 50.0.1.11/24
+ ipv6 address 50:0:1::11/48
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/host2/bgpd.conf b/tests/topotests/bgp-evpn-overlay-index-gateway/host2/bgpd.conf
new file mode 100644 (file)
index 0000000..cdf4cb4
--- /dev/null
@@ -0,0 +1 @@
+!
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/host2/zebra.conf b/tests/topotests/bgp-evpn-overlay-index-gateway/host2/zebra.conf
new file mode 100644 (file)
index 0000000..9135545
--- /dev/null
@@ -0,0 +1,4 @@
+!
+int host1-eth0
+ ip address 50.0.1.21/24
+ ipv6 address 50:0:1::21/48
diff --git a/tests/topotests/bgp-evpn-overlay-index-gateway/test_bgp_evpn_overlay_index_gateway.py b/tests/topotests/bgp-evpn-overlay-index-gateway/test_bgp_evpn_overlay_index_gateway.py
new file mode 100755 (executable)
index 0000000..fbce280
--- /dev/null
@@ -0,0 +1,385 @@
+#!/usr/bin/env 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.
+#
+
+"""
+test_bgp_evpn_overlay_index_gateway.py: Test EVPN gateway IP overlay index functionality
+Following functionality is covered:
+
+         +--------+ BGP     +--------+ BGP  +--------+      +--------+
+    SN1  |        | IPv4/v6 |        | EVPN |        |      |        |
+   ======+ Host1  +---------+   PE1  +------+   PE2  +------+  Host2 +
+         |        |         |        |      |        |      |        |
+         +--------+         +--------+      +--------+      +--------+
+
+    Host1 is connected to PE1 and host2 is connected to PE2
+    Host1 and PE1 have IPv4/v6 BGP sessions.
+    PE1 and PE2 gave EVPN session.
+    Host1 advertises IPv4/v6 prefixes to PE1.
+    PE1 advertises these prefixes to PE2 as EVPN type-5 routes.
+    Gateway IP for these EVPN type-5 routes is host1 IP.
+    Host1 MAC/IP is advertised by PE1 as EVPN type-2 route
+
+Following testcases are covered:
+TC_1:
+Check BGP and zebra states for above topology at PE1 and PE2.
+
+TC_2:
+Stop advertising prefixes from host1. It should withdraw type-5 routes. Check states at PE1 and PE2
+Advertise the prefixes again. Check states.
+
+TC_3:
+Shut down VxLAN interface at PE1. This should withdraw type-2 routes. Check states at PE1 and PE2.
+Enable VxLAN interface again. Check states.
+"""
+
+import os
+import sys
+import json
+from functools import partial
+import pytest
+import time
+import platform
+
+#Current Working Directory
+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
+from lib.common_config import (
+    step,
+    write_test_header,
+    write_test_footer,
+    generate_support_bundle,
+)
+
+# Required to instantiate the topology builder class.
+from mininet.topo import Topo
+
+#Global variables
+PES = ['PE1', 'PE2']
+HOSTS = ['host1', 'host2']
+PE_SUFFIX = {'PE1': '1', 'PE2': '2'}
+HOST_SUFFIX = {'host1': '1', 'host2': '2'}
+TRIGGERS = ["base", "no_rt5", "no_rt2"]
+
+
+class TemplateTopo(Topo):
+    """Test topology builder"""
+
+    def build(self, *_args, **_opts):
+        """Build function"""
+        tgen = get_topogen(self)
+
+        # This function only purpose is to define allocation and relationship
+        # between routers and add links.
+
+        # Create routers
+        for pe in PES:
+            tgen.add_router(pe)
+        for host in HOSTS:
+            tgen.add_router(host)
+
+        krel = platform.release()
+        logger.info('Kernel version ' + krel)
+
+        #Add links
+        tgen.add_link(tgen.gears['PE1'], tgen.gears['PE2'], 'PE1-eth0', 'PE2-eth0')
+        tgen.add_link(tgen.gears['PE1'], tgen.gears['host1'], 'PE1-eth1', 'host1-eth0')
+        tgen.add_link(tgen.gears['PE2'], tgen.gears['host2'], 'PE2-eth1', 'host2-eth0')
+
+
+def setup_module(mod):
+    "Sets up the pytest environment"
+
+    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(TemplateTopo, mod.__name__)
+    # ... and here it calls Mininet initialization functions.
+
+    kernelv = platform.release()
+    if topotest.version_cmp(kernelv, "4.15") < 0:
+        logger.info("For EVPN, kernel version should be minimum 4.15. Kernel present {}".format(kernelv))
+        return
+
+    if topotest.version_cmp(kernelv, '4.15') == 0:
+        l3mdev_accept = 1
+        logger.info('setting net.ipv4.tcp_l3mdev_accept={}'.format(l3mdev_accept))
+    else:
+        l3mdev_accept = 0
+
+    # Starting topology, create tmp files which are loaded to routers
+    #  to start deamons and then start routers
+    tgen.start_topology()
+
+    # Configure MAC address for hosts as these MACs are advertised with EVPN type-2 routes
+    for (name, host) in tgen.gears.items():
+        if name not in HOSTS:
+            continue
+
+        host_mac = "1a:2b:3c:4d:5e:6{}".format(HOST_SUFFIX[name])
+        host.run("ip link set dev {}-eth0 down").format(name)
+        host.run("ip link set dev {0}-eth0 address {1}".format(name, host_mac))
+        host.run("ip link set dev {}-eth0 up").format(name)
+
+    # Configure PE VxLAN and Bridge interfaces
+    for (name, pe) in tgen.gears.items():
+        if name not in PES:
+            continue
+        vtep_ip = "10.100.0.{}".format(PE_SUFFIX[name])
+        bridge_ip = "50.0.1.{}/24".format(PE_SUFFIX[name])
+        bridge_ipv6 = "50:0:1::{}/48".format(PE_SUFFIX[name])
+
+        pe.run("ip link add vrf-blue type vrf table 10")
+        pe.run("ip link set dev vrf-blue up")
+        pe.run("ip link add vxlan100 type vxlan id 100 dstport 4789 local {}".format(vtep_ip))
+        pe.run("ip link add name br100 type bridge stp_state 0")
+        pe.run("ip link set dev vxlan100 master br100")
+        pe.run("ip link set dev {}-eth1 master br100".format(name))
+        pe.run("ip addr add {} dev br100".format(bridge_ip))
+        pe.run("ip link set up dev br100")
+        pe.run("ip link set up dev vxlan100")
+        pe.run("ip link set up dev {}-eth1".format(name))
+        pe.run("ip link set dev br100 master vrf-blue")
+        pe.run("ip -6 addr add {} dev br100".format(bridge_ipv6))
+
+        pe.run("ip link add vxlan1000 type vxlan id 1000 dstport 4789 local {}".format(vtep_ip))
+        pe.run("ip link add name br1000 type bridge stp_state 0")
+        pe.run("ip link set dev vxlan1000 master br100")
+        pe.run("ip link set up dev br1000")
+        pe.run("ip link set up dev vxlan1000")
+        pe.run("ip link set dev br1000 master vrf-blue")
+
+        pe.run("sysctl -w net.ipv4.ip_forward=1")
+        pe.run("sysctl -w net.ipv6.conf.all.forwarding=1")
+        pe.run("sysctl -w net.ipv4.udp_l3mdev_accept={}".format(l3mdev_accept))
+        pe.run("sysctl -w net.ipv4.tcp_l3mdev_accept={}".format(l3mdev_accept))
+
+    # For all registred routers, load the zebra configuration file
+    for (name, router) in tgen.routers().items():
+        router.load_config(
+            TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(name))
+        )
+        router.load_config(
+            TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(name))
+        )
+
+    # After loading the configurations, this function loads configured daemons.
+    tgen.start_router()
+
+    logger.info("Running setup_module() done")
+    topotest.sleep(200)
+
+
+def teardown_module(mod):
+    """Teardown the pytest environment"""
+
+    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 evpn_gateway_ip_show_op_check(trigger=" "):
+    """
+    This function checks CLI O/P for commands mentioned in show_commands for a given trigger
+    :param trigger: Should be a trigger present in TRIGGERS
+    :return: Returns a tuple (result: None for success, retmsg: Log message to be printed on failure)
+    """
+    tgen = get_topogen()
+
+    if trigger not in TRIGGERS:
+        return "Unexpected trigger", "Unexpected trigger {}".format(trigger)
+
+    show_commands = {'bgp_vni_routes': 'show bgp l2vpn evpn route vni 100 json',
+                     'bgp_vrf_ipv4'  : 'show bgp vrf vrf-blue ipv4 json',
+                     'bgp_vrf_ipv6'  : 'show bgp vrf vrf-blue ipv6 json',
+                     'zebra_vrf_ipv4': 'show ip route vrf vrf-blue json',
+                     'zebra_vrf_ipv6': 'show ipv6 route vrf vrf-blue json'}
+
+    for (name, pe) in tgen.gears.items():
+        if name not in PES:
+            continue
+
+        for (cmd_key, command) in show_commands.items():
+            expected_op_file = "{0}/{1}/{2}_{3}.json".format(CWD, name, cmd_key, trigger)
+            expected_op = json.loads(open(expected_op_file).read())
+
+            test_func = partial(topotest.router_json_cmp, pe, command, expected_op)
+            ret, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+            assertmsg = '"{0}" JSON output mismatch for {1}'.format(name, command)
+            if result is not None:
+                return result, assertmsg
+
+    return None, "Pass"
+
+
+def test_evpn_gateway_ip_basic_topo(request):
+    """
+    Tets EVPN overlay index gateway IP functionality. VErify show O/Ps on PE1 and PE2
+    """
+
+    tgen = get_topogen()
+    tc_name = request.node.name
+    write_test_header(tc_name)
+
+    kernelv = platform.release()
+    if topotest.version_cmp(kernelv, "4.15") < 0:
+        logger.info("For EVPN, kernel version should be minimum 4.15")
+        write_test_footer(tc_name)
+        return
+
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    step("Check O/Ps for EVPN gateway IP overlay Index functionality at PE1 and PE2")
+
+    result, assertmsg = evpn_gateway_ip_show_op_check("base")
+
+    if result is not None:
+        generate_support_bundle()
+    assert result is None, assertmsg
+
+    write_test_footer(tc_name)
+
+
+def test_evpn_gateway_ip_flap_rt5(request):
+    """
+    Withdraw EVPN type-5 routes and check O/Ps at PE1 and PE2
+    """
+    tgen = get_topogen()
+    tc_name = request.node.name
+    write_test_header(tc_name)
+
+    kernelv = platform.release()
+    if topotest.version_cmp(kernelv, "4.15") < 0:
+        logger.info("For EVPN, kernel version should be minimum 4.15")
+        write_test_footer(tc_name)
+        return
+
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    h1 = tgen.gears['host1']
+
+    step("Withdraw type-5 routes")
+
+    h1.run('vtysh  -c "config t" \
+                   -c "router bgp 111" \
+                   -c "address-family ipv4" \
+                   -c "no network 100.0.0.21/32"')
+    h1.run('vtysh  -c "config t" \
+                   -c "router bgp 111" \
+                   -c "address-family ipv6" \
+                   -c "no network 100::21/128"')
+
+    result, assertmsg = evpn_gateway_ip_show_op_check("no_rt5")
+    if result is not None:
+        generate_support_bundle()
+    assert result is None, assertmsg
+
+    step("Advertise type-5 routes again")
+
+    h1.run('vtysh  -c "config t" \
+                   -c "router bgp 111" \
+                   -c "address-family ipv4" \
+                   -c "network 100.0.0.21/32"')
+    h1.run('vtysh  -c "config t" \
+                   -c "router bgp 111" \
+                   -c "address-family ipv6" \
+                   -c "network 100::21/128"')
+
+    result, assertmsg = evpn_gateway_ip_show_op_check("base")
+    if result is not None:
+        generate_support_bundle()
+
+    assert result is None, assertmsg
+
+    write_test_footer(tc_name)
+
+
+def test_evpn_gateway_ip_flap_rt2(request):
+    """
+     Withdraw EVPN type-2 routes and check O/Ps at PE1 and PE2
+     """
+    tgen = get_topogen()
+    tc_name = request.node.name
+    write_test_header(tc_name)
+
+    kernelv = platform.release()
+    if topotest.version_cmp(kernelv, "4.15") < 0:
+        logger.info("For EVPN, kernel version should be minimum 4.15")
+        write_test_footer(tc_name)
+        return
+
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+
+    step("Shut down VxLAN interface at PE1 which results in withdraw of type-2 routes")
+
+    pe1 = tgen.gears['PE1']
+
+    pe1.run('ip link set dev vxlan100 down')
+
+    result, assertmsg = evpn_gateway_ip_show_op_check("no_rt2")
+    if result is not None:
+        generate_support_bundle()
+    assert result is None, assertmsg
+
+    step("Bring up VxLAN interface at PE1 and advertise type-2 routes again")
+
+    pe1.run('ip link set dev vxlan100 up')
+
+    result, assertmsg = evpn_gateway_ip_show_op_check("base")
+    if result is not None:
+        generate_support_bundle()
+    assert result is None, assertmsg
+
+    write_test_footer(tc_name)
+
+
+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_default_route_route_map_match2/__init__.py b/tests/topotests/bgp_default_route_route_map_match2/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/topotests/bgp_default_route_route_map_match2/r1/bgpd.conf b/tests/topotests/bgp_default_route_route_map_match2/r1/bgpd.conf
new file mode 100644 (file)
index 0000000..ee7a92f
--- /dev/null
@@ -0,0 +1,13 @@
+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
+!
+ip prefix-list r2 permit 10.0.0.0/22
+!
+route-map default permit 10
+  match ip address prefix-list r2
+!
diff --git a/tests/topotests/bgp_default_route_route_map_match2/r1/zebra.conf b/tests/topotests/bgp_default_route_route_map_match2/r1/zebra.conf
new file mode 100644 (file)
index 0000000..e2c399e
--- /dev/null
@@ -0,0 +1,6 @@
+!
+interface r1-eth0
+ ip address 192.168.255.1/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_default_route_route_map_match2/r2/bgpd.conf b/tests/topotests/bgp_default_route_route_map_match2/r2/bgpd.conf
new file mode 100644 (file)
index 0000000..00c96cc
--- /dev/null
@@ -0,0 +1,8 @@
+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_match2/r2/zebra.conf b/tests/topotests/bgp_default_route_route_map_match2/r2/zebra.conf
new file mode 100644 (file)
index 0000000..f355ab1
--- /dev/null
@@ -0,0 +1,9 @@
+!
+interface lo
+ ip address 10.0.0.1/22
+!
+interface r2-eth0
+ ip address 192.168.255.2/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_default_route_route_map_match2/test_bgp_default-originate_route-map_match2.py b/tests/topotests/bgp_default_route_route_map_match2/test_bgp_default-originate_route-map_match2.py
new file mode 100644 (file)
index 0000000..42a6b6e
--- /dev/null
@@ -0,0 +1,138 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2021 by
+# Donatas Abraitis <donatas.abraitis@gmail.com>
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+Test if default-originate works with conditional match.
+If 10.0.0.0/22 is recived from r2, then we announce 0.0.0.0/0
+to r2.
+"""
+
+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
+from lib.common_config import step
+
+
+class TemplateTopo(Topo):
+    def build(self, *_args, **_opts):
+        tgen = get_topogen(self)
+
+        for routern in range(1, 3):
+            tgen.add_router("r{}".format(routern))
+
+        switch = tgen.add_switch("s1")
+        switch.add_link(tgen.gears["r1"])
+        switch.add_link(tgen.gears["r2"])
+
+
+def setup_module(mod):
+    tgen = Topogen(TemplateTopo, mod.__name__)
+    tgen.start_topology()
+
+    router_list = tgen.routers()
+
+    for i, (rname, router) in enumerate(router_list.items(), 1):
+        router.load_config(
+            TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
+        )
+        router.load_config(
+            TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
+        )
+
+    tgen.start_router()
+
+
+def teardown_module(mod):
+    tgen = get_topogen()
+    tgen.stop_topology()
+
+
+def test_bgp_default_originate_route_map():
+    tgen = get_topogen()
+
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    router = tgen.gears["r2"]
+
+    def _bgp_converge(router):
+        output = json.loads(router.vtysh_cmd("show ip bgp neighbor 192.168.255.1 json"))
+        expected = {
+            "192.168.255.1": {
+                "bgpState": "Established",
+                "addressFamilyInfo": {"ipv4Unicast": {"acceptedPrefixCounter": 1}},
+            }
+        }
+        return topotest.json_cmp(output, expected)
+
+    def _bgp_default_route_is_valid(router):
+        output = json.loads(router.vtysh_cmd("show ip bgp 0.0.0.0/0 json"))
+        expected = {"paths": [{"valid": True}]}
+        return topotest.json_cmp(output, expected)
+
+    step("Converge network")
+    test_func = functools.partial(_bgp_converge, router)
+    success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5)
+    assert result is None, "Failed to see bgp convergence at r2"
+
+    step("Withdraw 10.0.0.0/22 from R2")
+    router.vtysh_cmd(
+        "conf t\nrouter bgp\naddress-family ipv4\nno redistribute connected"
+    )
+
+    step("Check if we don't have 0.0.0.0/0 at R2")
+    test_func = functools.partial(_bgp_default_route_is_valid, router)
+    success, result = topotest.run_and_expect(test_func, not None, count=30, wait=0.5)
+    assert result is not None, "0.0.0.0/0 exists at r2"
+
+    step("Announce 10.0.0.0/22 from R2")
+    router.vtysh_cmd("conf t\nrouter bgp\naddress-family ipv4\nredistribute connected")
+
+    step("Check if we have 0.0.0.0/0 at R2")
+    test_func = functools.partial(_bgp_default_route_is_valid, router)
+    success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5)
+    assert result is None, "0.0.0.0/0 does not exist at r2"
+
+    step("Withdraw 10.0.0.0/22 from R2 again")
+    router.vtysh_cmd(
+        "conf t\nrouter bgp\naddress-family ipv4\nno redistribute connected"
+    )
+
+    step("Check if we don't have 0.0.0.0/0 at R2 again")
+    test_func = functools.partial(_bgp_default_route_is_valid, router)
+    success, result = topotest.run_and_expect(test_func, not None, count=30, wait=0.5)
+    assert result is not None, "0.0.0.0/0 exists at r2"
+
+
+if __name__ == "__main__":
+    args = ["-s"] + sys.argv[1:]
+    sys.exit(pytest.main(args))
index 6ef8b1c0f48062b36d8750efcc0ce0a25195bd1a..32ac7c517b7eb2bf4ac8184fe8b46262b16dbe08 100644 (file)
@@ -12,6 +12,7 @@ bgp community-list standard default seq 5 permit 65000:1
 route-map default permit 10
   match community default
   set metric 123
+  set as-path prepend 65000 65000 65000
 !
 route-map internal permit 10
   set community 65000:1
index d9ea5db2789c85194c2ef05360b94a8eb885998e..12d1d01bfb6ea26b7c8516b63b5496ff2d8e9288 100644 (file)
@@ -94,7 +94,9 @@ def test_bgp_default_originate_route_map():
 
     def _bgp_default_route_has_metric(router):
         output = json.loads(router.vtysh_cmd("show ip bgp 0.0.0.0/0 json"))
-        expected = {"paths": [{"metric": 123}]}
+        expected = {
+            "paths": [{"aspath": {"string": "65000 65000 65000 65000"}, "metric": 123}]
+        }
         return topotest.json_cmp(output, expected)
 
     test_func = functools.partial(_bgp_converge, router)
index cb07ea9fdfb4d4b98e7fcada1f863cb824de1949..6f6d39440235fd08b19ad5034fe91188626a697a 100644 (file)
@@ -8,4 +8,5 @@ router bgp 65000
 !
 route-map default permit 10
   set metric 123
+  set as-path prepend 65000 65000 65000
 !
index 9a22c58b16d6da3134f547aaea0e45e29d083ff9..2622c33f5bf9cd4605cd2d37f89a3c73d8c08059 100644 (file)
@@ -93,7 +93,9 @@ def test_bgp_default_originate_route_map():
 
     def _bgp_default_route_has_metric(router):
         output = json.loads(router.vtysh_cmd("show ip bgp 0.0.0.0/0 json"))
-        expected = {"paths": [{"metric": 123}]}
+        expected = {
+            "paths": [{"aspath": {"string": "65000 65000 65000 65000"}, "metric": 123}]
+        }
         return topotest.json_cmp(output, expected)
 
     test_func = functools.partial(_bgp_converge, router)
diff --git a/tests/topotests/config_timing/r1/staticd.conf b/tests/topotests/config_timing/r1/staticd.conf
new file mode 100644 (file)
index 0000000..0f9f97c
--- /dev/null
@@ -0,0 +1 @@
+log timestamp precision 3
diff --git a/tests/topotests/config_timing/r1/zebra.conf b/tests/topotests/config_timing/r1/zebra.conf
new file mode 100644 (file)
index 0000000..46fd965
--- /dev/null
@@ -0,0 +1,18 @@
+log timestamp precision 3
+
+ip prefix-list ANY permit 0.0.0.0/0 le 32
+ipv6 prefix-list ANY seq 10 permit any
+
+route-map RM-NONE4 deny 10
+exit-route-map
+
+route-map RM-NONE6 deny 10
+exit-route-map
+
+interface r1-eth0
+  ip address 100.0.0.1/24
+  ipv6 address 2102::1/64
+exit
+
+ip protocol static route-map RM-NONE4
+ipv6 protocol static route-map RM-NONE6
diff --git a/tests/topotests/config_timing/test_config_timing.py b/tests/topotests/config_timing/test_config_timing.py
new file mode 100644 (file)
index 0000000..db8baa8
--- /dev/null
@@ -0,0 +1,186 @@
+#!/usr/bin/env python
+#
+# June 2 2021, Christian Hopps <chopps@labn.net>
+#
+# Copyright (c) 2021, LabN Consulting, L.L.C.
+# Copyright (c) 2019-2020 by
+# Donatas Abraitis <donatas.abraitis@gmail.com>
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+Test the timing of config operations.
+
+The initial add of 10k routes is used as a baseline for timing and all future
+operations are expected to complete in under 2 times that baseline. This is a
+lot of slop; however, the pre-batching code some of these operations (e.g.,
+adding the same set of 10k routes) would take 100 times longer, so the intention
+is to catch those types of regressions.
+"""
+
+import datetime
+import ipaddress
+import math
+import os
+import sys
+import pytest
+
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+from mininet.topo import Topo
+
+pytestmark = [pytest.mark.staticd]
+
+class TimingTopo(Topo):
+    def build(self, *_args, **_opts):
+        tgen = get_topogen(self)
+        tgen.add_router("r1")
+        switch = tgen.add_switch("s1")
+        switch.add_link(tgen.gears["r1"])
+
+
+def setup_module(mod):
+    tgen = Topogen(TimingTopo, mod.__name__)
+    tgen.start_topology()
+
+    router_list = tgen.routers()
+    for rname, router in router_list.items():
+        router.load_config(
+            TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)),
+        )
+        router.load_config(
+            TopoRouter.RD_STATIC, os.path.join(CWD, "{}/staticd.conf".format(rname))
+        )
+
+    tgen.start_router()
+
+
+def teardown_module(mod):
+    tgen = get_topogen()
+    tgen.stop_topology()
+
+def get_ip_networks(super_prefix, count):
+    count_log2 = math.log(count, 2)
+    if count_log2 != int(count_log2):
+        count_log2 = int(count_log2) + 1
+    else:
+        count_log2 = int(count_log2)
+    network = ipaddress.ip_network(super_prefix)
+    return tuple(network.subnets(count_log2))[0:count]
+
+def test_static_timing():
+    tgen = get_topogen()
+
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    def do_config(
+            count, bad_indices, base_delta, d_multiplier, add=True, do_ipv6=False, super_prefix=None, en_dbg=False
+    ):
+        router_list = tgen.routers()
+        tot_delta = float(0)
+
+        optype = "adding" if add else "removing"
+        iptype = "IPv6" if do_ipv6 else "IPv4"
+        if super_prefix is None:
+            super_prefix = u"2001::/48" if do_ipv6 else u"10.0.0.0/8"
+        via = u"lo"
+        optyped = "added" if add else "removed"
+
+        for rname, router in router_list.items():
+            router.logger.info("{} {} static {} routes".format(
+                optype, count, iptype)
+            )
+
+            # Generate config file.
+            config_file = os.path.join(
+                router.logdir, rname, "{}-routes-{}.conf".format(
+                    iptype.lower(), optype
+                )
+            )
+            with open(config_file, "w") as f:
+                for i, net in enumerate(get_ip_networks(super_prefix, count)):
+                    if i in bad_indices:
+                        if add:
+                            f.write("ip route {} {} bad_input\n".format(net, via))
+                        else:
+                            f.write("no ip route {} {} bad_input\n".format(net, via))
+                    elif add:
+                        f.write("ip route {} {}\n".format(net, via))
+                    else:
+                        f.write("no ip route {} {}\n".format(net, via))
+
+            # Enable debug
+            if en_dbg:
+                router.vtysh_cmd("debug northbound callbacks configuration")
+
+            # Load config file.
+            load_command = 'vtysh -f "{}"'.format(config_file)
+            tstamp = datetime.datetime.now()
+            output = router.run(load_command)
+            delta = (datetime.datetime.now() - tstamp).total_seconds()
+            tot_delta += delta
+
+            router.logger.info(
+                "\nvtysh command => {}\nvtysh output <= {}\nin {}s".format(
+                    load_command, output, delta
+                )
+            )
+
+        limit_delta = base_delta * d_multiplier
+        logger.info(
+            "{} {} {} static routes under {} in {}s (limit: {}s)".format(
+                optyped, count, iptype.lower(), super_prefix, tot_delta, limit_delta
+            )
+        )
+        if limit_delta:
+            assert tot_delta <= limit_delta
+
+        return tot_delta
+
+    # Number of static routes
+    prefix_count = 10000
+    prefix_base = [[u"10.0.0.0/8", u"11.0.0.0/8"],
+                   [u"2100:1111:2220::/44", u"2100:3333:4440::/44"]]
+
+    bad_indices = []
+    for ipv6 in [False, True]:
+        base_delta = do_config(prefix_count, bad_indices, 0, 0, True, ipv6, prefix_base[ipv6][0])
+
+        # Another set of same number of prefixes
+        do_config(prefix_count, bad_indices, base_delta, 2, True, ipv6, prefix_base[ipv6][1])
+
+        # Duplicate config
+        do_config(prefix_count, bad_indices, base_delta, 2, True, ipv6, prefix_base[ipv6][0])
+
+        # Remove 1/2 of duplicate
+        do_config(prefix_count / 2, bad_indices, base_delta, 2, False, ipv6, prefix_base[ipv6][0])
+
+        # Add all back in so 1/2 replicate 1/2 new
+        do_config(prefix_count, bad_indices, base_delta, 2, True, ipv6, prefix_base[ipv6][0])
+
+        # remove all
+        delta = do_config(prefix_count, bad_indices, base_delta, 2, False, ipv6, prefix_base[ipv6][0])
+        delta += do_config(prefix_count, bad_indices, base_delta, 2, False, ipv6, prefix_base[ipv6][1])
+
+if __name__ == "__main__":
+    args = ["-s"] + sys.argv[1:]
+    sys.exit(pytest.main(args))
index de5c584e919534738c8ad7d7b9121aa8ea058f62..e57db7471c9905f83061ae30417d1260434e8602 100755 (executable)
@@ -2,8 +2,10 @@
 Topotest conftest.py file.
 """
 
+import glob
 import os
 import pdb
+import re
 import pytest
 
 from lib.topogen import get_topogen, diagnose_env
@@ -11,6 +13,12 @@ from lib.topotest import json_cmp_result
 from lib.topotest import g_extra_config as topotest_extra_config
 from lib.topolog import logger
 
+try:
+    from _pytest._code.code import ExceptionInfo
+    leak_check_ok = True
+except ImportError:
+    leak_check_ok = False
+
 
 def pytest_addoption(parser):
     """
@@ -66,6 +74,18 @@ def pytest_addoption(parser):
         help="Only set up this topology, don't run tests",
     )
 
+    parser.addoption(
+        "--valgrind-extra",
+        action="store_true",
+        help="Generate suppression file, and enable more precise (slower) valgrind checks",
+    )
+
+    parser.addoption(
+        "--valgrind-memleaks",
+        action="store_true",
+        help="Run all daemons under valgrind for memleak detection",
+    )
+
     parser.addoption(
         "--vtysh",
         metavar="ROUTER[,ROUTER...]",
@@ -79,6 +99,37 @@ def pytest_addoption(parser):
     )
 
 
+def check_for_memleaks():
+    if not topotest_extra_config["valgrind_memleaks"]:
+        return
+
+    leaks = []
+    tgen = get_topogen()
+    latest = []
+    existing = []
+    if tgen is not None:
+        logdir = "/tmp/topotests/{}".format(tgen.modname)
+        if hasattr(tgen, "valgrind_existing_files"):
+            existing = tgen.valgrind_existing_files
+        latest = glob.glob(os.path.join(logdir, "*.valgrind.*"))
+
+    for vfile in latest:
+        if vfile in existing:
+            continue
+        with open(vfile) as vf:
+            vfcontent = vf.read()
+            match = re.search(r"ERROR SUMMARY: (\d+) errors", vfcontent)
+            if match and match.group(1) != "0":
+                emsg = '{} in {}'.format(match.group(1), vfile)
+                leaks.append(emsg)
+
+    if leaks:
+        if leak_check_ok:
+            pytest.fail("Memleaks found:\n\t" + "\n\t".join(leaks))
+        else:
+            logger.error("Memleaks found:\n\t" + "\n\t".join(leaks))
+
+
 def pytest_runtest_call():
     """
     This function must be run after setup_module(), it does standarized post
@@ -139,6 +190,9 @@ def pytest_configure(config):
     shell_on_error = config.getoption("--shell-on-error")
     topotest_extra_config["shell_on_error"] = shell_on_error
 
+    topotest_extra_config["valgrind_extra"] = config.getoption("--valgrind-extra")
+    topotest_extra_config["valgrind_memleaks"] = config.getoption("--valgrind-memleaks")
+
     vtysh = config.getoption("--vtysh")
     topotest_extra_config["vtysh"] = vtysh.split(",") if vtysh else []
 
@@ -159,6 +213,12 @@ def pytest_runtest_makereport(item, call):
     else:
         pause = False
 
+    if call.excinfo is None and call.when == "call":
+        try:
+            check_for_memleaks()
+        except:
+            call.excinfo = ExceptionInfo()
+
     if call.excinfo is None:
         error = False
     else:
index 50cb586acdfef0642c7b70c8a4a61bf0b58534b1..db7b3586f13af630877d1d8dc8ae73bf26f96793 100644 (file)
@@ -990,7 +990,7 @@ def modify_bgp_config_when_bgpd_down(tgen, topo, input_dict):
 # Verification APIs
 #############################################
 @retry(attempts=4, wait=2, return_is_str=True)
-def verify_router_id(tgen, topo, input_dict):
+def verify_router_id(tgen, topo, input_dict, expected=True):
     """
     Running command "show ip bgp json" for DUT and reading router-id
     from input_dict and verifying with command output.
@@ -1006,6 +1006,8 @@ def verify_router_id(tgen, topo, input_dict):
     * `topo`: input json file data
     * `input_dict`: input dictionary, have details of Device Under Test, for
                     which user wants to test the data
+    * `expected` : expected results from API, by-default True
+
     Usage
     -----
     # Verify if router-id for r1 is 12.12.12.12
@@ -1060,7 +1062,7 @@ def verify_router_id(tgen, topo, input_dict):
 
 
 @retry(attempts=50, wait=3, return_is_str=True)
-def verify_bgp_convergence(tgen, topo, dut=None):
+def verify_bgp_convergence(tgen, topo, dut=None, expected=True):
     """
     API will verify if BGP is converged with in the given time frame.
     Running "show bgp summary json" command and verify bgp neighbor
@@ -1070,6 +1072,8 @@ def verify_bgp_convergence(tgen, topo, dut=None):
     * `tgen`: topogen object
     * `topo`: input json file data
     * `dut`: device under test
+    * `expected` : expected results from API, by-default True
+
     Usage
     -----
     # To veriry is BGP is converged for all the routers used in
@@ -1264,7 +1268,7 @@ def verify_bgp_convergence(tgen, topo, dut=None):
 
 @retry(attempts=4, wait=4, return_is_str=True)
 def verify_bgp_community(
-    tgen, addr_type, router, network, input_dict=None, vrf=None, bestpath=False
+    tgen, addr_type, router, network, input_dict=None, vrf=None, bestpath=False, expected=True
 ):
     """
     API to veiryf BGP large community is attached in route for any given
@@ -1280,6 +1284,7 @@ def verify_bgp_community(
             values needs to be verified
     * `vrf`: VRF name
     * `bestpath`: To check best path cli
+    * `expected` : expected results from API, by-default True
 
     Usage
     -----
@@ -1423,7 +1428,7 @@ def modify_as_number(tgen, topo, input_dict):
 
 
 @retry(attempts=4, wait=2, return_is_str=True)
-def verify_as_numbers(tgen, topo, input_dict):
+def verify_as_numbers(tgen, topo, input_dict, expected=True):
     """
     This API is to verify AS numbers for given DUT by running
     "show ip bgp neighbor json" command. Local AS and Remote AS
@@ -1435,6 +1440,7 @@ def verify_as_numbers(tgen, topo, input_dict):
     * `topo`: input json file data
     * `addr_type` : ip type, ipv4/ipv6
     * `input_dict`: defines - for which router, AS numbers needs to be verified
+    * `expected` : expected results from API, by-default True
 
     Usage
     -----
@@ -1522,7 +1528,7 @@ def verify_as_numbers(tgen, topo, input_dict):
 
 
 @retry(attempts=50, wait=3, return_is_str=True)
-def verify_bgp_convergence_from_running_config(tgen, dut=None):
+def verify_bgp_convergence_from_running_config(tgen, dut=None, expected=True):
     """
     API to verify BGP convergence b/w loopback and physical interface.
     This API would be used when routers have BGP neighborship is loopback
@@ -1532,6 +1538,7 @@ def verify_bgp_convergence_from_running_config(tgen, dut=None):
     ----------
     * `tgen`: topogen object
     * `dut`: device under test
+    * `expected` : expected results from API, by-default True
 
     Usage
     -----
@@ -2086,6 +2093,7 @@ def verify_bgp_attributes(
     input_dict=None,
     seq_id=None,
     nexthop=None,
+    expected=True
 ):
     """
     API will verify BGP attributes set by Route-map for given prefix and
@@ -2101,6 +2109,7 @@ def verify_bgp_attributes(
     * `rmap_name`: route map name for which set criteria needs to be verified
     * `input_dict`: defines for which router, AS numbers needs
     * `seq_id`: sequence number of rmap, default is None
+    * `expected` : expected results from API, by-default True
 
     Usage
     -----
@@ -2216,7 +2225,7 @@ def verify_bgp_attributes(
 
 @retry(attempts=4, wait=2, return_is_str=True)
 def verify_best_path_as_per_bgp_attribute(
-    tgen, addr_type, router, input_dict, attribute
+    tgen, addr_type, router, input_dict, attribute, expected=True
 ):
     """
     API is to verify best path according to BGP attributes for given routes.
@@ -2231,6 +2240,8 @@ def verify_best_path_as_per_bgp_attribute(
     * `attribute` : calculate best path using this attribute
     * `input_dict`: defines different routes to calculate for which route
                     best path is selected
+    * `expected` : expected results from API, by-default True
+
     Usage
     -----
     # To verify best path for routes 200.50.2.0/32 and 200.60.2.0/32 from
@@ -2420,7 +2431,7 @@ def verify_best_path_as_per_bgp_attribute(
 
 @retry(attempts=5, wait=2, return_is_str=True)
 def verify_best_path_as_per_admin_distance(
-    tgen, addr_type, router, input_dict, attribute
+    tgen, addr_type, router, input_dict, attribute, expected=True
 ):
     """
     API is to verify best path according to admin distance for given
@@ -2435,6 +2446,8 @@ def verify_best_path_as_per_admin_distance(
     * `attribute` : calculate best path using admin distance
     * `input_dict`: defines different routes with different admin distance
                     to calculate for which route best path is selected
+    * `expected` : expected results from API, by-default True
+
     Usage
     -----
     # To verify best path for route 200.50.2.0/32 from  router r2 to
@@ -2532,7 +2545,7 @@ def verify_best_path_as_per_admin_distance(
 
 @retry(attempts=5, wait=2, return_is_str=True, initial_wait=2)
 def verify_bgp_rib(
-    tgen, addr_type, dut, input_dict, next_hop=None, aspath=None, multi_nh=None
+    tgen, addr_type, dut, input_dict, next_hop=None, aspath=None, multi_nh=None, expected=True
 ):
     """
     This API is to verify whether bgp rib has any
@@ -2547,6 +2560,7 @@ def verify_bgp_rib(
     * `next_hop`[optional]: next_hop which needs to be verified,
        default = static
     * 'aspath'[optional]: aspath which needs to be verified
+    * `expected` : expected results from API, by-default True
 
     Usage
     -----
@@ -2833,7 +2847,7 @@ def verify_bgp_rib(
 
 
 @retry(attempts=5, wait=2, return_is_str=True)
-def verify_graceful_restart(tgen, topo, addr_type, input_dict, dut, peer):
+def verify_graceful_restart(tgen, topo, addr_type, input_dict, dut, peer, expected=True):
     """
     This API is to verify verify_graceful_restart configuration of DUT and
     cross verify the same from the peer bgp routerrouter.
@@ -2847,6 +2861,7 @@ def verify_graceful_restart(tgen, topo, addr_type, input_dict, dut, peer):
                     which user wants to test the data
     * `dut`: input dut router name
     * `peer`: input peer router name
+    * `expected` : expected results from API, by-default True
 
     Usage
     -----
@@ -3082,7 +3097,7 @@ def verify_graceful_restart(tgen, topo, addr_type, input_dict, dut, peer):
 
 
 @retry(attempts=5, wait=2, return_is_str=True)
-def verify_r_bit(tgen, topo, addr_type, input_dict, dut, peer):
+def verify_r_bit(tgen, topo, addr_type, input_dict, dut, peer, expected=True):
     """
     This API is to verify r_bit in the BGP gr capability advertised
     by the neighbor router
@@ -3096,6 +3111,8 @@ def verify_r_bit(tgen, topo, addr_type, input_dict, dut, peer):
                     which user wants to test the data
     * `dut`: input dut router name
     * `peer`: peer name
+    * `expected` : expected results from API, by-default True
+
     Usage
     -----
     input_dict = {
@@ -3200,7 +3217,7 @@ def verify_r_bit(tgen, topo, addr_type, input_dict, dut, peer):
 
 
 @retry(attempts=5, wait=2, return_is_str=True)
-def verify_eor(tgen, topo, addr_type, input_dict, dut, peer):
+def verify_eor(tgen, topo, addr_type, input_dict, dut, peer, expected=True):
     """
     This API is to verify EOR
 
@@ -3363,7 +3380,7 @@ def verify_eor(tgen, topo, addr_type, input_dict, dut, peer):
 
 
 @retry(attempts=4, wait=2, return_is_str=True)
-def verify_f_bit(tgen, topo, addr_type, input_dict, dut, peer):
+def verify_f_bit(tgen, topo, addr_type, input_dict, dut, peer, expected=True):
     """
     This API is to verify f_bit in the BGP gr capability advertised
     by the neighbor router
@@ -3377,6 +3394,7 @@ def verify_f_bit(tgen, topo, addr_type, input_dict, dut, peer):
                     which user wants to test the data
     * `dut`: input dut router name
     * `peer`: peer name
+    * `expected` : expected results from API, by-default True
 
     Usage
     -----
@@ -3516,6 +3534,8 @@ def verify_graceful_restart_timers(tgen, topo, addr_type, input_dict, dut, peer)
                     for which user wants to test the data
     * `dut`: input dut router name
     * `peer`: peer name
+    * `expected` : expected results from API, by-default True
+
     Usage
     -----
     # Configure graceful-restart
@@ -3629,7 +3649,7 @@ def verify_graceful_restart_timers(tgen, topo, addr_type, input_dict, dut, peer)
 
 
 @retry(attempts=4, wait=2, return_is_str=True)
-def verify_gr_address_family(tgen, topo, addr_type, addr_family, dut):
+def verify_gr_address_family(tgen, topo, addr_type, addr_family, dut, expected=True):
     """
     This API is to verify gr_address_family in the BGP gr capability advertised
     by the neighbor router
@@ -3641,6 +3661,7 @@ def verify_gr_address_family(tgen, topo, addr_type, addr_family, dut):
     * `addr_type` : ip type ipv4/ipv6
     * `addr_type` : ip type IPV4 Unicast/IPV6 Unicast
     * `dut`: input dut router name
+    * `expected` : expected results from API, by-default True
 
     Usage
     -----
@@ -3730,6 +3751,7 @@ def verify_attributes_for_evpn_routes(
     ipLen=None,
     rd_peer=None,
     rt_peer=None,
+    expected=True
 ):
     """
     API to verify rd and rt value using "sh bgp l2vpn evpn 10.1.1.1"
@@ -3747,6 +3769,8 @@ def verify_attributes_for_evpn_routes(
     * `ipLen` : IP prefix length
     * `rd_peer` : Peer name from which RD will be auto-generated
     * `rt_peer` : Peer name from which RT will be auto-generated
+    * `expected` : expected results from API, by-default True
+
     Usage
     -----
         input_dict_1 = {
@@ -4117,7 +4141,7 @@ def verify_attributes_for_evpn_routes(
 
 @retry(attempts=5, wait=2, return_is_str=True)
 def verify_evpn_routes(
-    tgen, topo, dut, input_dict, routeType=5, EthTag=0, next_hop=None
+    tgen, topo, dut, input_dict, routeType=5, EthTag=0, next_hop=None, expected=True
 ):
     """
     API to verify evpn routes using "sh bgp l2vpn evpn"
@@ -4132,6 +4156,8 @@ def verify_evpn_routes(
     * `route_type` : Route type 5 is supported as of now
     * `EthTag` : Ethernet tag, by-default is 0
     * `next_hop` : Prefered nexthop for the evpn routes
+    * `expected` : expected results from API, by-default True
+
     Usage
     -----
         input_dict_1 = {
index ee7cd6a7af7b5f97bc8499a17c71571c698546bd..3f78f020bccdb2892ab6c355968c3bfba5ef3a1a 100644 (file)
@@ -123,6 +123,17 @@ DEBUG_LOGS = {
         "debug ospf te",
         "debug ospf zebra",
     ],
+    "ospf6": [
+        "debug ospf6 event",
+        "debug ospf6 ism",
+        "debug ospf6 lsa",
+        "debug ospf6 nsm",
+        "debug ospf6 nssa",
+        "debug ospf6 packet all",
+        "debug ospf6 sr",
+        "debug ospf6 te",
+        "debug ospf6 zebra",
+    ],
 }
 
 if config.has_option("topogen", "verbosity"):
@@ -422,7 +433,10 @@ def check_router_status(tgen):
                     daemons.append("zebra")
                 if "pimd" in result:
                     daemons.append("pimd")
-
+                if "ospfd" in result:
+                    daemons.append("ospfd")
+                if "ospf6d" in result:
+                    daemons.append("ospf6d")
                 rnode.startDaemons(daemons)
 
     except Exception as e:
@@ -890,6 +904,10 @@ def topo_daemons(tgen, topo):
         for val in topo["routers"][rtr]["links"].values():
             if "pim" in val and "pimd" not in daemon_list:
                 daemon_list.append("pimd")
+            if "ospf" in val and "ospfd" not in daemon_list:
+                daemon_list.append("ospfd")
+            if "ospf6" in val and "ospf6d" not in daemon_list:
+                daemon_list.append("ospf6d")
                 break
 
     return daemon_list
diff --git a/tests/topotests/lib/mcast-tester.py b/tests/topotests/lib/mcast-tester.py
new file mode 100755 (executable)
index 0000000..07e4ab8
--- /dev/null
@@ -0,0 +1,129 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2021 by
+# Network Device Education Foundation, Inc. ("NetDEF")
+#
+# 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 THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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.
+
+"""
+Subscribe to a multicast group so that the kernel sends an IGMP JOIN
+for the multicast group we subscribed to.
+"""
+
+import argparse
+import os
+import json
+import socket
+import subprocess
+import struct
+import sys
+import time
+
+#
+# Functions
+#
+def interface_name_to_index(name):
+    "Gets the interface index using its name. Returns None on failure."
+    interfaces = json.loads(
+        subprocess.check_output('ip -j link show', shell=True))
+
+    for interface in interfaces:
+        if interface['ifname'] == name:
+            return interface['ifindex']
+
+    return None
+
+
+def multicast_join(sock, ifindex, group, port):
+    "Joins a multicast group."
+    mreq = struct.pack(
+        "=4sLL", socket.inet_aton(args.group), socket.INADDR_ANY, ifindex
+    )
+
+    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+    sock.bind((group, port))
+    sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
+
+
+#
+# Main code.
+#
+parser = argparse.ArgumentParser(description="Multicast RX utility")
+parser.add_argument('socket', help='Point to topotest UNIX socket')
+parser.add_argument('group', help='Multicast IP')
+parser.add_argument('interface', help='Interface name')
+parser.add_argument(
+    '--send',
+    help='Transmit instead of join with interval (defaults to 0.7 sec)',
+    type=float, default=0)
+args = parser.parse_args()
+
+ttl = 16
+port = 1000
+
+# Get interface index/validate.
+ifindex = interface_name_to_index(args.interface)
+if ifindex is None:
+    sys.stderr.write('Interface {} does not exists\n'.format(args.interface))
+    sys.exit(1)
+
+# We need root privileges to set up multicast.
+if os.geteuid() != 0:
+    sys.stderr.write("ERROR: You must have root privileges\n")
+    sys.exit(1)
+
+# Wait for topotest to synchronize with us.
+toposock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM, 0)
+while True:
+    try:
+        toposock.connect(args.socket)
+        break
+    except ConnectionRefusedError:
+        time.sleep(1)
+        continue
+
+msock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+if args.send > 0:
+    # Prepare multicast bit in that interface.
+    msock.setsockopt(
+        socket.SOL_SOCKET, 25,
+        struct.pack("%ds" % len(args.interface),
+                    args.interface.encode('utf-8')))
+    # Set packets TTL.
+    msock.setsockopt(
+        socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, struct.pack("b", ttl))
+    # Block to ensure packet send.
+    msock.setblocking(True)
+    # Set topotest socket non blocking so we can multiplex the main loop.
+    toposock.setblocking(False)
+else:
+    multicast_join(msock, ifindex, args.group, port)
+
+counter = 0
+while True:
+    if args.send > 0:
+        msock.sendto(b"test %d" % counter, (args.group, port))
+        counter += 1
+        time.sleep(args.send)
+
+    try:
+        data = toposock.recv(1)
+        if data == b'':
+            print(' -> Connection closed')
+            break
+    except BlockingIOError:
+        continue
+
+msock.close()
+
+sys.exit(0)
index 7ad64de4a1ec32a1c3f6e66791f37b80167d56f6..3f39b93d8cd7ae258fcf0b7e363d389ced206b00 100644 (file)
 # OF THIS SOFTWARE.
 #
 
-from copy import deepcopy
 import traceback
+import ipaddr
+import ipaddress
+import sys
+
+from copy import deepcopy
 from time import sleep
 from lib.topolog import logger
-import ipaddr
 from lib.topotest import frr_unicode
-
+from ipaddress import IPv6Address
 # Import common_config to use commomnly used APIs
 from lib.common_config import (
     create_common_configuration,
@@ -86,10 +89,21 @@ def create_router_ospf(tgen, topo, input_dict=None, build=False, load_config=Tru
             logger.debug("Router %s: 'ospf' not present in input_dict", router)
             continue
 
-        result = __create_ospf_global(tgen, input_dict, router, build, load_config)
+        result = __create_ospf_global(
+            tgen, input_dict, router, build, load_config)
         if result is True:
             ospf_data = input_dict[router]["ospf"]
 
+    for router in input_dict.keys():
+        if "ospf6" not in input_dict[router]:
+            logger.debug("Router %s: 'ospf6' not present in input_dict", router)
+            continue
+
+        result = __create_ospf_global(
+            tgen, input_dict, router, build, load_config, ospf='ospf6')
+        if result is True:
+            ospf_data = input_dict[router]["ospf6"]
+
     logger.debug("Exiting lib API: create_router_ospf()")
     return result
 
@@ -158,6 +172,7 @@ def __create_ospf_global(
 
         config_data.append(cmd)
 
+
         # router id
         router_id = ospf_data.setdefault("router_id", None)
         del_router_id = ospf_data.setdefault("del_router_id", False)
@@ -166,6 +181,33 @@ def __create_ospf_global(
         if router_id:
             config_data.append("{} router-id {}".format(ospf, router_id))
 
+        # log-adjacency-changes
+        log_adj_changes = ospf_data.setdefault("log_adj_changes", None)
+        del_log_adj_changes = ospf_data.setdefault("del_log_adj_changes", False)
+        if del_log_adj_changes:
+            config_data.append("no log-adjacency-changes detail")
+        if log_adj_changes:
+            config_data.append("log-adjacency-changes {}".format(
+                log_adj_changes))
+
+        # aggregation timer
+        aggr_timer = ospf_data.setdefault("aggr_timer", None)
+        del_aggr_timer = ospf_data.setdefault("del_aggr_timer", False)
+        if del_aggr_timer:
+            config_data.append("no aggregation timer")
+        if aggr_timer:
+            config_data.append("aggregation timer {}".format(
+                aggr_timer))
+
+        # maximum path information
+        ecmp_data = ospf_data.setdefault("maximum-paths", {})
+        if ecmp_data:
+            cmd = "maximum-paths {}".format(ecmp_data)
+            del_action = ospf_data.setdefault("del_max_path", False)
+            if del_action:
+                cmd = "no maximum-paths"
+            config_data.append(cmd)
+
         # redistribute command
         redistribute_data = ospf_data.setdefault("redistribute", {})
         if redistribute_data:
@@ -203,6 +245,34 @@ def __create_ospf_global(
                         cmd = "no {}".format(cmd)
                     config_data.append(cmd)
 
+        #def route information
+        def_rte_data = ospf_data.setdefault("default-information", {})
+        if def_rte_data:
+            if "originate" not in def_rte_data:
+                logger.debug("Router %s: 'originate key' not present in "
+                            "input_dict", router)
+            else:
+                cmd = "default-information originate"
+
+                if "always" in def_rte_data:
+                    cmd = cmd + " always"
+
+                if "metric" in def_rte_data:
+                    cmd = cmd + " metric {}".format(def_rte_data["metric"])
+
+                if "metric-type" in def_rte_data:
+                    cmd = cmd + " metric-type {}".format(def_rte_data[
+                        "metric-type"])
+
+                if "route-map" in def_rte_data:
+                    cmd = cmd + " route-map {}".format(def_rte_data[
+                        "route-map"])
+
+                del_action = def_rte_data.setdefault("delete", False)
+                if del_action:
+                    cmd = "no {}".format(cmd)
+                config_data.append(cmd)
+
         # area interface information for ospf6d only
         if ospf == "ospf6":
             area_iface = ospf_data.setdefault("neighbors", {})
@@ -217,6 +287,21 @@ def __create_ospf_global(
                             cmd = "no {}".format(cmd)
                         config_data.append(cmd)
 
+                    try:
+                        if "area" in input_dict[router]['links'][neighbor][
+                            'ospf6']:
+                            iface = input_dict[router]["links"][neighbor]["interface"]
+                            cmd = "interface {} area {}".format(
+                                iface, input_dict[router]['links'][neighbor][
+                            'ospf6']['area'])
+                            if input_dict[router]['links'][neighbor].setdefault(
+                                "delete", False):
+                                cmd = "no {}".format(cmd)
+                            config_data.append(cmd)
+                    except KeyError:
+                            pass
+
+
         # summary information
         summary_data = ospf_data.setdefault("summary-address", {})
         if summary_data:
@@ -427,11 +512,11 @@ def config_ospf_interface(tgen, topo, input_dict=None, build=False, load_config=
                 result = create_common_configuration(
                     tgen, router, config_data, "interface_config", build=build
                 )
-    logger.debug("Exiting lib API: create_igmp_config()")
+    logger.debug("Exiting lib API: config_ospf_interface()")
     return result
 
 
-def clear_ospf(tgen, router):
+def clear_ospf(tgen, router, ospf=None):
     """
     This API is to clear ospf neighborship by running
     clear ip ospf interface * command,
@@ -451,11 +536,16 @@ def clear_ospf(tgen, router):
         return False
 
     rnode = tgen.routers()[router]
-
     # Clearing OSPF
-    logger.info("Clearing ospf process for router %s..", router)
+    if ospf:
+        version = "ipv6"
+    else:
+        version = "ip"
 
-    run_frr_cmd(rnode, "clear ip ospf interface ")
+    cmd = "clear {} ospf interface".format(version)
+    logger.info(
+        "Clearing ospf process on router %s.. using command '%s'", router, cmd)
+    run_frr_cmd(rnode, cmd)
 
     logger.debug("Exiting lib API: clear_ospf()")
 
@@ -490,7 +580,7 @@ def redistribute_ospf(tgen, topo, dut, route_type, **kwargs):
 # Verification procs
 ################################
 @retry(attempts=40, wait=2, return_is_str=True)
-def verify_ospf_neighbor(tgen, topo, dut=None, input_dict=None, lan=False):
+def verify_ospf_neighbor(tgen, topo, dut=None, input_dict=None, lan=False, expected=True):
     """
     This API is to verify ospf neighborship by running
     show ip ospf neighbour command,
@@ -502,6 +592,7 @@ def verify_ospf_neighbor(tgen, topo, dut=None, input_dict=None, lan=False):
     * `dut`: device under test
     * `input_dict` : Input dict data, required when configuring from testcase
     * `lan` : verify neighbors in lan topology
+    * `expected` : expected results from API, by-default True
 
     Usage
     -----
@@ -683,70 +774,194 @@ def verify_ospf_neighbor(tgen, topo, dut=None, input_dict=None, lan=False):
 ################################
 # Verification procs
 ################################
-@retry(attempts=40, wait=2, return_is_str=True)
-def verify_ospf6_neighbor(tgen, topo):
+@retry(attempts=10, wait=2, return_is_str=True)
+def verify_ospf6_neighbor(tgen, topo, dut=None, input_dict=None, lan=False):
     """
     This API is to verify ospf neighborship by running
-    show ip ospf neighbour command,
+    show ipv6 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
     -----
-    Check FULL neighbors.
-    verify_ospf_neighbor(tgen, topo)
+    1. To check FULL neighbors.
+    verify_ospf_neighbor(tgen, topo, dut=dut)
 
-    result = verify_ospf_neighbor(tgen, topo)
+    2. To check neighbors with their roles.
+    input_dict = {
+        "r0": {
+            "ospf6": {
+                "neighbors": {
+                    "r1": {
+                        "state": "Full",
+                        "role": "DR"
+                    },
+                    "r2": {
+                        "state": "Full",
+                        "role": "DROther"
+                    },
+                    "r3": {
+                        "state": "Full",
+                        "role": "DROther"
+                    }
+                }
+            }
+        }
+    }
+    result = verify_ospf6_neighbor(tgen, topo, dut, input_dict, lan=True)
 
     Returns
     -------
     True or False (Error Message)
     """
-
-    logger.debug("Entering lib API: verify_ospf6_neighbor()")
+    logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
     result = False
-    for router, rnode in tgen.routers().items():
-        if "ospf6" not in topo["routers"][router]:
-            continue
 
-        logger.info("Verifying OSPF6 neighborship on router %s:", router)
-        show_ospf_json = run_frr_cmd(
-            rnode, "show ipv6 ospf6 neighbor json", isjson=True
-        )
+    if input_dict:
+        for router, rnode in tgen.routers().items():
+            if 'ospf6' not in topo['routers'][router]:
+                continue
 
-        if not show_ospf_json:
-            return "OSPF6 is not running"
-
-        ospf_nbr_list = topo["routers"][router]["ospf6"]["neighbors"]
-        no_of_peer = 0
-        for ospf_nbr in ospf_nbr_list:
-            ospf_nbr_rid = topo["routers"][ospf_nbr]["ospf6"]["router_id"]
-            for neighbor in show_ospf_json["neighbors"]:
-                if neighbor["neighborId"] == ospf_nbr_rid:
-                    nh_state = neighbor["state"]
-                    break
-            else:
-                return "[DUT: {}] OSPF6 peer {} missing".format(router, ospf_nbr_rid)
+            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 ipv6 ospf neighbor json", isjson=True)
+            # Verifying output dictionary show_ospf_json is empty or not
+            if not bool(show_ospf_json):
+                errormsg = "OSPF6 is not running"
+                return errormsg
+
+            ospf_data_list = input_dict[router]["ospf6"]
+            ospf_nbr_list = ospf_data_list['neighbors']
+
+            for ospf_nbr, nbr_data in ospf_nbr_list.items():
+                data_ip = data_rid = topo['routers'][ospf_nbr]['ospf6']['router_id']
+                if ospf_nbr in data_ip:
+                    nbr_details = nbr_data[ospf_nbr]
+                elif lan:
+                    for switch in topo['switches']:
+                        if 'ospf6' in topo['switches'][switch]['links'][router]:
+                            neighbor_ip = data_ip
+                        else:
+                            continue
+                else:
+                    neighbor_ip = data_ip[router]['ipv6'].split("/")[0]
 
-            if nh_state == "Full":
-                no_of_peer += 1
+                nh_state = None
+                neighbor_ip = neighbor_ip.lower()
+                nbr_rid = data_rid
+                get_index_val = dict((d['neighborId'], dict( \
+                        d, index=index)) for (index, d) in enumerate( \
+                            show_ospf_json['neighbors']))
+                try:
+                    nh_state =  get_index_val.get(neighbor_ip)['state']
+                    intf_state = get_index_val.get(neighbor_ip)['ifState']
+                except TypeError:
+                    errormsg = "[DUT: {}] OSPF peer {} missing,from "\
+                        "{} ".format(router,
+                    nbr_rid, ospf_nbr)
+                    return errormsg
 
-        if no_of_peer == len(ospf_nbr_list):
-            logger.info("[DUT: {}] OSPF6 is Converged".format(router))
-            result = True
-        else:
-            return "[DUT: {}] OSPF6 is not Converged".format(router)
+                nbr_state = nbr_data.setdefault("state",None)
+                nbr_role = nbr_data.setdefault("role",None)
 
-    logger.debug("Exiting API: verify_ospf6_neighbor()")
+                if nbr_state:
+                    if nbr_state == nh_state:
+                        logger.info("[DUT: {}] OSPF6 Nbr is {}:{} State {}".format
+                        (router, ospf_nbr, nbr_rid, nh_state))
+                        result = True
+                    else:
+                        errormsg = ("[DUT: {}] OSPF6 is not Converged, neighbor"
+                        " state is {} , Expected state is {}".format(router,
+                        nh_state, nbr_state))
+                        return errormsg
+                if nbr_role:
+                    if nbr_role == intf_state:
+                        logger.info("[DUT: {}] OSPF6 Nbr is {}: {} Role {}".format(
+                        router, ospf_nbr, nbr_rid, nbr_role))
+                    else:
+                        errormsg = ("[DUT: {}] OSPF6 is not Converged with rid"
+                        "{}, role is {}, Expected role is {}".format(router,
+                        nbr_rid, intf_state, nbr_role))
+                        return errormsg
+                continue
+    else:
+
+        for router, rnode in tgen.routers().items():
+            if 'ospf6' not in topo['routers'][router]:
+                continue
+
+            if dut is not None and dut != router:
+                continue
+
+            logger.info("Verifying OSPF6 neighborship on router %s:", router)
+            show_ospf_json = run_frr_cmd(rnode,
+                "show ipv6 ospf neighbor json", isjson=True)
+            # Verifying output dictionary show_ospf_json is empty or not
+            if not bool(show_ospf_json):
+                errormsg = "OSPF6 is not running"
+                return errormsg
+
+            ospf_data_list = topo["routers"][router]["ospf6"]
+            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():
+                data_ip = data_rid = topo['routers'][ospf_nbr]['ospf6']['router_id']
+                if ospf_nbr in data_ip:
+                    nbr_details = nbr_data[ospf_nbr]
+                elif lan:
+                    for switch in topo['switches']:
+                        if 'ospf6' in topo['switches'][switch]['links'][router]:
+                            neighbor_ip = data_ip
+                        else:
+                            continue
+                else:
+                    neighbor_ip = data_ip
+
+                nh_state = None
+                neighbor_ip = neighbor_ip.lower()
+                nbr_rid = data_rid
+                get_index_val = dict((d['neighborId'], dict( \
+                        d, index=index)) for (index, d) in enumerate( \
+                            show_ospf_json['neighbors']))
+                try:
+                    nh_state =  get_index_val.get(neighbor_ip)['state']
+                    intf_state = get_index_val.get(neighbor_ip)['ifState']
+                except TypeError:
+                    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: {}] OSPF6 is Converged".format(router))
+                result = True
+            else:
+                errormsg = ("[DUT: {}] OSPF6 is not Converged".format(router))
+                return errormsg
+
+    logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
     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
+    tgen, dut, input_dict, next_hop=None, tag=None, metric=None, fib=None, expected=True
 ):
     """
     This API is to verify ospf routes by running
@@ -761,6 +976,7 @@ def verify_ospf_rib(
     * `tag` : tag to be verified
     * `metric` : metric to be verified
     * `fib` : True if the route is installed in FIB.
+    * `expected` : expected results from API, by-default True
 
     Usage
     -----
@@ -1021,7 +1237,7 @@ def verify_ospf_rib(
 
 
 @retry(attempts=10, wait=2, return_is_str=True)
-def verify_ospf_interface(tgen, topo, dut=None, lan=False, input_dict=None):
+def verify_ospf_interface(tgen, topo, dut=None, lan=False, input_dict=None, expected=True):
     """
     This API is to verify ospf routes by running
     show ip ospf interface command.
@@ -1033,6 +1249,7 @@ def verify_ospf_interface(tgen, topo, dut=None, lan=False, input_dict=None):
     * `dut`: device under test
     * `lan`: if set to true this interface belongs to LAN.
     * `input_dict` : Input dict data, required when configuring from testcase
+    * `expected` : expected results from API, by-default True
 
     Usage
     -----
@@ -1110,7 +1327,7 @@ def verify_ospf_interface(tgen, topo, dut=None, lan=False, input_dict=None):
 
 
 @retry(attempts=11, wait=2, return_is_str=True)
-def verify_ospf_database(tgen, topo, dut, input_dict):
+def verify_ospf_database(tgen, topo, dut, input_dict, expected=True):
     """
     This API is to verify ospf lsa's by running
     show ip ospf database command.
@@ -1121,6 +1338,7 @@ def verify_ospf_database(tgen, topo, dut, input_dict):
     * `dut`: device under test
     * `input_dict` : Input dict data, required when configuring from testcase
     * `topo` : next to be verified
+    * `expected` : expected results from API, by-default True
 
     Usage
     -----
@@ -1273,7 +1491,7 @@ def verify_ospf_database(tgen, topo, dut, input_dict):
 
 
 @retry(attempts=10, wait=2, return_is_str=True)
-def verify_ospf_summary(tgen, topo, dut, input_dict):
+def verify_ospf_summary(tgen, topo, dut, input_dict, expected=True):
     """
     This API is to verify ospf routes by running
     show ip ospf interface command.
@@ -1284,6 +1502,7 @@ def verify_ospf_summary(tgen, topo, dut, input_dict):
     * `topo` : topology descriptions
     * `dut`: device under test
     * `input_dict` : Input dict data, required when configuring from testcase
+    * `expected` : expected results from API, by-default True
 
     Usage
     -----
@@ -1349,3 +1568,667 @@ def verify_ospf_summary(tgen, topo, dut, input_dict):
 
     logger.debug("Exiting API: verify_ospf_summary()")
     return result
+
+
+
+@retry(attempts=10, wait=3, return_is_str=True)
+def verify_ospf6_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_ospf6_rib(tgen, dut, input_dict,next_hop=nh)
+
+    Returns
+    -------
+    True or False (Error Message)
+    """
+
+    logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+    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 ipv6 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)
+
+                    # Fix for PR 2644182
+                    try:
+                        ospf_rib_json = ospf_rib_json['routes']
+                    except KeyError:
+                        pass
+
+                    # Verifying output dictionary ospf_rib_json is not empty
+                    if bool(ospf_rib_json) is False:
+                        errormsg = "[DUT: {}] No routes found in OSPF6 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(ipaddress.ip_network(frr_unicode(st_rt)))
+
+                        _addr_type = validate_ip_address(st_rt)
+                        if _addr_type != 'ipv6':
+                            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['nextHop'] 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 "destinationType" not in ospf_rib_json[
+                                    st_rt]:
+                                    errormsg = ("[DUT: {}]: destinationType missing"
+                                                "for route {} in OSPF RIB \n".\
+                                                format(dut, st_rt))
+                                    return errormsg
+                                elif _rtype != ospf_rib_json[st_rt][
+                                    "destinationType"]:
+                                    errormsg = ("[DUT: {}]: destinationType mismatch"
+                                                "for route {} in OSPF RIB \n".\
+                                                format(dut, st_rt))
+                                    return errormsg
+                                else:
+                                    logger.info("DUT: {}]: Found destinationType {}"
+                                                "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.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+    return result
+
+
+@retry(attempts=3, wait=2, return_is_str=True)
+def verify_ospf6_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': {
+                    'ospf6':{
+                        '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: {}".format(sys._getframe().f_code.co_name))
+    result = False
+
+    for router, rnode in tgen.routers().iteritems():
+        if 'ospf6' 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 ipv6 ospf interface json",
+                                    isjson=True)
+
+        # Verifying output dictionary show_ospf_json is empty or not
+        if not bool(show_ospf_json):
+            errormsg = "OSPF6 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:
+                for intf_attribute in intf_data['ospf6']:
+                    if intf_data['ospf6'][intf_attribute] is not list:
+                        if intf_data['ospf6'][intf_attribute] ==  show_ospf_json[
+                            intf][intf_attribute]:
+                            logger.info("[DUT: %s] OSPF6 interface %s: %s is %s",
+                            router, intf, intf_attribute, intf_data['ospf6'][
+                                intf_attribute])
+                    elif intf_data['ospf6'][intf_attribute] is list:
+                        for addr_list in len(show_ospf_json[intf][intf_attribute]):
+                            if show_ospf_json[intf][intf_attribute][addr_list][
+                                'address'].split('/')[0] == intf_data['ospf6'][
+                                    'internetAddress'][0]['address']:
+                                    break
+                            else:
+                                errormsg= "[DUT: {}] OSPF6 interface {}: {} is {}, \
+                                    Expected is {}".format(router, intf, intf_attribute,
+                                    intf_data['ospf6'][intf_attribute], intf_data['ospf6'][
+                                    intf_attribute])
+                                return errormsg
+                    else:
+                        errormsg= "[DUT: {}] OSPF6 interface {}: {} is {}, \
+                        Expected is {}".format(router, intf, intf_attribute,
+                        intf_data['ospf6'][intf_attribute], intf_data['ospf6'][
+                            intf_attribute])
+                        return errormsg
+        result = True
+    logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+    return result
+
+
+@retry(attempts=11, wait=2, return_is_str=True)
+def verify_ospf6_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": {
+            "routerLinkStates": {
+                "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
+                }
+            },
+            "networkLinkStates": {
+                "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: {}".format(sys._getframe().f_code.co_name))
+
+    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(
+        'asExternalLinkStates', None)
+
+    if ospf_db_data:
+            for ospf_area, area_lsa in ospf_db_data.items():
+                if ospf_area in show_ospf_json['areas']:
+                    if 'routerLinkStates' in area_lsa:
+                        for lsa in area_lsa['routerLinkStates']:
+                            for rtrlsa in show_ospf_json['areas'][ospf_area][
+                                'routerLinkStates']:
+                                if lsa['lsaId'] == rtrlsa['lsaId'] and \
+                                    lsa['advertisedRouter'] == rtrlsa[
+                                        'advertisedRouter']:
+                                                result = True
+                                                break
+                            if result:
+                                logger.info(
+                                    "[DUT: %s]  OSPF LSDB area %s:Router "
+                                    "LSA %s", router, ospf_area, lsa)
+                                break
+                        else:
+                            errormsg = \
+                            "[DUT: {}]  OSPF LSDB area {}: expected" \
+                            " Router LSA is {}".format(router, ospf_area, lsa)
+                            return errormsg
+
+                    if 'networkLinkStates' in area_lsa:
+                        for lsa in area_lsa['networkLinkStates']:
+                            for netlsa in show_ospf_json['areas'][ospf_area][
+                                'networkLinkStates']:
+                                if lsa in show_ospf_json['areas'][ospf_area][
+                                    'networkLinkStates']:
+                                    if lsa['lsaId'] == netlsa['lsaId'] and \
+                                    lsa['advertisedRouter'] == netlsa[
+                                        'advertisedRouter']:
+                                                result = True
+                                                break
+                            if result:
+                                logger.info(
+                                    "[DUT: %s]  OSPF LSDB area %s:Network "
+                                    "LSA %s", router, ospf_area, lsa)
+                                break
+                            else:
+                                errormsg = \
+                                "[DUT: {}]  OSPF LSDB area {}: expected" \
+                                " Network LSA is {}".format(router, ospf_area, lsa)
+                                return errormsg
+
+                    if 'summaryLinkStates' in area_lsa:
+                        for lsa in area_lsa['summaryLinkStates']:
+                            for t3lsa in show_ospf_json['areas'][ospf_area][
+                                'summaryLinkStates']:
+                                if lsa['lsaId'] == t3lsa['lsaId'] and \
+                                lsa['advertisedRouter'] == t3lsa[
+                                    'advertisedRouter']:
+                                            result = True
+                                            break
+                            if result:
+                                logger.info(
+                                    "[DUT: %s]  OSPF LSDB area %s:Summary "
+                                    "LSA %s", router, ospf_area, lsa)
+                                break
+                            else:
+                                errormsg = \
+                                "[DUT: {}]  OSPF LSDB area {}: expected" \
+                                " Summary LSA is {}".format(router, ospf_area, lsa)
+                                return errormsg
+
+                    if 'nssaExternalLinkStates' in area_lsa:
+                        for lsa in area_lsa['nssaExternalLinkStates']:
+                            for t7lsa in show_ospf_json['areas'][ospf_area][
+                                'nssaExternalLinkStates']:
+                                if lsa['lsaId'] == t7lsa['lsaId'] and \
+                                lsa['advertisedRouter'] == t7lsa[
+                                    'advertisedRouter']:
+                                            result = True
+                                            break
+                            if result:
+                                logger.info(
+                                    "[DUT: %s]  OSPF LSDB area %s:Type7 "
+                                    "LSA %s", router, ospf_area, lsa)
+                                break
+                            else:
+                                errormsg = \
+                                "[DUT: {}]  OSPF LSDB area {}: expected" \
+                                " Type7 LSA is {}".format(router, ospf_area, lsa)
+                                return errormsg
+
+                    if 'asbrSummaryLinkStates' in area_lsa:
+                        for lsa in area_lsa['asbrSummaryLinkStates']:
+                            for t4lsa in show_ospf_json['areas'][ospf_area][
+                                'asbrSummaryLinkStates']:
+                                if lsa['lsaId'] == t4lsa['lsaId'] and \
+                                lsa['advertisedRouter'] == t4lsa[
+                                    'advertisedRouter']:
+                                            result = True
+                                            break
+                            if result:
+                                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 'linkLocalOpaqueLsa' in area_lsa:
+                        for lsa in area_lsa['linkLocalOpaqueLsa']:
+                            try:
+                                for lnklsa in show_ospf_json['areas'][ospf_area][
+                                    'linkLocalOpaqueLsa']:
+                                    if lsa['lsaId'] in lnklsa['lsaId'] and \
+                                        'linkLocalOpaqueLsa' in show_ospf_json[
+                                            'areas'][ospf_area]:
+                                        logger.info((
+                                        "[DUT: FRR]  OSPF LSDB area %s:Opaque-LSA"
+                                        "%s", ospf_area, lsa))
+                                        result = True
+                                    else:
+                                        errormsg = ("[DUT: FRR] OSPF LSDB area: {} "
+                                    "expected Opaque-LSA is {}, Found is {}".format(
+                                        ospf_area, lsa, show_ospf_json))
+                                        raise ValueError (errormsg)
+                                        return errormsg
+                            except KeyError:
+                                errormsg = ("[DUT: FRR] linkLocalOpaqueLsa Not "
+                                                "present")
+                                return errormsg
+
+    if ospf_external_lsa:
+            for lsa in ospf_external_lsa:
+                try:
+                    for t5lsa in show_ospf_json['asExternalLinkStates']:
+                        if lsa['lsaId'] == t5lsa['lsaId'] and \
+                            lsa['advertisedRouter'] == t5lsa[
+                                        'advertisedRouter']:
+                            result = True
+                            break
+                except KeyError:
+                        result = False
+                if result:
+                    logger.info(
+                            "[DUT: %s]  OSPF LSDB:External LSA %s",
+                            router, lsa)
+                    result = True
+                else:
+                    errormsg = \
+                            "[DUT: {}]  OSPF LSDB : expected" \
+                            " External LSA is {}".format(router, lsa)
+                    return errormsg
+
+    logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+    return result
+
+
+
+def config_ospf6_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_ospf6_interface(tgen, topo, r1_ospf_auth)
+
+    Returns
+    -------
+    True or False
+    """
+    logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+    result = False
+    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 "ospf6" not in input_dict[router]['links'][lnk]:
+                logger.debug("Router %s: ospf6 configs is not present in"
+                             "input_dict, passed input_dict", router,
+                             input_dict)
+                continue
+            ospf_data = input_dict[router]['links'][lnk]['ospf6']
+            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)
+            data_ospf_mtu = ospf_data.setdefault("mtu_ignore", 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 = "ipv6 ospf area {}".format(data_ospf_area)
+                config_data.append(cmd)
+
+            # interface ospf dr priority
+            if data_ospf_dr_priority:
+                cmd = "ipv6 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:
+                cmd = "ipv6 ospf cost {}".format(
+                    ospf_data["cost"])
+                if 'del_action' in ospf_data:
+                    cmd = "no {}".format(cmd)
+                config_data.append(cmd)
+
+            # interface ospf mtu
+            if data_ospf_mtu:
+                cmd = "ipv6 ospf mtu-ignore"
+                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: {}".format(sys._getframe().f_code.co_name))
+    return result
index 61a5705a5de2a578720140eeea69499322263977..ce90717fa4b5023311d47cf1bd989e0f2b81495e 100644 (file)
@@ -496,7 +496,7 @@ def configure_pim_force_expire(tgen, topo, input_dict, build=False):
 # Verification APIs
 #############################################
 @retry(attempts=6, wait=2, return_is_str=True)
-def verify_pim_neighbors(tgen, topo, dut=None, iface=None, nbr_ip=None):
+def verify_pim_neighbors(tgen, topo, dut=None, iface=None, nbr_ip=None, expected=True):
     """
     Verify all PIM neighbors are up and running, config is verified
     using "show ip pim neighbor" cli
@@ -508,6 +508,7 @@ def verify_pim_neighbors(tgen, topo, dut=None, iface=None, nbr_ip=None):
     * `dut` : dut info
     * `iface` : link for which PIM nbr need to check
     * `nbr_ip` : neighbor ip of interface
+    * `expected` : expected results from API, by-default True
 
     Usage
     -----
@@ -619,7 +620,7 @@ def verify_pim_neighbors(tgen, topo, dut=None, iface=None, nbr_ip=None):
 
 
 @retry(attempts=21, wait=2, return_is_str=True)
-def verify_igmp_groups(tgen, dut, interface, group_addresses):
+def verify_igmp_groups(tgen, dut, interface, group_addresses, expected=True):
     """
     Verify IGMP groups are received from an intended interface
     by running "show ip igmp groups" command
@@ -630,6 +631,7 @@ def verify_igmp_groups(tgen, dut, interface, group_addresses):
     * `dut`: device under test
     * `interface`: interface, from which IGMP groups would be received
     * `group_addresses`: IGMP group address
+    * `expected` : expected results from API, by-default True
 
     Usage
     -----
@@ -693,7 +695,7 @@ def verify_igmp_groups(tgen, dut, interface, group_addresses):
 
 @retry(attempts=31, wait=2, return_is_str=True)
 def verify_upstream_iif(
-    tgen, dut, iif, src_address, group_addresses, joinState=None, refCount=1
+    tgen, dut, iif, src_address, group_addresses, joinState=None, refCount=1, expected=True
 ):
     """
     Verify upstream inbound interface  is updated correctly
@@ -708,6 +710,7 @@ def verify_upstream_iif(
     * `group_addresses`: IGMP group address
     * `joinState`: upstream join state
     * `refCount`: refCount value
+    * `expected` : expected results from API, by-default True
 
     Usage
     -----
@@ -845,7 +848,7 @@ def verify_upstream_iif(
 
 
 @retry(attempts=6, wait=2, return_is_str=True)
-def verify_join_state_and_timer(tgen, dut, iif, src_address, group_addresses):
+def verify_join_state_and_timer(tgen, dut, iif, src_address, group_addresses, expected=True):
     """
     Verify  join state is updated correctly and join timer is
     running with the help of "show ip pim upstream" cli
@@ -857,6 +860,7 @@ def verify_join_state_and_timer(tgen, dut, iif, src_address, group_addresses):
     * `iif`: inbound interface
     * `src_address`: source address
     * `group_addresses`: IGMP group address
+    * `expected` : expected results from API, by-default True
 
     Usage
     -----
@@ -964,7 +968,7 @@ def verify_join_state_and_timer(tgen, dut, iif, src_address, group_addresses):
 
 @retry(attempts=41, wait=2, return_is_dict=True)
 def verify_ip_mroutes(
-    tgen, dut, src_address, group_addresses, iif, oil, return_uptime=False, mwait=0
+    tgen, dut, src_address, group_addresses, iif, oil, return_uptime=False, mwait=0, expected=True
 ):
     """
     Verify ip mroutes and make sure (*, G)/(S, G) is present in mroutes
@@ -980,7 +984,7 @@ def verify_ip_mroutes(
     * `oil`: Outgoing interface
     * `return_uptime`: If True, return uptime dict, default is False
     * `mwait`: Wait time, default is 0
-
+    * `expected` : expected results from API, by-default True
 
     Usage
     -----
@@ -1161,7 +1165,7 @@ def verify_ip_mroutes(
 
 @retry(attempts=31, wait=2, return_is_str=True)
 def verify_pim_rp_info(
-    tgen, topo, dut, group_addresses, oif=None, rp=None, source=None, iamrp=None
+    tgen, topo, dut, group_addresses, oif=None, rp=None, source=None, iamrp=None, expected=True
 ):
     """
     Verify pim rp info by running "show ip pim rp-info" cli
@@ -1176,6 +1180,7 @@ def verify_pim_rp_info(
     * `rp`: RP address
     * `source`: Source of RP
     * `iamrp`: User defined RP
+    * `expected` : expected results from API, by-default True
 
     Usage
     -----
@@ -1317,7 +1322,7 @@ def verify_pim_rp_info(
 
 @retry(attempts=31, wait=2, return_is_str=True)
 def verify_pim_state(
-    tgen, dut, iif, oil, group_addresses, src_address=None, installed_fl=None
+    tgen, dut, iif, oil, group_addresses, src_address=None, installed_fl=None, expected=True
 ):
     """
     Verify pim state by running "show ip pim state" cli
@@ -1331,6 +1336,7 @@ def verify_pim_state(
     * `group_addresses`: IGMP group address
     * `src_address`: source address, default = None
     * installed_fl` : Installed flag
+    * `expected` : expected results from API, by-default True
 
     Usage
     -----
@@ -1485,7 +1491,7 @@ def verify_pim_interface_traffic(tgen, input_dict):
 
 
 @retry(attempts=21, wait=2, return_is_str=True)
-def verify_pim_interface(tgen, topo, dut, interface=None, interface_ip=None):
+def verify_pim_interface(tgen, topo, dut, interface=None, interface_ip=None, expected=True):
     """
     Verify all PIM interface are up and running, config is verified
     using "show ip pim interface" cli
@@ -1497,6 +1503,7 @@ def verify_pim_interface(tgen, topo, dut, interface=None, interface_ip=None):
     * `dut` : device under test
     * `interface` : interface name
     * `interface_ip` : interface ip address
+    * `expected` : expected results from API, by-default True
 
     Usage
     -----
@@ -1791,7 +1798,7 @@ def clear_ip_igmp_interfaces(tgen, dut):
 
 
 @retry(attempts=10, wait=2, return_is_str=True)
-def clear_ip_mroute_verify(tgen, dut):
+def clear_ip_mroute_verify(tgen, dut, expected=True):
     """
     Clear ip mroute by running "clear ip mroute" cli and verify
     mroutes are up again after mroute clear
@@ -1800,6 +1807,8 @@ def clear_ip_mroute_verify(tgen, dut):
     ----------
     * `tgen`: topogen object
     * `dut`: Device Under Test
+    * `expected` : expected results from API, by-default True
+
     Usage
     -----
 
@@ -2165,7 +2174,7 @@ def find_rp_from_bsrp_info(tgen, dut, bsr, grp=None):
 
 
 @retry(attempts=6, wait=2, return_is_str=True)
-def verify_pim_grp_rp_source(tgen, topo, dut, grp_addr, rp_source, rpadd=None):
+def verify_pim_grp_rp_source(tgen, topo, dut, grp_addr, rp_source, rpadd=None, expected=True):
     """
     Verify pim rp info by running "show ip pim rp-info" cli
 
@@ -2177,6 +2186,7 @@ def verify_pim_grp_rp_source(tgen, topo, dut, grp_addr, rp_source, rpadd=None):
     * `grp_addr`: IGMP group address
     * 'rp_source': source from which rp installed
     * 'rpadd': rp address
+    * `expected` : expected results from API, by-default True
 
     Usage
     -----
@@ -2267,7 +2277,7 @@ def verify_pim_grp_rp_source(tgen, topo, dut, grp_addr, rp_source, rpadd=None):
 
 
 @retry(attempts=31, wait=2, return_is_str=True)
-def verify_pim_bsr(tgen, topo, dut, bsr_ip):
+def verify_pim_bsr(tgen, topo, dut, bsr_ip, expected=True):
     """
     Verify all PIM interface are up and running, config is verified
     using "show ip pim interface" cli
@@ -2278,6 +2288,7 @@ def verify_pim_bsr(tgen, topo, dut, bsr_ip):
     * `topo` : json file data
     * `dut` : device under test
     * 'bsr' : bsr ip to be verified
+    * `expected` : expected results from API, by-default True
 
     Usage
     -----
@@ -2322,7 +2333,7 @@ def verify_pim_bsr(tgen, topo, dut, bsr_ip):
 
 
 @retry(attempts=31, wait=2, return_is_str=True)
-def verify_ip_pim_upstream_rpf(tgen, topo, dut, interface, group_addresses, rp=None):
+def verify_ip_pim_upstream_rpf(tgen, topo, dut, interface, group_addresses, rp=None, expected=True):
     """
     Verify IP PIM upstream rpf, config is verified
     using "show ip pim neighbor" cli
@@ -2336,6 +2347,7 @@ def verify_ip_pim_upstream_rpf(tgen, topo, dut, interface, group_addresses, rp=N
     * `group_addresses` : list of group address for which upstream info
                           needs to be checked
     * `rp` : RP address
+    * `expected` : expected results from API, by-default True
 
     Usage
     -----
@@ -2519,7 +2531,7 @@ def enable_disable_pim_bsm(tgen, router, intf, enable=True):
 
 
 @retry(attempts=31, wait=2, return_is_str=True)
-def verify_ip_pim_join(tgen, topo, dut, interface, group_addresses, src_address=None):
+def verify_ip_pim_join(tgen, topo, dut, interface, group_addresses, src_address=None, expected=True):
     """
     Verify ip pim join by running "show ip pim join" cli
 
@@ -2531,6 +2543,7 @@ def verify_ip_pim_join(tgen, topo, dut, interface, group_addresses, src_address=
     * `interface`: interface name, from which PIM join would come
     * `group_addresses`: IGMP group address
     * `src_address`: Source address
+    * `expected` : expected results from API, by-default True
 
     Usage
     -----
@@ -2609,7 +2622,7 @@ def verify_ip_pim_join(tgen, topo, dut, interface, group_addresses, src_address=
 
 
 @retry(attempts=31, wait=2, return_is_dict=True)
-def verify_igmp_config(tgen, input_dict, stats_return=False):
+def verify_igmp_config(tgen, input_dict, stats_return=False, expected=True):
     """
     Verify igmp interface details, verifying following configs:
     timerQueryInterval
@@ -2623,6 +2636,7 @@ def verify_igmp_config(tgen, input_dict, stats_return=False):
     * `input_dict` : Input dict data, required to verify
                      timer
     * `stats_return`: If user wants API to return statistics
+    * `expected` : expected results from API, by-default True
 
     Usage
     -----
@@ -2898,7 +2912,7 @@ def verify_igmp_config(tgen, input_dict, stats_return=False):
 
 
 @retry(attempts=31, wait=2, return_is_str=True)
-def verify_pim_config(tgen, input_dict):
+def verify_pim_config(tgen, input_dict, expected=True):
     """
     Verify pim interface details, verifying following configs:
     drPriority
@@ -2912,6 +2926,7 @@ def verify_pim_config(tgen, input_dict):
     * `tgen`: topogen object
     * `input_dict` : Input dict data, required to verify
                      timer
+    * `expected` : expected results from API, by-default True
 
     Usage
     -----
@@ -3023,7 +3038,7 @@ def verify_pim_config(tgen, input_dict):
 
 
 @retry(attempts=21, wait=2, return_is_dict=True)
-def verify_multicast_traffic(tgen, input_dict, return_traffic=False):
+def verify_multicast_traffic(tgen, input_dict, return_traffic=False, expected=True):
     """
     Verify multicast traffic by running
     "show multicast traffic count json" cli
@@ -3034,6 +3049,8 @@ def verify_multicast_traffic(tgen, input_dict, return_traffic=False):
     * `input_dict(dict)`: defines DUT, what and for which interfaces
                           traffic needs to be verified
     * `return_traffic`: returns traffic stats
+    * `expected` : expected results from API, by-default True
+
     Usage
     -----
     input_dict = {
@@ -3264,7 +3281,7 @@ def get_refCount_for_mroute(tgen, dut, iif, src_address, group_addresses):
 
 
 @retry(attempts=21, wait=2, return_is_str=True)
-def verify_multicast_flag_state(tgen, dut, src_address, group_addresses, flag):
+def verify_multicast_flag_state(tgen, dut, src_address, group_addresses, flag, expected=True):
     """
     Verify flag state for mroutes and make sure (*, G)/(S, G) are having
     coorect flags by running "show ip mroute" cli
@@ -3276,6 +3293,7 @@ def verify_multicast_flag_state(tgen, dut, src_address, group_addresses, flag):
     * `src_address`: source address
     * `group_addresses`: IGMP group address
     * `flag`: flag state, needs to be verified
+    * `expected` : expected results from API, by-default True
 
     Usage
     -----
@@ -3358,7 +3376,7 @@ def verify_multicast_flag_state(tgen, dut, src_address, group_addresses, flag):
 
 
 @retry(attempts=21, wait=2, return_is_str=True)
-def verify_igmp_interface(tgen, topo, dut, igmp_iface, interface_ip):
+def verify_igmp_interface(tgen, topo, dut, igmp_iface, interface_ip, expected=True):
     """
     Verify all IGMP interface are up and running, config is verified
     using "show ip igmp interface" cli
@@ -3370,6 +3388,7 @@ def verify_igmp_interface(tgen, topo, dut, igmp_iface, interface_ip):
     * `dut` : device under test
     * `igmp_iface` : interface name
     * `interface_ip` : interface ip address
+    * `expected` : expected results from API, by-default True
 
     Usage
     -----
index 553f2bc6cf03758c45e8a9c021bf6e831ab31ebc..ade5933504ac1a554dadd16109538021acd2ff66 100644 (file)
@@ -222,6 +222,22 @@ class Topogen(object):
         self.peern += 1
         return self.gears[name]
 
+    def add_host(self, name, ip, defaultRoute):
+        """
+        Adds a new host to the topology. This function has the following
+        parameters:
+        * `ip`: the peer address (e.g. '1.2.3.4/24')
+        * `defaultRoute`: the peer default route (e.g. 'via 1.2.3.1')
+        """
+        if name is None:
+            name = "host{}".format(self.peern)
+        if name in self.gears:
+            raise KeyError("host already exists")
+
+        self.gears[name] = TopoHost(self, name, ip=ip, defaultRoute=defaultRoute)
+        self.peern += 1
+        return self.gears[name]
+
     def add_link(self, node1, node2, ifname1=None, ifname2=None):
         """
         Creates a connection between node1 and node2. The nodes can be the
@@ -641,6 +657,8 @@ class TopoRouter(TopoGear):
 
         # Try to find relevant old logfiles in /tmp and delete them
         map(os.remove, glob.glob("{}/{}/*.log".format(self.logdir, self.name)))
+        # Remove old valgrind files
+        map(os.remove, glob.glob("{}/{}.valgrind.*".format(self.logdir, self.name)))
         # Remove old core files
         map(os.remove, glob.glob("{}/{}/*.dmp".format(self.logdir, self.name)))
 
index 2a5bd173619cddab72e88598eebb8884d9d6dd9c..d1f60bfe0dbc1ce938ac0299ecfd40131956fa8b 100644 (file)
@@ -1454,6 +1454,8 @@ class Router(Node):
         gdb_breakpoints = g_extra_config["gdb_breakpoints"]
         gdb_daemons = g_extra_config["gdb_daemons"]
         gdb_routers = g_extra_config["gdb_routers"]
+        valgrind_extra = g_extra_config["valgrind_extra"]
+        valgrind_memleaks = g_extra_config["valgrind_memleaks"]
 
         bundle_data = ""
 
@@ -1503,7 +1505,14 @@ class Router(Node):
                 ) + "/var/run/{}/snmpd.pid -x /etc/frr/agentx".format(self.routertype)
             else:
                 binary = os.path.join(self.daemondir, daemon)
+
                 cmdenv = "ASAN_OPTIONS=log_path={0}.asan".format(daemon)
+                if valgrind_memleaks:
+                    this_dir = os.path.dirname(os.path.abspath(os.path.realpath(__file__)))
+                    supp_file = os.path.abspath(os.path.join(this_dir, "../../../tools/valgrind.supp"))
+                    cmdenv += " /usr/bin/valgrind --num-callers=50 --log-file={1}/{2}.valgrind.{0}.%p --leak-check=full --suppressions={3}".format(daemon, self.logdir, self.name, supp_file)
+                    if valgrind_extra:
+                        cmdenv += "--gen-suppressions=all --expensive-definedness-checks=yes"
                 cmdopt = "{} --log file:{}.log --log-level debug".format(
                     daemon_opts, daemon
                 )
diff --git a/tests/topotests/msdp_mesh_topo1/__init__.py b/tests/topotests/msdp_mesh_topo1/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/topotests/msdp_mesh_topo1/r1/bgpd.conf b/tests/topotests/msdp_mesh_topo1/r1/bgpd.conf
new file mode 100644 (file)
index 0000000..953d90a
--- /dev/null
@@ -0,0 +1,7 @@
+router bgp 65000
+ neighbor 10.254.254.2 remote-as 65000
+ neighbor 10.254.254.2 update-source 10.254.254.1
+ address-family ipv4 unicast
+  redistribute connected
+ exit-address-family
+!
diff --git a/tests/topotests/msdp_mesh_topo1/r1/ospfd.conf b/tests/topotests/msdp_mesh_topo1/r1/ospfd.conf
new file mode 100644 (file)
index 0000000..c1adbd5
--- /dev/null
@@ -0,0 +1,8 @@
+interface r1-eth0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
+router ospf
+ network 192.168.1.0/24 area 0.0.0.0
+ redistribute connected
+!
diff --git a/tests/topotests/msdp_mesh_topo1/r1/pimd.conf b/tests/topotests/msdp_mesh_topo1/r1/pimd.conf
new file mode 100644 (file)
index 0000000..49341ef
--- /dev/null
@@ -0,0 +1,15 @@
+interface lo
+ ip pim
+ ip pim use-source 10.254.254.1
+!
+interface r1-eth0
+ ip pim
+!
+interface r1-eth1
+ ip pim
+ ip igmp
+!
+ip pim rp 10.254.254.1
+ip msdp mesh-group mg-1 source 10.254.254.1
+ip msdp mesh-group mg-1 member 10.254.254.2
+ip msdp mesh-group mg-1 member 10.254.254.3
diff --git a/tests/topotests/msdp_mesh_topo1/r1/zebra.conf b/tests/topotests/msdp_mesh_topo1/r1/zebra.conf
new file mode 100644 (file)
index 0000000..42c850f
--- /dev/null
@@ -0,0 +1,11 @@
+ip forwarding
+!
+interface lo
+ ip address 10.254.254.1/32
+!
+interface r1-eth0
+ ip address 192.168.1.2/24
+!
+interface r1-eth1
+ ip address 192.168.10.1/24
+!
diff --git a/tests/topotests/msdp_mesh_topo1/r2/bgpd.conf b/tests/topotests/msdp_mesh_topo1/r2/bgpd.conf
new file mode 100644 (file)
index 0000000..f442efc
--- /dev/null
@@ -0,0 +1,10 @@
+router bgp 65000
+ neighbor pg-1 peer-group
+ neighbor pg-1 update-source 10.254.254.1
+ neighbor pg-1 remote-as 65000
+ neighbor 10.254.254.1 peer-group pg-1
+ neighbor 10.254.254.3 peer-group pg-1
+ address-family ipv4 unicast
+  redistribute connected
+ exit-address-family
+!
diff --git a/tests/topotests/msdp_mesh_topo1/r2/ospfd.conf b/tests/topotests/msdp_mesh_topo1/r2/ospfd.conf
new file mode 100644 (file)
index 0000000..9e9ac5f
--- /dev/null
@@ -0,0 +1,13 @@
+interface r2-eth0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
+interface r2-eth1
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
+router ospf
+ network 192.168.1.0/24 area 0.0.0.0
+ network 192.168.2.0/24 area 0.0.0.0
+ redistribute connected
+!
diff --git a/tests/topotests/msdp_mesh_topo1/r2/pimd.conf b/tests/topotests/msdp_mesh_topo1/r2/pimd.conf
new file mode 100644 (file)
index 0000000..9005263
--- /dev/null
@@ -0,0 +1,14 @@
+interface lo
+ ip pim
+ ip pim use-source 10.254.254.2
+!
+interface r2-eth0
+ ip pim
+!
+interface r2-eth1
+ ip pim
+!
+ip pim rp 10.254.254.2
+ip msdp mesh-group mg-1 source 10.254.254.2
+ip msdp mesh-group mg-1 member 10.254.254.1
+ip msdp mesh-group mg-1 member 10.254.254.3
diff --git a/tests/topotests/msdp_mesh_topo1/r2/zebra.conf b/tests/topotests/msdp_mesh_topo1/r2/zebra.conf
new file mode 100644 (file)
index 0000000..6b26194
--- /dev/null
@@ -0,0 +1,11 @@
+ip forwarding
+!
+interface lo
+ ip address 10.254.254.2/32
+!
+interface r2-eth0
+ ip address 192.168.1.1/24
+!
+interface r2-eth1
+ ip address 192.168.2.1/24
+!
diff --git a/tests/topotests/msdp_mesh_topo1/r3/bgpd.conf b/tests/topotests/msdp_mesh_topo1/r3/bgpd.conf
new file mode 100644 (file)
index 0000000..6c3f89a
--- /dev/null
@@ -0,0 +1,7 @@
+router bgp 65000
+ neighbor 192.168.2.1 remote-as 65000
+ neighbor 192.168.2.1 update-source 10.254.254.3
+ address-family ipv4 unicast
+  redistribute connected
+ exit-address-family
+!
diff --git a/tests/topotests/msdp_mesh_topo1/r3/ospfd.conf b/tests/topotests/msdp_mesh_topo1/r3/ospfd.conf
new file mode 100644 (file)
index 0000000..7b7b1ab
--- /dev/null
@@ -0,0 +1,8 @@
+interface r3-eth0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 10
+!
+router ospf
+ network 192.168.2.0/24 area 0.0.0.0
+ redistribute connected
+!
diff --git a/tests/topotests/msdp_mesh_topo1/r3/pimd.conf b/tests/topotests/msdp_mesh_topo1/r3/pimd.conf
new file mode 100644 (file)
index 0000000..30e1148
--- /dev/null
@@ -0,0 +1,15 @@
+interface lo
+ ip pim
+ ip pim use-source 10.254.254.3
+!
+interface r3-eth0
+ ip pim
+!
+interface r3-eth1
+ ip pim
+ ip igmp
+!
+ip pim rp 10.254.254.3
+ip msdp mesh-group mg-1 source 10.254.254.3
+ip msdp mesh-group mg-1 member 10.254.254.1
+ip msdp mesh-group mg-1 member 10.254.254.2
diff --git a/tests/topotests/msdp_mesh_topo1/r3/zebra.conf b/tests/topotests/msdp_mesh_topo1/r3/zebra.conf
new file mode 100644 (file)
index 0000000..a8a15f3
--- /dev/null
@@ -0,0 +1,11 @@
+ip forwarding
+!
+interface lo
+ ip address 10.254.254.3/32
+!
+interface r3-eth0
+ ip address 192.168.2.2/24
+!
+interface r3-eth1
+ ip address 192.168.30.1/24
+!
diff --git a/tests/topotests/msdp_mesh_topo1/test_msdp_mesh_topo1.dot b/tests/topotests/msdp_mesh_topo1/test_msdp_mesh_topo1.dot
new file mode 100644 (file)
index 0000000..8792e2c
--- /dev/null
@@ -0,0 +1,88 @@
+## 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="msdp_mesh_topo1";
+
+  # Routers
+  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,
+  ];
+  h1 [
+    shape=doubleoctagon
+    label="h1",
+    fillcolor="#4f4f4f",
+    style=filled,
+  ];
+  h2 [
+    shape=doubleoctagon
+    label="h2",
+    fillcolor="#4f4f4f",
+    style=filled,
+  ];
+
+  # Switches
+  s1 [
+    shape=oval,
+    label="sw1\n192.168.1.0/24",
+    fillcolor="#d0e0d0",
+    style=filled,
+  ];
+  s2 [
+    shape=oval,
+    label="sw2\n192.168.2.0/24",
+    fillcolor="#d0e0d0",
+    style=filled,
+  ];
+  s3 [
+    shape=oval,
+    label="sw3\n192.168.10.0/24",
+    fillcolor="#d0e0d0",
+    style=filled,
+  ];
+  s4 [
+    shape=oval,
+    label="sw3\n192.168.30.0/24",
+    fillcolor="#d0e0d0",
+    style=filled,
+  ];
+
+  # Connections
+  r1 -- s1 [label="eth0\n.2"];
+  r2 -- s1 [label="eth0\n.1"];
+
+  r2 -- s2 [label="eth1\n.1"];
+  r3 -- s2 [label="eth0\n.2"];
+
+  r1 -- s3 [label="eth1\n.1"];
+  h1 -- s3 [label="eth0\n.2"];
+
+  r3 -- s4 [label="eth1\n.1"];
+  h2 -- s4 [label="eth0\n.2"];
+}
diff --git a/tests/topotests/msdp_mesh_topo1/test_msdp_mesh_topo1.png b/tests/topotests/msdp_mesh_topo1/test_msdp_mesh_topo1.png
new file mode 100644 (file)
index 0000000..9a15b8b
Binary files /dev/null and b/tests/topotests/msdp_mesh_topo1/test_msdp_mesh_topo1.png differ
diff --git a/tests/topotests/msdp_mesh_topo1/test_msdp_mesh_topo1.py b/tests/topotests/msdp_mesh_topo1/test_msdp_mesh_topo1.py
new file mode 100644 (file)
index 0000000..719ead0
--- /dev/null
@@ -0,0 +1,296 @@
+#!/usr/bin/env python
+
+#
+# test_msdp_mesh_topo1.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (C) 2021 by
+# Network Device Education Foundation, Inc. ("NetDEF")
+#
+# 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_msdp_mesh_topo1.py: Test the FRR PIM MSDP mesh groups.
+"""
+
+import os
+import sys
+import json
+from functools import partial
+import pytest
+import socket
+
+# 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
+
+pytestmark = [pytest.mark.bgpd, pytest.mark.ospfd, pytest.mark.pimd]
+
+#
+# Test global variables:
+# They are used to handle communicating with external application.
+#
+APP_SOCK_PATH = '/tmp/topotests/apps.sock'
+HELPER_APP_PATH = os.path.join(CWD, "../lib/mcast-tester.py")
+app_listener = None
+app_clients = {}
+
+def listen_to_applications():
+    "Start listening socket to connect with applications."
+    # Remove old socket.
+    try:
+        os.unlink(APP_SOCK_PATH)
+    except OSError:
+        pass
+
+    sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM, 0)
+    sock.bind(APP_SOCK_PATH)
+    sock.listen(10)
+    global app_listener
+    app_listener = sock
+
+def accept_host(host):
+    "Accept connection from application running in hosts."
+    global app_listener, app_clients
+    conn = app_listener.accept()
+    app_clients[host] = {
+        'fd': conn[0],
+        'address': conn[1]
+    }
+
+def close_applications():
+    "Signal applications to stop and close all sockets."
+    global app_listener, app_clients
+
+    # Close listening socket.
+    app_listener.close()
+
+    # Remove old socket.
+    try:
+        os.unlink(APP_SOCK_PATH)
+    except OSError:
+        pass
+
+    # Close all host connections.
+    for host in ["h1", "h2"]:
+        if app_clients.get(host) is None:
+            continue
+        app_clients["h1"]["fd"].close()
+
+
+class MSDPMeshTopo1(Topo):
+    "Test topology builder"
+
+    def build(self, *_args, **_opts):
+        "Build function"
+        tgen = get_topogen(self)
+
+        # Create 3 routers
+        for routern in range(1, 4):
+            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"])
+
+        # Create stub networks for multicast traffic.
+        tgen.add_host("h1", "192.168.10.2/24", "192.168.10.1")
+        switch = tgen.add_switch("s3")
+        switch.add_link(tgen.gears["r1"])
+        switch.add_link(tgen.gears["h1"])
+
+        tgen.add_host("h2", "192.168.30.2/24", "192.168.30.1")
+        switch = tgen.add_switch("s4")
+        switch.add_link(tgen.gears["r3"])
+        switch.add_link(tgen.gears["h2"])
+
+
+def setup_module(mod):
+    "Sets up the pytest environment"
+    tgen = Topogen(MSDPMeshTopo1, mod.__name__)
+    tgen.start_topology()
+
+    router_list = tgen.routers()
+    for rname, router in router_list.items():
+        daemon_file = "{}/{}/zebra.conf".format(CWD, rname)
+        if os.path.isfile(daemon_file):
+            router.load_config(TopoRouter.RD_ZEBRA, daemon_file)
+
+        daemon_file = "{}/{}/bgpd.conf".format(CWD, rname)
+        if os.path.isfile(daemon_file):
+            router.load_config(TopoRouter.RD_BGP, daemon_file)
+
+        daemon_file = "{}/{}/ospfd.conf".format(CWD, rname)
+        if os.path.isfile(daemon_file):
+            router.load_config(TopoRouter.RD_OSPF, daemon_file)
+
+        daemon_file = "{}/{}/pimd.conf".format(CWD, rname)
+        if os.path.isfile(daemon_file):
+            router.load_config(TopoRouter.RD_PIM, daemon_file)
+
+    # Initialize all routers.
+    tgen.start_router()
+
+    # Start applications socket.
+    listen_to_applications()
+
+
+def test_wait_ospf_convergence():
+    "Wait for OSPF to converge"
+    tgen = get_topogen()
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    logger.info("waiting for protocols to converge")
+
+    def expect_loopback_route(router, iptype, route, proto):
+        "Wait until route is present on RIB for protocol."
+        logger.info("waiting route {} in {}".format(route, router))
+        test_func = partial(
+            topotest.router_json_cmp,
+            tgen.gears[router],
+            "show {} route json".format(iptype),
+            {route: [{"protocol": proto}]}
+        )
+        _, result = topotest.run_and_expect(test_func, None, count=40, wait=1)
+        assertmsg = '"{}" OSPF convergence failure'.format(router)
+        assert result is None, assertmsg
+
+    # Wait for R1 <-> R2 convergence.
+    expect_loopback_route("r1", "ip", "10.254.254.2/32", "ospf")
+    # Wait for R1 <-> R3 convergence.
+    expect_loopback_route("r1", "ip", "10.254.254.3/32", "ospf")
+
+    # Wait for R2 <-> R1 convergence.
+    expect_loopback_route("r2", "ip", "10.254.254.1/32", "ospf")
+    # Wait for R2 <-> R3 convergence.
+    expect_loopback_route("r2", "ip", "10.254.254.3/32", "ospf")
+
+    # Wait for R3 <-> R1 convergence.
+    expect_loopback_route("r3", "ip", "10.254.254.1/32", "ospf")
+    # Wait for R3 <-> R2 convergence.
+    expect_loopback_route("r3", "ip", "10.254.254.2/32", "ospf")
+
+
+def test_wait_msdp_convergence():
+    "Wait for MSDP to converge"
+    tgen = get_topogen()
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    logger.info("test MSDP convergence")
+
+    tgen.gears["h1"].run("{} --send='0.7' '{}' '{}' '{}' &".format(
+        HELPER_APP_PATH, APP_SOCK_PATH, '229.0.1.10', 'h1-eth0'))
+    accept_host("h1")
+
+    tgen.gears["h2"].run("{} '{}' '{}' '{}' &".format(
+        HELPER_APP_PATH, APP_SOCK_PATH, '229.0.1.10', 'h2-eth0'))
+    accept_host("h2")
+
+    def expect_msdp_peer(router, peer, sa_count=0):
+        "Expect MSDP peer connection to be established with SA amount."
+        logger.info("waiting MSDP connection from peer {} on router {}".format(peer, router))
+        test_func = partial(
+            topotest.router_json_cmp,
+            tgen.gears[router],
+            "show ip msdp peer json",
+            {peer: {"state": "established", "saCount": sa_count}}
+        )
+        _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+        assertmsg = '"{}" MSDP connection failure'.format(router)
+        assert result is None, assertmsg
+
+    # R1 peers.
+    expect_msdp_peer("r1", "10.254.254.2")
+    expect_msdp_peer("r1", "10.254.254.3")
+
+    # R2 peers.
+    expect_msdp_peer("r2", "10.254.254.1", 1)
+    expect_msdp_peer("r2", "10.254.254.3")
+
+    # R3 peers.
+    expect_msdp_peer("r3", "10.254.254.1", 1)
+    expect_msdp_peer("r3", "10.254.254.2")
+
+
+def test_msdp_sa_configuration():
+    "Expect the multicast traffic SA to be created"
+    tgen = get_topogen()
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    logger.info("test MSDP SA")
+
+    def expect_msdp_sa(router, source, group, local, rp, spt_setup):
+        "Expect MSDP SA."
+        logger.info("waiting MSDP SA on router {}".format(router))
+        test_func = partial(
+            topotest.router_json_cmp,
+            tgen.gears[router],
+            "show ip msdp sa json",
+            {group: {source: {"local": local, "rp": rp, "sptSetup": spt_setup}}}
+        )
+        _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+        assertmsg = '"{}" MSDP SA failure'.format(router)
+        assert result is None, assertmsg
+
+    source = "192.168.10.2"
+    group = "229.0.1.10"
+    rp = "10.254.254.1"
+
+    # R1 SA.
+    expect_msdp_sa("r1", source, group, "yes", "-", "-")
+
+    # R2 SA.
+    expect_msdp_sa("r2", source, group, "no", rp, "no")
+
+    # R3 peers.
+    expect_msdp_sa("r3", source, group, "no", rp, "yes")
+
+
+def teardown_module(_mod):
+    "Teardown the pytest environment"
+    tgen = get_topogen()
+    close_applications()
+    tgen.stop_topology()
+
+
+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))
index a2ddf7c5ae154cc6b1ee7979607d39f46f811a17..96489b07562f29546f9483b10b8ae52d87164750 100644 (file)
@@ -4,6 +4,6 @@ O>* fc00:3:3:3::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX
 O>* fc00:4:4:4::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX
 O   fc00:a:a:a::/64 [110/10] is directly connected, r1-sw5, weight 1, XX:XX:XX
 O>* fc00:b:b:b::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX
-O>* fc00:2222:2222:2222::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX
-O>* fc00:3333:3333:3333::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX
+O>* fc00:2222:2222:2222::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX
+O>* fc00:3333:3333:3333::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX
 O>* fc00:4444:4444:4444::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX
index 1f642b1b2234d12f243953d1ab1c2c1ad864b182..78c1ad883061424f3866e758f5abbb5f5fdcd126 100644 (file)
@@ -4,7 +4,7 @@ O>* fc00:3:3:3::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX
 O>* fc00:4:4:4::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX
 O   fc00:a:a:a::/64 [110/10] is directly connected, r2-sw5, weight 1, XX:XX:XX
 O>* fc00:b:b:b::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX
-O>* fc00:1111:1111:1111::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX
-O>* fc00:3333:3333:3333::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX
+O>* fc00:1111:1111:1111::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX
+O>* fc00:3333:3333:3333::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX
 O>* fc00:4444:4444:4444::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX
 
index 8e3afa583ab82c0313664fb744f1adfe635c6343..dc0acbe0c5dc01b0be53618cd7efb083a8eb18a6 100644 (file)
@@ -4,7 +4,7 @@ O   fc00:3:3:3::/64 [110/10] is directly connected, r3-stubnet, weight 1, XX:XX:
 O>* fc00:4:4:4::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw6, weight 1, XX:XX:XX
 O   fc00:a:a:a::/64 [110/10] is directly connected, r3-sw5, weight 1, XX:XX:XX
 O   fc00:b:b:b::/64 [110/10] is directly connected, r3-sw6, weight 1, XX:XX:XX
-O>* fc00:1111:1111:1111::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5, weight 1, XX:XX:XX
-O>* fc00:2222:2222:2222::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5, weight 1, XX:XX:XX
-O>* fc00:4444:4444:4444::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw6, weight 1, XX:XX:XX
+O>* fc00:1111:1111:1111::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5, weight 1, XX:XX:XX
+O>* fc00:2222:2222:2222::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5, weight 1, XX:XX:XX
+O>* fc00:4444:4444:4444::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw6, weight 1, XX:XX:XX
 
index 0df652ffb31d2ee1aea3e58fb991bc284abb383b..730fd9f2d5956dea10e28d2afc7b08885a078c74 100644 (file)
@@ -6,4 +6,4 @@ O>* fc00:a:a:a::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, weight 1, XX
 O   fc00:b:b:b::/64 [110/10] is directly connected, r4-sw6, weight 1, XX:XX:XX
 O>* fc00:1111:1111:1111::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, weight 1, XX:XX:XX
 O>* fc00:2222:2222:2222::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, weight 1, XX:XX:XX
-O>* fc00:3333:3333:3333::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, weight 1, XX:XX:XX
+O>* fc00:3333:3333:3333::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, weight 1, XX:XX:XX
index f8c3476e18ff37cc5a235a473e9ad2e33c56d194..bbd18a57ff4adb6d12b77339007735cbf78abd13 100644 (file)
@@ -360,6 +360,36 @@ def test_linux_ipv6_kernel_routingTable():
             )
 
 
+def test_ospfv3_routingTable_write_multiplier():
+
+    tgen = get_topogen()
+    if tgen.routers_have_failure():
+        pytest.skip("skipped because of router(s) failure")
+
+    # For debugging, uncomment the next line
+    # tgen.mininet_cli()
+
+    # Modify R1 write muliplier and reset the interfaces
+    r1 = tgen.gears["r1"]
+
+    r1.vtysh_cmd("conf t\nrouter ospf6\n write-multiplier 100")
+    r1.vtysh_cmd("clear ipv6 ospf interface r1-stubnet")
+    r1.vtysh_cmd("clear ipv6 ospf interface r1-sw5")
+
+    # Verify OSPFv3 Routing Table
+    for router, rnode in tgen.routers().items():
+        logger.info('Waiting for router "%s" convergence', router)
+
+        # Load expected results from the command
+        reffile = os.path.join(CWD, "{}/show_ipv6_route.ref".format(router))
+        expected = open(reffile).read()
+
+        # Run test function until we get an result. Wait at most 60 seconds.
+        test_func = partial(compare_show_ipv6, router, expected)
+        result, diff = topotest.run_and_expect(test_func, "", count=120, wait=0.5)
+        assert result, "OSPFv3 did not converge on {}:\n{}".format(router, diff)
+
+
 def test_shutdown_check_stderr():
 
     tgen = get_topogen()
index 3ed0b8fbe2bdc590a27da9cde005d354fe3eb213..18bca5c54f6bfd1bfe066854e00566f2ec18d4b1 100644 (file)
@@ -54,10 +54,12 @@ Simplified `R1` config (R1 is similar)
        hostname r1
        !
        interface r1-stubnet vrf r1-cust1
+        ipv6 ospf6 area 0.0.0.0
         ipv6 address fc00:1:1:1::1/64
         ipv6 ospf6 network broadcast
        !
        interface r1-sw5 vrf r1-cust1
+        ipv6 ospf6 area 0.0.0.0
         ipv6 address fc00:a:a:a::1/64
         ipv6 ospf6 network broadcast
        !
@@ -65,8 +67,6 @@ Simplified `R1` config (R1 is similar)
         router-id 10.0.0.1
         log-adjacency-changes detail
         redistribute static
-        interface r1-stubnet area 0.0.0.0
-        interface r1-sw5 area 0.0.0.0
        !
        ipv6 route fc00:1111:1111:1111::/64 fc00:1:1:1::1234 vrf r1-cust1
 
@@ -75,14 +75,17 @@ Simplified `R3` config
        hostname r3
        !
        interface r3-stubnet vrf r3-cust1
+        ipv6 ospf6 area 0.0.0.0
         ipv6 address fc00:3:3:3::3/64
         ipv6 ospf6 network broadcast
        !
        interface r3-sw5 vrf r3-cust1
+        ipv6 ospf6 area 0.0.0.0
         ipv6 address fc00:a:a:a::3/64
         ipv6 ospf6 network broadcast
        !
        interface r3-sw6 vrf r3-cust1
+        ipv6 ospf6 area 0.0.0.1
         ipv6 address fc00:b:b:b::3/64
         ipv6 ospf6 network broadcast
        !
@@ -90,9 +93,6 @@ Simplified `R3` config
         router-id 10.0.0.3
         log-adjacency-changes detail
         redistribute static
-        interface r3-stubnet area 0.0.0.0
-        interface r3-sw5 area 0.0.0.0
-        interface r3-sw6 area 0.0.0.1
        !
        ipv6 route fc00:3333:3333:3333::/64 fc00:3:3:3::1234 vrf r3-cust1
 
index ed480354e4d35bac289d2667f509355ce3109b7f..83bdfb7c81f538d85e140fb1cd450ed7dcababa2 100644 (file)
@@ -9,12 +9,14 @@ debug ospf6 neighbor
 debug ospf6 route table
 debug ospf6 flooding
 !
-interface r1-stubnet vrf r1-cust1
+interface r1-stubnet
+ ipv6 ospf6 area 0.0.0.0
  ipv6 ospf6 network broadcast
  ipv6 ospf6 hello-interval 2
  ipv6 ospf6 dead-interval 10
 !
-interface r1-sw5 vrf r1-cust1
+interface r1-sw5
+ ipv6 ospf6 area 0.0.0.0
  ipv6 ospf6 network broadcast
  ipv6 ospf6 hello-interval 2
  ipv6 ospf6 dead-interval 10
@@ -23,8 +25,6 @@ router ospf6 vrf r1-cust1
  ospf6 router-id 10.0.0.1
  log-adjacency-changes detail
  redistribute static
- interface r1-stubnet area 0.0.0.0
- interface r1-sw5 area 0.0.0.0
 !
 line vty
  exec-timeout 0 0
index a2ddf7c5ae154cc6b1ee7979607d39f46f811a17..96489b07562f29546f9483b10b8ae52d87164750 100644 (file)
@@ -4,6 +4,6 @@ O>* fc00:3:3:3::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX
 O>* fc00:4:4:4::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX
 O   fc00:a:a:a::/64 [110/10] is directly connected, r1-sw5, weight 1, XX:XX:XX
 O>* fc00:b:b:b::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX
-O>* fc00:2222:2222:2222::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX
-O>* fc00:3333:3333:3333::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX
+O>* fc00:2222:2222:2222::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX
+O>* fc00:3333:3333:3333::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX
 O>* fc00:4444:4444:4444::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, weight 1, XX:XX:XX
index 485771e7d54512ad9d3b14d5bf7480e452d3e8c5..7fd01aa0ccf33b6f45b89f7cf6d34c0e4e5558c5 100644 (file)
@@ -9,12 +9,14 @@ debug ospf6 neighbor
 debug ospf6 route table
 debug ospf6 flooding
 !
-interface r2-stubnet vrf r2-cust1
+interface r2-stubnet
+ ipv6 ospf6 area 0.0.0.0
  ipv6 ospf6 network broadcast
  ipv6 ospf6 dead-interval 10
  ipv6 ospf6 hello-interval 2
 !
-interface r2-sw5 vrf r2-cust1
+interface r2-sw5
+ ipv6 ospf6 area 0.0.0.0
  ipv6 ospf6 network broadcast
  ipv6 ospf6 dead-interval 10
  ipv6 ospf6 hello-interval 2
@@ -23,8 +25,6 @@ router ospf6 vrf r2-cust1
  ospf6 router-id 10.0.0.2
  log-adjacency-changes detail
  redistribute static
- interface r2-stubnet area 0.0.0.0
- interface r2-sw5 area 0.0.0.0
 !
 line vty
  exec-timeout 0 0
index 328961941464960f15022cc62a73110b20a19a66..4c390f7cd645498a902583113d71e6374ff94eaa 100644 (file)
@@ -4,6 +4,6 @@ O>* fc00:3:3:3::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX
 O>* fc00:4:4:4::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX
 O   fc00:a:a:a::/64 [110/10] is directly connected, r2-sw5, weight 1, XX:XX:XX
 O>* fc00:b:b:b::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX
-O>* fc00:1111:1111:1111::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX
-O>* fc00:3333:3333:3333::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX
+O>* fc00:1111:1111:1111::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX
+O>* fc00:3333:3333:3333::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX
 O>* fc00:4444:4444:4444::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, weight 1, XX:XX:XX
index f5837bf6fd5d2fa98f8d0553cc7cc221aeed4965..df5aed3a6a4357e2d0fa3372dde015aee6281853 100644 (file)
@@ -9,17 +9,20 @@ debug ospf6 neighbor
 debug ospf6 route table
 debug ospf6 flooding
 !
-interface r3-stubnet vrf r3-cust1 
+interface r3-stubnet
+ ipv6 ospf6 area 0.0.0.0
  ipv6 ospf6 network broadcast
  ipv6 ospf6 dead-interval 10
  ipv6 ospf6 hello-interval 2
 !
-interface r3-sw5 vrf r3-cust1
+interface r3-sw5
+ ipv6 ospf6 area 0.0.0.0
  ipv6 ospf6 network broadcast
  ipv6 ospf6 dead-interval 10
  ipv6 ospf6 hello-interval 2
 !
-interface r3-sw6 vrf r3-cust1
+interface r3-sw6
+ ipv6 ospf6 area 0.0.0.1
  ipv6 ospf6 network broadcast
  ipv6 ospf6 dead-interval 10
  ipv6 ospf6 hello-interval 2
@@ -28,9 +31,6 @@ router ospf6 vrf r3-cust1
  ospf6 router-id 10.0.0.3
  log-adjacency-changes detail
  redistribute static
- interface r3-stubnet area 0.0.0.0
- interface r3-sw5 area 0.0.0.0
- interface r3-sw6 area 0.0.0.1
 !
 line vty
  exec-timeout 0 0
index ac713190ff107698e3f2c32b242e7b20bfa16219..989213f963b5d40243bfa882d6db3f10e39f846d 100644 (file)
@@ -4,6 +4,6 @@ O   fc00:3:3:3::/64 [110/10] is directly connected, r3-stubnet, weight 1, XX:XX:
 O>* fc00:4:4:4::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw6, weight 1, XX:XX:XX
 O   fc00:a:a:a::/64 [110/10] is directly connected, r3-sw5, weight 1, XX:XX:XX
 O   fc00:b:b:b::/64 [110/10] is directly connected, r3-sw6, weight 1, XX:XX:XX
-O>* fc00:1111:1111:1111::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5, weight 1, XX:XX:XX
-O>* fc00:2222:2222:2222::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5, weight 1, XX:XX:XX
-O>* fc00:4444:4444:4444::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw6, weight 1, XX:XX:XX
+O>* fc00:1111:1111:1111::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5, weight 1, XX:XX:XX
+O>* fc00:2222:2222:2222::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5, weight 1, XX:XX:XX
+O>* fc00:4444:4444:4444::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw6, weight 1, XX:XX:XX
index ab67d06ff4aec7f37fa0cdfdc6b01d80a89443a7..465defb40fd746f3a96811998f5488fa646588e0 100644 (file)
@@ -9,12 +9,14 @@ debug ospf6 neighbor
 debug ospf6 route table
 debug ospf6 flooding
 !
-interface r4-stubnet vrf r4-cust1 
+interface r4-stubnet
+ ipv6 ospf6 area 0.0.0.1
  ipv6 ospf6 network broadcast
  ipv6 ospf6 hello-interval 2
  ipv6 ospf6 dead-interval 10
 !
-interface r4-sw6 vrf r4-cust1
+interface r4-sw6
+ ipv6 ospf6 area 0.0.0.1
  ipv6 ospf6 network broadcast
  ipv6 ospf6 hello-interval 2
  ipv6 ospf6 dead-interval 10
@@ -23,8 +25,6 @@ router ospf6 vrf r4-cust1
  ospf6 router-id 10.0.0.4
  log-adjacency-changes detail
  redistribute static
- interface r4-stubnet area 0.0.0.1
- interface r4-sw6 area 0.0.0.1
 !
 line vty
  exec-timeout 0 0
index 0df652ffb31d2ee1aea3e58fb991bc284abb383b..730fd9f2d5956dea10e28d2afc7b08885a078c74 100644 (file)
@@ -6,4 +6,4 @@ O>* fc00:a:a:a::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, weight 1, XX
 O   fc00:b:b:b::/64 [110/10] is directly connected, r4-sw6, weight 1, XX:XX:XX
 O>* fc00:1111:1111:1111::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, weight 1, XX:XX:XX
 O>* fc00:2222:2222:2222::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, weight 1, XX:XX:XX
-O>* fc00:3333:3333:3333::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, weight 1, XX:XX:XX
+O>* fc00:3333:3333:3333::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, weight 1, XX:XX:XX
index e1857abc4f509da49371c7e9d102bc9dd8ab44be..b158099d9a7373073394e4c482294c89c26576ba 100755 (executable)
@@ -5,7 +5,7 @@
 # Part of NetDEF Topology Tests
 #
 # Copyright (c) 2021 by Niral Networks, Inc. ("Niral Networks")
-# Used Copyright (c) 2016 by Network Device Education Foundation, 
+# Used Copyright (c) 2016 by Network Device Education Foundation,
 # Inc. ("NetDEF") in this file.
 #
 # Permission to use, copy, modify, and/or distribute this software
@@ -179,13 +179,9 @@ def setup_module(mod):
         "ip link set {0}-stubnet master {0}-cust1",
     ]
 
-    cmds1 = [
-        "ip link set {0}-sw5 master {0}-cust1",
-    ]
+    cmds1 = ["ip link set {0}-sw5 master {0}-cust1"]
 
-    cmds2 = [
-        "ip link set {0}-sw6 master {0}-cust1",
-    ]
+    cmds2 = ["ip link set {0}-sw6 master {0}-cust1"]
 
     # For all registered routers, load the zebra configuration file
     for rname, router in tgen.routers().items():
@@ -219,6 +215,7 @@ def teardown_module(mod):
     tgen = get_topogen()
     tgen.stop_topology()
 
+
 def test_wait_protocol_convergence():
     "Wait for OSPFv3 to converge"
     tgen = get_topogen()
@@ -261,7 +258,7 @@ def compare_show_ipv6_vrf(rname, expected):
     # Use the vtysh output, with some masking to make comparison easy
     vrf_name = "{0}-cust1".format(rname)
     current = topotest.ip6_route_zebra(tgen.gears[rname], vrf_name)
-    
+
     # Use just the 'O'spf lines of the output
     linearr = []
     for line in current.splitlines():
@@ -331,7 +328,11 @@ def test_linux_ipv6_kernel_routingTable():
 
     for i in range(1, 5):
         # Actual output from router
-        actual = tgen.gears["r{}".format(i)].run("ip -6 route show vrf r{}-cust1".format(i)).rstrip()
+        actual = (
+            tgen.gears["r{}".format(i)]
+            .run("ip -6 route show vrf r{}-cust1".format(i))
+            .rstrip()
+        )
         if "nhid" in actual:
             refTableFile = os.path.join(CWD, "r{}/ip_6_address.nhg.ref".format(i))
         else:
@@ -362,9 +363,9 @@ def test_linux_ipv6_kernel_routingTable():
                     "unreachable fe80::/64 "
                 ):
                     continue
-                if 'anycast' in line:
+                if "anycast" in line:
                     continue
-                if 'multicast' in line:
+                if "multicast" in line:
                     continue
                 filtered_lines.append(line)
             actual = "\n".join(filtered_lines).splitlines(1)
@@ -398,6 +399,35 @@ def test_linux_ipv6_kernel_routingTable():
             )
 
 
+def test_ospfv3_routingTable_write_multiplier():
+
+    tgen = get_topogen()
+    if tgen.routers_have_failure():
+        pytest.skip("skipped because of router(s) failure")
+
+    # For debugging, uncomment the next line
+    # tgen.mininet_cli()
+    # Modify R1 write muliplier and reset the interfaces
+    r1 = tgen.gears["r1"]
+
+    r1.vtysh_cmd("conf t\nrouter ospf6 vrf r1-cust1 \n write-multiplier 100")
+    r1.vtysh_cmd("clear ipv6 ospf interface r1-stubnet")
+    r1.vtysh_cmd("clear ipv6 ospf interface r1-sw5")
+
+    # Verify OSPFv3 Routing Table
+    for router, rnode in tgen.routers().iteritems():
+        logger.info('Waiting for router "%s" convergence', router)
+
+        # Load expected results from the command
+        reffile = os.path.join(CWD, "{}/show_ipv6_vrf_route.ref".format(router))
+        expected = open(reffile).read()
+
+        # Run test function until we get an result. Wait at most 60 seconds.
+        test_func = partial(compare_show_ipv6_vrf, router, expected)
+        result, diff = topotest.run_and_expect(test_func, "", count=120, wait=0.5)
+        assert result, "OSPFv3 did not converge on {}:\n{}".format(router, diff)
+
+
 def test_shutdown_check_stderr():
 
     tgen = get_topogen()
index d4bb0e2a412b7b4ee06107e630ec96e851043e78..e88e965c78333f35cbb80d55273d138e2acb7ad6 100644 (file)
@@ -6,12 +6,18 @@ interface r2-eth1
  ipv6 ospf6 hello-interval 2
  ipv6 ospf6 dead-interval 10
 !
+interface r2-eth2
+ ipv6 ospf6 hello-interval 2
+ ipv6 ospf6 dead-interval 10
+!
 router ospf6
  ospf6 router-id 10.254.254.2
  redistribute connected
  redistribute static
  default-information originate always metric 123
  area 0.0.0.1 stub
+ area 0.0.0.2 nssa
  interface r2-eth0 area 0.0.0.1
  interface r2-eth1 area 0.0.0.0
+ interface r2-eth2 area 0.0.0.2
 !
index 891945a4e7eb6e95c62120fd33d4cc07954baa8e..559f502b0c69d7af813eace1663f67e3b02e1580 100644 (file)
@@ -6,3 +6,6 @@ interface r2-eth0
 interface r2-eth1
  ipv6 address 2001:db8:2::2/64
 !
+interface r2-eth2
+ ipv6 address 2001:db8:3::1/64
+!
diff --git a/tests/topotests/ospf6_topo2/r4/ospf6d.conf b/tests/topotests/ospf6_topo2/r4/ospf6d.conf
new file mode 100644 (file)
index 0000000..813c0ab
--- /dev/null
@@ -0,0 +1,9 @@
+interface r4-eth0
+ ipv6 ospf6 hello-interval 2
+ ipv6 ospf6 dead-interval 10
+!
+router ospf6
+ ospf6 router-id 10.254.254.4
+ area 0.0.0.2 nssa
+ interface r4-eth0 area 0.0.0.2
+!
diff --git a/tests/topotests/ospf6_topo2/r4/zebra.conf b/tests/topotests/ospf6_topo2/r4/zebra.conf
new file mode 100644 (file)
index 0000000..86cb972
--- /dev/null
@@ -0,0 +1,5 @@
+ipv6 forwarding
+!
+interface r4-eth0
+ ipv6 address 2001:db8:3::2/64
+!
index ba7a36f2b558e85c85532a39e9f7a73c61b7f6c4..238ec7a5a0030da96a31a7cb7fd7ec89aff79ecc 100644 (file)
@@ -34,6 +34,12 @@ graph template {
     fillcolor="#f08080",
     style=filled,
   ];
+  r4 [
+    shape=doubleoctagon
+    label="r4",
+    fillcolor="#f08080",
+    style=filled,
+  ];
 
   # Switches
   sw1 [
@@ -62,10 +68,16 @@ graph template {
   }
 
   subgraph cluster1 {
+    label="area 0.0.0.2";
+    r4 -- sw3 [label="eth0\n.2"];
+  }
+
+  subgraph cluster2 {
     label="area 0.0.0.0";
     r2 -- sw1 [label="eth0\n.1"];
     r2 -- sw2 [label="eth1\n.2"];
+    r2 -- sw3 [label="eth2\n.1"];
+
     r3 -- sw2 [label="eth0\n.1"];
-    r3 -- sw3 [label="eth1\n.2"];
   }
 }
index ee1de607368f251e0a653bb965b13c141b3edcd0..4e79559a60f803450775a174c91e8743d43127d3 100644 (file)
Binary files a/tests/topotests/ospf6_topo2/test_ospf6_topo2.png and b/tests/topotests/ospf6_topo2/test_ospf6_topo2.png differ
index efc8565bb3d925ad207e2aaee2c9420a50d23378..0fe5228ce63acf5b7d0fcecb4f97053cc0590d0b 100644 (file)
@@ -47,6 +47,49 @@ from mininet.topo import Topo
 pytestmark = [pytest.mark.ospf6d]
 
 
+def expect_lsas(router, area, lsas, wait=5, extra_params=""):
+    """
+    Run the OSPFv3 show LSA database command and expect the supplied LSAs.
+
+    Optional parameters:
+     * `wait`: amount of seconds to wait.
+     * `extra_params`: extra LSA database parameters.
+     * `inverse`: assert the inverse of the expected.
+    """
+    tgen = get_topogen()
+
+    command = "show ipv6 ospf6 database {} json".format(extra_params)
+
+    logger.info("waiting OSPFv3 router '{}' LSA".format(router))
+    test_func = partial(
+        topotest.router_json_cmp,
+        tgen.gears[router],
+        command,
+        {"areaScopedLinkStateDb": [{"areaId": area, "lsa": lsas}]},
+    )
+    _, result = topotest.run_and_expect(test_func, None, count=wait, wait=1)
+    assertmsg = '"{}" convergence failure'.format(router)
+
+    assert result is None, assertmsg
+
+
+def expect_ospfv3_routes(router, routes, wait=5):
+    "Run command `ipv6 ospf6 route` and expect route with type."
+    tgen = get_topogen()
+
+    logger.info("waiting OSPFv3 router '{}' route".format(router))
+    test_func = partial(
+        topotest.router_json_cmp,
+        tgen.gears[router],
+        "show ipv6 ospf6 route json",
+        {"routes": routes}
+    )
+    _, result = topotest.run_and_expect(test_func, None, count=wait, wait=1)
+    assertmsg = '"{}" convergence failure'.format(router)
+
+    assert result is None, assertmsg
+
+
 class OSPFv3Topo2(Topo):
     "Test topology builder"
 
@@ -54,8 +97,8 @@ class OSPFv3Topo2(Topo):
         "Build function"
         tgen = get_topogen(self)
 
-        # Create 3 routers
-        for routern in range(1, 4):
+        # Create 4 routers
+        for routern in range(1, 5):
             tgen.add_router("r{}".format(routern))
 
         switch = tgen.add_switch("s1")
@@ -66,6 +109,10 @@ class OSPFv3Topo2(Topo):
         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"])
+
 
 def setup_module(mod):
     "Sets up the pytest environment"
@@ -110,7 +157,52 @@ def test_wait_protocol_convergence():
     expect_neighbor_full("r1", "10.254.254.2")
     expect_neighbor_full("r2", "10.254.254.1")
     expect_neighbor_full("r2", "10.254.254.3")
+    expect_neighbor_full("r2", "10.254.254.4")
     expect_neighbor_full("r3", "10.254.254.2")
+    expect_neighbor_full("r4", "10.254.254.2")
+
+
+def test_ospfv3_expected_route_types():
+    "Test routers route type to determine if NSSA/Stub is working as expected."
+    tgen = get_topogen()
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    logger.info("waiting for protocols to converge")
+
+    def expect_ospf6_route_types(router, expected_summary):
+        "Expect the correct route types."
+        logger.info("waiting OSPFv3 router '{}'".format(router))
+        test_func = partial(
+            topotest.router_json_cmp,
+            tgen.gears[router],
+            "show ipv6 ospf6 route summary json",
+            expected_summary,
+        )
+        _, result = topotest.run_and_expect(test_func, None, count=10, wait=1)
+        assertmsg = '"{}" convergence failure'.format(router)
+        assert result is None, assertmsg
+
+    # Stub router: no external routes.
+    expect_ospf6_route_types(
+        "r1",
+        {
+            "numberOfIntraAreaRoutes": 1,
+            "numberOfInterAreaRoutes": 3,
+            "numberOfExternal1Routes": 0,
+            "numberOfExternal2Routes": 0,
+        },
+    )
+    # NSSA router: no external routes.
+    expect_ospf6_route_types(
+        "r4",
+        {
+            "numberOfIntraAreaRoutes": 1,
+            "numberOfInterAreaRoutes": 2,
+            "numberOfExternal1Routes": 0,
+            "numberOfExternal2Routes": 0,
+        },
+    )
 
 
 def test_ospf6_default_route():
@@ -134,36 +226,96 @@ def test_ospf6_default_route():
         assertmsg = '"{}" convergence failure'.format(router)
         assert result is None, assertmsg
 
-    def expect_lsa(router, area, prefix, metric):
-        "Test OSPF6 LSA existence."
-        logger.info("waiting OSPFv3 router '{}' LSA".format(router))
-        test_func = partial(
-            topotest.router_json_cmp,
-            tgen.gears[router],
-            "show ipv6 ospf6 database inter-prefix detail json",
-            {
-                "areaScopedLinkStateDb": [
-                    {
-                        "areaId": area,
-                        "lsa": [
-                            {
-                                "prefix": prefix,
-                                "metric": metric,
-                            }
-                        ],
-                    }
-                ]
-            },
-        )
-        _, result = topotest.run_and_expect(test_func, None, count=4, wait=1)
-        assertmsg = '"{}" convergence failure'.format(router)
-        assert result is None, assertmsg
-
     metric = 123
-    expect_lsa("r1", "0.0.0.1", "::/0", metric)
+    expect_lsas(
+        "r1",
+        "0.0.0.1",
+        [{"prefix": "::/0", "metric": metric}],
+        extra_params="inter-prefix detail",
+    )
     expect_route("r1", "::/0", metric + 10)
 
 
+def test_nssa_lsa_type7():
+    """
+    Test that static route gets announced as external route when redistributed
+    and gets removed when redistribution stops.
+    """
+    tgen = get_topogen()
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    #
+    # Add new static route and check if it gets announced as LSA Type-7.
+    #
+    config = """
+    configure terminal
+    ipv6 route 2001:db8:100::/64 Null0
+    """
+    tgen.gears["r2"].vtysh_cmd(config)
+
+    lsas = [
+        {
+            "type": "NSSA",
+            "advertisingRouter": "10.254.254.2",
+            "prefix": "2001:db8:100::/64",
+            "forwardingAddress": "2001:db8:3::1",
+        }
+    ]
+    route = {
+        "2001:db8:100::/64": {
+            "pathType": "E1",
+            "nextHops": [
+                {"nextHop": "::", "interfaceName": "r4-eth0"}
+            ]
+        }
+    }
+
+    logger.info("Expecting LSA type-7 and OSPFv3 route 2001:db8:100::/64 to show up")
+    expect_lsas("r4", "0.0.0.2", lsas, wait=30, extra_params="type-7 detail")
+    expect_ospfv3_routes("r4", route, wait=30)
+
+    #
+    # Remove static route and check for LSA Type-7 removal.
+    #
+    config = """
+    configure terminal
+    no ipv6 route 2001:db8:100::/64 Null0
+    """
+    tgen.gears["r2"].vtysh_cmd(config)
+
+    def dont_expect_lsa(unexpected_lsa):
+        "Specialized test function to expect LSA go missing"
+        output = tgen.gears["r4"].vtysh_cmd("show ipv6 ospf6 database type-7 detail json", isjson=True)
+        for lsa in output['areaScopedLinkStateDb'][0]['lsa']:
+            if lsa["prefix"] == unexpected_lsa["prefix"]:
+                if lsa["forwardingAddress"] == unexpected_lsa["forwardingAddress"]:
+                    return lsa
+        return None
+
+    def dont_expect_route(unexpected_route):
+        "Specialized test function to expect route go missing"
+        output = tgen.gears["r4"].vtysh_cmd("show ipv6 ospf6 route json", isjson=True)
+        if output["routes"].has_key(unexpected_route):
+            return output["routes"][unexpected_route]
+        return None
+
+
+    logger.info("Expecting LSA type-7 and OSPFv3 route 2001:db8:100::/64 to go away")
+
+    # Test that LSA doesn't exist.
+    test_func = partial(dont_expect_lsa, lsas[0])
+    _, result = topotest.run_and_expect(test_func, None, count=130, wait=1)
+    assertmsg = '"{}" LSA still exists'.format("r4")
+    assert result is None, assertmsg
+
+    # Test that route doesn't exist.
+    test_func = partial(dont_expect_route, "2001:db8:100::/64")
+    _, result = topotest.run_and_expect(test_func, None, count=130, wait=1)
+    assertmsg = '"{}" route still exists'.format("r4")
+    assert result is None, assertmsg
+
+
 def teardown_module(_mod):
     "Teardown the pytest environment"
     tgen = get_topogen()
diff --git a/tests/topotests/ospf_basic_functionality/ospf_asbr_summary_topo1.json b/tests/topotests/ospf_basic_functionality/ospf_asbr_summary_topo1.json
new file mode 100644 (file)
index 0000000..1ddccb8
--- /dev/null
@@ -0,0 +1,195 @@
+{
+    "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"
+                    }
+                },
+                "r3-link0": {
+                    "ipv4": "auto",
+                    "description": "DummyIntftoR3"
+                }
+            },
+            "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"
+                    }
+                },
+                "r0-link0": {
+                    "ipv4": "auto",
+                    "description": "DummyIntftoR0"
+                },
+                "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": {}
+                }
+            }
+        }
+    }
+}
diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_asbr_summary_topo1.py b/tests/topotests/ospf_basic_functionality/test_ospf_asbr_summary_topo1.py
new file mode 100644 (file)
index 0000000..88b5497
--- /dev/null
@@ -0,0 +1,779 @@
+#!/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 Summarisation 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 ipaddress
+from time import sleep
+
+# Import topoJson from lib, to create topology and initial configuration
+from lib.common_config import (
+    start_topology,
+    write_test_header,
+    kill_router_daemons,
+    write_test_footer,
+    reset_config_on_routers,
+    stop_router,
+    start_router,
+    verify_rib,
+    create_static_routes,
+    step,
+    start_router_daemons,
+    create_route_maps,
+    shutdown_bringup_interface,
+    topo_daemons,
+    create_prefix_lists,
+    create_route_maps,
+    create_interfaces_cfg,
+)
+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_summary,
+)
+
+# Global variables
+topo = None
+# Reading the data from JSON File for topology creation
+jsonFile = "{}/ospf_asbr_summary_topo1.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",
+    ]
+}
+NETWORK_11 = {"ipv4": ["11.0.20.6/32", "11.0.20.7/32"]}
+
+NETWORK2 = {
+    "ipv4": [
+        "12.0.20.1/32",
+        "12.0.20.2/32",
+        "12.0.20.3/32",
+        "12.0.20.4/32",
+        "12.0.20.5/32",
+    ]
+}
+SUMMARY = {"ipv4": ["11.0.0.0/8", "12.0.0.0/8", "11.0.0.0/24"]}
+"""
+TOPOOLOGY =
+      Please view in a fixed-width font such as Courier.
+      +---+  A0       +---+
+      +R1 +------------+R2 |
+      +-+-+-           +--++
+        |  --        --  |
+        |    -- A0 --    |
+      A0|      ----      |
+        |      ----      | A0
+        |    --    --    |
+        |  --        --  |
+      +-+-+-            +-+-+
+      +R0 +-------------+R3 |
+      +---+     A0     +---+
+
+TESTCASES =
+1. OSPF summarisation functionality.
+2. OSPF summarisation with metric type 2.
+3. OSPF summarisation with Tag option
+4. OSPF summarisation with advertise and no advertise option
+5. OSPF summarisation Chaos.
+6. OSPF summarisation with route map filtering.
+7. OSPF summarisation with route map modification of metric type.
+8. OSPF CLI Show  verify ospf ASBR summary config and show commands behaviours.
+"""
+
+
+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.
+
+    Parameters
+    ----------
+    * `dut` : DUT on which configs have to be made.
+    * `config` : True or False, True by default for configure, set False for
+                 unconfiguration.
+    """
+    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
+
+    Parameters
+    ----------
+    * `dut` : DUT on which configs have to be made.
+    * `config` : True or False, True by default for configure, set False for
+                 unconfiguration.
+    """
+    global topo
+    tgen = get_topogen()
+    if config:
+        ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "connected"}]}}}
+    else:
+        ospf_red = {
+            dut: {
+                "ospf": {"redistribute": [{"redist_type": "connected", "delete": 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_type5_summary_tc43_p0(request):
+    """OSPF summarisation with metric type 2."""
+    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)
+
+    protocol = "ospf"
+
+    step(
+        "Configure 5 static routes from the same network on R0"
+        "5 static routes from different networks and redistribute in R0"
+    )
+    input_dict_static_rtes = {
+        "r0": {
+            "static_routes": [
+                {"network": NETWORK["ipv4"], "next_hop": "blackhole"},
+                {"network": NETWORK2["ipv4"], "next_hop": "blackhole"},
+            ]
+        }
+    }
+    result = create_static_routes(tgen, input_dict_static_rtes)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    dut = "r0"
+    red_static(dut)
+
+    step("Verify that routes are learnt on R1.")
+    dut = "r1"
+
+    result = verify_ospf_rib(tgen, dut, input_dict_static_rtes)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+    result = verify_rib(tgen, "ipv4", dut, input_dict_static_rtes, protocol=protocol)
+    assert (
+        result is True
+    ), "Testcase {} : Failed" "Error: Routes is missing in RIB".format(tc_name)
+
+    step(
+        "Configure External Route summary in R0 to summarise 5" " routes to one route."
+    )
+    ospf_summ_r1 = {
+        "r0": {
+            "ospf": {
+                "summary-address": [
+                    {"prefix": SUMMARY["ipv4"][0].split("/")[0], "mask": "8"}
+                ]
+            }
+        }
+    }
+    result = create_router_ospf(tgen, topo, ospf_summ_r1)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+    step(
+        "Verify that external routes are summarised to configured summary "
+        "address on R0 after 5 secs of delay timer expiry and only one "
+        "route is sent to R1."
+    )
+    input_dict_summary = {"r0": {"static_routes": [{"network": SUMMARY["ipv4"][0]}]}}
+    dut = "r1"
+
+    result = verify_ospf_rib(tgen, dut, input_dict_summary)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    result = verify_rib(tgen, "ipv4", dut, input_dict_summary, protocol=protocol)
+    assert (
+        result is True
+    ), "Testcase {} : Failed" "Error: Routes is missing in RIB".format(tc_name)
+
+    step("Verify that show ip ospf summary should show the summaries.")
+    input_dict = {
+        SUMMARY["ipv4"][0]: {
+            "Summary address": SUMMARY["ipv4"][0],
+            "Metric-type": "E2",
+            "Metric": 20,
+            "Tag": 0,
+            "External route count": 5,
+        }
+    }
+    dut = "r0"
+    result = verify_ospf_summary(tgen, topo, dut, input_dict)
+    assert (
+        result is True
+    ), "Testcase {} : Failed" "Error: Summary missing in OSPF DB".format(tc_name)
+
+    step("Change the summary address mask to lower match (ex - 16 to 8)")
+    ospf_summ_r1 = {
+        "r0": {
+            "ospf": {
+                "summary-address": [
+                    {"prefix": SUMMARY["ipv4"][0].split("/")[0], "mask": "16"}
+                ]
+            }
+        }
+    }
+    result = create_router_ospf(tgen, topo, ospf_summ_r1)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    input_dict = {
+        "11.0.0.0/16": {
+            "Summary address": "11.0.0.0/16",
+            "Metric-type": "E2",
+            "Metric": 20,
+            "Tag": 0,
+            "External route count": 5,
+        }
+    }
+    dut = "r0"
+    result = verify_ospf_summary(tgen, topo, dut, input_dict)
+    assert (
+        result is True
+    ), "Testcase {} : Failed" "Error: Summary missing in OSPF DB".format(tc_name)
+
+    step(
+        "Verify that external routes(static / connected) are summarised"
+        " to configured summary address with newly configured mask."
+    )
+
+    input_dict_summary = {"r0": {"static_routes": [{"network": "11.0.0.0/16"}]}}
+    dut = "r1"
+
+    result = verify_ospf_rib(tgen, dut, input_dict_summary)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    result = verify_rib(tgen, "ipv4", dut, input_dict_summary, protocol=protocol)
+    assert (
+        result is True
+    ), "Testcase {} : Failed" "Error: Routes is missing in RIB".format(tc_name)
+
+    step("Change the summary address mask to higher match (ex - 8 to 24)")
+    ospf_summ_r1 = {
+        "r0": {
+            "ospf": {
+                "summary-address": [
+                    {"prefix": SUMMARY["ipv4"][0].split("/")[0], "mask": "24"}
+                ]
+            }
+        }
+    }
+    result = create_router_ospf(tgen, topo, ospf_summ_r1)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    input_dict = {
+        "11.0.0.0/16": {
+            "Summary address": "11.0.0.0/24",
+            "Metric-type": "E2",
+            "Metric": 20,
+            "Tag": 0,
+            "External route count": 0,
+        }
+    }
+    dut = "r0"
+    result = verify_ospf_summary(tgen, topo, dut, input_dict)
+    assert (
+        result is True
+    ), "Testcase {} : Failed" "Error: Summary missing in OSPF DB".format(tc_name)
+
+    step(
+        "Verify that external routes(static / connected) are summarised"
+        " to configured summary address with newly configured mask."
+    )
+    step("Configure 2 summary address with different mask of same network.")
+    step(
+        "Verify that external routes(static / connected) are summarised "
+        "to configured summary address with highest match."
+    )
+
+    input_dict_summary = {"r0": {"static_routes": [{"network": "11.0.0.0/16"}]}}
+    dut = "r1"
+
+    result = verify_ospf_rib(tgen, dut, input_dict_summary)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    result = verify_rib(tgen, "ipv4", dut, input_dict_summary, protocol=protocol)
+    assert (
+        result is True
+    ), "Testcase {} : Failed" "Error: Routes is missing in RIB".format(tc_name)
+
+    step(" Un configure one of the summary address.")
+    ospf_summ_r1 = {
+        "r0": {
+            "ospf": {
+                "summary-address": [
+                    {
+                        "prefix": SUMMARY["ipv4"][0].split("/")[0],
+                        "mask": "24",
+                        "delete": True,
+                    }
+                ]
+            }
+        }
+    }
+    result = create_router_ospf(tgen, topo, ospf_summ_r1)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    step(
+        "Verify that external routes(static / connected) are summarised"
+        " to configured summary address with newly configured mask."
+    )
+
+    input_dict_summary = {"r0": {"static_routes": [{"network": "11.0.0.0/16"}]}}
+    dut = "r1"
+
+    result = verify_ospf_rib(tgen, dut, input_dict_summary)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    result = verify_rib(tgen, "ipv4", dut, input_dict_summary, protocol=protocol)
+    assert (
+        result is True
+    ), "Testcase {} : Failed" "Error: Routes is missing in RIB".format(tc_name)
+
+    ospf_summ_r1 = {
+        "r0": {
+            "ospf": {
+                "summary-address": [
+                    {"prefix": SUMMARY["ipv4"][0].split("/")[0], "mask": "24"}
+                ]
+            }
+        }
+    }
+    result = create_router_ospf(tgen, topo, ospf_summ_r1)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    step(
+        "Verify that external routes(static / connected) are summarised "
+        "to configured summary address with highest match."
+    )
+    input_dict_summary = {"r0": {"static_routes": [{"network": "11.0.0.0/16"}]}}
+    dut = "r1"
+
+    result = verify_ospf_rib(tgen, dut, input_dict_summary)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    result = verify_rib(tgen, "ipv4", dut, input_dict_summary, protocol=protocol)
+    assert (
+        result is True
+    ), "Testcase {} : Failed" "Error: Routes is missing in RIB".format(tc_name)
+
+    write_test_footer(tc_name)
+
+
+def test_ospf_type5_summary_tc48_p0(request):
+    """OSPF summarisation with route map modification of metric type."""
+    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)
+
+    protocol = "ospf"
+
+    step(
+        "Configure 5 static routes from the same network on R0"
+        "5 static routes from different networks and redistribute in R0"
+    )
+    input_dict_static_rtes = {
+        "r0": {
+            "static_routes": [
+                {"network": NETWORK["ipv4"], "next_hop": "blackhole"},
+                {"network": NETWORK2["ipv4"], "next_hop": "blackhole"},
+            ]
+        }
+    }
+    result = create_static_routes(tgen, input_dict_static_rtes)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    dut = "r0"
+    red_static(dut)
+
+    step("Verify that routes are learnt on R1.")
+    dut = "r1"
+
+    result = verify_ospf_rib(tgen, dut, input_dict_static_rtes)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+    result = verify_rib(tgen, "ipv4", dut, input_dict_static_rtes, protocol=protocol)
+    assert (
+        result is True
+    ), "Testcase {} : Failed" "Error: Routes is missing in RIB".format(tc_name)
+
+    step(
+        "Configure External Route summary in R0 to summarise 5" " routes to one route."
+    )
+
+    ospf_summ_r1 = {
+        "r0": {
+            "ospf": {
+                "summary-address": [
+                    {"prefix": SUMMARY["ipv4"][0].split("/")[0], "mask": "8"}
+                ]
+            }
+        }
+    }
+    result = create_router_ospf(tgen, topo, ospf_summ_r1)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    step(
+        "Verify that external routes are summarised to configured summary "
+        "address on R0 after 5 secs of delay timer expiry and only one "
+        "route is sent to R1."
+    )
+    input_dict_summary = {"r0": {"static_routes": [{"network": SUMMARY["ipv4"][0]}]}}
+    dut = "r1"
+
+    result = verify_ospf_rib(tgen, dut, input_dict_summary)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    result = verify_rib(tgen, "ipv4", dut, input_dict_summary, protocol=protocol)
+    assert (
+        result is True
+    ), "Testcase {} : Failed" "Error: Routes is missing in RIB".format(tc_name)
+
+    step("Verify that show ip ospf summary should show the summaries.")
+    input_dict = {
+        SUMMARY["ipv4"][0]: {
+            "Summary address": SUMMARY["ipv4"][0],
+            "Metric-type": "E2",
+            "Metric": 20,
+            "Tag": 0,
+            "External route count": 5,
+        }
+    }
+    dut = "r0"
+    result = verify_ospf_summary(tgen, topo, dut, input_dict)
+    assert (
+        result is True
+    ), "Testcase {} : Failed" "Error: Summary missing in OSPF DB".format(tc_name)
+
+    step("Verify that originally advertised routes are withdraw from there" " peer.")
+    input_dict = {
+        "r0": {"static_routes": [{"network": NETWORK["ipv4"], "next_hop": "blackhole"}]}
+    }
+    dut = "r1"
+    result = verify_ospf_rib(tgen, dut, input_dict, expected=False)
+    assert (
+        result is not True
+    ), "Testcase {} : Failed \n Error: " "Routes still present in OSPF RIB {}".format(
+        tc_name, result
+    )
+
+    result = verify_rib(
+        tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False
+    )
+    assert (
+        result is not True
+    ), "Testcase {} : Failed" "Error: Routes still present in RIB".format(tc_name)
+
+    step(
+        "Configure route map and & rule to permit configured summary address,"
+        " redistribute static & connected routes with the route map."
+    )
+    step("Configure prefixlist to permit the static routes, add to route map.")
+    # 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)
+
+    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)
+
+    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 external routes are summarised to configured"
+        "summary address on R0 and only one route is sent to R1. Verify that "
+        "show ip ospf summary should show the configure summaries."
+    )
+
+    input_dict_summary = {"r0": {"static_routes": [{"network": SUMMARY["ipv4"][0]}]}}
+    dut = "r1"
+
+    result = verify_ospf_rib(tgen, dut, input_dict_summary)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    result = verify_rib(tgen, "ipv4", dut, input_dict_summary, protocol=protocol)
+    assert (
+        result is True
+    ), "Testcase {} : Failed" "Error: Routes is missing in RIB".format(tc_name)
+
+    input_dict = {
+        SUMMARY["ipv4"][0]: {
+            "Summary address": SUMMARY["ipv4"][0],
+            "Metric-type": "E2",
+            "Metric": 20,
+            "Tag": 0,
+            "External route count": 5,
+        }
+    }
+    dut = "r0"
+    result = verify_ospf_summary(tgen, topo, dut, input_dict)
+    assert (
+        result is True
+    ), "Testcase {} : Failed" "Error: Summary missing in OSPF DB".format(tc_name)
+
+    step("Configure metric type as 1 in route map.")
+
+    routemaps = {
+        "r0": {
+            "route_maps": {
+                "rmap_ipv4": [{"action": "permit", "set": {"metric-type": "type-1"}}]
+            }
+        }
+    }
+    result = create_route_maps(tgen, routemaps)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    step(
+        "Verify that external routes(static / connected) are summarised"
+        " to configured summary address with metric type 2."
+    )
+    input_dict = {
+        SUMMARY["ipv4"][0]: {
+            "Summary address": SUMMARY["ipv4"][0],
+            "Metric-type": "E2",
+            "Metric": 20,
+            "Tag": 0,
+            "External route count": 5,
+        }
+    }
+    dut = "r0"
+    result = verify_ospf_summary(tgen, topo, dut, input_dict)
+    assert (
+        result is True
+    ), "Testcase {} : Failed" "Error: Summary missing in OSPF DB".format(tc_name)
+
+    step("Un configure metric type from route map.")
+
+    routemaps = {
+        "r0": {
+            "route_maps": {
+                "rmap_ipv4": [
+                    {
+                        "action": "permit",
+                        "set": {"metric-type": "type-1"},
+                        "delete": True,
+                    }
+                ]
+            }
+        }
+    }
+    result = create_route_maps(tgen, routemaps)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    step(
+        "Verify that external routes(static / connected) are summarised"
+        " to configured summary address with metric type 2."
+    )
+    input_dict = {
+        SUMMARY["ipv4"][0]: {
+            "Summary address": SUMMARY["ipv4"][0],
+            "Metric-type": "E2",
+            "Metric": 20,
+            "Tag": 0,
+            "External route count": 5,
+        }
+    }
+    dut = "r0"
+    result = verify_ospf_summary(tgen, topo, dut, input_dict)
+    assert (
+        result is True
+    ), "Testcase {} : Failed" "Error: Summary missing in OSPF DB".format(tc_name)
+
+    step("Change rule from permit to deny in prefix list.")
+    pfx_list = {
+        "r0": {
+            "prefix_lists": {
+                "ipv4": {
+                    "pf_list_1_ipv4": [
+                        {"seqid": 10, "network": "any", "action": "deny"}
+                    ]
+                }
+            }
+        }
+    }
+    result = create_prefix_lists(tgen, pfx_list)
+    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))
index 1bfd6942ea643ab32cc3d4c9a4fd39f24c093bd3..d01511c0ee9fcee95432dc760fe5aa277a2707ca 100644 (file)
@@ -1,13 +1,13 @@
 *N IA 2001:db8:1::/64                ::                        r1-eth0 00:02:11
 *N IA 2001:db8:2::/64                fe80::b038:bcff:fe27:e2d6 r1-eth1 00:02:06
- N E1 2001:db8:2::/64                fe80::b038:bcff:fe27:e2d6 r1-eth1 00:02:06
+ N E2 2001:db8:2::/64                fe80::b038:bcff:fe27:e2d6 r1-eth1 00:02:06
 *N IA 2001:db8:3::/64                ::                        r1-eth1 00:02:11
- N E1 2001:db8:3::/64                fe80::50b7:d8ff:fe5f:8ff0 r1-eth1 00:02:06
- N E1 2001:db8:3::/64                fe80::b038:bcff:fe27:e2d6 r1-eth1 00:02:06
+ N E2 2001:db8:3::/64                fe80::50b7:d8ff:fe5f:8ff0 r1-eth1 00:02:06
+ N E2 2001:db8:3::/64                fe80::b038:bcff:fe27:e2d6 r1-eth1 00:02:06
 *N IA 2001:db8:100::/64              fe80::50b7:d8ff:fe5f:8ff0 r1-eth1 00:02:06
- N E1 2001:db8:100::/64              fe80::50b7:d8ff:fe5f:8ff0 r1-eth1 00:02:06
+ N E2 2001:db8:100::/64              fe80::50b7:d8ff:fe5f:8ff0 r1-eth1 00:02:06
 *N IE 2001:db8:200::/64              fe80::50b7:d8ff:fe5f:8ff0 r1-eth1 00:02:06
- N E1 2001:db8:200::/64              fe80::50b7:d8ff:fe5f:8ff0 r1-eth1 00:02:06
- N E1 2001:db8:200::/64              fe80::50b7:d8ff:fe5f:8ff0 r1-eth1 00:02:04
+ N E2 2001:db8:200::/64              fe80::50b7:d8ff:fe5f:8ff0 r1-eth1 00:02:06
+ N E2 2001:db8:200::/64              fe80::50b7:d8ff:fe5f:8ff0 r1-eth1 00:02:04
 *N IE 2001:db8:300::/64              fe80::50b7:d8ff:fe5f:8ff0 r1-eth1 00:02:04
- N E1 2001:db8:300::/64              fe80::50b7:d8ff:fe5f:8ff0 r1-eth1 00:02:04
+ N E2 2001:db8:300::/64              fe80::50b7:d8ff:fe5f:8ff0 r1-eth1 00:02:04
index 1ce96c86c035aa067e3093a8c8143bb7793c1dfe..57113d049f295e2340ecf6b05f9f5264269c427e 100644 (file)
@@ -1,5 +1,5 @@
 *N IA 2001:db8:1::/64                ::                        r1-eth0 00:01:51
 *N IA 2001:db8:2::/64                fe80::281a:23ff:fe22:8a40 r1-eth1 00:00:52
- N E1 2001:db8:2::/64                fe80::281a:23ff:fe22:8a40 r1-eth1 00:00:52
+ N E2 2001:db8:2::/64                fe80::281a:23ff:fe22:8a40 r1-eth1 00:00:52
 *N IA 2001:db8:3::/64                ::                        r1-eth1 00:00:52
- N E1 2001:db8:3::/64                fe80::281a:23ff:fe22:8a40 r1-eth1 00:00:52
+ N E2 2001:db8:3::/64                fe80::281a:23ff:fe22:8a40 r1-eth1 00:00:52
index 4df6e5ec005eddf0448d034d7532537c3e449a0f..48e9209a04ad79ac9bf2f42cbb3bdc860d1af54a 100644 (file)
@@ -1,13 +1,13 @@
 *N IA 2001:db8:1::/64                ::                        r1-eth0 00:06:13
 *N IA 2001:db8:2::/64                fe80::e8bb:62ff:fee8:7022 r1-eth1 00:06:08
- N E1 2001:db8:2::/64                fe80::e8bb:62ff:fee8:7022 r1-eth1 00:06:08
+ N E2 2001:db8:2::/64                fe80::e8bb:62ff:fee8:7022 r1-eth1 00:06:08
 *N IA 2001:db8:3::/64                ::                        r1-eth1 00:06:13
- N E1 2001:db8:3::/64                fe80::400f:dff:fe35:a1e7  r1-eth1 00:06:08
+ N E2 2001:db8:3::/64                fe80::400f:dff:fe35:a1e7  r1-eth1 00:06:08
                                      fe80::e8bb:62ff:fee8:7022 r1-eth1 
 *N IA 2001:db8:100::/64              fe80::400f:dff:fe35:a1e7  r1-eth1 00:06:08
- N E1 2001:db8:100::/64              fe80::400f:dff:fe35:a1e7  r1-eth1 00:06:08
+ N E2 2001:db8:100::/64              fe80::400f:dff:fe35:a1e7  r1-eth1 00:06:08
 *N IE 2001:db8:200::/64              fe80::400f:dff:fe35:a1e7  r1-eth1 00:06:08
- N E1 2001:db8:200::/64              fe80::400f:dff:fe35:a1e7  r1-eth1 00:06:08
- N E1 2001:db8:200::/64              fe80::400f:dff:fe35:a1e7  r1-eth1 00:06:07
+ N E2 2001:db8:200::/64              fe80::400f:dff:fe35:a1e7  r1-eth1 00:06:08
+ N E2 2001:db8:200::/64              fe80::400f:dff:fe35:a1e7  r1-eth1 00:06:07
 *N IE 2001:db8:300::/64              fe80::400f:dff:fe35:a1e7  r1-eth1 00:06:07
- N E1 2001:db8:300::/64              fe80::400f:dff:fe35:a1e7  r1-eth1 00:06:07
+ N E2 2001:db8:300::/64              fe80::400f:dff:fe35:a1e7  r1-eth1 00:06:07
index 7d3ce5b2070e65018c91364ee18a204a85f06579..71c84d2ebd17deb9935fdad5d1032e1159245c7e 100644 (file)
@@ -1,13 +1,13 @@
 *N IA 2001:db8:1::/64                fe80::b49b:4cff:fe80:4e87 r2-eth1 00:03:34
- N E1 2001:db8:1::/64                fe80::b49b:4cff:fe80:4e87 r2-eth1 00:03:34
+ N E2 2001:db8:1::/64                fe80::b49b:4cff:fe80:4e87 r2-eth1 00:03:34
 *N IA 2001:db8:2::/64                ::                        r2-eth0 00:03:39
 *N IA 2001:db8:3::/64                ::                        r2-eth1 00:03:34
- N E1 2001:db8:3::/64                fe80::b49b:4cff:fe80:4e87 r2-eth1 00:03:34
- N E1 2001:db8:3::/64                fe80::50b7:d8ff:fe5f:8ff0 r2-eth1 00:03:34
+ N E2 2001:db8:3::/64                fe80::b49b:4cff:fe80:4e87 r2-eth1 00:03:34
+ N E2 2001:db8:3::/64                fe80::50b7:d8ff:fe5f:8ff0 r2-eth1 00:03:34
 *N IA 2001:db8:100::/64              fe80::50b7:d8ff:fe5f:8ff0 r2-eth1 00:03:34
- N E1 2001:db8:100::/64              fe80::50b7:d8ff:fe5f:8ff0 r2-eth1 00:03:34
+ N E2 2001:db8:100::/64              fe80::50b7:d8ff:fe5f:8ff0 r2-eth1 00:03:34
 *N IE 2001:db8:200::/64              fe80::50b7:d8ff:fe5f:8ff0 r2-eth1 00:03:34
- N E1 2001:db8:200::/64              fe80::50b7:d8ff:fe5f:8ff0 r2-eth1 00:03:34
- N E1 2001:db8:200::/64              fe80::50b7:d8ff:fe5f:8ff0 r2-eth1 00:03:32
+ N E2 2001:db8:200::/64              fe80::50b7:d8ff:fe5f:8ff0 r2-eth1 00:03:34
+ N E2 2001:db8:200::/64              fe80::50b7:d8ff:fe5f:8ff0 r2-eth1 00:03:32
 *N IE 2001:db8:300::/64              fe80::50b7:d8ff:fe5f:8ff0 r2-eth1 00:03:32
- N E1 2001:db8:300::/64              fe80::50b7:d8ff:fe5f:8ff0 r2-eth1 00:03:32
+ N E2 2001:db8:300::/64              fe80::50b7:d8ff:fe5f:8ff0 r2-eth1 00:03:32
index acfffc9f1cafd326829492002eb4312ef0298ad1..a1f041218b8ad394eb65628d4e0a36dd171a7b75 100644 (file)
@@ -1,5 +1,5 @@
 *N IA 2001:db8:1::/64                fe80::fc0b:daff:fe31:6791 r2-eth1 00:06:19
- N E1 2001:db8:1::/64                fe80::fc0b:daff:fe31:6791 r2-eth1 00:06:19
+ N E2 2001:db8:1::/64                fe80::fc0b:daff:fe31:6791 r2-eth1 00:06:19
 *N IA 2001:db8:2::/64                ::                        r2-eth0 00:07:17
 *N IA 2001:db8:3::/64                ::                        r2-eth1 00:06:27
- N E1 2001:db8:3::/64                fe80::fc0b:daff:fe31:6791 r2-eth1 00:06:19
+ N E2 2001:db8:3::/64                fe80::fc0b:daff:fe31:6791 r2-eth1 00:06:19
index f58b501e315904ac3385e6d9a83d8306cea76883..0c06d234cf599088da6afe0a4d135cd0ea11ecd3 100644 (file)
@@ -1,13 +1,13 @@
 *N IA 2001:db8:1::/64                fe80::98cd:28ff:fe5e:3d93 r2-eth1 00:07:04
- N E1 2001:db8:1::/64                fe80::98cd:28ff:fe5e:3d93 r2-eth1 00:07:04
+ N E2 2001:db8:1::/64                fe80::98cd:28ff:fe5e:3d93 r2-eth1 00:07:04
 *N IA 2001:db8:2::/64                ::                        r2-eth0 00:07:09
 *N IA 2001:db8:3::/64                ::                        r2-eth1 00:07:04
- N E1 2001:db8:3::/64                fe80::400f:dff:fe35:a1e7  r2-eth1 00:07:04
+ N E2 2001:db8:3::/64                fe80::400f:dff:fe35:a1e7  r2-eth1 00:07:04
                                      fe80::98cd:28ff:fe5e:3d93 r2-eth1 
 *N IA 2001:db8:100::/64              fe80::400f:dff:fe35:a1e7  r2-eth1 00:07:04
- N E1 2001:db8:100::/64              fe80::400f:dff:fe35:a1e7  r2-eth1 00:07:04
+ N E2 2001:db8:100::/64              fe80::400f:dff:fe35:a1e7  r2-eth1 00:07:04
 *N IE 2001:db8:200::/64              fe80::400f:dff:fe35:a1e7  r2-eth1 00:07:04
- N E1 2001:db8:200::/64              fe80::400f:dff:fe35:a1e7  r2-eth1 00:07:04
- N E1 2001:db8:200::/64              fe80::400f:dff:fe35:a1e7  r2-eth1 00:07:03
+ N E2 2001:db8:200::/64              fe80::400f:dff:fe35:a1e7  r2-eth1 00:07:04
+ N E2 2001:db8:200::/64              fe80::400f:dff:fe35:a1e7  r2-eth1 00:07:03
 *N IE 2001:db8:300::/64              fe80::400f:dff:fe35:a1e7  r2-eth1 00:07:03
- N E1 2001:db8:300::/64              fe80::400f:dff:fe35:a1e7  r2-eth1 00:07:03
+ N E2 2001:db8:300::/64              fe80::400f:dff:fe35:a1e7  r2-eth1 00:07:03
index b123c426507b9b053aa3c20bff903610b6fc219b..69c99b4fd13a9761874df9707ea0f43065ed0d11 100644 (file)
@@ -1,12 +1,12 @@
 *N IA 2001:db8:1::/64                fe80::b49b:4cff:fe80:4e87 r3-eth0 00:04:03
- N E1 2001:db8:1::/64                fe80::b49b:4cff:fe80:4e87 r3-eth0 00:04:03
+ N E2 2001:db8:1::/64                fe80::b49b:4cff:fe80:4e87 r3-eth0 00:04:03
 *N IA 2001:db8:2::/64                fe80::b038:bcff:fe27:e2d6 r3-eth0 00:04:03
- N E1 2001:db8:2::/64                fe80::b038:bcff:fe27:e2d6 r3-eth0 00:04:03
+ N E2 2001:db8:2::/64                fe80::b038:bcff:fe27:e2d6 r3-eth0 00:04:03
 *N IA 2001:db8:3::/64                ::                        r3-eth0 00:04:08
- N E1 2001:db8:3::/64                fe80::b49b:4cff:fe80:4e87 r3-eth0 00:04:03
- N E1 2001:db8:3::/64                fe80::b038:bcff:fe27:e2d6 r3-eth0 00:04:03
+ N E2 2001:db8:3::/64                fe80::b49b:4cff:fe80:4e87 r3-eth0 00:04:03
+ N E2 2001:db8:3::/64                fe80::b038:bcff:fe27:e2d6 r3-eth0 00:04:03
 *N IA 2001:db8:100::/64              ::                        r3-eth1 00:04:08
 *N IA 2001:db8:200::/64              ::                        r3-eth2 00:04:05
- N E1 2001:db8:200::/64              fe80::78e0:deff:feb1:ec0  r3-eth2 00:04:00
+ N E2 2001:db8:200::/64              fe80::78e0:deff:feb1:ec0  r3-eth2 00:04:00
 *N IA 2001:db8:300::/64              fe80::78e0:deff:feb1:ec0  r3-eth2 00:04:00
- N E1 2001:db8:300::/64              fe80::78e0:deff:feb1:ec0  r3-eth2 00:04:00
+ N E2 2001:db8:300::/64              fe80::78e0:deff:feb1:ec0  r3-eth2 00:04:00
index ed69a8376b0d449eda27a2c3b632d406538d4751..645ee0bfc4391535f23a9e0ef0a086432dacf67d 100644 (file)
@@ -1,5 +1,5 @@
 *N IA 2001:db8:100::/64              ::                        r3-eth1 00:08:06
 *N IA 2001:db8:200::/64              ::                        r3-eth2 00:08:04
- N E1 2001:db8:200::/64              fe80::80a6:c3ff:fea9:88be r3-eth2 00:07:59
+ N E2 2001:db8:200::/64              fe80::80a6:c3ff:fea9:88be r3-eth2 00:07:59
 *N IA 2001:db8:300::/64              fe80::80a6:c3ff:fea9:88be r3-eth2 00:07:59
- N E1 2001:db8:300::/64              fe80::80a6:c3ff:fea9:88be r3-eth2 00:07:59
+ N E2 2001:db8:300::/64              fe80::80a6:c3ff:fea9:88be r3-eth2 00:07:59
index 54e575adcb5e555ecf04d5c157857bd7c569022c..ecd51be4ef9aa24c1f59b2df269702ede2b1050d 100644 (file)
@@ -1,12 +1,12 @@
 *N IA 2001:db8:1::/64                fe80::98cd:28ff:fe5e:3d93 r3-eth0 00:08:58
- N E1 2001:db8:1::/64                fe80::98cd:28ff:fe5e:3d93 r3-eth0 00:08:58
+ N E2 2001:db8:1::/64                fe80::98cd:28ff:fe5e:3d93 r3-eth0 00:08:58
 *N IA 2001:db8:2::/64                fe80::e8bb:62ff:fee8:7022 r3-eth0 00:08:58
- N E1 2001:db8:2::/64                fe80::e8bb:62ff:fee8:7022 r3-eth0 00:08:58
+ N E2 2001:db8:2::/64                fe80::e8bb:62ff:fee8:7022 r3-eth0 00:08:58
 *N IA 2001:db8:3::/64                ::                        r3-eth0 00:09:03
- N E1 2001:db8:3::/64                fe80::98cd:28ff:fe5e:3d93 r3-eth0 00:08:58
+ N E2 2001:db8:3::/64                fe80::98cd:28ff:fe5e:3d93 r3-eth0 00:08:58
                                      fe80::e8bb:62ff:fee8:7022 r3-eth0 
 *N IA 2001:db8:100::/64              ::                        r3-eth1 00:09:03
 *N IA 2001:db8:200::/64              ::                        r3-eth2 00:09:02
- N E1 2001:db8:200::/64              fe80::d0dc:aff:fec5:5973  r3-eth2 00:08:57
+ N E2 2001:db8:200::/64              fe80::d0dc:aff:fec5:5973  r3-eth2 00:08:57
 *N IA 2001:db8:300::/64              fe80::d0dc:aff:fec5:5973  r3-eth2 00:08:57
- N E1 2001:db8:300::/64              fe80::d0dc:aff:fec5:5973  r3-eth2 00:08:57
+ N E2 2001:db8:300::/64              fe80::d0dc:aff:fec5:5973  r3-eth2 00:08:57
index ceeee2cac8d35b2c6249b34a78ebbad3f062fd67..3a4f5efdf0c052f30cac297d3b15a48707d2798b 100644 (file)
@@ -1,13 +1,13 @@
 *N IE 2001:db8:1::/64                fe80::987b:baff:fe8a:c864 r4-eth0 00:04:25
- N E1 2001:db8:1::/64                fe80::987b:baff:fe8a:c864 r4-eth0 00:04:25
+ N E2 2001:db8:1::/64                fe80::987b:baff:fe8a:c864 r4-eth0 00:04:25
 *N IE 2001:db8:2::/64                fe80::987b:baff:fe8a:c864 r4-eth0 00:04:25
- N E1 2001:db8:2::/64                fe80::987b:baff:fe8a:c864 r4-eth0 00:04:25
+ N E2 2001:db8:2::/64                fe80::987b:baff:fe8a:c864 r4-eth0 00:04:25
 *N IE 2001:db8:3::/64                fe80::987b:baff:fe8a:c864 r4-eth0 00:04:25
- N E1 2001:db8:3::/64                fe80::987b:baff:fe8a:c864 r4-eth0 00:04:25
- N E1 2001:db8:3::/64                fe80::987b:baff:fe8a:c864 r4-eth0 00:04:25
- N E1 2001:db8:3::/64                fe80::987b:baff:fe8a:c864 r4-eth0 00:04:25
+ N E2 2001:db8:3::/64                fe80::987b:baff:fe8a:c864 r4-eth0 00:04:25
+ N E2 2001:db8:3::/64                fe80::987b:baff:fe8a:c864 r4-eth0 00:04:25
+ N E2 2001:db8:3::/64                fe80::987b:baff:fe8a:c864 r4-eth0 00:04:25
 *N IE 2001:db8:100::/64              fe80::987b:baff:fe8a:c864 r4-eth0 00:04:25
- N E1 2001:db8:100::/64              fe80::987b:baff:fe8a:c864 r4-eth0 00:04:25
+ N E2 2001:db8:100::/64              fe80::987b:baff:fe8a:c864 r4-eth0 00:04:25
 *N IA 2001:db8:200::/64              ::                        r4-eth0 00:04:30
- N E1 2001:db8:200::/64              fe80::987b:baff:fe8a:c864 r4-eth0 00:04:25
+ N E2 2001:db8:200::/64              fe80::987b:baff:fe8a:c864 r4-eth0 00:04:25
 *N IA 2001:db8:300::/64              ::                        r4-eth1 00:04:30
index 4ad636dd981effe891a943c16fa0a0d8952de896..165f8dbdf8a6d33aac5809e5cb391e82af88762e 100644 (file)
@@ -1,5 +1,5 @@
 *N IE 2001:db8:100::/64              fe80::b44b:a1ff:fe48:3d69 r4-eth0 00:01:45
- N E1 2001:db8:100::/64              fe80::b44b:a1ff:fe48:3d69 r4-eth0 00:01:45
+ N E2 2001:db8:100::/64              fe80::b44b:a1ff:fe48:3d69 r4-eth0 00:01:45
 *N IA 2001:db8:200::/64              ::                        r4-eth0 00:01:50
- N E1 2001:db8:200::/64              fe80::b44b:a1ff:fe48:3d69 r4-eth0 00:01:45
+ N E2 2001:db8:200::/64              fe80::b44b:a1ff:fe48:3d69 r4-eth0 00:01:45
 *N IA 2001:db8:300::/64              ::                        r4-eth1 00:01:50
index b5cb10b72b59080dde28a0d7a5e43e1d144cb963..d0d72a876f5668f684a530112f457f70edaddfec 100644 (file)
@@ -1,12 +1,12 @@
 *N IE 2001:db8:1::/64                fe80::78fe:fcff:fe51:9afc r4-eth0 00:09:13
- N E1 2001:db8:1::/64                fe80::78fe:fcff:fe51:9afc r4-eth0 00:09:13
+ N E2 2001:db8:1::/64                fe80::78fe:fcff:fe51:9afc r4-eth0 00:09:13
 *N IE 2001:db8:2::/64                fe80::78fe:fcff:fe51:9afc r4-eth0 00:09:13
- N E1 2001:db8:2::/64                fe80::78fe:fcff:fe51:9afc r4-eth0 00:09:13
+ N E2 2001:db8:2::/64                fe80::78fe:fcff:fe51:9afc r4-eth0 00:09:13
 *N IE 2001:db8:3::/64                fe80::78fe:fcff:fe51:9afc r4-eth0 00:09:13
- N E1 2001:db8:3::/64                fe80::78fe:fcff:fe51:9afc r4-eth0 00:09:13
- N E1 2001:db8:3::/64                fe80::78fe:fcff:fe51:9afc r4-eth0 00:09:13
+ N E2 2001:db8:3::/64                fe80::78fe:fcff:fe51:9afc r4-eth0 00:09:13
+ N E2 2001:db8:3::/64                fe80::78fe:fcff:fe51:9afc r4-eth0 00:09:13
 *N IE 2001:db8:100::/64              fe80::78fe:fcff:fe51:9afc r4-eth0 00:09:13
- N E1 2001:db8:100::/64              fe80::78fe:fcff:fe51:9afc r4-eth0 00:09:13
+ N E2 2001:db8:100::/64              fe80::78fe:fcff:fe51:9afc r4-eth0 00:09:13
 *N IA 2001:db8:200::/64              ::                        r4-eth0 00:09:17
- N E1 2001:db8:200::/64              fe80::78fe:fcff:fe51:9afc r4-eth0 00:09:13
+ N E2 2001:db8:200::/64              fe80::78fe:fcff:fe51:9afc r4-eth0 00:09:13
 *N IA 2001:db8:300::/64              ::                        r4-eth1 00:09:18
diff --git a/tests/topotests/ospfv3_basic_functionality/ospfv3_rte_calc.json b/tests/topotests/ospfv3_basic_functionality/ospfv3_rte_calc.json
new file mode 100644 (file)
index 0000000..3669b3a
--- /dev/null
@@ -0,0 +1,173 @@
+{
+    "feature": [
+        "bgp"
+    ],
+    "address_types": [
+        "ipv6"
+    ],
+    "ipv6base": "fd00::",
+    "ipv6mask": 64,
+    "link_ip_start": {
+        "ipv6": "fd00::",
+        "v6mask": 64
+    },
+    "lo_prefix": {
+        "ipv6": "2001:db8:f::",
+        "v6mask": 128
+    },
+    "routers": {
+        "r0": {
+            "links": {
+                "lo": {
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r1": {
+                    "ipv6": "auto",
+                    "ospf6": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4
+                    }
+                },
+                "r2": {
+                    "ipv6": "auto",
+                    "ospf6": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4
+                    }
+                },
+                "r3": {
+                    "ipv6": "auto",
+                    "ospf6": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4
+                    }
+                }
+            },
+            "ospf6": {
+                "router_id": "100.1.1.0",
+                "neighbors": {
+                    "r1": {},
+                    "r2": {}
+                }
+            }
+        },
+        "r1": {
+            "links": {
+                "lo": {
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r0": {
+                    "ipv6": "auto",
+                    "ospf6": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4
+                    }
+                },
+                "r2": {
+                    "ipv6": "auto",
+                    "ospf6": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4
+                    }
+                },
+                "r3": {
+                    "ipv6": "auto",
+                    "ospf6": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4
+                    }
+                }
+            },
+            "ospf6": {
+                "router_id": "100.1.1.1",
+                "neighbors": {
+                    "r0": {},
+                    "r2": {},
+                    "r3": {}
+                }
+            }
+        },
+        "r2": {
+            "links": {
+                "lo": {
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r0": {
+                    "ipv6": "auto",
+                    "ospf6": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4
+                    }
+                },
+                "r1": {
+                    "ipv6": "auto",
+                    "ospf6": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4
+                    }
+                },
+                "r3": {
+                    "ipv6": "auto",
+                    "ospf6": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4
+                    }
+                }
+            },
+            "ospf6": {
+                "router_id": "100.1.1.2",
+                "neighbors": {
+                    "r1": {},
+                    "r0": {},
+                    "r3": {}
+                }
+            }
+        },
+        "r3": {
+            "links": {
+                "lo": {
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r0": {
+                    "ipv6": "auto"
+                },
+                "r1": {
+                    "ipv6": "auto",
+                    "ospf6": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4
+                    }
+                },
+                "r2": {
+                    "ipv6": "auto",
+                    "ospf6": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4
+                    }
+                }
+            },
+            "ospf6": {
+                "router_id": "100.1.1.3",
+                "neighbors": {
+                    "r1": {},
+                    "r2": {}
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/topotests/ospfv3_basic_functionality/ospfv3_single_area.json b/tests/topotests/ospfv3_basic_functionality/ospfv3_single_area.json
new file mode 100644 (file)
index 0000000..d93eb1f
--- /dev/null
@@ -0,0 +1,190 @@
+{
+    "address_types": [
+        "ipv6"
+    ],
+    "ipv6base": "fd00::",
+    "ipv6mask": 64,
+    "link_ip_start": {
+        "ipv6": "fd00::",
+        "v6mask": 64
+    },
+    "lo_prefix": {
+        "ipv6": "2001:db8:f::",
+        "v6mask": 128
+    },
+    "routers": {
+        "r0": {
+            "links": {
+                "lo": {
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r1": {
+                    "ipv6": "auto",
+                    "ospf6": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4
+                    }
+                },
+                "r2": {
+                    "ipv6": "auto",
+                    "ospf6": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4
+                    }
+                },
+                "r3": {
+                    "ipv6": "auto",
+                    "ospf6": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4,
+                        "network": "point-to-point"
+                    }
+                }
+            },
+            "ospf6": {
+                "router_id": "100.1.1.0",
+                "neighbors": {
+                    "r1": {},
+                    "r2": {},
+                    "r3": {}
+                }
+            }
+        },
+        "r1": {
+            "links": {
+                "lo": {
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r0": {
+                    "ipv6": "auto",
+                    "ospf6": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4
+                    }
+                },
+                "r2": {
+                    "ipv6": "auto",
+                    "ospf6": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4
+                    }
+                },
+                "r3": {
+                    "ipv6": "auto",
+                    "ospf6": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4
+                    }
+                },
+                "r3-link0": {
+                    "ipv6": "auto",
+                    "description": "DummyIntftoR3"
+                }
+            },
+            "ospf6": {
+                "router_id": "100.1.1.1",
+                "neighbors": {
+                    "r0": {},
+                    "r2": {},
+                    "r3": {}
+                }
+            }
+        },
+        "r2": {
+            "links": {
+                "lo": {
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r0": {
+                    "ipv6": "auto",
+                    "ospf6": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4
+                    }
+                },
+                "r1": {
+                    "ipv6": "auto",
+                    "ospf6": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4
+                    }
+                },
+                "r3": {
+                    "ipv6": "auto",
+                    "ospf6": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4
+                    }
+                }
+            },
+            "ospf6": {
+                "router_id": "100.1.1.2",
+                "neighbors": {
+                    "r1": {},
+                    "r0": {},
+                    "r3": {}
+                }
+            }
+        },
+        "r3": {
+            "links": {
+                "lo": {
+                    "ipv6": "auto",
+                    "type": "loopback"
+                },
+                "r0": {
+                    "ipv6": "auto",
+                    "ospf6": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4,
+                        "network": "point-to-point"
+                    }
+                },
+                "r1": {
+                    "ipv6": "auto",
+                    "ospf6": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4
+                    }
+                },
+                "r2": {
+                    "ipv6": "auto",
+                    "ospf6": {
+                        "area": "0.0.0.0",
+                        "hello_interval": 1,
+                        "dead_interval": 4
+                    }
+                },
+                "r1-link0": {
+                    "ipv6": "auto",
+                    "description": "DummyIntftoR1",
+                    "ospf6": {
+                        "area": "0.0.0.0"
+                    }
+                }
+            },
+            "ospf6": {
+                "router_id": "1.0.4.17",
+                "neighbors": {
+                    "r0": {},
+                    "r1": {},
+                    "r2": {}
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_rte_calc.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_rte_calc.py
new file mode 100644 (file)
index 0000000..4aa71bf
--- /dev/null
@@ -0,0 +1,374 @@
+#!/usr/bin/python
+#
+# Copyright (c) 2021 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
+from lib.topotest import frr_unicode
+
+# 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
+from lib.bgp import verify_bgp_convergence, create_router_bgp
+
+# 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,
+    get_frr_ipv6_linklocal,
+)
+
+from lib.topolog import logger
+from lib.topojson import build_topo_from_json, build_config_from_json
+
+from lib.ospf import (
+    verify_ospf6_neighbor,
+    config_ospf_interface,
+    clear_ospf,
+    verify_ospf6_rib,
+    create_router_ospf,
+    verify_ospf6_interface,
+    verify_ospf6_database,
+    config_ospf6_interface,
+)
+
+from ipaddress import IPv6Address
+
+# Global variables
+topo = None
+
+# Reading the data from JSON File for topology creation
+jsonFile = "{}/ospfv3_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 = {
+    "ipv6": [
+        "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": ["2::1/128", "2::2/128", "2::3/128", "2::4/128", "2::5/128"],
+}
+TOPOOLOGY = """
+      Please view in a fixed-width font such as Courier.
+      +---+  A1       +---+
+      +R1 +------------+R2 |
+      +-+-+-           +--++
+        |  --        --  |
+        |    -- A0 --    |
+      A0|      ----      |
+        |      ----      | A2
+        |    --    --    |
+        |  --        --  |
+      +-+-+-            +-+-+
+      +R0 +-------------+R3 |
+      +---+     A3     +---+
+"""
+
+TESTCASES = """
+1. OSPF Cost - verifying ospf interface cost functionality
+"""
+
+
+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_ospf6_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 get_llip(onrouter, intf):
+    """
+    API to get the link local ipv6 address of a perticular interface
+
+    Parameters
+    ----------
+    * `fromnode`: Source node
+    * `tonode` : interface for which link local ip needs to be returned.
+
+    Usage
+    -----
+    result = get_llip('r1', 'r2-link0')
+
+    Returns
+    -------
+    1) link local ipv6 address from the interface.
+    2) errormsg - when link local ip not found.
+    """
+    tgen = get_topogen()
+    intf = topo["routers"][onrouter]["links"][intf]["interface"]
+    llip = get_frr_ipv6_linklocal(tgen, onrouter, intf)
+    if llip:
+        logger.info("llip ipv6 address to be set as NH is %s", llip)
+        return llip
+    return None
+
+
+def get_glipv6(onrouter, intf):
+    """
+    API to get the global ipv6 address of a perticular interface
+
+    Parameters
+    ----------
+    * `onrouter`: Source node
+    * `intf` : interface for which link local ip needs to be returned.
+
+    Usage
+    -----
+    result = get_glipv6('r1', 'r2-link0')
+
+    Returns
+    -------
+    1) global ipv6 address from the interface.
+    2) errormsg - when link local ip not found.
+    """
+    glipv6 = (topo["routers"][onrouter]["links"][intf]["ipv6"]).split("/")[0]
+    if glipv6:
+        logger.info("Global ipv6 address to be set as NH is %s", glipv6)
+        return glipv6
+    return None
+
+
+def red_static(dut, config=True):
+    """Local def for Redstribute static routes inside ospf."""
+    global topo
+    tgen = get_topogen()
+    if config:
+        ospf_red = {dut: {"ospf6": {"redistribute": [{"redist_type": "static"}]}}}
+    else:
+        ospf_red = {
+            dut: {
+                "ospf6": {
+                    "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: {"ospf6": {"redistribute": [{"redist_type": "connected"}]}}}
+    else:
+        ospf_red = {
+            dut: {
+                "ospf6": {
+                    "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_ospfv3_cost_tc52_p0(request):
+    """OSPF Cost - verifying ospf interface cost functionality"""
+    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 cost as 20 on interface between R0 and R1. "
+        "Configure ospf cost as 30 between interface between R0 and R2."
+    )
+
+    r0_ospf_cost = {
+        "r0": {"links": {"r1": {"ospf6": {"cost": 20}}, "r2": {"ospf6": {"cost": 30}}}}
+    }
+    result = config_ospf6_interface(tgen, topo, r0_ospf_cost)
+    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+    step(
+        "Verify that cost is updated in the ospf interface between"
+        " r0 and r1 as 30 and r0 and r2 as 20"
+    )
+    dut = "r0"
+    result = verify_ospf6_interface(tgen, topo, dut=dut, input_dict=r0_ospf_cost)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    step(
+        "Swap the costs between interfaces on r0, between r0 and r1 to 30"
+        ", r0 and r2 to 20"
+    )
+
+    r0_ospf_cost = {
+        "r0": {"links": {"r1": {"ospf6": {"cost": 30}}, "r2": {"ospf6": {"cost": 20}}}}
+    }
+    result = config_ospf6_interface(tgen, topo, r0_ospf_cost)
+    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+    step(
+        "Verify that cost is updated in the ospf interface between r0 "
+        "and r1 as 30 and r0 and r2 as 20."
+    )
+    result = verify_ospf6_interface(tgen, topo, dut=dut, input_dict=r0_ospf_cost)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    step(" Un configure cost from the interface r0 - r1.")
+
+    r0_ospf_cost = {
+        "r0": {"links": {"r1": {"ospf6": {"cost": 30, "del_action": True}}}}
+    }
+    result = config_ospf6_interface(tgen, topo, r0_ospf_cost)
+    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+    input_dict = {
+        "r0": {"links": {"r1": {"ospf6": {"cost": 10}}, "r2": {"ospf6": {"cost": 20}}}}
+    }
+    step(
+        "Verify that cost is updated in the ospf interface between r0"
+        " and r1 as 10 and r0 and r2 as 20."
+    )
+
+    result = verify_ospf6_interface(tgen, topo, dut=dut, input_dict=input_dict)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    step(" Un configure cost from the interface r0 - r2.")
+
+    r0_ospf_cost = {
+        "r0": {"links": {"r2": {"ospf6": {"cost": 20, "del_action": True}}}}
+    }
+    result = config_ospf6_interface(tgen, topo, r0_ospf_cost)
+    assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+    step(
+        "Verify that cost is updated in the ospf interface between r0"
+        "and r1 as 10 and r0 and r2 as 10"
+    )
+
+    input_dict = {
+        "r0": {"links": {"r1": {"ospf6": {"cost": 10}}, "r2": {"ospf6": {"cost": 10}}}}
+    }
+    result = verify_ospf6_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/ospfv3_basic_functionality/test_ospfv3_single_area.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_single_area.py
new file mode 100644 (file)
index 0000000..a84f1a1
--- /dev/null
@@ -0,0 +1,417 @@
+#!/usr/bin/python
+
+#
+# Copyright (c) 2021 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
+from lib.topotest import frr_unicode
+
+# 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_ospf6_neighbor,
+    config_ospf_interface,
+    clear_ospf,
+    verify_ospf6_rib,
+    create_router_ospf,
+    verify_ospf6_interface,
+    verify_ospf6_database,
+    config_ospf6_interface,
+)
+
+from ipaddress import IPv6Address
+
+# Global variables
+topo = None
+
+# Reading the data from JSON File for topology creation
+jsonFile = "{}/ospfv3_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.
+5. Verify NFSM events when ospf nbr changes with different MTU values.
+ """
+
+
+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_ospf6_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_ospfv3_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": {"ospf6": {"ospf6Enabled": True}}}}}
+    result = verify_ospf6_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": {
+                    "ipv6": topo["routers"]["r0"]["links"]["r3"]["ipv6"],
+                    "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"]["ipv6"]
+    topo_modify_change_ip["routers"]["r0"]["links"]["r3"]["ipv6"] = str(
+        IPv6Address(frr_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": {
+                    "ospf6": {
+                        "internetAddress": [
+                            {
+                                "type": "inet6",
+                                "address": topo_modify_change_ip["routers"]["r0"][
+                                    "links"
+                                ]["r3"]["ipv6"].split("/")[0],
+                            }
+                        ],
+                    }
+                }
+            }
+        }
+    }
+    result = verify_ospf6_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"]["ipv6"]
+    mask = topo_modify_change_ip["routers"]["r0"]["links"]["r3"]["ipv6"]
+    step("Delete the ip address")
+    topo1 = {
+        "r0": {
+            "links": {
+                "r3": {
+                    "ipv6": 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"]["ipv6"]
+    topo_modify_change_ip["routers"]["r0"]["links"]["r3"]["ipv6"] = str(
+        IPv6Address(frr_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": {
+                    "ospf6": {
+                        "internetAddress": [
+                            {
+                                "type": "inet6",
+                                "address": topo_modify_change_ip["routers"]["r0"][
+                                    "links"
+                                ]["r3"]["ipv6"].split("/")[0],
+                            }
+                        ],
+                    }
+                }
+            }
+        }
+    }
+    result = verify_ospf6_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": {
+                    "ipv6": topo_modify_change_ip["routers"]["r0"]["links"]["r3"][
+                        "ipv6"
+                    ],
+                    "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"],
+                    "ospf6": {"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"],
+                    "ospf6": {"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": {"ospf6": {"ospf6Enabled": True}}}}}
+    result = verify_ospf6_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"],
+                    "ospf6": {"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"],
+                    "ospf6": {"area": "0.0.0.0"},
+                }
+            }
+        }
+    }
+
+    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": {"ospf6": {"ospf6Enabled": True}}}}}
+    result = verify_ospf6_interface(tgen, topo, dut=dut, input_dict=input_dict)
+    assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+    step("verify the all neighbors are up after clearing the process.")
+    for rtr in topo["routers"]:
+        clear_ospf(tgen, rtr, ospf="ospf6")
+
+    ospf_covergence = verify_ospf6_neighbor(tgen, topo)
+    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))
index 0d6432048875239b81bdb5c9e30827e255f0503b..732470f828441c0fc6f4c98e9a9b8c3f35a3f6cb 100644 (file)
@@ -31,7 +31,29 @@ show bgp ipv6 statistics
 show bgp martian next-hop
 show bgp nexthop
 
+show bgp vrf all summary
+show bgp vrf all ipv4
+show bgp vrf all ipv6
+show bgp vrf all neighbors
+
 show bgp evpn route
+show bgp l2vpn evpn route vni all
+show bgp l2vpn evpn vni
+show bgp l2vpn evpn import-rt
+show bgp l2vpn evpn vrf-import-rt
+show bgp l2vpn evpn all overlay
+show bgp l2vpn evpn summary
+show bgp l2vpn evpn route detail
+show bgp l2vpn evpn vni remote-ip-hash
+show bgp l2vpn evpn vni-svi-hash
+
+show evpn
+show evpn arp-cache vni all detail
+show evpn mac vni all detail
+show evpn next-hops vni all
+show evpn rmac vni all
+show evpn vni detail
+
 CMD_LIST_END
 
 # Zebra Support Bundle Command List
index 448ab79ead8ee937993ff734e46665e5710b3805..eb8753fd088b36f732b520e6f96263bcc3018b32 100755 (executable)
@@ -595,10 +595,12 @@ end
             "ip ",
             "ipv6 ",
             "log ",
+            "mac access-list ",
             "mpls lsp",
             "mpls label",
             "no ",
             "password ",
+            "pbr ",
             "ptm-enable",
             "router-id ",
             "service ",
@@ -1388,6 +1390,53 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del):
                                 if found_add_bfd_nbr:
                                     lines_to_del_to_del.append((ctx_keys, line))
 
+                """
+                Neighbor changes of route-maps need to be accounted for in that we
+                do not want to do a `no route-map...` `route-map ....` when changing
+                a route-map.  This is bad mojo as that we will send/receive
+                data we don't want.
+                Additionally we need to ensure that if we have different afi/safi
+                variants that they actually match and if we are going from a very
+                old style command such that the neighbor command is under the
+                `router bgp ..` node that we need to handle that appropriately
+                """
+                re_nbr_rm = re.search("neighbor(.*)route-map(.*)(in|out)$", line)
+                if re_nbr_rm:
+                    adjust_for_bgp_node = 0
+                    neighbor_name = re_nbr_rm.group(1)
+                    rm_name_del = re_nbr_rm.group(2)
+                    dir = re_nbr_rm.group(3)
+                    search = "neighbor%sroute-map(.*)%s" % (neighbor_name, dir)
+                    save_line = "EMPTY"
+                    for (ctx_keys_al, add_line) in lines_to_add:
+                        if ctx_keys_al[0].startswith("router bgp"):
+                            if add_line:
+                                rm_match = re.search(search, add_line)
+                            if rm_match:
+                                rm_name_add = rm_match.group(1)
+                                if rm_name_add == rm_name_del:
+                                    continue
+                                if len(ctx_keys_al) == 1:
+                                    save_line = line
+                                    adjust_for_bgp_node = 1
+                                else:
+                                    if (
+                                        len(ctx_keys) > 1
+                                        and len(ctx_keys_al) > 1
+                                        and ctx_keys[1] == ctx_keys_al[1]
+                                    ):
+                                        lines_to_del_to_del.append((ctx_keys_al, line))
+
+                    if adjust_for_bgp_node == 1:
+                        for (ctx_keys_dl, dl_line) in lines_to_del:
+                            if (
+                                ctx_keys_dl[0].startswith("router bgp")
+                                and len(ctx_keys_dl) > 1
+                                and ctx_keys_dl[1] == "address-family ipv4 unicast"
+                            ):
+                                if save_line == dl_line:
+                                    lines_to_del_to_del.append((ctx_keys_dl, save_line))
+
                 """
                 We changed how we display the neighbor interface command. Older
                 versions of frr would display the following:
index 6c3863132d69fe73050fbaf3389aa045e1078249..7af9148a8e39f4d7d2ba8b88551b04011052fa38 100644 (file)
@@ -771,6 +771,7 @@ void vrrp_vty_init(void)
        install_node(&debug_node);
        install_node(&interface_node);
        install_node(&vrrp_node);
+       vrf_cmd_init(NULL, &vrrp_privs);
        if_cmd_init();
 
        install_element(VIEW_NODE, &vrrp_vrid_show_cmd);
index a50dccbda694de5844f835c81e0f0c1ace723ad0..41b7bc8a10d5674f3f354ca31176267babd76d82 100644 (file)
@@ -493,6 +493,7 @@ static int vtysh_execute_func(const char *line, int pager)
         */
        while (ret != CMD_SUCCESS && ret != CMD_SUCCESS_DAEMON
               && ret != CMD_WARNING && ret != CMD_WARNING_CONFIG_FAILED
+              && ret != CMD_ERR_AMBIGUOUS && ret != CMD_ERR_INCOMPLETE
               && vty->node > CONFIG_NODE) {
                vty->node = node_parent(vty->node);
                ret = cmd_execute(vty, line, &cmd, 1);
@@ -794,6 +795,7 @@ int vtysh_mark_file(const char *filename)
                 */
                while (ret != CMD_SUCCESS && ret != CMD_SUCCESS_DAEMON
                       && ret != CMD_WARNING && ret != CMD_WARNING_CONFIG_FAILED
+                      && ret != CMD_ERR_AMBIGUOUS && ret != CMD_ERR_INCOMPLETE
                       && vty->node > CONFIG_NODE) {
                        vty->node = node_parent(vty->node);
                        ret = cmd_execute_command_strict(vline, vty, &cmd);
@@ -1261,7 +1263,6 @@ static struct cmd_node pw_node = {
        .prompt = "%s(config-pw)# ",
 };
 
-#if defined(HAVE_PATHD)
 static struct cmd_node segment_routing_node = {
        .name = "segment-routing",
        .node = SEGMENT_ROUTING_NODE,
@@ -1269,6 +1270,7 @@ static struct cmd_node segment_routing_node = {
        .prompt = "%s(config-sr)# ",
 };
 
+#if defined(HAVE_PATHD)
 static struct cmd_node sr_traffic_eng_node = {
        .name = "sr traffic-eng",
        .node = SR_TRAFFIC_ENG_NODE,
@@ -2169,7 +2171,6 @@ DEFUNSH(VTYSH_FABRICD, router_openfabric, router_openfabric_cmd, "router openfab
 }
 #endif /* HAVE_FABRICD */
 
-#if defined(HAVE_PATHD)
 DEFUNSH(VTYSH_SR, segment_routing, segment_routing_cmd,
        "segment-routing",
        "Configure segment routing\n")
@@ -2178,6 +2179,7 @@ DEFUNSH(VTYSH_SR, segment_routing, segment_routing_cmd,
        return CMD_SUCCESS;
 }
 
+#if defined (HAVE_PATHD)
 DEFUNSH(VTYSH_PATHD, sr_traffic_eng, sr_traffic_eng_cmd,
        "traffic-eng",
        "Configure SR traffic engineering\n")
@@ -2662,6 +2664,18 @@ DEFUNSH(VTYSH_KEYS, vtysh_quit_keys, vtysh_quit_keys_cmd, "quit",
        return vtysh_exit_keys(self, vty, argc, argv);
 }
 
+DEFUNSH(VTYSH_SR, vtysh_exit_sr, vtysh_exit_sr_cmd, "exit",
+       "Exit current mode and down to previous mode\n")
+{
+       return vtysh_exit(vty);
+}
+
+DEFUNSH(VTYSH_SR, vtysh_quit_sr, vtysh_quit_sr_cmd, "quit",
+       "Exit current mode and down to previous mode\n")
+{
+       return vtysh_exit(vty);
+}
+
 #if defined(HAVE_PATHD)
 DEFUNSH(VTYSH_PATHD, vtysh_exit_pathd, vtysh_exit_pathd_cmd, "exit",
        "Exit current mode and down to previous mode\n")
@@ -4327,15 +4341,17 @@ void vtysh_init_vty(void)
        install_element(BFD_PROFILE_NODE, &vtysh_end_all_cmd);
 #endif /* HAVE_BFDD */
 
-#if defined(HAVE_PATHD)
        install_node(&segment_routing_node);
+       install_element(SEGMENT_ROUTING_NODE, &vtysh_exit_sr_cmd);
+       install_element(SEGMENT_ROUTING_NODE, &vtysh_quit_sr_cmd);
+       install_element(SEGMENT_ROUTING_NODE, &vtysh_end_all_cmd);
+
+#if defined(HAVE_PATHD)
        install_node(&sr_traffic_eng_node);
        install_node(&srte_segment_list_node);
        install_node(&srte_policy_node);
        install_node(&srte_candidate_dyn_node);
 
-       install_element(SEGMENT_ROUTING_NODE, &vtysh_exit_pathd_cmd);
-       install_element(SEGMENT_ROUTING_NODE, &vtysh_quit_pathd_cmd);
        install_element(SR_TRAFFIC_ENG_NODE, &vtysh_exit_pathd_cmd);
        install_element(SR_TRAFFIC_ENG_NODE, &vtysh_quit_pathd_cmd);
        install_element(SR_SEGMENT_LIST_NODE, &vtysh_exit_pathd_cmd);
@@ -4345,7 +4361,7 @@ void vtysh_init_vty(void)
        install_element(SR_CANDIDATE_DYN_NODE, &vtysh_exit_pathd_cmd);
        install_element(SR_CANDIDATE_DYN_NODE, &vtysh_quit_pathd_cmd);
 
-       install_element(SEGMENT_ROUTING_NODE, &vtysh_end_all_cmd);
+
        install_element(SR_TRAFFIC_ENG_NODE, &vtysh_end_all_cmd);
        install_element(SR_SEGMENT_LIST_NODE, &vtysh_end_all_cmd);
        install_element(SR_POLICY_NODE, &vtysh_end_all_cmd);
index 87f1f67443302879d53219372276a9f0412dbd77..71f672554bb2c2cdfffe4e6a785f9320bfbc1de1 100644 (file)
@@ -56,7 +56,7 @@ DECLARE_MGROUP(MVTYSH);
 #define VTYSH_ACL         VTYSH_BFDD|VTYSH_BABELD|VTYSH_BGPD|VTYSH_EIGRPD|VTYSH_ISISD|VTYSH_FABRICD|VTYSH_LDPD|VTYSH_NHRPD|VTYSH_OSPF6D|VTYSH_OSPFD|VTYSH_PBRD|VTYSH_PIMD|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_VRRPD|VTYSH_ZEBRA
 #define VTYSH_RMAP       VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_EIGRPD|VTYSH_FABRICD
 #define VTYSH_INTERFACE          VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_PBRD|VTYSH_FABRICD|VTYSH_VRRPD
-#define VTYSH_VRF        VTYSH_ZEBRA|VTYSH_PIMD|VTYSH_STATICD
+#define VTYSH_VRF        VTYSH_INTERFACE|VTYSH_STATICD
 #define VTYSH_KEYS        VTYSH_RIPD|VTYSH_EIGRPD
 /* Daemons who can process nexthop-group configs */
 #define VTYSH_NH_GROUP    VTYSH_PBRD|VTYSH_SHARPD
index ca60c8f7b6a4876d52719c8d70f61c12aafef373..1c990b5ed9e01845e9c8c4f884e8e24e70dc3880 100644 (file)
@@ -300,6 +300,18 @@ module frr-bgp-route-map {
       "Set BGP large community list (for deletion)";
   }
 
+  identity set-evpn-gateway-ip-ipv4 {
+    base frr-route-map:rmap-set-type;
+    description
+      "Set EVPN gateway IP overlay index IPv4";
+  }
+
+  identity set-evpn-gateway-ip-ipv6 {
+    base frr-route-map:rmap-set-type;
+    description
+      "Set EVPN gateway IP overlay index IPv6";
+  }
+
   grouping extcommunity-non-transitive-types {
     leaf two-octet-as-specific {
       type boolean;
@@ -816,5 +828,25 @@ module frr-bgp-route-map {
         type bgp-filter:bgp-list-name;
       }
     }
+    case evpn-gateway-ip-ipv4 {
+      when
+      "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action,
+      'frr-bgp-route-map:set-evpn-gateway-ip-ipv4')";
+      description
+        "Set EVPN gateway IP overlay index IPv4";
+      leaf evpn-gateway-ip-ipv4 {
+        type inet:ipv4-address;
+      }
+    }
+    case evpn-gateway-ip-ipv6 {
+      when
+      "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action,
+      'frr-bgp-route-map:set-evpn-gateway-ip-ipv6')";
+      description
+        "Set EVPN gateway IP overlay index IPv6";
+      leaf evpn-gateway-ip-ipv6 {
+        type inet:ipv6-address;
+      }
+    }
   }
 }
index 70adb37b26531876c6e843994091745bf2593838..4c4819ac25ac54689d08495d07d404dd73103553 100644 (file)
@@ -174,26 +174,36 @@ module frr-pim {
         "Enable ssmpingd operation.";
     }
 
-    container msdp-mesh-group {
-      presence
-        "Configure MSDP mesh-group.";
+    list msdp-mesh-groups {
+      key "name";
+      description
+        "RFC 3618 Section 10.2. MSDP mesh-group semantics
 
-      leaf mesh-group-name {
-        type string;
+         Groups multiple MSDP peers to reduce SA flooding typically used
+         in intra-domain settings.";
+
+      leaf name {
+        type string {
+          length 1..64;
+        }
         description
-          "MSDP mesh group name.";
+          "The mesh group name.";
       }
 
-      leaf-list member-ip {
+      leaf source {
         type inet:ip-address;
         description
-          "Peer ip address.";
+          "Source IP address for the TCP connections.";
       }
 
-      leaf source-ip {
-        type inet:ip-address;
-        description
-          "Source ip address for the TCP connection.";
+      list members {
+        key "address";
+
+        leaf address {
+          type inet:ip-address;
+          description
+            "Peer member IP address.";
+        }
       }
     }
 
index 06aaa706dcdaa167175f755db8f2991aff861989..d5969ab9bb62b78029e78fd959d7ba3d3bb5a8c9 100644 (file)
@@ -2848,7 +2848,7 @@ stream_failure:
 
 static void zread_table_manager_request(ZAPI_HANDLER_ARGS)
 {
-       /* to avoid sending other messages like ZERBA_INTERFACE_UP */
+       /* to avoid sending other messages like ZEBRA_INTERFACE_UP */
        if (hdr->command == ZEBRA_TABLE_MANAGER_CONNECT)
                zread_table_manager_connect(client, msg, zvrf_id(zvrf));
        else {
@@ -2856,7 +2856,7 @@ static void zread_table_manager_request(ZAPI_HANDLER_ARGS)
                if (!client->proto) {
                        flog_err(
                                EC_ZEBRA_TM_ALIENS,
-                               "Got table request from an unidentified client");
+                               "Got SRv6 request from an unidentified client");
                        return;
                }
                if (hdr->command == ZEBRA_GET_TABLE_CHUNK)
index 30f4a44769e756a649f0378ac6799f9a6778a656..816f46bac91c12feae1c2960cbe42994ce3bea1c 100644 (file)
@@ -134,6 +134,10 @@ void zebra_evpn_print(zebra_evpn_t *zevpn, void **ctxt)
        if (json == NULL) {
                vty_out(vty, " VxLAN interface: %s\n", zevpn->vxlan_if->name);
                vty_out(vty, " VxLAN ifIndex: %u\n", zevpn->vxlan_if->ifindex);
+               vty_out(vty, " SVI interface: %s\n",
+                       (zevpn->svi_if ? zevpn->svi_if->name : ""));
+               vty_out(vty, " SVI ifIndex: %u\n",
+                       (zevpn->svi_if ? zevpn->svi_if->ifindex : 0));
                vty_out(vty, " Local VTEP IP: %pI4\n",
                        &zevpn->local_vtep_ip);
                vty_out(vty, " Mcast group: %pI4\n",
@@ -142,6 +146,12 @@ void zebra_evpn_print(zebra_evpn_t *zevpn, void **ctxt)
                json_object_string_add(json, "vxlanInterface",
                                       zevpn->vxlan_if->name);
                json_object_int_add(json, "ifindex", zevpn->vxlan_if->ifindex);
+               if (zevpn->svi_if) {
+                       json_object_string_add(json, "sviInterface",
+                                              zevpn->svi_if->name);
+                       json_object_int_add(json, "sviIfindex",
+                                           zevpn->svi_if->ifindex);
+               }
                json_object_string_add(json, "vtepIp",
                                       inet_ntop(AF_INET, &zevpn->local_vtep_ip,
                                                 buf, sizeof(buf)));
@@ -1048,6 +1058,8 @@ int zebra_evpn_del(zebra_evpn_t *zevpn)
        zvrf = zebra_vrf_get_evpn();
        assert(zvrf);
 
+       zevpn->svi_if = NULL;
+
        /* Free the neighbor hash table. */
        hash_free(zevpn->neigh_table);
        zevpn->neigh_table = NULL;
@@ -1075,6 +1087,7 @@ int zebra_evpn_send_add_to_client(zebra_evpn_t *zevpn)
 {
        struct zserv *client;
        struct stream *s;
+       ifindex_t svi_index;
        int rc;
 
        client = zserv_find_client(ZEBRA_ROUTE_BGP, 0);
@@ -1082,6 +1095,8 @@ int zebra_evpn_send_add_to_client(zebra_evpn_t *zevpn)
        if (!client)
                return 0;
 
+       svi_index = zevpn->svi_if ? zevpn->svi_if->ifindex : 0;
+
        s = stream_new(ZEBRA_MAX_PACKET_SIZ);
 
        zclient_create_header(s, ZEBRA_VNI_ADD, zebra_vrf_get_evpn_id());
@@ -1089,15 +1104,18 @@ int zebra_evpn_send_add_to_client(zebra_evpn_t *zevpn)
        stream_put_in_addr(s, &zevpn->local_vtep_ip);
        stream_put(s, &zevpn->vrf_id, sizeof(vrf_id_t)); /* tenant vrf */
        stream_put_in_addr(s, &zevpn->mcast_grp);
+       stream_put(s, &svi_index, sizeof(ifindex_t));
 
        /* Write packet size. */
        stream_putw_at(s, 0, stream_get_endp(s));
 
        if (IS_ZEBRA_DEBUG_VXLAN)
-               zlog_debug("Send EVPN_ADD %u %pI4 tenant vrf %s to %s", zevpn->vni,
-                          &zevpn->local_vtep_ip,
-                          vrf_id_to_name(zevpn->vrf_id),
-                          zebra_route_string(client->proto));
+               zlog_debug(
+                       "Send EVPN_ADD %u %pI4 tenant vrf %s(%u) SVI index %u to %s",
+                       zevpn->vni, &zevpn->local_vtep_ip,
+                       vrf_id_to_name(zevpn->vrf_id), zevpn->vrf_id,
+                       (zevpn->svi_if ? zevpn->svi_if->ifindex : 0),
+                       zebra_route_string(client->proto));
 
        client->vniadd_cnt++;
        rc = zserv_send_message(client, s);
index 27392ec85c6e0c206bf9ef4f3393c70aae805ebd..ee9e1406e40cb97771b9d88645fe007647a0e9de 100644 (file)
@@ -98,6 +98,9 @@ struct zebra_evpn_t_ {
        /* Corresponding VxLAN interface. */
        struct interface *vxlan_if;
 
+       /* Corresponding SVI interface. */
+       struct interface *svi_if;
+
        /* List of remote VTEPs */
        zebra_vtep_t *vteps;
 
index cebd5763654bf465ba13ab79590306f0aedc88ca..efbd078a526352bc2cb7c228b7d1e80be2f34fc5 100644 (file)
@@ -42,6 +42,7 @@
 
 #include "zebra/zebra_fpm_private.h"
 #include "zebra/zebra_vxlan_private.h"
+#include "zebra/interface.h"
 
 /*
  * af_addr_size
@@ -164,7 +165,10 @@ static int netlink_route_info_add_nh(struct netlink_route_info *ri,
 {
        struct netlink_nh_info nhi;
        union g_addr *src;
-       zebra_l3vni_t *zl3vni = NULL;
+       struct zebra_vrf *zvrf = NULL;
+       struct interface *ifp = NULL, *link_if = NULL;
+       struct zebra_if *zif = NULL;
+       vni_t vni = 0;
 
        memset(&nhi, 0, sizeof(nhi));
        src = NULL;
@@ -199,12 +203,29 @@ static int netlink_route_info_add_nh(struct netlink_route_info *ri,
        if (re && CHECK_FLAG(re->flags, ZEBRA_FLAG_EVPN_ROUTE)) {
                nhi.encap_info.encap_type = FPM_NH_ENCAP_VXLAN;
 
-               zl3vni = zl3vni_from_vrf(nexthop->vrf_id);
-               if (zl3vni && is_l3vni_oper_up(zl3vni)) {
-
-                       /* Add VNI to VxLAN encap info */
-                       nhi.encap_info.vxlan_encap.vni = zl3vni->vni;
+               /* Extract VNI id for the nexthop SVI interface */
+               zvrf = zebra_vrf_lookup_by_id(nexthop->vrf_id);
+               if (zvrf) {
+                       ifp = if_lookup_by_index_per_ns(zvrf->zns,
+                                                       nexthop->ifindex);
+                       if (ifp) {
+                               zif = (struct zebra_if *)ifp->info;
+                               if (zif) {
+                                       if (IS_ZEBRA_IF_BRIDGE(ifp))
+                                               link_if = ifp;
+                                       else if (IS_ZEBRA_IF_VLAN(ifp))
+                                               link_if =
+                                               if_lookup_by_index_per_ns(
+                                                       zvrf->zns,
+                                                       zif->link_ifindex);
+                                       if (link_if)
+                                               vni = vni_id_from_svi(ifp,
+                                                                     link_if);
+                               }
+                       }
                }
+
+               nhi.encap_info.vxlan_encap.vni = vni;
        }
 
        /*
index ca6a33cd52ec8425301c93048c75e1ca7d3b45b7..5373f27882956353dd4253b157212c8666772c0d 100644 (file)
@@ -118,7 +118,7 @@ static struct client_gr_info *zebra_gr_client_info_create(struct zserv *client)
 }
 
 /*
- * A helper function to delte and destory client info.
+ * A helper function to delete and destroy client info.
  */
 static void zebra_gr_client_info_delte(struct zserv *client,
                                       struct client_gr_info *info)
@@ -162,7 +162,7 @@ int32_t zebra_gr_client_disconnect(struct zserv *client)
 
        client->restart_time = monotime(&tv);
 
-       /* For all the GR instance start the starle removal timer. */
+       /* For all the GR instance start the stale removal timer. */
        TAILQ_FOREACH (info, &client->gr_info_queue, gr_info) {
                if (ZEBRA_CLIENT_GR_ENABLED(info->capabilities)
                    && (info->t_stale_removal == NULL)) {
@@ -298,7 +298,7 @@ void zebra_gr_client_reconnect(struct zserv *client)
 /*
  * Update the graceful restart information
  * for the client instance.
- * This function handles all the capabilties that are received.
+ * This function handles all the capabilities that are received.
  */
 static void zebra_client_update_info(struct zserv *client, struct zapi_cap *api)
 {
@@ -334,7 +334,7 @@ static void zebra_client_update_info(struct zserv *client, struct zapi_cap *api)
                if (!info)
                        info = zebra_gr_client_info_create(client);
 
-               /* Udpate other parameters */
+               /* Update other parameters */
                if (!info->gr_enable) {
                        client->gr_instance_count++;
 
@@ -460,7 +460,7 @@ static int32_t zebra_gr_route_stale_delete_timer_expiry(struct thread *thread)
 
        cnt = zebra_gr_delete_stale_routes(info);
 
-       /* Retsart the timer */
+       /* Restart the timer */
        if (cnt > 0) {
                LOG_GR("%s: Client %s processed %d routes. Start timer again",
                       __func__, zebra_route_string(client->proto), cnt);
@@ -471,7 +471,7 @@ static int32_t zebra_gr_route_stale_delete_timer_expiry(struct thread *thread)
                                 &info->t_stale_removal);
        } else {
                /* No routes to delete for the VRF */
-               LOG_GR("%s: Client %s all starle routes processed", __func__,
+               LOG_GR("%s: Client %s all stale routes processed", __func__,
                       zebra_route_string(client->proto));
 
                XFREE(MTYPE_TMP, info->current_prefix);
@@ -668,7 +668,7 @@ static void zebra_gr_process_client_stale_routes(struct zserv *client,
         * Cancel the stale timer and process the routes
         */
        if (info->t_stale_removal) {
-               LOG_GR("%s: Client %s cancled stale delete timer vrf %d",
+               LOG_GR("%s: Client %s canceled stale delete timer vrf %d",
                       __func__, zebra_route_string(client->proto),
                       info->vrf_id);
                THREAD_OFF(info->t_stale_removal);
index 3b0c75151be2d71cb22a22714d8cc92d8c29f1cf..40a2c94e2aa80130bc62f9e013f0544afed2602f 100644 (file)
@@ -111,7 +111,7 @@ void zebra_mlag_process_mlag_data(uint8_t *data, uint32_t len)
        struct stream *s = NULL;
        int msg_type = 0;
 
-       s = stream_new(ZEBRA_MAX_PACKET_SIZ);
+       s = stream_new(ZEBRA_MLAG_BUF_LIMIT);
        /*
         * Place holder we need the message type first
         */
@@ -1081,7 +1081,7 @@ int zebra_mlag_protobuf_decode_message(struct stream *s, uint8_t *data,
                case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_ADD_BULK: {
                        ZebraMlagMrouteAddBulk *Bulk_msg = NULL;
                        ZebraMlagMrouteAdd *msg = NULL;
-                       size_t i;
+                       size_t i, length_spot;
 
                        Bulk_msg = zebra_mlag_mroute_add_bulk__unpack(
                                NULL, hdr->data.len, hdr->data.data);
@@ -1093,10 +1093,17 @@ int zebra_mlag_protobuf_decode_message(struct stream *s, uint8_t *data,
                        stream_putw(s, (Bulk_msg->n_mroute_add
                                        * sizeof(struct mlag_mroute_add)));
                        /* No. of msgs in Batch */
-                       stream_putw(s, Bulk_msg->n_mroute_add);
+                       length_spot = stream_putw(s, Bulk_msg->n_mroute_add);
 
                        /* Actual Data */
                        for (i = 0; i < Bulk_msg->n_mroute_add; i++) {
+                               if (STREAM_SIZE(s)
+                                   < VRF_NAMSIZ + 22 + INTERFACE_NAMSIZ) {
+                                       zlog_warn(
+                                               "We have received more messages than we can parse at this point in time: %zu",
+                                               Bulk_msg->n_mroute_add);
+                                       break;
+                               }
 
                                msg = Bulk_msg->mroute_add[i];
 
@@ -1116,13 +1123,16 @@ int zebra_mlag_protobuf_decode_message(struct stream *s, uint8_t *data,
                                else
                                        stream_put(s, NULL, INTERFACE_NAMSIZ);
                        }
+
+                       stream_putw_at(s, length_spot, i + 1);
+
                        zebra_mlag_mroute_add_bulk__free_unpacked(Bulk_msg,
                                                                  NULL);
                } break;
                case ZEBRA_MLAG__HEADER__MESSAGE_TYPE__ZEBRA_MLAG_MROUTE_DEL_BULK: {
                        ZebraMlagMrouteDelBulk *Bulk_msg = NULL;
                        ZebraMlagMrouteDel *msg = NULL;
-                       size_t i;
+                       size_t i, length_spot;
 
                        Bulk_msg = zebra_mlag_mroute_del_bulk__unpack(
                                NULL, hdr->data.len, hdr->data.data);
@@ -1134,10 +1144,16 @@ int zebra_mlag_protobuf_decode_message(struct stream *s, uint8_t *data,
                        stream_putw(s, (Bulk_msg->n_mroute_del
                                        * sizeof(struct mlag_mroute_del)));
                        /* No. of msgs in Batch */
-                       stream_putw(s, Bulk_msg->n_mroute_del);
+                       length_spot = stream_putw(s, Bulk_msg->n_mroute_del);
 
                        /* Actual Data */
                        for (i = 0; i < Bulk_msg->n_mroute_del; i++) {
+                               if (STREAM_SIZE(s)
+                                   < VRF_NAMSIZ + 16 + INTERFACE_NAMSIZ) {
+                                       zlog_warn(
+                                               "We have received more messages than we can parse at this time");
+                                       break;
+                               }
 
                                msg = Bulk_msg->mroute_del[i];
 
@@ -1154,6 +1170,9 @@ int zebra_mlag_protobuf_decode_message(struct stream *s, uint8_t *data,
                                else
                                        stream_put(s, NULL, INTERFACE_NAMSIZ);
                        }
+
+                       stream_putw_at(s, length_spot, i + 1);
+
                        zebra_mlag_mroute_del_bulk__free_unpacked(Bulk_msg,
                                                                  NULL);
                } break;
index a4382441c862c1a6243d24938baa1f3205ba5bd1..41d55c2e6c1a99c8ed78a71d50b6c5494c8041cc 100644 (file)
@@ -1367,7 +1367,6 @@ int zebra_send_rnh_update(struct rnh *rnh, struct zserv *client,
        stream_putw_at(s, 0, stream_get_endp(s));
 
        client->nh_last_upd_time = monotime(NULL);
-       client->last_write_cmd = cmd;
        return zserv_send_message(client, s);
 
 failure:
index 98158ecc12b2a22d1d9a694d1de255e93a7c51fd..6dd60af9fb059158c1cfc4b514b5430379733d7d 100644 (file)
@@ -161,7 +161,6 @@ static int zebra_sr_policy_notify_update_client(struct zebra_sr_policy *policy,
        stream_putw_at(s, 0, stream_get_endp(s));
 
        client->nh_last_upd_time = monotime(NULL);
-       client->last_write_cmd = ZEBRA_NEXTHOP_UPDATE;
        return zserv_send_message(client, s);
 
 failure:
index 5664a29682fd847b798bd5db2230a496eb37bfef..b11331a180a225b88063b728d4f9ccc83739cee0 100644 (file)
@@ -181,13 +181,13 @@ assign_srv6_locator_chunk(uint8_t proto,
 
                loc->status_up = false;
                chunk = srv6_locator_chunk_alloc();
-               chunk->proto = 0;
+               chunk->proto = NO_PROTO;
                listnode_add(loc->chunks, chunk);
                zebra_srv6_locator_add(loc);
        }
 
        for (ALL_LIST_ELEMENTS_RO((struct list *)loc->chunks, node, chunk)) {
-               if (chunk->proto != 0 && chunk->proto != proto)
+               if (chunk->proto != NO_PROTO && chunk->proto != proto)
                        continue;
                chunk_found = true;
                break;
@@ -199,6 +199,8 @@ assign_srv6_locator_chunk(uint8_t proto,
        }
 
        chunk->proto = proto;
+       chunk->instance = instance;
+       chunk->session_id = session_id;
        return loc;
 }
 
index 09eb78917ce8b9df1c84eefcaa6135e61c55d72d..2f3ea7475a008b49ca536b81c325a4c42d7809b0 100644 (file)
@@ -1012,6 +1012,7 @@ static int zevpn_build_hash_table_zns(struct ns *ns,
                                        vxl->access_vlan,
                                        zif->brslave_info.br_if);
                                if (vlan_if) {
+                                       zevpn->svi_if = vlan_if;
                                        zevpn->vrf_id = vlan_if->vrf_id;
                                        zl3vni = zl3vni_from_vrf(
                                                        vlan_if->vrf_id);
@@ -1841,6 +1842,27 @@ static zebra_l3vni_t *zl3vni_from_svi(struct interface *ifp,
        return zl3vni;
 }
 
+vni_t vni_id_from_svi(struct interface *ifp, struct interface *br_if)
+{
+       vni_t vni = 0;
+       zebra_evpn_t *zevpn = NULL;
+       zebra_l3vni_t *zl3vni = NULL;
+
+       /* Check if an L3VNI belongs to this SVI interface.
+        * If not, check if an L2VNI belongs to this SVI interface.
+        */
+       zl3vni = zl3vni_from_svi(ifp, br_if);
+       if (zl3vni)
+               vni = zl3vni->vni;
+       else {
+               zevpn = zebra_evpn_from_svi(ifp, br_if);
+               if (zevpn)
+                       vni = zevpn->vni;
+       }
+
+       return vni;
+}
+
 static inline void zl3vni_get_vrr_rmac(zebra_l3vni_t *zl3vni,
                                       struct ethaddr *rmac)
 {
@@ -4527,6 +4549,7 @@ int zebra_vxlan_svi_down(struct interface *ifp, struct interface *link_if)
                zevpn = zebra_evpn_from_svi(ifp, link_if);
 
                if (zevpn) {
+                       zevpn->svi_if = NULL;
                        zevpn->vrf_id = VRF_DEFAULT;
 
                        /* update the tenant vrf in BGP */
@@ -4582,6 +4605,7 @@ int zebra_vxlan_svi_up(struct interface *ifp, struct interface *link_if)
                                vrf_id_to_name(ifp->vrf_id));
 
                /* update the vrf information for l2-vni and inform bgp */
+               zevpn->svi_if = ifp;
                zevpn->vrf_id = ifp->vrf_id;
 
                if (if_is_operative(zevpn->vxlan_if))
@@ -4792,6 +4816,7 @@ int zebra_vxlan_if_up(struct interface *ifp)
                vlan_if = zvni_map_to_svi(vxl->access_vlan,
                                          zif->brslave_info.br_if);
                if (vlan_if) {
+                       zevpn->svi_if = vlan_if;
                        zevpn->vrf_id = vlan_if->vrf_id;
                        zl3vni = zl3vni_from_vrf(vlan_if->vrf_id);
                        if (zl3vni)
@@ -4894,6 +4919,7 @@ int zebra_vxlan_if_update(struct interface *ifp, uint16_t chgflags)
        struct zebra_l2info_vxlan *vxl = NULL;
        zebra_evpn_t *zevpn = NULL;
        zebra_l3vni_t *zl3vni = NULL;
+       struct interface *vlan_if = NULL;
 
        /* Check if EVPN is enabled. */
        if (!is_evpn_enabled())
@@ -4983,6 +5009,7 @@ int zebra_vxlan_if_update(struct interface *ifp, uint16_t chgflags)
                    && (zif->brslave_info.bridge_ifindex == IFINDEX_INTERNAL)) {
                        /* Delete from client, remove all remote VTEPs */
                        /* Also, free up all MACs and neighbors. */
+                       zevpn->svi_if = NULL;
                        zebra_evpn_send_del_to_client(zevpn);
                        zebra_evpn_neigh_del_all(zevpn, 1, 0, DEL_ALL_NEIGH);
                        zebra_evpn_mac_del_all(zevpn, 1, 0, DEL_ALL_MAC);
@@ -5012,6 +5039,11 @@ int zebra_vxlan_if_update(struct interface *ifp, uint16_t chgflags)
                        zebra_evpn_es_set_base_evpn(zevpn);
                }
                zevpn_vxlan_if_set(zevpn, ifp, true /* set */);
+               vlan_if = zvni_map_to_svi(vxl->access_vlan,
+                                         zif->brslave_info.br_if);
+               if (vlan_if)
+                       zevpn->svi_if = vlan_if;
+
                /* Take further actions needed.
                 * Note that if we are here, there is a change of interest.
                 */
@@ -5131,6 +5163,7 @@ int zebra_vxlan_if_add(struct interface *ifp)
                vlan_if = zvni_map_to_svi(vxl->access_vlan,
                                          zif->brslave_info.br_if);
                if (vlan_if) {
+                       zevpn->svi_if = vlan_if;
                        zevpn->vrf_id = vlan_if->vrf_id;
                        zl3vni = zl3vni_from_vrf(vlan_if->vrf_id);
                        if (zl3vni)
index 0556c4adced13b03c1eb6f92425307772b9a974c..84ac76b3b927af71c7f229494c6067e8a594ca5c 100644 (file)
@@ -224,6 +224,7 @@ extern struct interface *zl3vni_map_to_vxlan_if(zebra_l3vni_t *zl3vni);
 extern struct interface *zl3vni_map_to_svi_if(zebra_l3vni_t *zl3vni);
 extern struct interface *zl3vni_map_to_mac_vlan_if(zebra_l3vni_t *zl3vni);
 extern zebra_l3vni_t *zl3vni_lookup(vni_t vni);
+extern vni_t vni_id_from_svi(struct interface *ifp, struct interface *br_if);
 
 DECLARE_HOOK(zebra_rmac_update, (zebra_mac_t *rmac, zebra_l3vni_t *zl3vni,
             bool delete, const char *reason), (rmac, zl3vni, delete, reason));
index 0bf4d8ece298eb1ee0368bb436f42bc287179557..1d94fcae6bbd6e06312facb1c54eff355748a9c3 100644 (file)
@@ -1070,8 +1070,14 @@ static void zebra_show_client_detail(struct vty *vty, struct zserv *client)
                0, client->redist_v4_del_cnt);
        vty_out(vty, "Redist:v6   %-12u%-12u%-12u\n", client->redist_v6_add_cnt,
                0, client->redist_v6_del_cnt);
+       vty_out(vty, "VRF         %-12u%-12u%-12u\n", client->vrfadd_cnt, 0,
+               client->vrfdel_cnt);
        vty_out(vty, "Connected   %-12u%-12u%-12u\n", client->ifadd_cnt, 0,
                client->ifdel_cnt);
+       vty_out(vty, "Interface   %-12u%-12u%-12u\n", client->ifup_cnt, 0,
+               client->ifdown_cnt);
+       vty_out(vty, "Intf Addr   %-12u%-12u%-12u\n",
+               client->connected_rt_add_cnt, 0, client->connected_rt_del_cnt);
        vty_out(vty, "BFD peer    %-12u%-12u%-12u\n", client->bfd_peer_add_cnt,
                client->bfd_peer_upd8_cnt, client->bfd_peer_del_cnt);
        vty_out(vty, "NHT v4      %-12u%-12u%-12u\n",
@@ -1080,20 +1086,17 @@ static void zebra_show_client_detail(struct vty *vty, struct zserv *client)
                client->v6_nh_watch_add_cnt, 0, client->v6_nh_watch_rem_cnt);
        vty_out(vty, "VxLAN SG    %-12u%-12u%-12u\n", client->vxlan_sg_add_cnt,
                0, client->vxlan_sg_del_cnt);
-       vty_out(vty, "Interface Up Notifications: %u\n", client->ifup_cnt);
-       vty_out(vty, "Interface Down Notifications: %u\n", client->ifdown_cnt);
-       vty_out(vty, "VNI add notifications: %u\n", client->vniadd_cnt);
-       vty_out(vty, "VNI delete notifications: %u\n", client->vnidel_cnt);
-       vty_out(vty, "L3-VNI add notifications: %u\n", client->l3vniadd_cnt);
-       vty_out(vty, "L3-VNI delete notifications: %u\n", client->l3vnidel_cnt);
-       vty_out(vty, "MAC-IP add notifications: %u\n", client->macipadd_cnt);
-       vty_out(vty, "MAC-IP delete notifications: %u\n", client->macipdel_cnt);
-       vty_out(vty, "ES add notifications: %u\n", client->local_es_add_cnt);
-       vty_out(vty, "ES delete notifications: %u\n", client->local_es_del_cnt);
-       vty_out(vty, "ES-EVI add notifications: %u\n",
-                       client->local_es_evi_add_cnt);
-       vty_out(vty, "ES-EVI delete notifications: %u\n",
-                       client->local_es_evi_del_cnt);
+       vty_out(vty, "VNI         %-12u%-12u%-12u\n", client->vniadd_cnt, 0,
+               client->vnidel_cnt);
+       vty_out(vty, "L3-VNI      %-12u%-12u%-12u\n", client->l3vniadd_cnt, 0,
+               client->l3vnidel_cnt);
+       vty_out(vty, "MAC-IP      %-12u%-12u%-12u\n", client->macipadd_cnt, 0,
+               client->macipdel_cnt);
+       vty_out(vty, "ES          %-12u%-12u%-12u\n", client->local_es_add_cnt,
+               0, client->local_es_del_cnt);
+       vty_out(vty, "ES-EVI      %-12u%-12u%-12u\n",
+               client->local_es_evi_add_cnt, 0, client->local_es_evi_del_cnt);
+       vty_out(vty, "Errors: %u\n", client->error_cnt);
 
        TAILQ_FOREACH (info, &client->gr_info_queue, gr_info) {
                vty_out(vty, "VRF : %s\n", vrf_id_to_name(info->vrf_id));