]> git.proxmox.com Git - mirror_frr.git/commitdiff
Merge pull request #9471 from pguibert6WIND/table_manager_alloc2
authorRuss White <russ@riw.us>
Fri, 8 Oct 2021 17:49:54 +0000 (13:49 -0400)
committerGitHub <noreply@github.com>
Fri, 8 Oct 2021 17:49:54 +0000 (13:49 -0400)
zebra: extend table manager per vrf, add vty configuration

341 files changed:
.dir-locals.el
.gitignore
bfdd/control.c
bgpd/bgp_attr.c
bgpd/bgp_attr.h
bgpd/bgp_clist.c
bgpd/bgp_conditional_adv.c
bgpd/bgp_dump.c
bgpd/bgp_evpn.c
bgpd/bgp_evpn_mh.c
bgpd/bgp_evpn_mh.h
bgpd/bgp_evpn_vty.c
bgpd/bgp_mplsvpn.c
bgpd/bgp_mplsvpn.h
bgpd/bgp_network.c
bgpd/bgp_packet.c
bgpd/bgp_route.c
bgpd/bgp_route.h
bgpd/bgp_routemap_nb_config.c
bgpd/bgp_table.c
bgpd/bgp_table.h
bgpd/bgp_trace.h
bgpd/bgp_updgrp_adv.c
bgpd/bgp_vty.c
bgpd/bgp_zebra.c
bgpd/bgp_zebra.h
bgpd/bgpd.c
bgpd/bgpd.h
bgpd/rfapi/rfapi_vty.c
configure.ac
doc/developer/cli.rst
doc/developer/grpc.rst
doc/developer/logging.rst
doc/developer/topotests.rst
doc/developer/workflow.rst
doc/user/bgp.rst
doc/user/isisd.rst
doc/user/ospf6d.rst
doc/user/ospfd.rst
doc/user/routemap.rst
doc/user/setup.rst
doc/user/zebra.rst
docker/ubuntu20-ci/Dockerfile
eigrpd/eigrp_filter.c
eigrpd/eigrp_hello.c
eigrpd/eigrp_interface.c
eigrpd/eigrp_northbound.c
eigrpd/eigrp_packet.c
eigrpd/eigrp_update.c
eigrpd/eigrpd.c
isisd/fabricd.c
isisd/isis_cli.c
isisd/isis_redist.c
isisd/isis_snmp.c
isisd/isis_tx_queue.c
isisd/isisd.h
ldpd/accept.c
ldpd/interface.c
ldpd/lde.c
ldpd/lde_lib.c
ldpd/ldpd.c
ldpd/ldpe.c
ldpd/packet.c
lib/command.c
lib/command.h
lib/command_graph.c
lib/command_graph.h
lib/command_lex.l
lib/command_match.c
lib/command_parse.y
lib/command_py.c
lib/frr_zmq.c
lib/frr_zmq.h
lib/libfrr.c
lib/module.c
lib/module.h
lib/nexthop.c
lib/nexthop.h
lib/northbound_cli.c
lib/northbound_grpc.cpp
lib/prefix.h
lib/resolver.c
lib/routemap.c
lib/routemap.h
lib/skiplist.c
lib/skiplist.h
lib/vector.c
lib/vector.h
lib/vrf.c
lib/vrf.h
lib/zclient.c
lib/zclient.h
nhrpd/netlink_arp.c
nhrpd/nhrp_event.c
nhrpd/nhrp_multicast.c
nhrpd/nhrp_nhs.c
nhrpd/nhrp_peer.c
nhrpd/nhrp_shortcut.c
nhrpd/vici.c
ospf6d/ospf6_abr.c
ospf6d/ospf6_abr.h
ospf6d/ospf6_area.c
ospf6d/ospf6_area.h
ospf6d/ospf6_asbr.c
ospf6d/ospf6_flood.c
ospf6d/ospf6_flood.h
ospf6d/ospf6_gr.c [new file with mode: 0644]
ospf6d/ospf6_gr.h
ospf6d/ospf6_gr_helper.c
ospf6d/ospf6_interface.c
ospf6d/ospf6_interface.h
ospf6d/ospf6_intra.c
ospf6d/ospf6_intra.h
ospf6d/ospf6_lsa.c
ospf6d/ospf6_lsa.h
ospf6d/ospf6_message.c
ospf6d/ospf6_neighbor.c
ospf6d/ospf6_neighbor.h
ospf6d/ospf6_nssa.c
ospf6d/ospf6_nssa.h
ospf6d/ospf6_route.c
ospf6d/ospf6_route.h
ospf6d/ospf6_spf.c
ospf6d/ospf6_spf.h
ospf6d/ospf6_top.c
ospf6d/ospf6_top.h
ospf6d/ospf6_zebra.c
ospf6d/ospf6_zebra.h
ospf6d/ospf6d.c
ospf6d/ospf6d.h
ospf6d/subdir.am
ospfd/ospf_gr_helper.c
ospfd/ospf_interface.c
ospfd/ospf_nsm.c
ospfd/ospf_vty.c
pathd/path_cli.c
pimd/pim_assert.h
pimd/pim_bfd.c
pimd/pim_bsm.c
pimd/pim_cmd.c
pimd/pim_iface.c
pimd/pim_iface.h
pimd/pim_ifchannel.h
pimd/pim_igmp.c
pimd/pim_igmp.h
pimd/pim_igmpv3.c
pimd/pim_igmpv3.h
pimd/pim_instance.h
pimd/pim_mroute.h
pimd/pim_msdp.c
pimd/pim_msdp_socket.c
pimd/pim_nb_config.c
pimd/pim_neighbor.h
pimd/pim_oil.h
pimd/pim_pim.c
pimd/pim_rp.c
pimd/pim_rp.h
pimd/pim_rpf.c
pimd/pim_rpf.h
pimd/pim_upstream.h
pimd/pim_zebra.c
pimd/pim_zlookup.c
pimd/pimd.h
python/clidef.py
ripd/rip_interface.c
ripd/rip_peer.c
ripd/ripd.c
ripngd/ripng_interface.c
ripngd/ripngd.c
ripngd/ripngd.h
staticd/static_nb.c
staticd/static_nb_config.c
staticd/static_routes.c
staticd/static_routes.h
staticd/static_vrf.c
staticd/static_vty.c
staticd/static_vty.h
tests/bgpd/test_mpath.c
tests/lib/cli/test_cli.c
tests/lib/cli/test_cli.in
tests/lib/cli/test_cli.refout.in
tests/lib/test_grpc.cpp
tests/lib/test_nexthop.c
tests/lib/test_printfrr.c
tests/lib/test_skiplist.c [new file with mode: 0644]
tests/lib/test_timer_correctness.c
tests/lib/test_timer_performance.c
tests/subdir.am
tests/topotests/all_protocol_startup/test_all_protocol_startup.py
tests/topotests/bfd_ospf_topo1/rt1/ospf6d.conf
tests/topotests/bfd_ospf_topo1/rt1/ospfd.conf
tests/topotests/bfd_ospf_topo1/rt2/ospf6d.conf
tests/topotests/bfd_ospf_topo1/rt2/ospfd.conf
tests/topotests/bfd_ospf_topo1/rt3/ospf6d.conf
tests/topotests/bfd_ospf_topo1/rt3/ospfd.conf
tests/topotests/bfd_ospf_topo1/rt4/ospf6d.conf
tests/topotests/bfd_ospf_topo1/rt4/ospfd.conf
tests/topotests/bfd_ospf_topo1/rt5/ospf6d.conf
tests/topotests/bfd_ospf_topo1/rt5/ospfd.conf
tests/topotests/bfd_ospf_topo1/test_bfd_ospf_topo1.py
tests/topotests/bgp_default_route_route_map_match_set/test_bgp_default-originate_route-map_match_set.py
tests/topotests/bgp_evpn_overlay_index_gateway/host2/zebra.conf
tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py
tests/topotests/bgp_prefix_sid2/peer1/exabgp.cfg
tests/topotests/bgp_snmp_mplsl3vpn/test_bgp_snmp_mplsvpn.py
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/vpnv6_rib_locator_deleted.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/vpnv6_rib_locator_recreated.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/vrf10_rib.json
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/vrf20_rib.json
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/zebra.conf
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/vpnv6_rib_locator_deleted.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/vpnv6_rib_locator_recreated.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/vrf10_rib.json
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/vrf20_rib.json
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/zebra.conf
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/test_bgp_srv6l3vpn_to_bgp_vrf.py
tests/topotests/example_test/r1/zebra.conf [new file with mode: 0644]
tests/topotests/example_test/r2/zebra.conf [new file with mode: 0644]
tests/topotests/example_test/test_template.py
tests/topotests/lib/bgp.py
tests/topotests/lib/common_config.py
tests/topotests/lib/ltemplate.py
tests/topotests/lib/ospf.py
tests/topotests/lib/pim.py
tests/topotests/lib/topotest.py
tests/topotests/multicast_pim_sm_topo1/test_multicast_pim_sm_topo1.py
tests/topotests/ospf6_gr_topo1/__init__.py [new file with mode: 0644]
tests/topotests/ospf6_gr_topo1/rt1/ospf6d.conf [new file with mode: 0644]
tests/topotests/ospf6_gr_topo1/rt1/show_ipv6_ospf_database.json [new file with mode: 0644]
tests/topotests/ospf6_gr_topo1/rt1/show_ipv6_ospf_neighbor.json [new file with mode: 0644]
tests/topotests/ospf6_gr_topo1/rt1/show_ipv6_ospf_route.json [new file with mode: 0644]
tests/topotests/ospf6_gr_topo1/rt1/show_ipv6_route.json [new file with mode: 0644]
tests/topotests/ospf6_gr_topo1/rt1/zebra.conf [new file with mode: 0644]
tests/topotests/ospf6_gr_topo1/rt2/ospf6d.conf [new file with mode: 0644]
tests/topotests/ospf6_gr_topo1/rt2/show_ipv6_ospf_database.json [new file with mode: 0644]
tests/topotests/ospf6_gr_topo1/rt2/show_ipv6_ospf_neighbor.json [new file with mode: 0644]
tests/topotests/ospf6_gr_topo1/rt2/show_ipv6_ospf_route.json [new file with mode: 0644]
tests/topotests/ospf6_gr_topo1/rt2/show_ipv6_route.json [new file with mode: 0644]
tests/topotests/ospf6_gr_topo1/rt2/zebra.conf [new file with mode: 0644]
tests/topotests/ospf6_gr_topo1/rt3/ospf6d.conf [new file with mode: 0644]
tests/topotests/ospf6_gr_topo1/rt3/show_ipv6_ospf_database.json [new file with mode: 0644]
tests/topotests/ospf6_gr_topo1/rt3/show_ipv6_ospf_neighbor.json [new file with mode: 0644]
tests/topotests/ospf6_gr_topo1/rt3/show_ipv6_ospf_route.json [new file with mode: 0644]
tests/topotests/ospf6_gr_topo1/rt3/show_ipv6_route.json [new file with mode: 0644]
tests/topotests/ospf6_gr_topo1/rt3/zebra.conf [new file with mode: 0644]
tests/topotests/ospf6_gr_topo1/rt4/ospf6d.conf [new file with mode: 0644]
tests/topotests/ospf6_gr_topo1/rt4/show_ipv6_ospf_database.json [new file with mode: 0644]
tests/topotests/ospf6_gr_topo1/rt4/show_ipv6_ospf_neighbor.json [new file with mode: 0644]
tests/topotests/ospf6_gr_topo1/rt4/show_ipv6_ospf_route.json [new file with mode: 0644]
tests/topotests/ospf6_gr_topo1/rt4/show_ipv6_route.json [new file with mode: 0644]
tests/topotests/ospf6_gr_topo1/rt4/zebra.conf [new file with mode: 0644]
tests/topotests/ospf6_gr_topo1/rt5/ospf6d.conf [new file with mode: 0644]
tests/topotests/ospf6_gr_topo1/rt5/show_ipv6_ospf_database.json [new file with mode: 0644]
tests/topotests/ospf6_gr_topo1/rt5/show_ipv6_ospf_neighbor.json [new file with mode: 0644]
tests/topotests/ospf6_gr_topo1/rt5/show_ipv6_ospf_route.json [new file with mode: 0644]
tests/topotests/ospf6_gr_topo1/rt5/show_ipv6_route.json [new file with mode: 0644]
tests/topotests/ospf6_gr_topo1/rt5/zebra.conf [new file with mode: 0644]
tests/topotests/ospf6_gr_topo1/rt6/ospf6d.conf [new file with mode: 0644]
tests/topotests/ospf6_gr_topo1/rt6/show_ipv6_ospf_database.json [new file with mode: 0644]
tests/topotests/ospf6_gr_topo1/rt6/show_ipv6_ospf_neighbor.json [new file with mode: 0644]
tests/topotests/ospf6_gr_topo1/rt6/show_ipv6_ospf_route.json [new file with mode: 0644]
tests/topotests/ospf6_gr_topo1/rt6/show_ipv6_route.json [new file with mode: 0644]
tests/topotests/ospf6_gr_topo1/rt6/zebra.conf [new file with mode: 0644]
tests/topotests/ospf6_gr_topo1/rt7/ospf6d.conf [new file with mode: 0644]
tests/topotests/ospf6_gr_topo1/rt7/show_ipv6_ospf_database.json [new file with mode: 0644]
tests/topotests/ospf6_gr_topo1/rt7/show_ipv6_ospf_neighbor.json [new file with mode: 0644]
tests/topotests/ospf6_gr_topo1/rt7/show_ipv6_ospf_route.json [new file with mode: 0644]
tests/topotests/ospf6_gr_topo1/rt7/show_ipv6_route.json [new file with mode: 0644]
tests/topotests/ospf6_gr_topo1/rt7/zebra.conf [new file with mode: 0644]
tests/topotests/ospf6_gr_topo1/test_ospf6_gr_topo1.py [new file with mode: 0755]
tests/topotests/ospf6_topo2/test_ospf6_topo2.py
tests/topotests/ospf_gr_helper/test_ospf_gr_helper.py
tests/topotests/ospf_gr_topo1/rt1/ospfd.conf
tests/topotests/ospf_gr_topo1/rt2/ospfd.conf
tests/topotests/ospf_gr_topo1/rt3/ospfd.conf
tests/topotests/ospf_gr_topo1/rt4/ospfd.conf
tests/topotests/ospf_gr_topo1/rt5/ospfd.conf
tests/topotests/ospf_gr_topo1/rt6/ospfd.conf
tests/topotests/ospf_gr_topo1/rt7/ospfd.conf
tests/topotests/route_scale/scale_test_common.py [new file with mode: 0644]
tests/topotests/route_scale/test_route_scale.py [deleted file]
tests/topotests/route_scale/test_route_scale1.py [new file with mode: 0644]
tests/topotests/route_scale/test_route_scale2.py [new file with mode: 0644]
tests/topotests/srv6_locator/expected_chunks4.json
tests/topotests/srv6_locator/expected_chunks5.json
tests/topotests/srv6_locator/expected_chunks6.json [new file with mode: 0644]
tests/topotests/srv6_locator/expected_locators4.json
tests/topotests/srv6_locator/expected_locators5.json
tests/topotests/srv6_locator/expected_locators6.json [new file with mode: 0644]
tests/topotests/srv6_locator/test_srv6_locator.py
tests/topotests/zebra_netlink/r1/sharpd.conf [deleted file]
tests/topotests/zebra_netlink/r1/v4_route.json [deleted file]
tests/topotests/zebra_netlink/test_zebra_netlink.py
tests/zebra/test_lm_plugin.c
tools/coccinelle/struct_thread_null.cocci [new file with mode: 0644]
tools/coccinelle/zlog_no_newline.cocci [new file with mode: 0644]
tools/frr_babeltrace.py [new file with mode: 0755]
tools/permutations.c
tools/valgrind.supp
vtysh/extract.pl.in
vtysh/vtysh.c
vtysh/vtysh_config.c
watchfrr/watchfrr.c
watchfrr/watchfrr.h
watchfrr/watchfrr_vty.c
yang/frr-nexthop.yang
zebra/connected.c
zebra/connected.h
zebra/if_netlink.c
zebra/if_netlink.h
zebra/interface.c
zebra/interface.h
zebra/irdp_main.c
zebra/irdp_packet.c
zebra/kernel_netlink.c
zebra/kernel_netlink.h
zebra/kernel_socket.c
zebra/rt.h
zebra/rt_netlink.c
zebra/rtadv.c
zebra/rule_netlink.c
zebra/zapi_msg.c
zebra/zebra_dplane.c
zebra/zebra_dplane.h
zebra/zebra_evpn_neigh.c
zebra/zebra_fpm.c
zebra/zebra_fpm_netlink.c
zebra/zebra_fpm_private.h
zebra/zebra_l2.c
zebra/zebra_l2.h
zebra/zebra_netns_notify.c
zebra/zebra_nhg.c
zebra/zebra_ns.c
zebra/zebra_ns.h
zebra/zebra_ptm.c
zebra/zebra_rib.c
zebra/zebra_srv6.c
zebra/zebra_srv6_vty.c
zebra/zebra_vty.c
zebra/zebra_vxlan.c
zebra/zebra_vxlan.h

index 1332f7b6a2316b53d317025f61b5c2fa1fc43233..b2d7cf376dc1ea01bd6dd21ccf7653f4894107f2 100644 (file)
@@ -5,6 +5,4 @@
 ((c-mode . ((indent-tabs-mode . t)
             (show-trailing-whitespace . t)
             (c-basic-offset . 8)))
- (json-mode . ((js-indent-level 4)))
- (python-mode . ((python-formatter . black)
-                 (python-fill-column . 88))))
+ (json-mode . ((js-indent-level 4))))
index 40f6475a26f66518fbbd573c063ec5b86b35ac1f..fb40ee52fed9e6aea49dbfc872caa614a7564406 100644 (file)
@@ -113,3 +113,5 @@ refix
 .emacs.desktop*
 
 /test-suite.log
+pceplib/test/*.log
+pceplib/test/*.trs
index 4929bf1998478456d28a36f1f45e7986ad4c129a..e772aadfc41bc9992585c471e7340aed09f146b2 100644 (file)
@@ -167,7 +167,6 @@ int control_accept(struct thread *t)
 
        control_new(csock);
 
-       bglobal.bg_csockev = NULL;
        thread_add_read(master, control_accept, NULL, sd, &bglobal.bg_csockev);
 
        return 0;
index f1c953f21d22fc911c7de772139d1c1471e0bdaa..7de7a6628f8b1ffda3c6f898db34c2c4e557648b 100644 (file)
@@ -530,6 +530,12 @@ static uint32_t srv6_l3vpn_hash_key_make(const void *p)
        key = jhash(&l3vpn->sid, 16, key);
        key = jhash_1word(l3vpn->sid_flags, key);
        key = jhash_1word(l3vpn->endpoint_behavior, key);
+       key = jhash_1word(l3vpn->loc_block_len, key);
+       key = jhash_1word(l3vpn->loc_node_len, key);
+       key = jhash_1word(l3vpn->func_len, key);
+       key = jhash_1word(l3vpn->arg_len, key);
+       key = jhash_1word(l3vpn->transposition_len, key);
+       key = jhash_1word(l3vpn->transposition_offset, key);
        return key;
 }
 
@@ -540,7 +546,13 @@ static bool srv6_l3vpn_hash_cmp(const void *p1, const void *p2)
 
        return sid_same(&l3vpn1->sid, &l3vpn2->sid)
               && l3vpn1->sid_flags == l3vpn2->sid_flags
-              && l3vpn1->endpoint_behavior == l3vpn2->endpoint_behavior;
+              && l3vpn1->endpoint_behavior == l3vpn2->endpoint_behavior
+              && l3vpn1->loc_block_len == l3vpn2->loc_block_len
+              && l3vpn1->loc_node_len == l3vpn2->loc_node_len
+              && l3vpn1->func_len == l3vpn2->func_len
+              && l3vpn1->arg_len == l3vpn2->arg_len
+              && l3vpn1->transposition_len == l3vpn2->transposition_len
+              && l3vpn1->transposition_offset == l3vpn2->transposition_offset;
 }
 
 static bool srv6_l3vpn_same(const struct bgp_attr_srv6_l3vpn *h1,
@@ -691,6 +703,8 @@ unsigned int attrhash_key_make(const void *p)
        key = jhash(attr->mp_nexthop_local.s6_addr, IPV6_MAX_BYTELEN, key);
        MIX3(attr->nh_ifindex, attr->nh_lla_ifindex, attr->distance);
        MIX(attr->rmap_table_id);
+       MIX(attr->nh_type);
+       MIX(attr->bh_type);
 
        return key;
 }
@@ -747,7 +761,9 @@ bool attrhash_cmp(const void *p1, const void *p2)
                    && attr1->distance == attr2->distance
                    && srv6_l3vpn_same(attr1->srv6_l3vpn, attr2->srv6_l3vpn)
                    && srv6_vpn_same(attr1->srv6_vpn, attr2->srv6_vpn)
-                   && attr1->srte_color == attr2->srte_color)
+                   && attr1->srte_color == attr2->srte_color
+                   && attr1->nh_type == attr2->nh_type
+                   && attr1->bh_type == attr2->bh_type)
                        return true;
        }
 
@@ -2529,6 +2545,172 @@ static int bgp_attr_encap(uint8_t type, struct peer *peer, /* IN */
        return 0;
 }
 
+
+/* SRv6 Service Data Sub-Sub-TLV attribute
+ * draft-ietf-bess-srv6-services-07
+ */
+static bgp_attr_parse_ret_t
+bgp_attr_srv6_service_data(struct bgp_attr_parser_args *args)
+{
+       struct peer *const peer = args->peer;
+       struct attr *const attr = args->attr;
+       uint8_t type, loc_block_len, loc_node_len, func_len, arg_len,
+               transposition_len, transposition_offset;
+       uint16_t length;
+       size_t headersz = sizeof(type) + sizeof(length);
+
+       if (STREAM_READABLE(peer->curr) < headersz) {
+               flog_err(
+                       EC_BGP_ATTR_LEN,
+                       "Malformed SRv6 Service Data Sub-Sub-TLV attribute - insufficent data (need %zu for attribute header, have %zu remaining in UPDATE)",
+                       headersz, STREAM_READABLE(peer->curr));
+               return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+                                         args->total);
+       }
+
+       type = stream_getc(peer->curr);
+       length = stream_getw(peer->curr);
+
+       if (STREAM_READABLE(peer->curr) < length) {
+               flog_err(
+                       EC_BGP_ATTR_LEN,
+                       "Malformed SRv6 Service Data Sub-Sub-TLV attribute - insufficent data (need %hu for attribute data, have %zu remaining in UPDATE)",
+                       length, STREAM_READABLE(peer->curr));
+               return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+                                         args->total);
+       }
+
+       if (type == BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE) {
+               loc_block_len = stream_getc(peer->curr);
+               loc_node_len = stream_getc(peer->curr);
+               func_len = stream_getc(peer->curr);
+               arg_len = stream_getc(peer->curr);
+               transposition_len = stream_getc(peer->curr);
+               transposition_offset = stream_getc(peer->curr);
+
+               /* Log SRv6 Service Data Sub-Sub-TLV */
+               if (BGP_DEBUG(vpn, VPN_LEAK_LABEL)) {
+                       zlog_debug(
+                               "%s: srv6-l3-srv-data loc-block-len=%u, loc-node-len=%u func-len=%u, arg-len=%u, transposition-len=%u, transposition-offset=%u",
+                               __func__, loc_block_len, loc_node_len, func_len,
+                               arg_len, transposition_len,
+                               transposition_offset);
+               }
+
+               attr->srv6_l3vpn->loc_block_len = loc_block_len;
+               attr->srv6_l3vpn->loc_node_len = loc_node_len;
+               attr->srv6_l3vpn->func_len = func_len;
+               attr->srv6_l3vpn->arg_len = arg_len;
+               attr->srv6_l3vpn->transposition_len = transposition_len;
+               attr->srv6_l3vpn->transposition_offset = transposition_offset;
+       }
+
+       else {
+               if (bgp_debug_update(peer, NULL, NULL, 1))
+                       zlog_debug(
+                               "%s attr SRv6 Service Data Sub-Sub-TLV sub-sub-type=%u is not supported, skipped",
+                               peer->host, type);
+
+               stream_forward_getp(peer->curr, length);
+       }
+
+       return BGP_ATTR_PARSE_PROCEED;
+}
+
+/* SRv6 Service Sub-TLV attribute
+ * draft-ietf-bess-srv6-services-07
+ */
+static bgp_attr_parse_ret_t
+bgp_attr_srv6_service(struct bgp_attr_parser_args *args)
+{
+       struct peer *const peer = args->peer;
+       struct attr *const attr = args->attr;
+       struct in6_addr ipv6_sid;
+       uint8_t type, sid_flags;
+       uint16_t length, endpoint_behavior;
+       size_t headersz = sizeof(type) + sizeof(length);
+       bgp_attr_parse_ret_t err;
+       char buf[BUFSIZ];
+
+       if (STREAM_READABLE(peer->curr) < headersz) {
+               flog_err(
+                       EC_BGP_ATTR_LEN,
+                       "Malformed SRv6 Service Sub-TLV attribute - insufficent data (need %zu for attribute header, have %zu remaining in UPDATE)",
+                       headersz, STREAM_READABLE(peer->curr));
+               return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+                                         args->total);
+       }
+
+       type = stream_getc(peer->curr);
+       length = stream_getw(peer->curr);
+
+       if (STREAM_READABLE(peer->curr) < length) {
+               flog_err(
+                       EC_BGP_ATTR_LEN,
+                       "Malformed SRv6 Service Sub-TLV attribute - insufficent data (need %hu for attribute data, have %zu remaining in UPDATE)",
+                       length, STREAM_READABLE(peer->curr));
+               return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+                                         args->total);
+       }
+
+       if (type == BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO) {
+               stream_getc(peer->curr);
+               stream_get(&ipv6_sid, peer->curr, sizeof(ipv6_sid));
+               sid_flags = stream_getc(peer->curr);
+               endpoint_behavior = stream_getw(peer->curr);
+               stream_getc(peer->curr);
+
+               /* Log SRv6 Service Sub-TLV */
+               if (BGP_DEBUG(vpn, VPN_LEAK_LABEL)) {
+                       inet_ntop(AF_INET6, &ipv6_sid, buf, sizeof(buf));
+                       zlog_debug(
+                               "%s: srv6-l3-srv sid %s, sid-flags 0x%02x, end-behaviour 0x%04x",
+                               __func__, buf, sid_flags, endpoint_behavior);
+               }
+
+               /* Configure from Info */
+               if (attr->srv6_l3vpn) {
+                       flog_err(EC_BGP_ATTRIBUTE_REPEATED,
+                                "Prefix SID SRv6 L3VPN field repeated");
+                       return bgp_attr_malformed(
+                               args, BGP_NOTIFY_UPDATE_MAL_ATTR, args->total);
+               }
+               attr->srv6_l3vpn = XCALLOC(MTYPE_BGP_SRV6_L3VPN,
+                                          sizeof(struct bgp_attr_srv6_l3vpn));
+               sid_copy(&attr->srv6_l3vpn->sid, &ipv6_sid);
+               attr->srv6_l3vpn->sid_flags = sid_flags;
+               attr->srv6_l3vpn->endpoint_behavior = endpoint_behavior;
+               attr->srv6_l3vpn->loc_block_len = 0;
+               attr->srv6_l3vpn->loc_node_len = 0;
+               attr->srv6_l3vpn->func_len = 0;
+               attr->srv6_l3vpn->arg_len = 0;
+               attr->srv6_l3vpn->transposition_len = 0;
+               attr->srv6_l3vpn->transposition_offset = 0;
+
+               // Sub-Sub-TLV found
+               if (length > BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO_LENGTH) {
+                       err = bgp_attr_srv6_service_data(args);
+
+                       if (err != BGP_ATTR_PARSE_PROCEED)
+                               return err;
+               }
+
+               attr->srv6_l3vpn = srv6_l3vpn_intern(attr->srv6_l3vpn);
+       }
+
+       /* Placeholder code for unsupported type */
+       else {
+               if (bgp_debug_update(peer, NULL, NULL, 1))
+                       zlog_debug(
+                               "%s attr SRv6 Service Sub-TLV sub-type=%u is not supported, skipped",
+                               peer->host, type);
+
+               stream_forward_getp(peer->curr, length);
+       }
+
+       return BGP_ATTR_PARSE_PROCEED;
+}
+
 /*
  * Read an individual SID value returning how much data we have read
  * Returns 0 if there was an error that needs to be passed up the stack
@@ -2544,7 +2726,6 @@ static bgp_attr_parse_ret_t bgp_attr_psid_sub(uint8_t type, uint16_t length,
        uint32_t srgb_range;
        int srgb_count;
        uint8_t sid_type, sid_flags;
-       uint16_t endpoint_behavior;
        char buf[BUFSIZ];
 
        if (type == BGP_PREFIX_SID_LABEL_INDEX) {
@@ -2699,45 +2880,20 @@ static bgp_attr_parse_ret_t bgp_attr_psid_sub(uint8_t type, uint16_t length,
 
        /* Placeholder code for the SRv6 L3 Service type */
        else if (type == BGP_PREFIX_SID_SRV6_L3_SERVICE) {
-               if (STREAM_READABLE(peer->curr) < length
-                   || length != BGP_PREFIX_SID_SRV6_L3_SERVICE_LENGTH) {
-                       flog_err(EC_BGP_ATTR_LEN,
-                                "Prefix SID SRv6 L3-Service length is %hu instead of %u",
-                                length, BGP_PREFIX_SID_SRV6_L3_SERVICE_LENGTH);
+               if (STREAM_READABLE(peer->curr) < length) {
+                       flog_err(
+                               EC_BGP_ATTR_LEN,
+                               "Prefix SID SRv6 L3-Service length is %hu, but only %zu bytes remain",
+                               length, STREAM_READABLE(peer->curr));
                        return bgp_attr_malformed(args,
                                 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
                                 args->total);
                }
 
-               /* Parse L3-SERVICE Sub-TLV */
-               stream_getc(peer->curr);               /* reserved  */
-               stream_get(&ipv6_sid, peer->curr,
-                          sizeof(ipv6_sid)); /* sid_value */
-               sid_flags = stream_getc(peer->curr);   /* sid_flags */
-               endpoint_behavior = stream_getw(peer->curr); /* endpoint */
-               stream_getc(peer->curr);               /* reserved  */
-
-               /* Log L3-SERVICE Sub-TLV */
-               if (BGP_DEBUG(vpn, VPN_LEAK_LABEL)) {
-                       inet_ntop(AF_INET6, &ipv6_sid, buf, sizeof(buf));
-                       zlog_debug(
-                               "%s: srv6-l3-srv sid %s, sid-flags 0x%02x, end-behaviour 0x%04x",
-                               __func__, buf, sid_flags, endpoint_behavior);
-               }
+               /* ignore reserved */
+               stream_getc(peer->curr);
 
-               /* Configure from Info */
-               if (attr->srv6_l3vpn) {
-                       flog_err(EC_BGP_ATTRIBUTE_REPEATED,
-                                "Prefix SID SRv6 L3VPN field repeated");
-                       return bgp_attr_malformed(
-                               args, BGP_NOTIFY_UPDATE_MAL_ATTR, args->total);
-               }
-               attr->srv6_l3vpn = XCALLOC(MTYPE_BGP_SRV6_L3VPN,
-                                          sizeof(struct bgp_attr_srv6_l3vpn));
-               attr->srv6_l3vpn->sid_flags = sid_flags;
-               attr->srv6_l3vpn->endpoint_behavior = endpoint_behavior;
-               sid_copy(&attr->srv6_l3vpn->sid, &ipv6_sid);
-               attr->srv6_l3vpn = srv6_l3vpn_intern(attr->srv6_l3vpn);
+               return bgp_attr_srv6_service(args);
        }
 
        /* Placeholder code for Unsupported TLV */
@@ -4119,18 +4275,39 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
        /* SRv6 Service Information Attribute. */
        if ((afi == AFI_IP || afi == AFI_IP6) && safi == SAFI_MPLS_VPN) {
                if (attr->srv6_l3vpn) {
+                       uint8_t subtlv_len =
+                               BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH
+                               + BGP_ATTR_MIN_LEN
+                               + BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO_LENGTH;
+                       uint8_t tlv_len = subtlv_len + BGP_ATTR_MIN_LEN + 1;
+                       uint8_t attr_len = tlv_len + BGP_ATTR_MIN_LEN;
                        stream_putc(s, BGP_ATTR_FLAG_OPTIONAL
                                               | BGP_ATTR_FLAG_TRANS);
                        stream_putc(s, BGP_ATTR_PREFIX_SID);
-                       stream_putc(s, 24);     /* tlv len */
+                       stream_putc(s, attr_len);
                        stream_putc(s, BGP_PREFIX_SID_SRV6_L3_SERVICE);
-                       stream_putw(s, 21);     /* sub-tlv len */
+                       stream_putw(s, tlv_len);
+                       stream_putc(s, 0); /* reserved */
+                       stream_putc(s, BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO);
+                       stream_putw(s, subtlv_len);
                        stream_putc(s, 0);      /* reserved */
                        stream_put(s, &attr->srv6_l3vpn->sid,
                                   sizeof(attr->srv6_l3vpn->sid)); /* sid */
                        stream_putc(s, 0);      /* sid_flags */
                        stream_putw(s, 0xffff); /* endpoint */
                        stream_putc(s, 0);      /* reserved */
+                       stream_putc(
+                               s,
+                               BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE);
+                       stream_putw(
+                               s,
+                               BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH);
+                       stream_putc(s, attr->srv6_l3vpn->loc_block_len);
+                       stream_putc(s, attr->srv6_l3vpn->loc_node_len);
+                       stream_putc(s, attr->srv6_l3vpn->func_len);
+                       stream_putc(s, attr->srv6_l3vpn->arg_len);
+                       stream_putc(s, attr->srv6_l3vpn->transposition_len);
+                       stream_putc(s, attr->srv6_l3vpn->transposition_offset);
                } else if (attr->srv6_vpn) {
                        stream_putc(s, BGP_ATTR_FLAG_OPTIONAL
                                               | BGP_ATTR_FLAG_TRANS);
index a583581030845e74b6e17aebb5da763536de886e..3573c2ae03c0b6305dbe958e19d07f97ef63019f 100644 (file)
 #define BGP_PREFIX_SID_IPV6_LENGTH            19
 #define BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH  6
 #define BGP_PREFIX_SID_VPN_SID_LENGTH         19
-#define BGP_PREFIX_SID_SRV6_L3_SERVICE_LENGTH 21
+
+/* SRv6 Service Sub-TLV types */
+#define BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO 1
+#define BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO_LENGTH 21
+
+/* SRv6 Service Data Sub-Sub-TLV types */
+#define BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE 1
+#define BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH 6
+
+/* SRv6 SID Structure default values */
+#define BGP_PREFIX_SID_SRV6_LOCATOR_BLOCK_LENGTH 40
+#define BGP_PREFIX_SID_SRV6_LOCATOR_NODE_LENGTH 24
+#define BGP_PREFIX_SID_SRV6_FUNCTION_LENGTH 16
+#define BGP_PREFIX_SID_SRV6_ARGUMENT_LENGTH 0
+#define BGP_PREFIX_SID_SRV6_TRANSPOSITION_LENGTH 16
+#define BGP_PREFIX_SID_SRV6_TRANSPOSITION_OFFSET 64
 
 #define BGP_ATTR_NH_AFI(afi, attr) \
        ((afi != AFI_L2VPN) ? afi : \
@@ -136,6 +151,12 @@ struct bgp_attr_srv6_l3vpn {
        uint8_t sid_flags;
        uint16_t endpoint_behavior;
        struct in6_addr sid;
+       uint8_t loc_block_len;
+       uint8_t loc_node_len;
+       uint8_t func_len;
+       uint8_t arg_len;
+       uint8_t transposition_len;
+       uint8_t transposition_offset;
 };
 
 /* BGP core attribute structure. */
@@ -307,6 +328,12 @@ struct attr {
        /* EVPN DF preference and algorithm for DF election on local ESs */
        uint16_t df_pref;
        uint8_t df_alg;
+
+       /* Nexthop type */
+       enum nexthop_types_t nh_type;
+
+       /* If NEXTHOP_TYPE_BLACKHOLE, then blackhole type */
+       enum blackhole_type bh_type;
 };
 
 /* rmap_change_flags definition */
index 33e3db2c16696163bccade4977fc2c9bbe5fa4df..0e590a463c90c5ece4f80bbbc05613fbfc1784c9 100644 (file)
@@ -720,7 +720,7 @@ bool lcommunity_list_exact_match(struct lcommunity *lcom,
                        return entry->direct == COMMUNITY_PERMIT;
 
                if (entry->style == LARGE_COMMUNITY_LIST_STANDARD) {
-                       if (lcommunity_cmp(lcom, entry->u.com))
+                       if (lcommunity_cmp(lcom, entry->u.lcom))
                                return entry->direct == COMMUNITY_PERMIT;
                } else if (entry->style == LARGE_COMMUNITY_LIST_EXPANDED) {
                        if (lcommunity_regexp_match(lcom, entry->reg))
index 329bd3d696cadd11c172a609d95fe1b936c79284..82eb8a815e2ad20761aa96e010d281b460e62a44 100644 (file)
@@ -49,9 +49,9 @@ bgp_check_rmap_prefixes_in_bgp_table(struct bgp_table *table,
                        RESET_FLAG(dummy_attr.rmap_change_flags);
 
                        ret = route_map_apply(rmap, dest_p, &path);
-                       if (ret != RMAP_PERMITMATCH)
-                               bgp_attr_flush(&dummy_attr);
-                       else {
+                       bgp_attr_flush(&dummy_attr);
+
+                       if (ret == RMAP_PERMITMATCH) {
                                bgp_dest_unlock_node(dest);
                                if (BGP_DEBUG(update, UPDATE_OUT))
                                        zlog_debug(
@@ -84,6 +84,7 @@ static void bgp_conditional_adv_routes(struct peer *peer, afi_t afi,
        struct update_subgroup *subgrp;
        struct attr dummy_attr = {0}, attr = {0};
        struct bgp_path_info_extra path_extra = {0};
+       route_map_result_t ret;
 
        paf = peer_af_find(peer, afi, safi);
        if (!paf)
@@ -114,11 +115,11 @@ static void bgp_conditional_adv_routes(struct peer *peer, afi_t afi,
 
                        RESET_FLAG(dummy_attr.rmap_change_flags);
 
-                       if (route_map_apply(rmap, dest_p, &path)
-                           != RMAP_PERMITMATCH) {
-                               bgp_attr_flush(&dummy_attr);
+                       ret = route_map_apply(rmap, dest_p, &path);
+                       bgp_attr_flush(&dummy_attr);
+
+                       if (ret != RMAP_PERMITMATCH)
                                continue;
-                       }
 
                        if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)
                            || (addpath_capable
index 299ee305beafe17e429d860078f55349f93702d4..2f0b87aa3a4e4d09c86bae0a86d7fc98361c0b36 100644 (file)
@@ -165,13 +165,11 @@ static int bgp_dump_interval_add(struct bgp_dump *bgp_dump, int interval)
                        interval = interval
                                   - secs_into_day % interval; /* always > 0 */
                }
-               bgp_dump->t_interval = NULL;
                thread_add_timer(bm->master, bgp_dump_interval_func, bgp_dump,
                                 interval, &bgp_dump->t_interval);
        } else {
                /* One-off dump: execute immediately, don't affect any scheduled
                 * dumps */
-               bgp_dump->t_interval = NULL;
                thread_add_event(bm->master, bgp_dump_interval_func, bgp_dump,
                                 0, &bgp_dump->t_interval);
        }
@@ -453,7 +451,6 @@ static int bgp_dump_interval_func(struct thread *t)
 {
        struct bgp_dump *bgp_dump;
        bgp_dump = THREAD_ARG(t);
-       bgp_dump->t_interval = NULL;
 
        /* Reschedule dump even if file couldn't be opened this time... */
        if (bgp_dump_open_file(bgp_dump) != NULL) {
index cbd29c146a38b9aad03366f9af3682e1f53648ad..ea54c14222cf5f1bfbf5e5381215a54d68653e1c 100644 (file)
@@ -54,6 +54,7 @@
 #include "bgpd/bgp_mac.h"
 #include "bgpd/bgp_vty.h"
 #include "bgpd/bgp_nht.h"
+#include "bgpd/bgp_trace.h"
 
 /*
  * Definitions and external declarations.
@@ -653,6 +654,9 @@ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn,
                        &p->prefix.macip_addr.mac, &p->prefix.macip_addr.ip,
                        flags, seq, &remote_vtep_ip);
 
+       frrtrace(5, frr_bgp, evpn_mac_ip_zsend, add, vpn, p, remote_vtep_ip,
+                esi);
+
        return zclient_send_message(zclient);
 }
 
@@ -703,6 +707,8 @@ static int bgp_zebra_send_remote_vtep(struct bgp *bgp, struct bgpevpn *vpn,
                           add ? "ADD" : "DEL", vpn->vni,
                           &p->prefix.imet_addr.ip.ipaddr_v4);
 
+       frrtrace(3, frr_bgp, evpn_bum_vtep_zsend, add, vpn, p);
+
        return zclient_send_message(zclient);
 }
 
@@ -4334,6 +4340,54 @@ static void update_autort_vni(struct hash_bucket *bucket, struct bgp *bgp)
        }
 }
 
+/*
+ * Handle autort change for L3VNI.
+ */
+static void update_autort_l3vni(struct bgp *bgp)
+{
+       if ((CHECK_FLAG(bgp->vrf_flags, BGP_VRF_IMPORT_RT_CFGD))
+           && (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_EXPORT_RT_CFGD)))
+               return;
+
+       if (!CHECK_FLAG(bgp->vrf_flags, BGP_VRF_IMPORT_RT_CFGD)) {
+               if (is_l3vni_live(bgp))
+                       uninstall_routes_for_vrf(bgp);
+
+               /* Cleanup the RT to VRF mapping */
+               bgp_evpn_unmap_vrf_from_its_rts(bgp);
+
+               /* Remove auto generated RT */
+               evpn_auto_rt_import_delete_for_vrf(bgp);
+
+               list_delete_all_node(bgp->vrf_import_rtl);
+
+               /* Map auto derive or configured RTs */
+               evpn_auto_rt_import_add_for_vrf(bgp);
+       }
+
+       if (!CHECK_FLAG(bgp->vrf_flags, BGP_VRF_EXPORT_RT_CFGD)) {
+               list_delete_all_node(bgp->vrf_export_rtl);
+
+               evpn_auto_rt_export_delete_for_vrf(bgp);
+
+               evpn_auto_rt_export_add_for_vrf(bgp);
+
+               if (is_l3vni_live(bgp))
+                       bgp_evpn_map_vrf_to_its_rts(bgp);
+       }
+
+       if (!is_l3vni_live(bgp))
+               return;
+
+       /* advertise type-5 routes if needed */
+       update_advertise_vrf_routes(bgp);
+
+       /* install all remote routes belonging to this l3vni
+        * into corresponding vrf
+        */
+       install_routes_for_vrf(bgp);
+}
+
 /*
  * Public functions.
  */
@@ -4706,6 +4760,8 @@ void bgp_evpn_handle_autort_change(struct bgp *bgp)
                     (void (*)(struct hash_bucket *,
                               void*))update_autort_vni,
                     bgp);
+       if (bgp->l3vni)
+               update_autort_l3vni(bgp);
 }
 
 /*
@@ -6048,10 +6104,12 @@ bool bgp_evpn_is_prefix_nht_supported(const struct prefix *pfx)
         * type-5 routes. It may be tweaked later on for other routes, or
         * even removed completely when all routes are handled.
         */
-       if (pfx && pfx->family == AF_EVPN &&
-           (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE ||
-            evp->prefix.route_type == BGP_EVPN_IMET_ROUTE ||
-            evp->prefix.route_type == BGP_EVPN_IP_PREFIX_ROUTE))
+       if (pfx && pfx->family == AF_EVPN
+           && (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE
+               || evp->prefix.route_type == BGP_EVPN_AD_ROUTE
+               || evp->prefix.route_type == BGP_EVPN_ES_ROUTE
+               || evp->prefix.route_type == BGP_EVPN_IMET_ROUTE
+               || evp->prefix.route_type == BGP_EVPN_IP_PREFIX_ROUTE))
                return true;
 
        return false;
index 34094a0bde9831d3d49154a658066c10bb651d47..9316d218a28674ed79834e9e26612e048f949d4f 100644 (file)
@@ -50,6 +50,7 @@
 #include "bgpd/bgp_label.h"
 #include "bgpd/bgp_nht.h"
 #include "bgpd/bgp_mpath.h"
+#include "bgpd/bgp_trace.h"
 
 static void bgp_evpn_local_es_down(struct bgp *bgp,
                struct bgp_evpn_es *es);
@@ -1225,6 +1226,8 @@ static struct bgp_evpn_es_vtep *bgp_evpn_es_vtep_new(struct bgp_evpn_es *es,
 
        es_vtep->es = es;
        es_vtep->vtep_ip.s_addr = vtep_ip.s_addr;
+       inet_ntop(AF_INET, &es_vtep->vtep_ip, es_vtep->vtep_str,
+                 sizeof(es_vtep->vtep_str));
        listnode_init(&es_vtep->es_listnode, es_vtep);
        listnode_add_sort(es->es_vtep_list, &es_vtep->es_listnode);
 
@@ -1301,6 +1304,8 @@ static int bgp_zebra_send_remote_es_vtep(struct bgp *bgp,
                zlog_debug("Tx %s Remote ESI %s VTEP %pI4", add ? "ADD" : "DEL",
                           es->esi_str, &es_vtep->vtep_ip);
 
+       frrtrace(3, frr_bgp, evpn_mh_vtep_zsend, add, es, es_vtep);
+
        return zclient_send_message(zclient);
 }
 
@@ -2522,6 +2527,8 @@ static void bgp_evpn_l3nhg_zebra_add_v4_or_v6(struct bgp_evpn_es_vrf *es_vrf,
                           es_vrf->bgp_vrf->vrf_id,
                           v4_nhg ? "v4_nhg" : "v6_nhg", nhg_id);
 
+       frrtrace(4, frr_bgp, evpn_mh_nhg_zsend, true, v4_nhg, nhg_id, es_vrf);
+
        /* only the gateway ip changes for each NH. rest of the params
         * are constant
         */
@@ -2558,6 +2565,8 @@ static void bgp_evpn_l3nhg_zebra_add_v4_or_v6(struct bgp_evpn_es_vrf *es_vrf,
                        zlog_debug("nhg %u vtep %pI4 l3-svi %d", api_nhg.id,
                                   &es_vtep->vtep_ip,
                                   es_vrf->bgp_vrf->l3vni_svi_ifindex);
+
+               frrtrace(3, frr_bgp, evpn_mh_nh_zsend, nhg_id, es_vtep, es_vrf);
        }
 
        if (!api_nhg.nexthop_num)
@@ -2603,6 +2612,10 @@ static void bgp_evpn_l3nhg_zebra_del_v4_or_v6(struct bgp_evpn_es_vrf *es_vrf,
                           es_vrf->es->esi_str, es_vrf->bgp_vrf->vrf_id,
                           v4_nhg ? "v4_nhg" : "v6_nhg", api_nhg.id);
 
+
+       frrtrace(4, frr_bgp, evpn_mh_nhg_zsend, false, v4_nhg, api_nhg.id,
+                es_vrf);
+
        zclient_nhg_send(zclient, ZEBRA_NHG_DEL, &api_nhg);
 }
 
@@ -4202,6 +4215,8 @@ static void bgp_evpn_nh_zebra_update_send(struct bgp_evpn_nh *nh, bool add)
                                   nh->bgp_vrf->name, nh->nh_str);
        }
 
+       frrtrace(2, frr_bgp, evpn_mh_nh_rmac_zsend, add, nh);
+
        zclient_send_message(zclient);
 }
 
index 22a42156641d4d9b93fe5c001f3aa3abf9e485d7..37a46c2f0e073803a807010f0231c238707c9f41 100644 (file)
@@ -145,6 +145,8 @@ struct bgp_evpn_es_vtep {
        struct bgp_evpn_es *es; /* parent ES */
        struct in_addr vtep_ip;
 
+       char vtep_str[INET6_ADDRSTRLEN];
+
        uint32_t flags;
        /* Rxed a Type4 route from this PE */
 #define BGP_EVPNES_VTEP_ESR       (1 << 0)
index 867efb6099146c42d9e939cbace31492ef5c00f6..aced0177ea7ed9d02a3a7452752368372dfe1c57 100644 (file)
@@ -358,7 +358,7 @@ static void bgp_evpn_show_route_header(struct vty *vty, struct bgp *bgp,
                "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal\n");
        vty_out(vty, "Origin codes: i - IGP, e - EGP, ? - incomplete\n");
        vty_out(vty,
-               "EVPN type-1 prefix: [1]:[ESI]:[EthTag]:[IPlen]:[VTEP-IP]\n");
+               "EVPN type-1 prefix: [1]:[EthTag]:[ESI]:[IPlen]:[VTEP-IP]\n");
        vty_out(vty,
                "EVPN type-2 prefix: [2]:[EthTag]:[MAClen]:[MAC]:[IPlen]:[IP]\n");
        vty_out(vty, "EVPN type-3 prefix: [3]:[EthTag]:[IPlen]:[OrigIP]\n");
@@ -2723,7 +2723,7 @@ static void evpn_show_route_rd(struct vty *vty, struct bgp *bgp,
                        /* RD header and legend - once overall. */
                        if (rd_header && !json) {
                                vty_out(vty,
-                                       "EVPN type-1 prefix: [1]:[ESI]:[EthTag]:[IPlen]:[VTEP-IP]\n");
+                                       "EVPN type-1 prefix: [1]:[EthTag]:[ESI]:[IPlen]:[VTEP-IP]\n");
                                vty_out(vty,
                                        "EVPN type-2 prefix: [2]:[EthTag]:[MAClen]:[MAC]\n");
                                vty_out(vty,
index 1af2ab384f7eb910ba596d25ee997271b21f638b..659029b04ca9d7f28b3f7a6857f2cc3d040066d6 100644 (file)
@@ -522,13 +522,14 @@ static bool sid_exist(struct bgp *bgp, const struct in6_addr *sid)
  * if index != 0: try to allocate as index-mode
  * else: try to allocate as auto-mode
  */
-static bool alloc_new_sid(struct bgp *bgp, uint32_t index,
-                         struct in6_addr *sid)
+static uint32_t alloc_new_sid(struct bgp *bgp, uint32_t index,
+                             struct in6_addr *sid)
 {
        struct listnode *node;
        struct prefix_ipv6 *chunk;
        struct in6_addr sid_buf;
        bool alloced = false;
+       int label;
 
        if (!bgp || !sid)
                return false;
@@ -536,7 +537,8 @@ static bool alloc_new_sid(struct bgp *bgp, uint32_t index,
        for (ALL_LIST_ELEMENTS_RO(bgp->srv6_locator_chunks, node, chunk)) {
                sid_buf = chunk->prefix;
                if (index != 0) {
-                       sid_buf.s6_addr[15] = index;
+                       label = index << 12;
+                       transpose_sid(&sid_buf, label, 64, 16);
                        if (sid_exist(bgp, &sid_buf))
                                return false;
                        alloced = true;
@@ -544,9 +546,8 @@ static bool alloc_new_sid(struct bgp *bgp, uint32_t index,
                }
 
                for (size_t i = 1; i < 255; i++) {
-                       sid_buf.s6_addr[15] = (i & 0xff00) >> 8;
-                       sid_buf.s6_addr[14] = (i & 0x00ff);
-
+                       label = i << 12;
+                       transpose_sid(&sid_buf, label, 64, 16);
                        if (sid_exist(bgp, &sid_buf))
                                continue;
                        alloced = true;
@@ -555,20 +556,19 @@ static bool alloc_new_sid(struct bgp *bgp, uint32_t index,
        }
 
        if (!alloced)
-               return false;
+               return 0;
 
        sid_register(bgp, &sid_buf, bgp->srv6_locator_name);
        *sid = sid_buf;
-       return true;
+       return label;
 }
 
 void ensure_vrf_tovpn_sid(struct bgp *bgp_vpn, struct bgp *bgp_vrf, afi_t afi)
 {
        int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF);
-       bool alloced = false;
        char buf[256];
        struct in6_addr *sid;
-       uint32_t tovpn_sid_index = 0;
+       uint32_t tovpn_sid_index = 0, tovpn_sid_transpose_label;
        bool tovpn_sid_auto = false;
 
        if (debug)
@@ -602,8 +602,9 @@ void ensure_vrf_tovpn_sid(struct bgp *bgp_vpn, struct bgp *bgp_vrf, afi_t afi)
        }
 
        sid = XCALLOC(MTYPE_BGP_SRV6_SID, sizeof(struct in6_addr));
-       alloced = alloc_new_sid(bgp_vpn, tovpn_sid_index, sid);
-       if (!alloced) {
+       tovpn_sid_transpose_label =
+               alloc_new_sid(bgp_vpn, tovpn_sid_index, sid);
+       if (tovpn_sid_transpose_label == 0) {
                zlog_debug("%s: not allocated new sid for vrf %s: afi %s",
                           __func__, bgp_vrf->name_pretty, afi2str(afi));
                return;
@@ -615,9 +616,22 @@ void ensure_vrf_tovpn_sid(struct bgp *bgp_vpn, struct bgp *bgp_vrf, afi_t afi)
                           __func__, buf, bgp_vrf->name_pretty,
                           afi2str(afi));
        }
+       bgp_vrf->vpn_policy[afi].tovpn_sid_transpose_label =
+               tovpn_sid_transpose_label;
        bgp_vrf->vpn_policy[afi].tovpn_sid = sid;
 }
 
+void transpose_sid(struct in6_addr *sid, uint32_t label, uint8_t offset,
+                  uint8_t len)
+{
+       for (uint8_t idx = 0; idx < len; idx++) {
+               uint8_t tidx = offset + idx;
+               sid->s6_addr[tidx / 8] &= ~(0x1 << (7 - tidx % 8));
+               if (label >> (19 - idx) & 0x1)
+                       sid->s6_addr[tidx / 8] |= 0x1 << (7 - tidx % 8);
+       }
+}
+
 static bool ecom_intersect(struct ecommunity *e1, struct ecommunity *e2)
 {
        uint32_t i, j;
@@ -710,10 +724,19 @@ static void setsids(struct bgp_path_info *bpi,
 
        extra = bgp_path_info_extra_get(bpi);
        for (i = 0; i < num_sids; i++)
-               memcpy(&extra->sid[i], &sid[i], sizeof(struct in6_addr));
+               memcpy(&extra->sid[i].sid, &sid[i], sizeof(struct in6_addr));
        extra->num_sids = num_sids;
 }
 
+static void unsetsids(struct bgp_path_info *bpi)
+{
+       struct bgp_path_info_extra *extra;
+
+       extra = bgp_path_info_extra_get(bpi);
+       extra->num_sids = 0;
+       memset(extra->sid, 0, sizeof(extra->sid));
+}
+
 /*
  * returns pointer to new bgp_path_info upon success
  */
@@ -729,6 +752,7 @@ leak_update(struct bgp *bgp, /* destination bgp instance */
        struct bgp_path_info *bpi;
        struct bgp_path_info *bpi_ultimate;
        struct bgp_path_info *new;
+       struct bgp_path_info_extra *extra;
        uint32_t num_sids = 0;
 
        if (new_attr->srv6_l3vpn || new_attr->srv6_vpn)
@@ -815,13 +839,35 @@ leak_update(struct bgp *bgp, /* destination bgp instance */
                 * rewrite sid
                 */
                if (num_sids) {
-                       if (new_attr->srv6_l3vpn)
+                       if (new_attr->srv6_l3vpn) {
                                setsids(bpi, &new_attr->srv6_l3vpn->sid,
                                        num_sids);
-                       else if (new_attr->srv6_vpn)
+
+                               extra = bgp_path_info_extra_get(bpi);
+
+                               extra->sid[0].loc_block_len =
+                                       new_attr->srv6_l3vpn->loc_block_len;
+                               extra->sid[0].loc_node_len =
+                                       new_attr->srv6_l3vpn->loc_node_len;
+                               extra->sid[0].func_len =
+                                       new_attr->srv6_l3vpn->func_len;
+                               extra->sid[0].arg_len =
+                                       new_attr->srv6_l3vpn->arg_len;
+
+                               if (new_attr->srv6_l3vpn->transposition_len
+                                   != 0)
+                                       transpose_sid(
+                                               &extra->sid[0].sid,
+                                               decode_label(label),
+                                               new_attr->srv6_l3vpn
+                                                       ->transposition_offset,
+                                               new_attr->srv6_l3vpn
+                                                       ->transposition_len);
+                       } else if (new_attr->srv6_vpn)
                                setsids(bpi, &new_attr->srv6_vpn->sid,
                                        num_sids);
-               }
+               } else
+                       unsetsids(bpi);
 
                if (nexthop_self_flag)
                        bgp_path_info_set_flag(bn, bpi, BGP_PATH_ANNC_NH_SELF);
@@ -847,6 +893,17 @@ leak_update(struct bgp *bgp, /* destination bgp instance */
                        nh_valid = bgp_find_or_add_nexthop(
                                bgp, bgp_nexthop, afi, safi, bpi, NULL, 0, p);
 
+               /*
+                * If you are using SRv6 VPN instead of MPLS, it need to check
+                * the SID allocation. If the sid is not allocated, the rib
+                * will be invalid.
+                */
+               if (bgp->srv6_enabled
+                   && (!new_attr->srv6_l3vpn && !new_attr->srv6_vpn)) {
+                       bgp_path_info_unset_flag(bn, bpi, BGP_PATH_VALID);
+                       nh_valid = false;
+               }
+
                if (debug)
                        zlog_debug("%s: nexthop is %svalid (in vrf %s)",
                                __func__, (nh_valid ? "" : "not "),
@@ -889,11 +946,29 @@ leak_update(struct bgp *bgp, /* destination bgp instance */
         * rewrite sid
         */
        if (num_sids) {
-               if (new_attr->srv6_l3vpn)
+               if (new_attr->srv6_l3vpn) {
                        setsids(new, &new_attr->srv6_l3vpn->sid, num_sids);
-               else if (new_attr->srv6_vpn)
+
+                       extra = bgp_path_info_extra_get(new);
+
+                       extra->sid[0].loc_block_len =
+                               new_attr->srv6_l3vpn->loc_block_len;
+                       extra->sid[0].loc_node_len =
+                               new_attr->srv6_l3vpn->loc_node_len;
+                       extra->sid[0].func_len = new_attr->srv6_l3vpn->func_len;
+                       extra->sid[0].arg_len = new_attr->srv6_l3vpn->arg_len;
+
+                       if (new_attr->srv6_l3vpn->transposition_len != 0)
+                               transpose_sid(&extra->sid[0].sid,
+                                             decode_label(label),
+                                             new_attr->srv6_l3vpn
+                                                     ->transposition_offset,
+                                             new_attr->srv6_l3vpn
+                                                     ->transposition_len);
+               } else if (new_attr->srv6_vpn)
                        setsids(new, &new_attr->srv6_vpn->sid, num_sids);
-       }
+       } else
+               unsetsids(new);
 
        if (num_labels)
                setlabels(new, label, num_labels);
@@ -933,6 +1008,17 @@ leak_update(struct bgp *bgp, /* destination bgp instance */
                nh_valid = bgp_find_or_add_nexthop(bgp, bgp_nexthop, afi, safi,
                                                   new, NULL, 0, p);
 
+       /*
+        * If you are using SRv6 VPN instead of MPLS, it need to check
+        * the SID allocation. If the sid is not allocated, the rib
+        * will be invalid.
+        */
+       if (bgp->srv6_enabled
+           && (!new->attr->srv6_l3vpn && !new->attr->srv6_vpn)) {
+               bgp_path_info_unset_flag(bn, new, BGP_PATH_VALID);
+               nh_valid = false;
+       }
+
        if (debug)
                zlog_debug("%s: nexthop is %svalid (in vrf %s)",
                        __func__, (nh_valid ? "" : "not "),
@@ -1153,10 +1239,24 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn,          /* to */
 
        /* Set SID for SRv6 VPN */
        if (bgp_vrf->vpn_policy[afi].tovpn_sid) {
+               encode_label(bgp_vrf->vpn_policy[afi].tovpn_sid_transpose_label,
+                            &label);
                static_attr.srv6_l3vpn = XCALLOC(MTYPE_BGP_SRV6_L3VPN,
                                sizeof(struct bgp_attr_srv6_l3vpn));
                static_attr.srv6_l3vpn->sid_flags = 0x00;
                static_attr.srv6_l3vpn->endpoint_behavior = 0xffff;
+               static_attr.srv6_l3vpn->loc_block_len =
+                       BGP_PREFIX_SID_SRV6_LOCATOR_BLOCK_LENGTH;
+               static_attr.srv6_l3vpn->loc_node_len =
+                       BGP_PREFIX_SID_SRV6_LOCATOR_NODE_LENGTH;
+               static_attr.srv6_l3vpn->func_len =
+                       BGP_PREFIX_SID_SRV6_FUNCTION_LENGTH;
+               static_attr.srv6_l3vpn->arg_len =
+                       BGP_PREFIX_SID_SRV6_ARGUMENT_LENGTH;
+               static_attr.srv6_l3vpn->transposition_len =
+                       BGP_PREFIX_SID_SRV6_TRANSPOSITION_LENGTH;
+               static_attr.srv6_l3vpn->transposition_offset =
+                       BGP_PREFIX_SID_SRV6_TRANSPOSITION_OFFSET;
                memcpy(&static_attr.srv6_l3vpn->sid,
                       bgp_vrf->vpn_policy[afi].tovpn_sid,
                       sizeof(static_attr.srv6_l3vpn->sid));
index 38193721b3e04344f3ee667b13fd1e374e559390..b0d586223fa96c0723701c3b9b5357ddb9214c80 100644 (file)
@@ -81,6 +81,8 @@ extern void vpn_leak_zebra_vrf_sid_update(struct bgp *bgp, afi_t afi);
 extern void vpn_leak_zebra_vrf_sid_withdraw(struct bgp *bgp, afi_t afi);
 extern int vpn_leak_label_callback(mpls_label_t label, void *lblid, bool alloc);
 extern void ensure_vrf_tovpn_sid(struct bgp *vpn, struct bgp *vrf, afi_t afi);
+extern void transpose_sid(struct in6_addr *sid, uint32_t label, uint8_t offset,
+                         uint8_t size);
 extern void vrf_import_from_vrf(struct bgp *to_bgp, struct bgp *from_bgp,
                                afi_t afi, safi_t safi);
 void vrf_unimport_from_vrf(struct bgp *to_bgp, struct bgp *from_bgp,
@@ -243,6 +245,10 @@ static inline void vpn_leak_postchange(vpn_policy_direction_t direction,
                if (!bgp_vrf->vpn_policy[afi].tovpn_sid)
                        ensure_vrf_tovpn_sid(bgp_vpn, bgp_vrf, afi);
 
+               if (!bgp_vrf->vpn_policy[afi].tovpn_sid
+                   && bgp_vrf->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent)
+                       vpn_leak_zebra_vrf_sid_withdraw(bgp_vrf, afi);
+
                if (sid_diff(bgp_vrf->vpn_policy[afi].tovpn_sid,
                             bgp_vrf->vpn_policy[afi]
                                     .tovpn_zebra_vrf_sid_last_sent)) {
index f72f44f8a20689af8cbad07db156143b5d6309b5..09abb699683de1212ef8117543389da1ff2d9d6c 100644 (file)
@@ -46,6 +46,7 @@
 #include "bgpd/bgp_errors.h"
 #include "bgpd/bgp_network.h"
 #include "bgpd/bgp_zebra.h"
+#include "bgpd/bgp_nht.h"
 
 extern struct zebra_privs_t bgpd_privs;
 
@@ -603,6 +604,12 @@ static int bgp_accept(struct thread *thread)
                        BGP_EVENT_ADD(peer, TCP_connection_open);
        }
 
+       /*
+        * If we are doing nht for a peer that is v6 LL based
+        * massage the event system to make things happy
+        */
+       bgp_nht_interface_events(peer);
+
        return 0;
 }
 
index 783115baaf7d2bf78c40f33dd685adc046acc7e8..de9a89523b4eeff36ed1dd9e1ab7cf6e9a1e1d2a 100644 (file)
@@ -337,11 +337,13 @@ static void bgp_write_proceed_actions(struct peer *peer)
        struct peer_af *paf;
        struct bpacket *next_pkt;
        struct update_subgroup *subgrp;
+       enum bgp_af_index index;
 
-       FOREACH_AFI_SAFI (afi, safi) {
-               paf = peer_af_find(peer, afi, safi);
+       for (index = BGP_AF_START; index < BGP_AF_MAX; index++) {
+               paf = peer->peer_af_array[index];
                if (!paf)
                        continue;
+
                subgrp = paf->subgroup;
                if (!subgrp)
                        continue;
@@ -364,6 +366,9 @@ static void bgp_write_proceed_actions(struct peer *peer)
                        return;
                }
 
+               afi = paf->afi;
+               safi = paf->safi;
+
                /* No packets to send, see if EOR is pending */
                if (CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV)) {
                        if (!subgrp->t_coalesce && peer->afc_nego[afi][safi]
@@ -415,11 +420,16 @@ int bgp_generate_updgrp_packets(struct thread *thread)
                return 0;
 
        do {
+               enum bgp_af_index index;
+
                s = NULL;
-               FOREACH_AFI_SAFI (afi, safi) {
-                       paf = peer_af_find(peer, afi, safi);
+               for (index = BGP_AF_START; index < BGP_AF_MAX; index++) {
+                       paf = peer->peer_af_array[index];
                        if (!paf || !PAF_SUBGRP(paf))
                                continue;
+
+                       afi = paf->afi;
+                       safi = paf->safi;
                        next_pkt = paf->next_pkt_to_send;
 
                        /*
@@ -1951,6 +1961,7 @@ static int bgp_route_refresh_receive(struct peer *peer, bgp_size_t size)
        struct update_group *updgrp;
        struct peer *updgrp_peer;
        uint8_t subtype;
+       bool force_update = false;
        bgp_size_t msg_length =
                size - (BGP_MSG_ROUTE_REFRESH_MIN_SIZE - BGP_HEADER_SIZE);
 
@@ -2212,7 +2223,7 @@ static int bgp_route_refresh_receive(struct peer *peer, bgp_size_t size)
                /* Avoid supressing duplicate routes later
                 * when processing in subgroup_announce_table().
                 */
-               SET_FLAG(paf->subgroup->sflags, SUBGRP_STATUS_FORCE_UPDATES);
+               force_update = true;
 
                /* If the peer is configured for default-originate clear the
                 * SUBGRP_STATUS_DEFAULT_ORIGINATE flag so that we will
@@ -2344,7 +2355,7 @@ static int bgp_route_refresh_receive(struct peer *peer, bgp_size_t size)
        }
 
        /* Perform route refreshment to the peer */
-       bgp_announce_route(peer, afi, safi);
+       bgp_announce_route(peer, afi, safi, force_update);
 
        /* No FSM action necessary */
        return BGP_PACKET_NOOP;
@@ -2447,7 +2458,8 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt,
                                peer->afc_recv[afi][safi] = 1;
                                if (peer->afc[afi][safi]) {
                                        peer->afc_nego[afi][safi] = 1;
-                                       bgp_announce_route(peer, afi, safi);
+                                       bgp_announce_route(peer, afi, safi,
+                                                          false);
                                }
                        } else {
                                peer->afc_recv[afi][safi] = 0;
@@ -2718,7 +2730,7 @@ int bgp_packet_process_error(struct thread *thread)
 
        if (bgp_debug_neighbor_events(peer))
                zlog_debug("%s [Event] BGP error %d on fd %d",
-                          peer->host, peer->fd, code);
+                          peer->host, code, peer->fd);
 
        /* Closed connection or error on the socket */
        if (peer_established(peer)) {
index b164d710a516104f71dfb241ec558a6cadd54e18..0eb3cc61e3f425e65e5c304c7d9984c2adfbba21 100644 (file)
@@ -4042,15 +4042,48 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
                /* Update SRv6 SID */
                if (attr->srv6_l3vpn) {
                        extra = bgp_path_info_extra_get(pi);
-                       if (sid_diff(&extra->sid[0], &attr->srv6_l3vpn->sid)) {
-                               sid_copy(&extra->sid[0],
+                       if (sid_diff(&extra->sid[0].sid,
+                                    &attr->srv6_l3vpn->sid)) {
+                               sid_copy(&extra->sid[0].sid,
                                         &attr->srv6_l3vpn->sid);
                                extra->num_sids = 1;
+
+                               extra->sid[0].loc_block_len = 0;
+                               extra->sid[0].loc_node_len = 0;
+                               extra->sid[0].func_len = 0;
+                               extra->sid[0].arg_len = 0;
+
+                               if (attr->srv6_l3vpn->loc_block_len != 0) {
+                                       extra->sid[0].loc_block_len =
+                                               attr->srv6_l3vpn->loc_block_len;
+                                       extra->sid[0].loc_node_len =
+                                               attr->srv6_l3vpn->loc_node_len;
+                                       extra->sid[0].func_len =
+                                               attr->srv6_l3vpn->func_len;
+                                       extra->sid[0].arg_len =
+                                               attr->srv6_l3vpn->arg_len;
+                               }
+
+                               /*
+                                * draft-ietf-bess-srv6-services-07
+                                * The part of SRv6 SID may be encoded as MPLS
+                                * Label for the efficient packing.
+                                */
+                               if (attr->srv6_l3vpn->transposition_len != 0)
+                                       transpose_sid(
+                                               &extra->sid[0].sid,
+                                               decode_label(label),
+                                               attr->srv6_l3vpn
+                                                       ->transposition_offset,
+                                               attr->srv6_l3vpn
+                                                       ->transposition_len);
                        }
                } else if (attr->srv6_vpn) {
                        extra = bgp_path_info_extra_get(pi);
-                       if (sid_diff(&extra->sid[0], &attr->srv6_vpn->sid)) {
-                               sid_copy(&extra->sid[0], &attr->srv6_vpn->sid);
+                       if (sid_diff(&extra->sid[0].sid,
+                                    &attr->srv6_vpn->sid)) {
+                               sid_copy(&extra->sid[0].sid,
+                                        &attr->srv6_vpn->sid);
                                extra->num_sids = 1;
                        }
                }
@@ -4231,10 +4264,28 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
        if (safi == SAFI_MPLS_VPN) {
                extra = bgp_path_info_extra_get(new);
                if (attr->srv6_l3vpn) {
-                       sid_copy(&extra->sid[0], &attr->srv6_l3vpn->sid);
+                       sid_copy(&extra->sid[0].sid, &attr->srv6_l3vpn->sid);
                        extra->num_sids = 1;
+
+                       extra->sid[0].loc_block_len =
+                               attr->srv6_l3vpn->loc_block_len;
+                       extra->sid[0].loc_node_len =
+                               attr->srv6_l3vpn->loc_node_len;
+                       extra->sid[0].func_len = attr->srv6_l3vpn->func_len;
+                       extra->sid[0].arg_len = attr->srv6_l3vpn->arg_len;
+
+                       /*
+                        * draft-ietf-bess-srv6-services-07
+                        * The part of SRv6 SID may be encoded as MPLS Label for
+                        * the efficient packing.
+                        */
+                       if (attr->srv6_l3vpn->transposition_len != 0)
+                               transpose_sid(
+                                       &extra->sid[0].sid, decode_label(label),
+                                       attr->srv6_l3vpn->transposition_offset,
+                                       attr->srv6_l3vpn->transposition_len);
                } else if (attr->srv6_vpn) {
-                       sid_copy(&extra->sid[0], &attr->srv6_vpn->sid);
+                       sid_copy(&extra->sid[0].sid, &attr->srv6_vpn->sid);
                        extra->num_sids = 1;
                }
        }
@@ -4537,8 +4588,11 @@ static int bgp_announce_route_timer_expired(struct thread *t)
  * bgp_announce_route
  *
  * *Triggers* announcement of routes of a given AFI/SAFI to a peer.
+ *
+ * if force is true we will force an update even if the update
+ * limiting code is attempted to kick in.
  */
-void bgp_announce_route(struct peer *peer, afi_t afi, safi_t safi)
+void bgp_announce_route(struct peer *peer, afi_t afi, safi_t safi, bool force)
 {
        struct peer_af *paf;
        struct update_subgroup *subgrp;
@@ -4555,6 +4609,9 @@ void bgp_announce_route(struct peer *peer, afi_t afi, safi_t safi)
        if (!subgrp || paf->t_announce_route)
                return;
 
+       if (force)
+               SET_FLAG(subgrp->sflags, SUBGRP_STATUS_FORCE_UPDATES);
+
        /*
         * Start a timer to stagger/delay the announce. This serves
         * two purposes - announcement can potentially be combined for
@@ -4583,7 +4640,7 @@ void bgp_announce_route_all(struct peer *peer)
        safi_t safi;
 
        FOREACH_AFI_SAFI (afi, safi)
-               bgp_announce_route(peer, afi, safi);
+               bgp_announce_route(peer, afi, safi, false);
 }
 
 /* Flag or unflag bgp_dest to determine whether it should be treated by
@@ -4721,7 +4778,7 @@ static int bgp_soft_reconfig_table_task(struct thread *thread)
                                                table->soft_reconfig_peers,
                                                peer);
                                        bgp_announce_route(peer, table->afi,
-                                                          table->safi);
+                                                          table->safi, false);
                                        if (list_isempty(
                                                    table->soft_reconfig_peers)) {
                                                list_delete(
@@ -4749,7 +4806,7 @@ static int bgp_soft_reconfig_table_task(struct thread *thread)
        */
        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);
+               bgp_announce_route(peer, table->afi, table->safi, false);
        }
 
        list_delete(&table->soft_reconfig_peers);
@@ -8066,8 +8123,9 @@ DEFPY(aggregate_addressv6, aggregate_addressv6_cmd,
 void bgp_redistribute_add(struct bgp *bgp, struct prefix *p,
                          const union g_addr *nexthop, ifindex_t ifindex,
                          enum nexthop_types_t nhtype, uint8_t distance,
-                         uint32_t metric, uint8_t type,
-                         unsigned short instance, route_tag_t tag)
+                         enum blackhole_type bhtype, uint32_t metric,
+                         uint8_t type, unsigned short instance,
+                         route_tag_t tag)
 {
        struct bgp_path_info *new;
        struct bgp_path_info *bpi;
@@ -8109,8 +8167,10 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p,
                        attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL;
                        break;
                }
+               attr.bh_type = bhtype;
                break;
        }
+       attr.nh_type = nhtype;
        attr.nh_ifindex = ifindex;
 
        attr.med = metric;
@@ -8977,8 +9037,6 @@ void route_vty_out(struct vty *vty, const struct prefix *p,
                vty_out(vty, "\n");
 
                if (safi == SAFI_EVPN) {
-                       struct bgp_path_es_info *path_es_info = NULL;
-
                        if (bgp_evpn_is_esi_valid(&attr->esi)) {
                                /* XXX - add these params to the json out */
                                vty_out(vty, "%*s", 20, " ");
@@ -8986,13 +9044,6 @@ void route_vty_out(struct vty *vty, const struct prefix *p,
                                        esi_to_str(&attr->esi, esi_buf,
                                                   sizeof(esi_buf)));
 
-                               if (path->extra && path->extra->mh_info)
-                                       path_es_info =
-                                               path->extra->mh_info->es_info;
-
-                               if (path_es_info && path_es_info->es)
-                                       vty_out(vty, " VNI: %u",
-                                               path_es_info->vni);
                                vty_out(vty, "\n");
                        }
                        if (attr->flag &
@@ -9269,7 +9320,8 @@ void route_vty_out_tag(struct vty *vty, const struct prefix *p,
                        vty_out(vty, "notag/%d", label);
                        vty_out(vty, "\n");
                }
-       }
+       } else if (!json)
+               vty_out(vty, "\n");
 }
 
 void route_vty_out_overlay(struct vty *vty, const struct prefix *p,
@@ -10456,7 +10508,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
 
        /* Remote SID */
        if (path->extra && path->extra->num_sids > 0 && safi != SAFI_EVPN) {
-               inet_ntop(AF_INET6, &path->extra->sid, buf, sizeof(buf));
+               inet_ntop(AF_INET6, &path->extra->sid[0].sid, buf, sizeof(buf));
                if (json_paths)
                        json_object_string_add(json_path, "remoteSid", buf);
                else
@@ -10812,6 +10864,7 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
                                path.attr = &dummy_attr;
 
                                ret = route_map_apply(rmap, dest_p, &path);
+                               bgp_attr_flush(&dummy_attr);
                                if (ret == RMAP_DENYMATCH)
                                        continue;
                        }
@@ -11126,6 +11179,10 @@ static int bgp_show(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
                return CMD_WARNING;
        }
 
+       /* Labeled-unicast routes live in the unicast table. */
+       if (safi == SAFI_LABELED_UNICAST)
+               safi = SAFI_UNICAST;
+
        table = bgp->rib[afi][safi];
        /* use MPLS and ENCAP specific shows until they are merged */
        if (safi == SAFI_MPLS_VPN) {
@@ -11138,9 +11195,6 @@ static int bgp_show(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
                                               output_arg, use_json,
                                               1, NULL, NULL);
        }
-       /* labeled-unicast routes live in the unicast table */
-       else if (safi == SAFI_LABELED_UNICAST)
-               safi = SAFI_UNICAST;
 
        return bgp_show_table(vty, bgp, safi, table, type, output_arg, NULL, 1,
                              NULL, NULL, &json_header_depth, show_flags,
@@ -13913,10 +13967,11 @@ DEFPY (show_ip_bgp_instance_neighbor_advertised_route,
 
 DEFUN (show_ip_bgp_neighbor_received_prefix_filter,
        show_ip_bgp_neighbor_received_prefix_filter_cmd,
-       "show [ip] bgp [<ipv4|ipv6> [unicast]] neighbors <A.B.C.D|X:X::X:X|WORD> received prefix-filter [json]",
+       "show [ip] bgp [<view|vrf> VIEWVRFNAME] [<ipv4|ipv6> [unicast]] neighbors <A.B.C.D|X:X::X:X|WORD> received prefix-filter [json]",
        SHOW_STR
        IP_STR
        BGP_STR
+       BGP_INSTANCE_HELP_STR
        "Address Family\n"
        "Address Family\n"
        "Address Family modifier\n"
@@ -13931,50 +13986,28 @@ DEFUN (show_ip_bgp_neighbor_received_prefix_filter,
        afi_t afi = AFI_IP6;
        safi_t safi = SAFI_UNICAST;
        char *peerstr = NULL;
-
        char name[BUFSIZ];
-       union sockunion su;
        struct peer *peer;
-       int count, ret;
-
+       int count;
        int idx = 0;
+       struct bgp *bgp = NULL;
+       bool uj = use_json(argc, argv);
+
+       if (uj)
+               argc--;
+
+       bgp_vty_find_and_parse_afi_safi_bgp(vty, argv, argc, &idx, &afi, &safi,
+                                           &bgp, uj);
+       if (!idx)
+               return CMD_WARNING;
 
-       /* show [ip] bgp */
-       if (argv_find(argv, argc, "ip", &idx))
-               afi = AFI_IP;
-       /* [<ipv4|ipv6> [unicast]] */
-       if (argv_find(argv, argc, "ipv4", &idx))
-               afi = AFI_IP;
-       if (argv_find(argv, argc, "ipv6", &idx))
-               afi = AFI_IP6;
        /* neighbors <A.B.C.D|X:X::X:X|WORD> */
        argv_find(argv, argc, "neighbors", &idx);
        peerstr = argv[++idx]->arg;
 
-       bool uj = use_json(argc, argv);
-
-       ret = str2sockunion(peerstr, &su);
-       if (ret < 0) {
-               peer = peer_lookup_by_conf_if(NULL, peerstr);
-               if (!peer) {
-                       if (uj)
-                               vty_out(vty, "{}\n");
-                       else
-                               vty_out(vty,
-                                       "%% Malformed address or name: %s\n",
-                                       peerstr);
-                       return CMD_WARNING;
-               }
-       } else {
-               peer = peer_lookup(NULL, &su);
-               if (!peer) {
-                       if (uj)
-                               vty_out(vty, "{}\n");
-                       else
-                               vty_out(vty, "No peer\n");
-                       return CMD_WARNING;
-               }
-       }
+       peer = peer_lookup_in_view(vty, bgp, peerstr, uj);
+       if (!peer)
+               return CMD_WARNING;
 
        snprintf(name, sizeof(name), "%s.%d.%d", peer->host, afi, safi);
        count = prefix_bgp_show_prefix_list(NULL, afi, name, uj);
index 75da2723e6242db2621f18624650196f60a7d873..37bf675b674f2983e8cbee8376b06d6e8c9e78eb 100644 (file)
@@ -145,6 +145,14 @@ struct bgp_path_mh_info {
        struct bgp_path_evpn_nh_info *nh_info;
 };
 
+struct bgp_sid_info {
+       struct in6_addr sid;
+       uint8_t loc_block_len;
+       uint8_t loc_node_len;
+       uint8_t func_len;
+       uint8_t arg_len;
+};
+
 /* Ancillary information to struct bgp_path_info,
  * used for uncommonly used data (aggregation, MPLS, etc.)
  * and lazily allocated to save memory.
@@ -168,7 +176,7 @@ struct bgp_path_info_extra {
 #define BGP_EVPN_MACIP_TYPE_SVI_IP (1 << 0)
 
        /* SRv6 SID(s) for SRv6-VPN */
-       struct in6_addr sid[BGP_MAX_SIDS];
+       struct bgp_sid_info sid[BGP_MAX_SIDS];
        uint32_t num_sids;
 
 #ifdef ENABLE_BGP_VNC
@@ -600,7 +608,8 @@ extern void bgp_process_queue_init(struct bgp *bgp);
 extern void bgp_route_init(void);
 extern void bgp_route_finish(void);
 extern void bgp_cleanup_routes(struct bgp *);
-extern void bgp_announce_route(struct peer *, afi_t, safi_t);
+extern void bgp_announce_route(struct peer *peer, afi_t afi, safi_t safi,
+                              bool force);
 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);
@@ -642,8 +651,9 @@ extern bool bgp_maximum_prefix_overflow(struct peer *, afi_t, safi_t, int);
 extern void bgp_redistribute_add(struct bgp *bgp, struct prefix *p,
                                 const union g_addr *nexthop, ifindex_t ifindex,
                                 enum nexthop_types_t nhtype, uint8_t distance,
-                                uint32_t metric, uint8_t type,
-                                unsigned short instance, route_tag_t tag);
+                                enum blackhole_type bhtype, uint32_t metric,
+                                uint8_t type, unsigned short instance,
+                                route_tag_t tag);
 extern void bgp_redistribute_delete(struct bgp *, struct prefix *, uint8_t,
                                    unsigned short);
 extern void bgp_redistribute_withdraw(struct bgp *, afi_t, int, unsigned short);
index 85676e6758a2ee5dade70319b7b1cb88897dc5be..09a6be4010f9e5c0ce2b93c5f7d7900c3f7b2405 100644 (file)
@@ -1035,6 +1035,7 @@ lib_route_map_entry_match_condition_rmap_match_condition_comm_list_finish(
        char *argstr;
        const char *condition;
        route_map_event_t event;
+       int ret;
 
        /* Add configuration. */
        rhc = nb_running_get_entry(args->dnode, NULL, true);
@@ -1072,8 +1073,14 @@ lib_route_map_entry_match_condition_rmap_match_condition_comm_list_finish(
                rhc->rhc_event = RMAP_EVENT_ECLIST_DELETED;
        }
 
-       bgp_route_match_add(rhc->rhc_rmi, rhc->rhc_rule, argstr, event,
-                           args->errmsg, args->errmsg_len);
+       ret = bgp_route_match_add(rhc->rhc_rmi, rhc->rhc_rule, argstr, event,
+                                 args->errmsg, args->errmsg_len);
+       /*
+        * At this point if this is not a successful operation
+        * bgpd is about to crash.  Let's just cut to the
+        * chase and do it.
+        */
+       assert(ret == RMAP_COMPILE_SUCCESS);
 
        if (argstr != value)
                XFREE(MTYPE_ROUTE_MAP_COMPILED, argstr);
@@ -2440,6 +2447,7 @@ void lib_route_map_entry_set_action_rmap_set_action_aggregator_finish(
        const char *asn;
        const char *addr;
        char *argstr;
+       int ret;
 
        /* Add configuration. */
        rhc = nb_running_get_entry(args->dnode, NULL, true);
@@ -2456,8 +2464,15 @@ void lib_route_map_entry_set_action_rmap_set_action_aggregator_finish(
        rhc->rhc_rule = "aggregator as";
        rhc->rhc_event = RMAP_EVENT_SET_DELETED;
 
-       generic_set_add(rhc->rhc_rmi, rhc->rhc_rule, argstr,
-                       args->errmsg, args->errmsg_len);
+       ret = generic_set_add(rhc->rhc_rmi, rhc->rhc_rule, argstr, args->errmsg,
+                             args->errmsg_len);
+       /*
+        * At this point if this is not a successful operation
+        * bgpd is about to crash.  Let's just cut to the
+        * chase and do it.
+        */
+       assert(ret == CMD_SUCCESS);
+
        XFREE(MTYPE_ROUTE_MAP_COMPILED, argstr);
 }
 /*
@@ -2604,6 +2619,7 @@ lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_finish(
        enum ecommunity_lb_type lb_type;
        char str[VTY_BUFSIZ];
        uint16_t bandwidth;
+       int ret;
 
        /* Add configuration. */
        rhc = nb_running_get_entry(args->dnode, NULL, true);
@@ -2629,9 +2645,14 @@ lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_finish(
        if (yang_dnode_get_bool(args->dnode, "./two-octet-as-specific"))
                strlcat(str, " non-transitive", sizeof(str));
 
-       generic_set_add(rhc->rhc_rmi,
-                       "extcommunity bandwidth", str,
-                       args->errmsg, args->errmsg_len);
+       ret = generic_set_add(rhc->rhc_rmi, "extcommunity bandwidth", str,
+                             args->errmsg, args->errmsg_len);
+       /*
+        * At this point if this is not a successful operation
+        * bgpd is about to crash.  Let's just cut to the
+        * chase and do it.
+        */
+       assert(ret == CMD_SUCCESS);
 }
 
 /*
index 833bdec2ed998164da21dc444295bba1a10c8c1a..376172a6f91a608ff08679b5042eedfe10e0885e 100644 (file)
@@ -31,6 +31,7 @@
 #include "bgpd/bgpd.h"
 #include "bgpd/bgp_table.h"
 #include "bgp_addpath.h"
+#include "bgp_trace.h"
 
 void bgp_table_lock(struct bgp_table *rt)
 {
@@ -60,6 +61,42 @@ void bgp_table_finish(struct bgp_table **rt)
        }
 }
 
+/*
+ * bgp_dest_unlock_node
+ */
+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));
+}
+
+/*
+ * bgp_dest_lock_node
+ */
+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);
+}
+
+/*
+ * bgp_dest_get_prefix_str
+ */
+const char *bgp_dest_get_prefix_str(struct bgp_dest *dest)
+{
+       const struct prefix *p = NULL;
+       char str[PREFIX_STRLEN] = {0};
+
+       p = bgp_dest_get_prefix(dest);
+       if (p)
+               return prefix2str(p, str, sizeof(str));
+
+       return NULL;
+}
+
 /*
  * bgp_node_create
  */
index 8a5ed2442f716c2511bb46fa5cd307a80a69961f..d832383ab41b936d5e4e6c4ca0e5ca6c52887422 100644 (file)
@@ -31,7 +31,6 @@
 #include "linklist.h"
 #include "bgpd.h"
 #include "bgp_advertise.h"
-#include "bgpd/bgp_trace.h"
 
 struct bgp_table {
        /* table belongs to this instance */
@@ -135,6 +134,9 @@ extern struct bgp_table *bgp_table_init(struct bgp *bgp, afi_t, safi_t);
 extern void bgp_table_lock(struct bgp_table *);
 extern void bgp_table_unlock(struct bgp_table *);
 extern void bgp_table_finish(struct bgp_table **);
+extern void bgp_dest_unlock_node(struct bgp_dest *dest);
+extern struct bgp_dest *bgp_dest_lock_node(struct bgp_dest *dest);
+extern const char *bgp_dest_get_prefix_str(struct bgp_dest *dest);
 
 
 /*
@@ -179,16 +181,6 @@ static inline struct bgp_dest *bgp_dest_parent_nolock(struct bgp_dest *dest)
        return bgp_dest_from_rnode(rn);
 }
 
-/*
- * bgp_dest_unlock_node
- */
-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));
-}
-
 /*
  * bgp_table_top_nolock
  *
@@ -253,17 +245,6 @@ bgp_node_lookup(const struct bgp_table *const table, const struct prefix *p)
        return bgp_dest_from_rnode(rn);
 }
 
-/*
- * bgp_dest_lock_node
- */
-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);
-}
-
 /*
  * bgp_node_match
  */
index 8bc513009dbaff1c845a4574dd47ecc61aeef3aa..91a190722be3a74603bfe94e16d1229c351c3b9a 100644 (file)
 #include <lttng/tracepoint.h>
 
 #include "bgpd/bgpd.h"
+#include "bgpd/bgp_attr.h"
 #include "lib/stream.h"
+#include "bgpd/bgp_evpn_private.h"
+#include "bgpd/bgp_evpn_mh.h"
+
 
 /* clang-format off */
 
@@ -218,6 +222,118 @@ TRACEPOINT_EVENT(
 
 TRACEPOINT_LOGLEVEL(frr_bgp, bmp_process, TRACE_DEBUG)
 
+/*
+ * bgp_dest_lock/bgp_dest_unlock
+ */
+TRACEPOINT_EVENT(
+       frr_bgp,
+       bgp_dest_lock,
+       TP_ARGS(struct bgp_dest *, dest),
+       TP_FIELDS(
+               ctf_string(prefix, bgp_dest_get_prefix_str(dest))
+               ctf_integer(unsigned int, count, bgp_dest_get_lock_count(dest))
+       )
+)
+TRACEPOINT_LOGLEVEL(frr_bgp, bgp_dest_lock, TRACE_INFO)
+
+TRACEPOINT_EVENT(
+       frr_bgp,
+       bgp_dest_unlock,
+       TP_ARGS(struct bgp_dest *, dest),
+       TP_FIELDS(
+               ctf_string(prefix, bgp_dest_get_prefix_str(dest))
+               ctf_integer(unsigned int, count, bgp_dest_get_lock_count(dest))
+       )
+)
+TRACEPOINT_LOGLEVEL(frr_bgp, bgp_dest_unlock, TRACE_INFO)
+
+TRACEPOINT_EVENT(
+       frr_bgp,
+       evpn_mac_ip_zsend,
+       TP_ARGS(int, add, struct bgpevpn *, vpn,
+               const struct prefix_evpn *, pfx,
+               struct in_addr, vtep, esi_t *, esi),
+       TP_FIELDS(
+               ctf_string(action, add ? "add" : "del")
+               ctf_integer(vni_t, vni, vpn->vni)
+               ctf_array(unsigned char, mac, &pfx->prefix.macip_addr.mac,
+                       sizeof(struct ethaddr))
+               ctf_array(unsigned char, ip, &pfx->prefix.macip_addr.ip,
+                       sizeof(struct ipaddr))
+               ctf_integer_network_hex(unsigned int, vtep, vtep.s_addr)
+               ctf_array(unsigned char, esi, esi, sizeof(esi_t))
+       )
+)
+TRACEPOINT_LOGLEVEL(frr_bgp, evpn_mac_ip_zsend, TRACE_INFO)
+
+TRACEPOINT_EVENT(
+       frr_bgp,
+       evpn_bum_vtep_zsend,
+       TP_ARGS(int, add, struct bgpevpn *, vpn,
+               const struct prefix_evpn *, pfx),
+       TP_FIELDS(
+               ctf_string(action, add ? "add" : "del")
+               ctf_integer(vni_t, vni, vpn->vni)
+               ctf_integer_network_hex(unsigned int, vtep,
+                       pfx->prefix.imet_addr.ip.ipaddr_v4.s_addr)
+       )
+)
+TRACEPOINT_LOGLEVEL(frr_bgp, evpn_bum_vtep_zsend, TRACE_INFO)
+
+TRACEPOINT_EVENT(
+       frr_bgp,
+       evpn_mh_vtep_zsend,
+       TP_ARGS(bool, add, struct bgp_evpn_es *, es,
+               struct bgp_evpn_es_vtep *, es_vtep),
+       TP_FIELDS(
+               ctf_string(action, add ? "add" : "del")
+               ctf_string(esi, es->esi_str)
+               ctf_string(vtep, es_vtep->vtep_str)
+       )
+)
+TRACEPOINT_LOGLEVEL(frr_bgp, evpn_mh_vtep_zsend, TRACE_INFO)
+
+TRACEPOINT_EVENT(
+       frr_bgp,
+       evpn_mh_nhg_zsend,
+       TP_ARGS(bool, add, bool, type_v4, uint32_t, nhg_id,
+               struct bgp_evpn_es_vrf *, es_vrf),
+       TP_FIELDS(
+               ctf_string(action, add ? "add" : "del")
+               ctf_string(type, type_v4 ? "v4" : "v6")
+               ctf_integer(unsigned int, nhg, nhg_id)
+               ctf_string(esi, es_vrf->es->esi_str)
+               ctf_integer(int, vrf, es_vrf->bgp_vrf->vrf_id)
+       )
+)
+TRACEPOINT_LOGLEVEL(frr_bgp, evpn_mh_nhg_zsend, TRACE_INFO)
+
+TRACEPOINT_EVENT(
+       frr_bgp,
+       evpn_mh_nh_zsend,
+       TP_ARGS(uint32_t, nhg_id, struct bgp_evpn_es_vtep *, vtep,
+               struct bgp_evpn_es_vrf *, es_vrf),
+       TP_FIELDS(
+               ctf_integer(unsigned int, nhg, nhg_id)
+               ctf_string(vtep, vtep->vtep_str)
+               ctf_integer(int, svi, es_vrf->bgp_vrf->l3vni_svi_ifindex)
+       )
+)
+TRACEPOINT_LOGLEVEL(frr_bgp, evpn_mh_nh_zsend, TRACE_INFO)
+
+TRACEPOINT_EVENT(
+       frr_bgp,
+       evpn_mh_nh_rmac_zsend,
+       TP_ARGS(bool, add, struct bgp_evpn_nh *, nh),
+       TP_FIELDS(
+               ctf_string(action, add ? "add" : "del")
+               ctf_integer(int, vrf, nh->bgp_vrf->vrf_id)
+               ctf_string(nh, nh->nh_str)
+               ctf_array(unsigned char, rmac, &nh->rmac,
+                       sizeof(struct ethaddr))
+       )
+)
+TRACEPOINT_LOGLEVEL(frr_bgp, evpn_nh_rmac_zsend, TRACE_INFO)
 /* clang-format on */
 
 #include <lttng/tracepoint-event.h>
index 9c2288cba3999dbbf9dc35e3223a0f4e8913689e..96febcd5df12352ff86c24d43155165f8d07597d 100644 (file)
@@ -798,6 +798,9 @@ void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw)
 
        bgp_attr_default_set(&attr, BGP_ORIGIN_IGP);
 
+       /* make coverity happy */
+       assert(attr.aspath);
+
        attr.local_pref = bgp->default_local_pref;
 
        if ((afi == AFI_IP6) || peer_cap_enhe(peer, afi, safi)) {
@@ -812,6 +815,10 @@ void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw)
        }
 
        if (peer->default_rmap[afi][safi].name) {
+               struct bgp_path_info tmp_pi = {0};
+
+               tmp_pi.peer = bgp->peer_self;
+
                SET_FLAG(bgp->peer_self->rmap_type, PEER_RMAP_TYPE_DEFAULT);
 
                /* Iterate over the RIB to see if we can announce
@@ -825,24 +832,16 @@ void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw)
 
                        for (pi = bgp_dest_get_bgp_path_info(dest); pi;
                             pi = pi->next) {
-                               struct attr tmp_attr;
-                               struct bgp_path_info tmp_pi;
-                               struct bgp_path_info_extra tmp_pie;
+                               struct attr tmp_attr = attr;
 
-                               tmp_attr = *pi->attr;
-                               tmp_attr.aspath = attr.aspath;
+                               tmp_pi.attr = &tmp_attr;
 
-                               prep_for_rmap_apply(&tmp_pi, &tmp_pie, dest, pi,
-                                                   pi->peer, &tmp_attr);
-
-                               ret = route_map_apply(
+                               ret = route_map_apply_ext(
                                        peer->default_rmap[afi][safi].map,
-                                       bgp_dest_get_prefix(dest), &tmp_pi);
+                                       bgp_dest_get_prefix(dest), pi, &tmp_pi);
 
                                if (ret == RMAP_DENYMATCH) {
-                                       /* The aspath belongs to 'attr' */
-                                       tmp_attr.aspath = NULL;
-                                       bgp_attr_flush(&tmp_attr);
+                                       bgp_attr_undup(&tmp_attr, &attr);
                                        continue;
                                } else {
                                        new_attr = bgp_attr_intern(&tmp_attr);
@@ -939,6 +938,8 @@ void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw)
                        subgroup_default_update_packet(subgrp, new_attr, from);
                }
        }
+
+       aspath_unintern(&attr.aspath);
 }
 
 /*
index 6e427c0b7cf0896cc0b91af1efb394109cd1bad7..14f4fb731050b4af8825d2e8721506d6f2492401 100644 (file)
@@ -282,6 +282,57 @@ static const char *get_afi_safi_json_str(afi_t afi, safi_t safi)
        return "Unknown";
 }
 
+/* unset srv6 locator */
+static int bgp_srv6_locator_unset(struct bgp *bgp)
+{
+       int ret;
+       struct listnode *node, *nnode;
+       struct prefix_ipv6 *chunk;
+       struct bgp_srv6_function *func;
+       struct bgp *bgp_vrf;
+       struct in6_addr *tovpn_sid;
+
+       /* release chunk notification via ZAPI */
+       ret = bgp_zebra_srv6_manager_release_locator_chunk(
+                       bgp->srv6_locator_name);
+       if (ret < 0)
+               return -1;
+
+       /* refresh chunks */
+       for (ALL_LIST_ELEMENTS(bgp->srv6_locator_chunks, node, nnode, chunk))
+               listnode_delete(bgp->srv6_locator_chunks, chunk);
+
+       /* refresh functions */
+       for (ALL_LIST_ELEMENTS(bgp->srv6_functions, node, nnode, func))
+               listnode_delete(bgp->srv6_functions, func);
+
+       /* refresh tovpn_sid */
+       for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp_vrf)) {
+               if (bgp_vrf->inst_type != BGP_INSTANCE_TYPE_VRF)
+                       continue;
+
+               /* refresh vpnv4 tovpn_sid */
+               tovpn_sid = bgp_vrf->vpn_policy[AFI_IP].tovpn_sid;
+               if (tovpn_sid)
+                       XFREE(MTYPE_BGP_SRV6_SID,
+                             bgp_vrf->vpn_policy[AFI_IP].tovpn_sid);
+
+               /* refresh vpnv6 tovpn_sid */
+               tovpn_sid = bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid;
+               if (tovpn_sid)
+                       XFREE(MTYPE_BGP_SRV6_SID,
+                             bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid);
+       }
+
+       /* update vpn bgp processes */
+       vpn_leak_postchange_all();
+
+       /* clear locator name */
+       memset(bgp->srv6_locator_name, 0, sizeof(bgp->srv6_locator_name));
+
+       return 0;
+}
+
 /* Utility function to get address family from current node.  */
 afi_t bgp_node_afi(struct vty *vty)
 {
@@ -861,13 +912,19 @@ static int bgp_peer_clear(struct peer *peer, afi_t afi, safi_t safi,
        if ((afi == AFI_UNSPEC) && (safi == SAFI_UNSPEC)) {
                afi_t tmp_afi;
                safi_t tmp_safi;
+               enum bgp_af_index index;
+
+               for (index = BGP_AF_START; index < BGP_AF_MAX; index++) {
+                       paf = peer->peer_af_array[index];
+                       if (!paf)
+                               continue;
 
-               FOREACH_AFI_SAFI (tmp_afi, tmp_safi) {
-                       paf = peer_af_find(peer, tmp_afi, tmp_safi);
                        if (paf && paf->subgroup)
                                SET_FLAG(paf->subgroup->sflags,
                                         SUBGRP_STATUS_FORCE_UPDATES);
 
+                       tmp_afi = paf->afi;
+                       tmp_safi = paf->safi;
                        if (!peer->afc[tmp_afi][tmp_safi])
                                continue;
 
@@ -9096,6 +9153,23 @@ DEFUN_NOSH (bgp_segment_routing_srv6,
        return CMD_SUCCESS;
 }
 
+DEFUN (no_bgp_segment_routing_srv6,
+       no_bgp_segment_routing_srv6_cmd,
+       "no segment-routing srv6",
+       NO_STR
+       "Segment-Routing configuration\n"
+       "Segment-Routing SRv6 configuration\n")
+{
+       VTY_DECLVAR_CONTEXT(bgp, bgp);
+
+       if (strlen(bgp->srv6_locator_name) > 0)
+               if (bgp_srv6_locator_unset(bgp) < 0)
+                       return CMD_WARNING_CONFIG_FAILED;
+
+       bgp->srv6_enabled = false;
+       return CMD_SUCCESS;
+}
+
 DEFPY (bgp_srv6_locator,
        bgp_srv6_locator_cmd,
        "locator NAME$name",
@@ -9121,6 +9195,32 @@ DEFPY (bgp_srv6_locator,
        return CMD_SUCCESS;
 }
 
+DEFPY (no_bgp_srv6_locator,
+       no_bgp_srv6_locator_cmd,
+       "no locator NAME$name",
+       NO_STR
+       "Specify SRv6 locator\n"
+       "Specify SRv6 locator\n")
+{
+       VTY_DECLVAR_CONTEXT(bgp, bgp);
+
+       /* when locator isn't configured, do nothing */
+       if (strlen(bgp->srv6_locator_name) < 1)
+               return CMD_SUCCESS;
+
+       /* name validation */
+       if (strcmp(name, bgp->srv6_locator_name) != 0) {
+               vty_out(vty, "%% No srv6 locator is configured\n");
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       /* unset locator */
+       if (bgp_srv6_locator_unset(bgp) < 0)
+               return CMD_WARNING_CONFIG_FAILED;
+
+       return CMD_SUCCESS;
+}
+
 DEFPY (show_bgp_srv6,
        show_bgp_srv6_cmd,
        "show bgp segment-routing srv6",
@@ -9974,21 +10074,12 @@ static void bgp_show_failed_summary(struct vty *vty, struct bgp *bgp,
        }
 }
 
-/* If the peer's description includes whitespaces
- * then return the first occurrence. Also strip description
- * to the given size if needed.
- */
+/* Strip peer's description to the given size. */
 static char *bgp_peer_description_stripped(char *desc, uint32_t size)
 {
        static char stripped[BUFSIZ];
-       char *pnt;
        uint32_t len = size > strlen(desc) ? strlen(desc) : size;
 
-       pnt = strchr(desc, ' ');
-       if (pnt)
-               len = size > (uint32_t)(pnt - desc) ? (uint32_t)(pnt - desc)
-                                                   : size;
-
        strlcpy(stripped, desc, len + 1);
 
        return stripped;
@@ -10020,7 +10111,15 @@ static bool bgp_show_summary_is_peer_filtered(struct peer *peer,
        return false;
 }
 
-/* Show BGP peer's summary information. */
+/* Show BGP peer's summary information.
+ *
+ * Peer's description is stripped according to if `wide` option is given
+ * or not.
+ *
+ * When adding new columns to `show bgp summary` output, please make
+ * sure `Desc` is the lastest column to show because it can contain
+ * whitespaces and the whole output will be tricky.
+ */
 static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
                            struct peer *fpeer, int as_type, as_t as,
                            uint16_t show_flags)
@@ -10685,6 +10784,9 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
 
                                        vty_out(vty, " %8u", 0);
                                }
+                               /* Make sure `Desc` column is the lastest in
+                                * the output.
+                                */
                                if (peer->desc)
                                        vty_out(vty, " %s",
                                                bgp_peer_description_stripped(
@@ -18913,7 +19015,9 @@ void bgp_vty_init(void)
        /* srv6 commands */
        install_element(VIEW_NODE, &show_bgp_srv6_cmd);
        install_element(BGP_NODE, &bgp_segment_routing_srv6_cmd);
+       install_element(BGP_NODE, &no_bgp_segment_routing_srv6_cmd);
        install_element(BGP_SRV6_NODE, &bgp_srv6_locator_cmd);
+       install_element(BGP_SRV6_NODE, &no_bgp_srv6_locator_cmd);
        install_element(BGP_IPV4_NODE, &af_sid_vpn_export_cmd);
        install_element(BGP_IPV6_NODE, &af_sid_vpn_export_cmd);
 }
index 5ef49e5108d2c1a3e2a94d8357558b2ffec80e99..09fe399c295dd5e3cbb60b84c9690f596bb20358 100644 (file)
@@ -338,8 +338,11 @@ static int bgp_interface_address_add(ZAPI_CALLBACK_ARGS)
 
 static int bgp_interface_address_delete(ZAPI_CALLBACK_ARGS)
 {
+       struct listnode *node, *nnode;
        struct connected *ifc;
+       struct peer *peer;
        struct bgp *bgp;
+       struct prefix *addr;
 
        bgp = bgp_lookup_by_vrf_id(vrf_id);
 
@@ -356,6 +359,35 @@ static int bgp_interface_address_delete(ZAPI_CALLBACK_ARGS)
                bgp_connected_delete(bgp, ifc);
        }
 
+       addr = ifc->address;
+
+       if (bgp) {
+               /*
+                * When we are using the v6 global as part of the peering
+                * nexthops and we are removing it, then we need to
+                * clear the peer data saved for that nexthop and
+                * cause a re-announcement of the route.  Since
+                * we do not want the peering to bounce.
+                */
+               for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
+                       afi_t afi;
+                       safi_t safi;
+
+                       if (addr->family == AF_INET)
+                               continue;
+
+                       if (!IN6_IS_ADDR_LINKLOCAL(&addr->u.prefix6)
+                           && memcmp(&peer->nexthop.v6_global,
+                                     &addr->u.prefix6, 16)
+                                      == 0) {
+                               memset(&peer->nexthop.v6_global, 0, 16);
+                               FOREACH_AFI_SAFI (afi, safi)
+                                       bgp_announce_route(peer, afi, safi,
+                                                          true);
+                       }
+               }
+       }
+
        connected_free(&ifc);
 
        return 0;
@@ -472,8 +504,9 @@ static int bgp_interface_vrf_update(ZAPI_CALLBACK_ARGS)
 static int zebra_read_route(ZAPI_CALLBACK_ARGS)
 {
        enum nexthop_types_t nhtype;
+       enum blackhole_type bhtype = BLACKHOLE_UNSPEC;
        struct zapi_route api;
-       union g_addr nexthop;
+       union g_addr nexthop = {};
        ifindex_t ifindex;
        int add, i;
        struct bgp *bgp;
@@ -494,10 +527,16 @@ static int zebra_read_route(ZAPI_CALLBACK_ARGS)
            && IN6_IS_ADDR_LINKLOCAL(&api.prefix.u.prefix6))
                return 0;
 
-       nexthop = api.nexthops[0].gate;
        ifindex = api.nexthops[0].ifindex;
        nhtype = api.nexthops[0].type;
 
+       /* api_nh structure has union of gate and bh_type */
+       if (nhtype == NEXTHOP_TYPE_BLACKHOLE) {
+               /* bh_type is only applicable if NEXTHOP_TYPE_BLACKHOLE*/
+               bhtype = api.nexthops[0].bh_type;
+       } else
+               nexthop = api.nexthops[0].gate;
+
        add = (cmd == ZEBRA_REDISTRIBUTE_ROUTE_ADD);
        if (add) {
                /*
@@ -517,8 +556,8 @@ static int zebra_read_route(ZAPI_CALLBACK_ARGS)
 
                /* Now perform the add/update. */
                bgp_redistribute_add(bgp, &api.prefix, &nexthop, ifindex,
-                                    nhtype, api.distance, api.metric, api.type,
-                                    api.instance, api.tag);
+                                    nhtype, bhtype, api.distance, api.metric,
+                                    api.type, api.instance, api.tag);
        } else {
                bgp_redistribute_delete(bgp, &api.prefix, api.type,
                                        api.instance);
@@ -1076,8 +1115,10 @@ static bool update_ipv4nh_for_route_install(int nh_othervrf, struct bgp *nh_bgp,
         * a VRF (which are programmed as onlink on l3-vni SVI) as well as
         * connected routes leaked into a VRF.
         */
-       if (is_evpn) {
-
+       if (attr->nh_type == NEXTHOP_TYPE_BLACKHOLE) {
+               api_nh->type = attr->nh_type;
+               api_nh->bh_type = attr->bh_type;
+       } else if (is_evpn) {
                /*
                 * If the nexthop is EVPN overlay index gateway IP,
                 * treat the nexthop as NEXTHOP_TYPE_IPV4
@@ -1090,8 +1131,7 @@ static bool update_ipv4nh_for_route_install(int nh_othervrf, struct bgp *nh_bgp,
                        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) {
+       } else if (nh_othervrf && api_nh->gate.ipv4.s_addr == INADDR_ANY) {
                api_nh->type = NEXTHOP_TYPE_IFINDEX;
                api_nh->ifindex = attr->nh_ifindex;
        } else
@@ -1113,8 +1153,10 @@ static bool update_ipv6nh_for_route_install(int nh_othervrf, struct bgp *nh_bgp,
        attr = pi->attr;
        api_nh->vrf_id = nh_bgp->vrf_id;
 
-       if (is_evpn) {
-
+       if (attr->nh_type == NEXTHOP_TYPE_BLACKHOLE) {
+               api_nh->type = attr->nh_type;
+               api_nh->bh_type = attr->bh_type;
+       } else if (is_evpn) {
                /*
                 * If the nexthop is EVPN overlay index gateway IP,
                 * treat the nexthop as NEXTHOP_TYPE_IPV4
@@ -1169,7 +1211,8 @@ static bool update_ipv6nh_for_route_install(int nh_othervrf, struct bgp *nh_bgp,
                        api_nh->ifindex = 0;
                }
        }
-       if (nexthop)
+       /* api_nh structure has union of gate and bh_type */
+       if (nexthop && api_nh->type != NEXTHOP_TYPE_BLACKHOLE)
                api_nh->gate.ipv6 = *nexthop;
 
        return true;
@@ -1208,9 +1251,7 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
        struct zapi_nexthop *api_nh;
        int nh_family;
        unsigned int valid_nh_count = 0;
-       int has_valid_label = 0;
        bool allow_recursion = false;
-       int has_valid_sid = 0;
        uint8_t distance;
        struct peer *peer;
        struct bgp_path_info *mpinfo;
@@ -1423,7 +1464,6 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
                if (mpinfo->extra
                    && bgp_is_valid_label(&mpinfo->extra->label[0])
                    && !CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE)) {
-                       has_valid_label = 1;
                        label = label_pton(&mpinfo->extra->label[0]);
 
                        SET_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_LABEL);
@@ -1440,20 +1480,17 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
 
                api_nh->weight = nh_weight;
 
-               if (mpinfo->extra
-                   && !sid_zero(&mpinfo->extra->sid[0])
+               if (mpinfo->extra && !sid_zero(&mpinfo->extra->sid[0].sid)
                    && !CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE)) {
-                       has_valid_sid = 1;
-                       memcpy(&api_nh->seg6_segs, &mpinfo->extra->sid[0],
+                       memcpy(&api_nh->seg6_segs, &mpinfo->extra->sid[0].sid,
                               sizeof(api_nh->seg6_segs));
+
+                       SET_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_SEG6);
                }
 
                valid_nh_count++;
        }
 
-       if (has_valid_sid && !(CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE)))
-               SET_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_SEG6);
-
        is_add = (valid_nh_count || nhg_id) ? true : false;
 
        if (is_add && CHECK_FLAG(bm->flags, BM_FLAG_SEND_EXTRA_DATA_TO_ZEBRA)) {
@@ -1550,11 +1587,11 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p,
                        label_buf[0] = '\0';
                        eth_buf[0] = '\0';
                        segs_buf[0] = '\0';
-                       if (has_valid_label
+                       if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_LABEL)
                            && !CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE))
                                snprintf(label_buf, sizeof(label_buf),
                                        "label %u", api_nh->labels[0]);
-                       if (has_valid_sid
+                       if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_SEG6)
                            && !CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE)) {
                                inet_ntop(AF_INET6, &api_nh->seg6_segs,
                                          sid_buf, sizeof(sid_buf));
@@ -3077,6 +3114,88 @@ static void bgp_zebra_process_srv6_locator_chunk(ZAPI_CALLBACK_ARGS)
        vpn_leak_postchange_all();
 }
 
+static int bgp_zebra_process_srv6_locator_add(ZAPI_CALLBACK_ARGS)
+{
+       struct srv6_locator loc = {};
+       struct bgp *bgp = bgp_get_default();
+       const char *loc_name = bgp->srv6_locator_name;
+
+       if (zapi_srv6_locator_decode(zclient->ibuf, &loc) < 0)
+               return -1;
+
+       if (!bgp || !bgp->srv6_enabled)
+               return 0;
+
+       if (bgp_zebra_srv6_manager_get_locator_chunk(loc_name) < 0)
+               return -1;
+
+       return 0;
+}
+
+static int bgp_zebra_process_srv6_locator_delete(ZAPI_CALLBACK_ARGS)
+{
+       struct srv6_locator loc = {};
+       struct bgp *bgp = bgp_get_default();
+       struct listnode *node, *nnode;
+       struct prefix_ipv6 *chunk;
+       struct bgp_srv6_function *func;
+       struct bgp *bgp_vrf;
+       struct in6_addr *tovpn_sid;
+       struct prefix_ipv6 tmp_prefi;
+
+       if (zapi_srv6_locator_decode(zclient->ibuf, &loc) < 0)
+               return -1;
+
+       // refresh chunks
+       for (ALL_LIST_ELEMENTS(bgp->srv6_locator_chunks, node, nnode, chunk))
+               if (prefix_match((struct prefix *)&loc.prefix,
+                                (struct prefix *)chunk))
+                       listnode_delete(bgp->srv6_locator_chunks, chunk);
+
+       // refresh functions
+       for (ALL_LIST_ELEMENTS(bgp->srv6_functions, node, nnode, func)) {
+               tmp_prefi.family = AF_INET6;
+               tmp_prefi.prefixlen = 128;
+               tmp_prefi.prefix = func->sid;
+               if (prefix_match((struct prefix *)&loc.prefix,
+                                (struct prefix *)&tmp_prefi))
+                       listnode_delete(bgp->srv6_functions, func);
+       }
+
+       // refresh tovpn_sid
+       for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp_vrf)) {
+               if (bgp_vrf->inst_type != BGP_INSTANCE_TYPE_VRF)
+                       continue;
+
+               // refresh vpnv4 tovpn_sid
+               tovpn_sid = bgp_vrf->vpn_policy[AFI_IP].tovpn_sid;
+               if (tovpn_sid) {
+                       tmp_prefi.family = AF_INET6;
+                       tmp_prefi.prefixlen = 128;
+                       tmp_prefi.prefix = *tovpn_sid;
+                       if (prefix_match((struct prefix *)&loc.prefix,
+                                        (struct prefix *)&tmp_prefi))
+                               XFREE(MTYPE_BGP_SRV6_SID,
+                                     bgp_vrf->vpn_policy[AFI_IP].tovpn_sid);
+               }
+
+               // refresh vpnv6 tovpn_sid
+               tovpn_sid = bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid;
+               if (tovpn_sid) {
+                       tmp_prefi.family = AF_INET6;
+                       tmp_prefi.prefixlen = 128;
+                       tmp_prefi.prefix = *tovpn_sid;
+                       if (prefix_match((struct prefix *)&loc.prefix,
+                                        (struct prefix *)&tmp_prefi))
+                               XFREE(MTYPE_BGP_SRV6_SID,
+                                     bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid);
+               }
+       }
+
+       vpn_leak_postchange_all();
+       return 0;
+}
+
 void bgp_zebra_init(struct thread_master *master, unsigned short instance)
 {
        zclient_num_connects = 0;
@@ -3119,6 +3238,8 @@ void bgp_zebra_init(struct thread_master *master, unsigned short instance)
        zclient->iptable_notify_owner = iptable_notify_owner;
        zclient->route_notify_owner = bgp_zebra_route_notify_owner;
        zclient->instance = instance;
+       zclient->srv6_locator_add = bgp_zebra_process_srv6_locator_add;
+       zclient->srv6_locator_delete = bgp_zebra_process_srv6_locator_delete;
        zclient->process_srv6_locator_chunk =
                bgp_zebra_process_srv6_locator_chunk;
 }
@@ -3530,3 +3651,8 @@ int bgp_zebra_srv6_manager_get_locator_chunk(const char *name)
 {
        return srv6_manager_get_locator_chunk(zclient, name);
 }
+
+int bgp_zebra_srv6_manager_release_locator_chunk(const char *name)
+{
+       return srv6_manager_release_locator_chunk(zclient, name);
+}
index 02b6484943ed236d601b6f8ad096e96c97473042..9c0a1d8f1f4c34d172311f7a4ea055101a4001ed 100644 (file)
@@ -114,4 +114,5 @@ extern int bgp_zebra_send_capabilities(struct bgp *bgp, bool disable);
 extern int bgp_zebra_update(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type);
 extern int bgp_zebra_stale_timer_update(struct bgp *bgp);
 extern int bgp_zebra_srv6_manager_get_locator_chunk(const char *name);
+extern int bgp_zebra_srv6_manager_release_locator_chunk(const char *name);
 #endif /* _QUAGGA_BGP_ZEBRA_H */
index ec91e7e229948f3c6824794542efd6be7863edda..b191029d2fbd49663ab0730851c8ee8fe124cd5b 100644 (file)
@@ -2156,7 +2156,8 @@ static int peer_activate_af(struct peer *peer, afi_t afi, safi_t safi)
                                                    CAPABILITY_ACTION_SET);
                                if (peer->afc_recv[afi][safi]) {
                                        peer->afc_nego[afi][safi] = 1;
-                                       bgp_announce_route(peer, afi, safi);
+                                       bgp_announce_route(peer, afi, safi,
+                                                          false);
                                }
                        } else {
                                peer->last_reset = PEER_DOWN_AF_ACTIVATE;
@@ -4142,7 +4143,7 @@ void peer_change_action(struct peer *peer, afi_t afi, safi_t safi,
                                 SUBGRP_STATUS_FORCE_UPDATES);
 
                update_group_adjust_peer(paf);
-               bgp_announce_route(peer, afi, safi);
+               bgp_announce_route(peer, afi, safi, false);
        }
 }
 
@@ -5058,7 +5059,7 @@ int peer_default_originate_set(struct peer *peer, afi_t afi, safi_t 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);
+                       bgp_announce_route(peer, afi, safi, false);
                }
 
                /* Skip peer-group mechanics for regular peers. */
@@ -5095,7 +5096,7 @@ int peer_default_originate_set(struct peer *peer, afi_t afi, safi_t safi,
                        update_group_adjust_peer(
                                peer_af_find(member, afi, safi));
                        bgp_default_originate(member, afi, safi, 0);
-                       bgp_announce_route(member, afi, safi);
+                       bgp_announce_route(member, afi, safi, false);
                }
        }
 
@@ -5134,7 +5135,7 @@ int peer_default_originate_unset(struct peer *peer, afi_t afi, safi_t 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);
+                       bgp_announce_route(peer, afi, safi, false);
                }
 
                /* Skip peer-group mechanics for regular peers. */
@@ -5165,7 +5166,7 @@ int peer_default_originate_unset(struct peer *peer, afi_t afi, safi_t 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);
+                       bgp_announce_route(member, afi, safi, false);
                }
        }
 
@@ -5213,7 +5214,7 @@ 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_established(peer))
-                       bgp_announce_route(peer, afi, safi);
+                       bgp_announce_route(peer, afi, safi, false);
        } else {
                if (!peer_established(peer))
                        return;
@@ -6266,7 +6267,8 @@ static void peer_distribute_update(struct access_list *access)
 
        for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) {
                if (access->name)
-                       update_group_policy_update(bgp, BGP_POLICY_FILTER_LIST,
+                       update_group_policy_update(bgp,
+                                                  BGP_POLICY_DISTRIBUTE_LIST,
                                                   access->name, 0, 0);
                for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
                        FOREACH_AFI_SAFI (afi, safi) {
@@ -7479,7 +7481,7 @@ int peer_clear_soft(struct peer *peer, afi_t afi, safi_t safi,
                        UNSET_FLAG(paf->subgroup->sflags,
                                   SUBGRP_STATUS_DEFAULT_ORIGINATE);
 
-               bgp_announce_route(peer, afi, safi);
+               bgp_announce_route(peer, afi, safi, false);
        }
 
        if (stype == BGP_CLEAR_SOFT_IN_ORF_PREFIX) {
@@ -7882,8 +7884,7 @@ 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 %s\n",
-                               bgp->name_pretty);
+                       vty_out(vty, "No such neighbor in this view/vrf\n");
                return NULL;
        }
 
index 13b530a6137e661968f2b54ec6816747117b471e..5e1eacbb9e627ab13ba6581aa09d419919d13ae1 100644 (file)
@@ -241,6 +241,7 @@ struct vpn_policy {
         */
        uint32_t tovpn_sid_index; /* unset => set to 0 */
        struct in6_addr *tovpn_sid;
+       uint32_t tovpn_sid_transpose_label;
        struct in6_addr *tovpn_zebra_vrf_sid_last_sent;
 };
 
index 45ef7230b503ffd4e4ee802b102c8453f6ec4368..6762c2b4a247ee48319550f6d4e8b0ca0b3443d8 100644 (file)
@@ -435,8 +435,16 @@ void rfapi_vty_out_vncinfo(struct vty *vty, const struct prefix *p,
                        char buf[BUFSIZ];
 
                        vty_out(vty, " sid=%s",
-                               inet_ntop(AF_INET6, &bpi->extra->sid[0], buf,
-                                         sizeof(buf)));
+                               inet_ntop(AF_INET6, &bpi->extra->sid[0].sid,
+                                         buf, sizeof(buf)));
+
+                       if (bpi->extra->sid[0].loc_block_len != 0) {
+                               vty_out(vty, " sid_structure=[%d,%d,%d,%d]",
+                                       bpi->extra->sid[0].loc_block_len,
+                                       bpi->extra->sid[0].loc_node_len,
+                                       bpi->extra->sid[0].func_len,
+                                       bpi->extra->sid[0].arg_len);
+                       }
                }
        }
 
index 917e791182adcb20ec44db91bdb7ce2e817b4094..873ed18db854e80b0446ae93501cbd5a14e19ae8 100644 (file)
@@ -7,7 +7,7 @@
 ##
 AC_PREREQ([2.69])
 
-AC_INIT([frr], [8.1-dev], [https://github.com/frrouting/frr/issues])
+AC_INIT([frr], [8.2-dev], [https://github.com/frrouting/frr/issues])
 PACKAGE_URL="https://frrouting.org/"
 AC_SUBST([PACKAGE_URL])
 PACKAGE_FULLNAME="FRRouting"
@@ -1926,7 +1926,7 @@ dnl -----
 dnl LTTng
 dnl -----
 if test "$enable_lttng" = "yes"; then
-  PKG_CHECK_MODULES([UST], [lttng-ust >= 2.12.0], [
+  PKG_CHECK_MODULES([UST], [lttng-ust >= 2.9.0], [
     AC_DEFINE([HAVE_LTTNG], [1], [Enable LTTng support])
     LTTNG=true
   ], [
@@ -2519,6 +2519,7 @@ AC_DEFINE_UNQUOTED([LDPD_SOCKET], ["$frr_statedir%s%s/ldpd.sock"], [ldpd control
 AC_DEFINE_UNQUOTED([ZEBRA_SERV_PATH], ["$frr_statedir%s%s/zserv.api"], [zebra api socket])
 AC_DEFINE_UNQUOTED([BFDD_CONTROL_SOCKET], ["$frr_statedir%s%s/bfdd.sock"], [bfdd control socket])
 AC_DEFINE_UNQUOTED([OSPFD_GR_STATE], ["$frr_statedir%s/ospfd-gr.json"], [ospfd GR state information])
+AC_DEFINE_UNQUOTED([OSPF6D_GR_STATE], ["$frr_statedir/ospf6d-gr.json"], [ospf6d GR state information])
 AC_DEFINE_UNQUOTED([DAEMON_VTY_DIR], ["$frr_statedir%s%s"], [daemon vty directory])
 AC_DEFINE_UNQUOTED([DAEMON_DB_DIR], ["$frr_statedir"], [daemon database directory])
 
index edabe61d92fdddfe41aa354348b8b2237d23d438..9254eb473903e1afd6f78f669f20ca2ecd607371 100644 (file)
@@ -139,6 +139,7 @@ by the parser.
    selector: "<" `selector_seq_seq` ">" `varname_token`
            : "{" `selector_seq_seq` "}" `varname_token`
            : "[" `selector_seq_seq` "]" `varname_token`
+           : "![" `selector_seq_seq` "]" `varname_token`
    selector_seq_seq: `selector_seq_seq` "|" `selector_token_seq`
                    : `selector_token_seq`
    selector_token_seq: `selector_token_seq` `selector_token`
@@ -218,6 +219,10 @@ one-or-more selection and repetition.
    provide mutual exclusion. User input matches at most one option.
 -  ``[square brackets]`` -- Contains sequences of tokens that can be omitted.
    ``[<a|b>]`` can be shortened to ``[a|b]``.
+-  ``![exclamation square brackets]`` -- same as ``[square brackets]``, but
+   only allow skipping the contents if the command input starts with ``no``.
+   (For cases where the positive command needs a parameter, but the parameter
+   is optional for the negative case.)
 -  ``{curly|braces}`` -- similar to angle brackets, but instead of mutual
    exclusion, curly braces indicate that one or more of the pipe-separated
    sequences may be provided in any order.
@@ -767,6 +772,172 @@ User input:
 ``ip`` partially matches ``ipv6`` but exactly matches ``ip``, so ``ip`` will
 win.
 
+Adding a CLI Node
+-----------------
+
+To add a new CLI node, you should:
+
+- define a new numerical node constant
+- define a node structure in the relevant daemon
+- call ``install_node()`` in the relevant daemon
+- define and install the new node in vtysh
+- define corresponding node entry commands in daemon and vtysh
+- add a new entry to the ``ctx_keywords`` dictionary in ``tools/frr-reload.py``
+
+Defining the numerical node constant
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Add your new node value to the enum before ``NODE_TYPE_MAX`` in
+``lib/command.h``:
+
+.. code-block:: c
+
+   enum node_type {
+        AUTH_NODE,               // Authentication mode of vty interface.
+        VIEW_NODE,               // View node. Default mode of vty interface.
+        [...]
+        MY_NEW_NODE,
+        NODE_TYPE_MAX, // maximum
+   };
+
+Defining a node structure
+^^^^^^^^^^^^^^^^^^^^^^^^^
+In your daemon-specific code where you define your new commands that
+attach to the new node, add a node definition:
+
+.. code-block:: c
+
+   static struct cmd_node my_new_node = {
+        .name = "my new node name",
+        .node = MY_NEW_NODE, // enum node_type lib/command.h
+        .parent_node = CONFIG_NODE,
+        .prompt = "%s(my-new-node-prompt)# ",
+        .config_write = my_new_node_config_write,
+   };
+
+You will need to define ``my_new_node_config_write(struct vty \*vty)``
+(or omit this field if you have no relevant configuration to save).
+
+Calling ``install_node()``
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+In the daemon's initialization function, before installing your new commands
+with ``install_element()``, add a call ``install_node(&my_new_node)``.
+
+Defining and installing the new node in vtysh
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+The build tools automatically collect command definitions for vtysh.
+However, new nodes must be coded in vtysh specifically.
+
+In ``vtysh/vtysh.c``, define a stripped-down node structure and
+call ``install_node()``:
+
+.. code-block:: c
+
+   static struct cmd_node my_new_node = {
+        .name = "my new node name",
+        .node = MY_NEW_NODE, /* enum node_type lib/command.h */
+        .parent_node = CONFIG_NODE,
+        .prompt = "%s(my-new-node-prompt)# ",
+   };
+   [...]
+   void vtysh_init_vty(void)
+   {
+      [...]
+      install_node(&my_new_node)
+      [...]
+   }
+
+Defining corresponding node entry commands in daemon and vtysh
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+The command that descends into the new node is typically programmed
+with ``VTY_PUSH_CONTEXT`` or equivalent in the daemon's CLI handler function.
+(If the CLI has been updated to use the new northbound architecture,
+``VTY_PUSH_XPATH`` is used instead.)
+
+In vtysh, you must implement a corresponding node change so that vtysh
+tracks the daemon's movement through the node tree.
+
+Although the build tools typically scan daemon code for CLI definitions
+to replicate their parsing in vtysh, the node-descent function in the
+daemon must be blocked from this replication so that a hand-coded
+skeleton can be written in ``vtysh.c``.
+
+Accordingly, use one of the ``*_NOSH`` macros such as ``DEFUN_NOSH``,
+``DEFPY_NOSH``, or ``DEFUN_YANG_NOSH``  for the daemon's node-descent
+CLI definition, and use ``DEFUNSH`` in ``vtysh.c`` for the vtysh equivalent.
+
+.. seealso:: :ref:`vtysh-special-defuns`
+
+Examples:
+
+``zebra_whatever.c``
+
+.. code-block:: c
+
+   DEFPY_NOSH(my_new_node,
+        my_new_node_cmd,
+        "my-new-node foo",
+        "New Thing\n"
+        "A foo\n")
+   {
+      [...]
+      VTY_PUSH_CONTEXT(MY_NEW_NODE, bar);
+      [...]
+   }
+
+
+``ripd_whatever.c``
+
+.. code-block:: c
+
+   DEFPY_YANG_NOSH(my_new_node,
+        my_new_node_cmd,
+        "my-new-node foo",
+        "New Thing\n"
+        "A foo\n")
+   {
+      [...]
+      VTY_PUSH_XPATH(MY_NEW_NODE, xbar);
+      [...]
+   }
+
+
+``vtysh.c``
+
+.. code-block:: c
+
+   DEFUNSH(VTYSH_ZEBRA, my_new_node,
+        my_new_node_cmd,
+        "my-new-node foo",
+        "New Thing\n"
+        "A foo\n")
+   {
+        vty->node = MY_NEW_NODE;
+        return CMD_SUCCESS;
+   }
+   [...]
+   install_element(CONFIG_NODE, &my_new_node_cmd);
+
+
+Adding a new entry to the ``ctx_keywords`` dictionary
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+In file ``tools/frr-reload.py``, the ``ctx_keywords`` dictionary
+describes the various node relationships.
+Add a new node entry at the appropriate level in this dictionary.
+
+.. code-block:: python
+
+        ctx_keywords = {
+            [...]
+            "key chain ": {
+                "key ": {}
+            },
+            [...]
+            "my-new-node": {},
+            [...]
+        }
+
+
+
 Inspection & Debugging
 ----------------------
 
index cb164bdabf19b47b776eb6977bf4dd8d1d20bfd5..4e81adf8b243a069bd7917b4fa9c44fd7b33b6a7 100644 (file)
@@ -42,6 +42,7 @@ Generating C++ FRR Bindings
 Generating FRR northbound bindings for C++ example:
 
 ::
+
    # Install gRPC (e.g., on Ubuntu 20.04)
    sudo apt-get install libgrpc++-dev libgrpc-dev
 
index b827afd6cc5cc9eccae1341b7caa518d128f8e68..681fc1173c54efe4243f284f378569fa14ec101f 100644 (file)
@@ -191,6 +191,10 @@ Networking data types
 
    ``%pNHs``: :frrfmtout:`1.2.3.4 if 15` â€” same as :c:func:`nexthop2str()`
 
+   ``%pNHcg``: :frrfmtout:`1.2.3.4` â€” compact gateway only
+
+   ``%pNHci``: :frrfmtout:`eth0` â€” compact interface only
+
 .. frrfmt:: %pBD (struct bgp_dest *)
 
    :frrfmtout:`fe80::1234/64`
index fa6a1ba660f99d7b1a9f91ff6f281986f45967e6..b4f6ec521c063c7a7a9c4344c381eaff295d3764 100644 (file)
@@ -130,12 +130,42 @@ And create ``frr`` user and ``frrvty`` group as follows:
 Executing Tests
 ---------------
 
+Configure your sudo environment
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Topotests must be run as root. Normally this will be accomplished through the
+use of the ``sudo`` command. In order for topotests to be able to open new
+windows (either XTerm or byobu/screen/tmux windows) certain environment
+variables must be passed through the sudo command. One way to do this is to
+specify the :option:`-E` flag to ``sudo``. This will carry over most if not all
+your environment variables include ``PATH``. For example:
+
+.. code:: shell
+
+   sudo -E python3 -m pytest -s -v
+
+If you do not wish to use :option:`-E` (e.g., to avoid ``sudo`` inheriting
+``PATH``) you can modify your `/etc/sudoers` config file to specifically pass
+the environment variables required by topotests. Add the following commands to
+your ``/etc/sudoers`` config file.
+
+.. code:: shell
+
+   Defaults env_keep="TMUX"
+   Defaults env_keep+="TMUX_PANE"
+   Defaults env_keep+="STY"
+   Defaults env_keep+="DISPLAY"
+
+If there was already an ``env_keep`` configuration there be sure to use the
+``+=`` rather than ``=`` on the first line above as well.
+
+
 Execute all tests in distributed test mode
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 .. code:: shell
 
-   py.test -s -v -nauto --dist=loadfile
+   sudo -E pytest -s -v -nauto --dist=loadfile
 
 The above command must be executed from inside the topotests directory.
 
@@ -167,7 +197,7 @@ the run.
 
 Here we see that 4 tests have failed. We an dig deeper by displaying the
 captured logs and errors. First let's redisplay the results enumerated by adding
-the ``-E`` flag
+the :option:`-E` flag
 
 .. code:: shell
 
@@ -353,6 +383,12 @@ be run within ``tmux`` (or ``screen``)_, as ``gdb``, the shell or ``vtysh`` will
 be launched using that windowing program, otherwise ``xterm`` will be attempted
 to launch the given programs.
 
+NOTE: you must run the topotest (pytest) such that your DISPLAY, STY or TMUX
+environment variables are carried over. You can do this by passing the
+:option:`-E` flag to ``sudo`` or you can modify your ``/etc/sudoers`` config to
+automatically pass that environment variable through to the ``sudo``
+environment.
+
 .. _screen: https://www.gnu.org/software/screen/
 .. _tmux: https://github.com/tmux/tmux/wiki
 
@@ -364,7 +400,7 @@ One can have a debugging CLI invoked on test failures by specifying the
 
 .. code:: shell
 
-   pytest --cli-on-error all-protocol-startup
+   sudo -E pytest --cli-on-error all-protocol-startup
 
 The debugging CLI can run shell or vtysh commands on any combination of routers
 It can also open shells or vtysh in their own windows for any combination of
@@ -415,7 +451,7 @@ Here's an example of launching ``vtysh`` on routers ``rt1`` and ``rt2``.
 
 .. code:: shell
 
-   pytest --vtysh=rt1,rt2 all-protocol-startup
+   sudo -E pytest --vtysh=rt1,rt2 all-protocol-startup
 
 Debugging with GDB
 """"""""""""""""""
@@ -436,7 +472,7 @@ Here's an example of launching ``zebra`` and ``bgpd`` inside ``gdb`` on router
 
 .. code:: shell
 
-   pytest --gdb-routers=r1 \
+   sudo -E pytest --gdb-routers=r1 \
           --gdb-daemons=bgpd,zebra \
           --gdb-breakpoints=nb_config_diff \
           all-protocol-startup
@@ -453,7 +489,7 @@ memleak detection is enabled.
 
 .. code:: shell
 
-   pytest --valgrind-memleaks all-protocol-startup
+   sudo -E pytest --valgrind-memleaks all-protocol-startup
 
 .. _topotests_docker:
 
@@ -555,21 +591,21 @@ top level directory of topotest:
    $ # Change to the top level directory of topotests.
    $ cd path/to/topotests
    $ # Tests must be run as root, since micronet requires it.
-   $ sudo pytest
+   $ sudo -E pytest
 
 In order to run a specific test, you can use the following command:
 
 .. code:: shell
 
    $ # running a specific topology
-   $ sudo pytest ospf-topo1/
+   $ sudo -E pytest ospf-topo1/
    $ # or inside the test folder
    $ cd ospf-topo1
-   $ sudo pytest # to run all tests inside the directory
-   $ sudo pytest test_ospf_topo1.py # to run a specific test
+   $ sudo -E pytest # to run all tests inside the directory
+   $ sudo -E pytest test_ospf_topo1.py # to run a specific test
    $ # or outside the test folder
    $ cd ..
-   $ sudo pytest ospf-topo1/test_ospf_topo1.py # to run a specific one
+   $ sudo -E pytest ospf-topo1/test_ospf_topo1.py # to run a specific one
 
 The output of the tested daemons will be available at the temporary folder of
 your machine:
@@ -588,7 +624,7 @@ You can also run memory leak tests to get reports:
 .. code:: shell
 
    $ # Set the environment variable to apply to a specific test...
-   $ sudo env TOPOTESTS_CHECK_MEMLEAK="/tmp/memleak_report_" pytest ospf-topo1/test_ospf_topo1.py
+   $ sudo -E env TOPOTESTS_CHECK_MEMLEAK="/tmp/memleak_report_" pytest ospf-topo1/test_ospf_topo1.py
    $ # ...or apply to all tests adding this line to the configuration file
    $ echo 'memleak_path = /tmp/memleak_report_' >> pytest.ini
    $ # You can also use your editor
@@ -626,12 +662,12 @@ Some things to keep in mind:
 - Using sleep is almost never appropriate. As an example: if the test resets the
   peers in BGP, the test should look for the peers re-converging instead of just
   sleeping an arbitrary amount of time and continuing on. See
-  `verify_bgp_convergence` as a good example of this. In particular look at it's
-  use of the `@retry` decorator. If you are having troubles figuring out what to
-  look for, please do not be afraid to ask.
+  ``verify_bgp_convergence`` as a good example of this. In particular look at
+  it's use of the ``@retry`` decorator. If you are having troubles figuring out
+  what to look for, please do not be afraid to ask.
 - Don't duplicate effort. There exists many protocol utility functions that can
-  be found in their eponymous module under `tests/topotests/lib/` (e.g.,
-  `ospf.py`)
+  be found in their eponymous module under ``tests/topotests/lib/`` (e.g.,
+  ``ospf.py``)
 
 
 
@@ -827,11 +863,11 @@ that using the following example commands:
 .. code:: shell
 
    $ # Running your bootstraped topology
-   $ sudo pytest -s --topology-only new-topo/test_new_topo.py
+   $ sudo -E pytest -s --topology-only new-topo/test_new_topo.py
    $ # Running the test_template.py topology
-   $ sudo pytest -s --topology-only example-test/test_template.py
+   $ sudo -E pytest -s --topology-only example-test/test_template.py
    $ # Running the ospf_topo1.py topology
-   $ sudo pytest -s --topology-only ospf-topo1/test_ospf_topo1.py
+   $ sudo -E pytest -s --topology-only ospf-topo1/test_ospf_topo1.py
 
 Parameters explanation:
 
@@ -851,7 +887,7 @@ output:
 
 .. code:: shell
 
-    frr/tests/topotests# sudo pytest -s --topology-only ospf_topo1/test_ospf_topo1.py
+    frr/tests/topotests# sudo -E pytest -s --topology-only ospf_topo1/test_ospf_topo1.py
     ============================= test session starts ==============================
     platform linux -- Python 3.9.2, pytest-6.2.4, py-1.10.0, pluggy-0.13.1
     rootdir: /home/chopps/w/frr/tests/topotests, configfile: pytest.ini
@@ -983,22 +1019,20 @@ Writing Tests
 """""""""""""
 
 Test topologies should always be bootstrapped from
-:file:`tests/topotests/example-test/test_template.py` because it contains
+:file:`tests/topotests/example_test/test_template.py` because it contains
 important boilerplate code that can't be avoided, like:
 
 Example:
 
 .. code:: py
 
-   # For all registered routers, load the zebra configuration file
-   CWD = os.path.dirname(os.path.realpath(__file__))
-   for rname, router in router_list.items():
-       router.load_config(
-           TopoRouter.RD_ZEBRA,
-           os.path.join(CWD, '{}/zebra.conf'.format(rname))
-       )
-       # os.path.join() joins the CWD string with arguments adding the necessary
-       # slashes ('/'). Arguments must not begin with '/'.
+       # For all routers arrange for:
+       # - starting zebra using config file from <rtrname>/zebra.conf
+       # - starting ospfd using an empty config file.
+       for rname, router in router_list.items():
+           router.load_config(TopoRouter.RD_ZEBRA, "zebra.conf")
+           router.load_config(TopoRouter.RD_OSPF)
+
 
 - The topology definition or build function
 
@@ -1013,27 +1047,31 @@ Example:
        # topology build code
        ...
 
-- pytest ``setup_module()`` and ``teardown_module()`` to start the topology
+- pytest setup/teardown fixture to start the topology and supply ``tgen``
+  argument to tests.
 
 .. code:: py
 
-   def setup_module(module):
+
+   @pytest.fixture(scope="module")
+   def tgen(request):
+       "Setup/Teardown the environment and provide tgen argument to tests"
+
        tgen = Topogen(topodef, module.__name__)
        # or
        tgen = Topogen(build_topo, module.__name__)
 
-       tgen.start_topology('debug')
+       ...
 
-   def teardown_module(_m):
-       tgen = get_topogen()
-       tgen.stop_topology()
+       # Start and configure the router daemons
+       tgen.start_router()
 
-- ``__main__`` initialization code (to support running the script directly)
+       # Provide tgen as argument to each test function
+       yield tgen
 
-.. code:: py
+       # Teardown after last test runs
+       tgen.stop_topology()
 
-   if __name__ == '__main__':
-       sys.exit(pytest.main(["-s"]))
 
 Requirements:
 
index c703be62fccc821588e5fc32722612c9d35c2e71..2ce5f5d1c8c9cd7d4ec82af4e415da2eb6f14cad 100644 (file)
@@ -637,6 +637,39 @@ well as CERT or MISRA C guidelines may provide useful input on safe C code.
 However, these rules are not applied as-is;  some of them expressly collide
 with established practice.
 
+
+Container implementations
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+In particular to gain defensive coding benefits from better compiler type
+checks, there is a set of replacement container data structures to be found
+in :file:`lib/typesafe.h`.  They're documented under :ref:`lists`.
+
+Unfortunately, the FRR codebase is quite large, and migrating existing code to
+use these new structures is a tedious and far-reaching process (even if it
+can be automated with coccinelle, the patches would touch whole swaths of code
+and create tons of merge conflicts for ongoing work.)  Therefore, little
+existing code has been migrated.
+
+However, both **new code and refactors of existing code should use the new
+containers**.  If there are any reasons this can't be done, please work to
+remove these reasons (e.g. by adding necessary features to the new containers)
+rather than falling back to the old code.
+
+In order of likelyhood of removal, these are the old containers:
+
+- :file:`nhrpd/list.*`, ``hlist_*`` â‡’ ``DECLARE_LIST``
+- :file:`nhrpd/list.*`, ``list_*`` â‡’ ``DECLARE_DLIST``
+- :file:`lib/skiplist.*`, ``skiplist_*`` â‡’ ``DECLARE_SKIPLIST``
+- :file:`lib/*_queue.h` (BSD), ``SLIST_*`` â‡’ ``DECLARE_LIST``
+- :file:`lib/*_queue.h` (BSD), ``LIST_*`` â‡’ ``DECLARE_DLIST``
+- :file:`lib/*_queue.h` (BSD), ``STAILQ_*`` â‡’ ``DECLARE_LIST``
+- :file:`lib/*_queue.h` (BSD), ``TAILQ_*`` â‡’ ``DECLARE_DLIST``
+- :file:`lib/hash.*`, ``hash_*`` â‡’ ``DECLARE_HASH``
+- :file:`lib/linklist.*`, ``list_*`` â‡’ ``DECLARE_DLIST``
+- open-coded linked lists â‡’ ``DECLARE_LIST``/``DECLARE_DLIST``
+
+
 Code Formatting
 ---------------
 
index 5c9d96e32b09874501c05574084913fbeeaa8871..5fcddafaaad233436c541ff9fa015fcbedb30098 100644 (file)
@@ -2145,7 +2145,7 @@ Numbered Community Lists
 When number is used for BGP community list name, the number has
 special meanings. Community list number in the range from 1 and 99 is
 standard community list. Community list number in the range from 100
-to 199 is expanded community list. These community lists are called
+to 500 is expanded community list. These community lists are called
 as numbered community lists. On the other hand normal community lists
 is called as named community lists.
 
@@ -2154,10 +2154,10 @@ is called as named community lists.
    This command defines a new community list. The argument to (1-99) defines
    the list identifier.
 
-.. clicmd:: bgp community-list (100-199) permit|deny COMMUNITY
+.. clicmd:: bgp community-list (100-500) permit|deny COMMUNITY
 
    This command defines a new expanded community list. The argument to
-   (100-199) defines the list identifier.
+   (100-500) defines the list identifier.
 
 .. _bgp-community-alias:
 
@@ -3540,6 +3540,10 @@ structure is extended with :clicmd:`show bgp [afi] [safi]`.
    The ``received-routes`` keyword displays all routes belonging to this
    address-family (prior to inbound policy) that were received by this peer.
 
+.. clicmd:: show bgp [<view|vrf> VIEWVRFNAME] [afi] [safi] neighbors PEER received prefix-filter [json]
+
+   Display Address Prefix ORFs received from this peer.
+
 .. clicmd:: show bgp [afi] [safi] [all] dampening dampened-paths [wide|json]
 
    Display paths suppressed due to dampening of the selected afi and safi
index 66f8fd56789a71f0e678fb36d1151eb30f357a40..4a711a8febe680abde5d5712e9c95e55845d4656 100644 (file)
@@ -394,10 +394,6 @@ Known limitations:
    clear the Node flag that is set by default for Prefix-SIDs associated to
    loopback addresses. This option is necessary to configure Anycast-SIDs.
 
-.. clicmd:: show isis segment-routing prefix-sids
-
-   Show detailed information about all learned Segment Routing Prefix-SIDs.
-
 .. clicmd:: show isis segment-routing nodes
 
    Show detailed information about all learned Segment Routing Nodes.
index 4fd86ffb139e9f64224e524ee86e4a2699cd22c4..093c5382cfa07ecd514757546127efcde86c326e 100644 (file)
@@ -178,7 +178,7 @@ OSPF6 area
 
 .. clicmd:: area A.B.C.D nssa [no-summary]
 
-.. clicmd:: area (0-4294967295) nssa [no-summary]
+.. clicmd:: area (0-4294967295) nssa [no-summary] [default-information-originate [metric-type (1-2)] [metric (0-16777214)]]
 
    Configure the area to be a NSSA (Not-So-Stubby Area).
 
@@ -198,6 +198,53 @@ OSPF6 area
    advertisement of summaries into the area. In that case, a single Type-3 LSA
    containing a default route is originated into the NSSA.
 
+   NSSA ABRs and ASBRs can be configured with `default-information-originate`
+   option to originate a Type-7 default route into the NSSA area. In the case
+   of NSSA ASBRs, the origination of the default route is conditioned to the
+   existence of a default route in the RIB that wasn't learned via the OSPF
+   protocol.
+
+.. clicmd:: area A.B.C.D export-list NAME
+
+.. clicmd:: area (0-4294967295) export-list NAME
+
+   Filter Type-3 summary-LSAs announced to other areas originated from intra-
+   area paths from specified area.
+
+   .. code-block:: frr
+
+      router ospf6
+       area 0.0.0.10 export-list foo
+      !
+      ipv6 access-list foo permit 2001:db8:1000::/64
+      ipv6 access-list foo deny any
+
+   With example above any intra-area paths from area 0.0.0.10 and from range
+   2001:db8::/32 (for example 2001:db8:1::/64 and 2001:db8:2::/64) are announced
+   into other areas as Type-3 summary-LSA's, but any others (for example
+   2001:200::/48) aren't.
+
+   This command is only relevant if the router is an ABR for the specified
+   area.
+
+.. clicmd:: area A.B.C.D import-list NAME
+
+.. clicmd:: area (0-4294967295) import-list NAME
+
+   Same as export-list, but it applies to paths announced into specified area
+   as Type-3 summary-LSAs.
+
+.. clicmd:: area A.B.C.D filter-list prefix NAME in
+
+.. clicmd:: area A.B.C.D filter-list prefix NAME out
+
+.. clicmd:: area (0-4294967295) filter-list prefix NAME in
+
+.. clicmd:: area (0-4294967295) filter-list prefix NAME out
+
+   Filtering Type-3 summary-LSAs to/from area using prefix lists. This command
+   makes sense in ABR only.
+
 .. _ospf6-interface:
 
 OSPF6 interface
@@ -264,10 +311,19 @@ Redistribute routes to OSPF6
    argument injects the default route regardless of it being present in the
    router. Metric values and route-map can also be specified optionally.
 
-Graceful Restart Helper
-=======================
+Graceful Restart
+================
+
+.. clicmd:: graceful-restart [grace-period (1-1800)]
+
 
-.. clicmd:: graceful-restart helper-only [A.B.C.D]
+   Configure Graceful Restart (RFC 5187) restarting support.
+   When enabled, the default grace period is 120 seconds.
+
+   To perform a graceful shutdown, the "graceful-restart prepare ipv6 ospf"
+   EXEC-level command needs to be issued before restarting the ospf6d daemon.
+
+.. clicmd:: graceful-restart helper enable [A.B.C.D]
 
 
    Configure Graceful Restart (RFC 5187) helper support.
@@ -297,6 +353,16 @@ Graceful Restart Helper
    restarts. By default, it supports both planned and
    unplanned outages.
 
+.. clicmd:: graceful-restart prepare ipv6 ospf
+
+
+   Initiate a graceful restart for all OSPFv3 instances configured with the
+   "graceful-restart" command. The ospf6d daemon should be restarted during
+   the instance-specific grace period, otherwise the graceful restart will fail.
+
+   This is an EXEC-level command.
+
+
 .. _showing-ospf6-information:
 
 Showing OSPF6 information
@@ -410,9 +476,10 @@ The following debug commands are supported:
 
    Toggle OSPFv3 ASBR debugging messages.
 
-.. clicmd:: debug ospf6 border-routers
+.. clicmd:: debug ospf6 border-routers {router-id [A.B.C.D] | area-id [A.B.C.D]}
 
-   Toggle OSPFv3 border router debugging messages.
+   Toggle OSPFv3 border router debugging messages. This can be specified for a
+   router with specific Router-ID/Area-ID.
 
 .. clicmd:: debug ospf6 flooding
 
index e8ca3947276cc9c0460e1246cb4ef14169e4e5e7..26675c27fd6251a721f2a034705e86a9795cf312 100644 (file)
@@ -691,13 +691,12 @@ Redistribution
    the 'always' keyword is given then the default is always advertised, even
    when there is no default present in the routing table.
 
-.. clicmd:: distribute-list NAME out (kernel|connected|static|rip|ospf
-
-
 .. _ospf-distribute-list:
 
+.. clicmd:: distribute-list NAME out <kernel|connected|static|rip|isis|bgp|eigrp|nhrp|table|vnc|babel|openfabric>
+
    Apply the access-list filter, NAME, to redistributed routes of the given
-   type before allowing the routes to redistributed into OSPF
+   type before allowing the routes to be redistributed into OSPF
    (:ref:`ospf redistribution <ospf-redistribute>`).
 
 .. clicmd:: default-metric (0-16777214)
@@ -722,7 +721,7 @@ Graceful Restart
    To perform a graceful shutdown, the "graceful-restart prepare ip ospf"
    EXEC-level command needs to be issued before restarting the ospfd daemon.
 
-.. clicmd:: graceful-restart helper-only [A.B.C.D]
+.. clicmd:: graceful-restart helper enable [A.B.C.D]
 
 
    Configure Graceful Restart (RFC 3623) helper support.
@@ -954,8 +953,6 @@ Router Information
 
    Show Router Capabilities PCE parameters.
 
-.. _debugging-ospf:
-
 Segment Routing
 ===============
 
@@ -1042,6 +1039,8 @@ TI-LFA requires a proper Segment Routing configuration.
 
    Note that so far only P2P interfaces are supported.
 
+.. _debugging-ospf:
+
 Debugging OSPF
 ==============
 
index 2714b81dbedf73038f9b22953090766bef4bad40..e1fe4bbbdba3b6a98149d5bc0aa98a292d370ccb 100644 (file)
@@ -279,6 +279,10 @@ Route Map Set Command
 
    Set the BGP AS path to prepend.
 
+.. clicmd:: set as-path exclude AS-NUMBER...
+
+   Drop AS-NUMBER from the BGP AS path.
+
 .. clicmd:: set community COMMUNITY
 
    Set the BGP community attribute.
index 64a33765c2650d1d220900ba899aaf92facc077d..dbbfca21e7f42e1b97e103c9760faf11ef89674a 100644 (file)
@@ -176,6 +176,27 @@ Operations
 
 This section covers a few common operational tasks and how to perform them.
 
+Interactive Shell
+^^^^^^^^^^^^^^^^^
+FRR offers an IOS-like interactive shell called ``vtysh`` where a user can run
+individual configuration or show commands. To get into this shell, issue the
+``vtysh`` command from either a privilege user (root, or with sudo) or a user
+account that is part of the ``frrvty`` group.
+e.g.
+
+.. code-block:: console
+
+   root@ub18:~# vtysh
+
+   Hello, this is FRRouting (version 8.1-dev).
+   Copyright 1996-2005 Kunihiro Ishiguro, et al.
+
+   ub18#
+
+.. note::
+   The default install location for vtysh is /usr/bin/vtysh
+
+
 Restarting
 ^^^^^^^^^^
 
index 1ab4dcce255d1ae2c4ced0822ca7860a232c63fb..5eb97ff06d309644ab9ad2e5a2b9791fdd6703bb 100644 (file)
@@ -1256,36 +1256,103 @@ For protocols requiring an IPv6 router-id, the following commands are available:
 
 .. _zebra-sysctl:
 
-Expected sysctl settings
-========================
+sysctl settings
+===============
 
 The linux kernel has a variety of sysctl's that affect it's operation as a router.  This
 section is meant to act as a starting point for those sysctl's that must be used in
 order to provide FRR with smooth operation as a router.  This section is not meant
 as the full documentation for sysctl's.  The operator must use the sysctl documentation
-with the linux kernel for that.
+with the linux kernel for that. The following link has helpful references to many relevant
+sysctl values:  https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt
+
+Expected sysctl settings
+------------------------
 
 .. option:: net.ipv4.ip_forward = 1
 
-   This option allows the linux kernel to forward ipv4 packets incoming from one interface
-   to an outgoing interface.  Without this no forwarding will take place from off box packets.
+   This global option allows the linux kernel to forward (route) ipv4 packets incoming from one
+   interface to an outgoing interface. If this is set to 0, the system will not route transit
+   ipv4 packets, i.e. packets that are not sent to/from a process running on the local system.
 
-.. option:: net.ipv6.conf.all_forwarding=1
+.. option:: net.ipv4.conf.{all,default,<interface>}.forwarding = 1
 
-   This option allows the linux kernel to forward ipv6 packets incoming from one interface
-   to an outgoing interface.  Without this no forwarding will take place from off box packets.
+   The linux kernel can selectively enable forwarding (routing) of ipv4 packets on a per
+   interface basis. The forwarding check in the kernel dataplane occurs against the ingress
+   Layer 3 interface, i.e. if the ingress L3 interface has forwarding set to 0, packets will not
+   be routed.
 
-.. option:: net.ipv6.conf.all.keep_addr_on_down=1
+.. option:: net.ipv6.conf.{all,default,<interface>}.forwarding = 1
+
+   This per interface option allows the linux kernel to forward (route) transit ipv6 packets
+   i.e. incoming from one Layer 3 interface to an outgoing Layer 3 interface.
+   The forwarding check in the kernel dataplane occurs against the ingress Layer 3 interface,
+   i.e. if the ingress L3 interface has forwarding set to 0, packets will not be routed.
+
+.. option:: net.ipv6.conf.all.keep_addr_on_down = 1
 
    When an interface is taken down, do not remove the v6 addresses associated with the interface.
    This option is recommended because this is the default behavior for v4 as well.
 
-.. option:: net.ipv6.route.skip_notify_on_dev_down=1
+.. option:: net.ipv6.route.skip_notify_on_dev_down = 1
 
    When an interface is taken down, the linux kernel will not notify, via netlink, about routes
    that used that interface being removed from the FIB.  This option is recommended because this
    is the default behavior for v4 as well.
 
+Optional sysctl settings
+------------------------
+
+.. option:: net.ipv4.conf.{all,default,<interface>}.bc_forwarding = 0
+
+   This per interface option allows the linux kernel to optionally allow Directed Broadcast
+   (i.e. Routed Broadcast or Subnet Broadcast) packets to be routed onto the connected network
+   segment where the subnet exists.
+   If the local router receives a routed packet destined for a broadcast address of a connected
+   subnet, setting bc_forwarding to 1 on the interface with the target subnet assigned to it will
+   allow non locally-generated packets to be routed via the broadcast route.
+   If bc_forwarding is set to 0, routed packets destined for a broadcast route will be dropped.
+   e.g.
+   Host1 (SIP:192.0.2.10, DIP:10.0.0.255) -> (eth0:192.0.2.1/24) Router1 (eth1:10.0.0.1/24) -> BC
+   If net.ipv4.conf.{all,default,<interface>}.bc_forwarding=1, then Router1 will forward each
+   packet destined to 10.0.0.255 onto the eth1 interface with a broadcast DMAC (ff:ff:ff:ff:ff:ff).
+
+.. option:: net.ipv4.conf.{all,default,<interface>}.arp_accept = 1
+
+   This per interface option allows the linux kernel to optionally skip the creation of ARP
+   entries upon the receipt of a Gratuitous ARP (GARP) frame carrying an IP that is not already
+   present in the ARP cache. Setting arp_accept to 0 on an interface will ensure NEW ARP entries
+   are not created due to the arrival of a GARP frame.
+   Note: This does not impact how the kernel reacts to GARP frames that carry a "known" IP
+   (that is already in the ARP cache) -- an existing ARP entry will always be updated
+   when a GARP for that IP is received.
+
+.. option:: net.ipv4.conf.{all,default,<interface>}.arp_ignore = 0
+
+   This per interface option allows the linux kernel to control what conditions must be met in
+   order for an ARP reply to be sent in response to an ARP request targeting a local IP address.
+   When arp_ignore is set to 0, the kernel will send ARP replies in response to any ARP Request
+   with a Target-IP matching a local address.
+   When arp_ignore is set to 1, the kernel will send ARP replies if the Target-IP in the ARP
+   Request matches an IP address on the interface the Request arrived at.
+   When arp_ignore is set to 2, the kernel will send ARP replies only if the Target-IP matches an
+   IP address on the interface where the Request arrived AND the Sender-IP falls within the subnet
+   assigned to the local IP/interface.
+
+.. option:: net.ipv4.conf.{all,default,<interface>}.arp_notify = 1
+
+   This per interface option allows the linux kernel to decide whether to send a Gratuitious ARP
+   (GARP) frame when the Layer 3 interface comes UP.
+   When arp_notify is set to 0, no GARP is sent.
+   When arp_notify is set to 1, a GARP is sent when the interface comes UP.
+
+.. option:: net.ipv6.conf.{all,default,<interface>}.ndisc_notify = 1
+
+   This per interface option allows the linux kernel to decide whether to send an Unsolicited
+   Neighbor Advertisement (U-NA) frame when the Layer 3 interface comes UP.
+   When ndisc_notify is set to 0, no U-NA is sent.
+   When ndisc_notify is set to 1, a U-NA is sent when the interface comes UP.
+
 Debugging
 =========
 
index 032db8b8ed36f44a63f5212c585788e094ef87b3..b9fe385c3a9eb8b0fc90658a46d14d56f101c7a5 100644 (file)
@@ -11,7 +11,6 @@ RUN apt update && \
       install-info build-essential libsnmp-dev perl \
       libcap-dev python2 libelf-dev \
       sudo gdb curl iputils-ping time \
-      libgrpc++-dev libgrpc-dev protobuf-compiler-grpc \
       lua5.3 liblua5.3-dev \
       net-tools iproute2 && \
       curl https://bootstrap.pypa.io/pip/2.7/get-pip.py --output /tmp/get-pip.py && \
@@ -61,7 +60,6 @@ RUN cd ~/frr && \
        --sbindir=/usr/lib/frr \
        --sysconfdir=/etc/frr \
        --enable-vtysh \
-       --enable-grpc \
        --enable-pimd \
        --enable-sharpd \
        --enable-multipath=64 \
index 8f80b78d200ffb0975c3e7a27324b1ac7a97e34a..bb0cf51bd8f32ac473b5ce71cf64ccc9a7a9dc7d 100644 (file)
@@ -203,9 +203,8 @@ void eigrp_distribute_update(struct distribute_ctx *ctx,
        /* Cancel GR scheduled */
        thread_cancel(&(ei->t_distribute));
        /* schedule Graceful restart for interface in 10sec */
-       e->t_distribute = NULL;
        thread_add_timer(master, eigrp_distribute_timer_interface, ei, 10,
-                        &e->t_distribute);
+                        &ei->t_distribute);
 }
 
 /*
@@ -263,7 +262,6 @@ int eigrp_distribute_timer_process(struct thread *thread)
        struct eigrp *eigrp;
 
        eigrp = THREAD_ARG(thread);
-       eigrp->t_distribute = NULL;
 
        /* execute GR for whole process */
        eigrp_update_send_process_GR(eigrp, EIGRP_GR_FILTER, NULL);
index e3680b31a33ffd745abd935b29eb2c4b05a49ac0..2ff8fc5f39f1215ec68090c6861a68088fcbb07f 100644 (file)
@@ -86,7 +86,6 @@ int eigrp_hello_timer(struct thread *thread)
        struct eigrp_interface *ei;
 
        ei = THREAD_ARG(thread);
-       ei->t_hello = NULL;
 
        if (IS_DEBUG_EIGRP(0, TIMERS))
                zlog_debug("Start Hello Timer (%s) Expire [%u]", IF_NAME(ei),
@@ -96,7 +95,6 @@ int eigrp_hello_timer(struct thread *thread)
        eigrp_hello_send(ei, EIGRP_HELLO_NORMAL, NULL);
 
        /* Hello timer set. */
-       ei->t_hello = NULL;
        thread_add_timer(master, eigrp_hello_timer, ei, ei->params.v_hello,
                         &ei->t_hello);
 
index 02e943043f19e028825ba7867a3b55678e4702f0..28987b4af65e303f0c303afedf35e1e16a0b188f 100644 (file)
@@ -265,7 +265,7 @@ int eigrp_if_up(struct eigrp_interface *ei)
        /* Set multicast memberships appropriately for new state. */
        eigrp_if_set_multicast(ei);
 
-       thread_add_event(master, eigrp_hello_timer, ei, (1), NULL);
+       thread_add_event(master, eigrp_hello_timer, ei, (1), &ei->t_hello);
 
        /*Prepare metrics*/
        metric.bandwidth = eigrp_bandwidth_to_scaled(ei->params.bandwidth);
index 482667f633c214effffed11e30b9b4cc6d382e40..3ad711164b4de3ffb445a6849b7aa02b50e2860a 100644 (file)
@@ -79,6 +79,7 @@ static int eigrpd_instance_create(struct nb_cb_create_args *args)
 {
        struct eigrp *eigrp;
        const char *vrf;
+       struct vrf *pVrf;
        vrf_id_t vrfid;
 
        switch (args->event) {
@@ -87,7 +88,12 @@ static int eigrpd_instance_create(struct nb_cb_create_args *args)
                break;
        case NB_EV_PREPARE:
                vrf = yang_dnode_get_string(args->dnode, "./vrf");
-               vrfid = vrf_name_to_id(vrf);
+
+               pVrf = vrf_lookup_by_name(vrf);
+               if (pVrf)
+                       vrfid = pVrf->vrf_id;
+               else
+                       vrfid = VRF_DEFAULT;
 
                eigrp = eigrp_get(yang_dnode_get_uint16(args->dnode, "./asn"),
                                  vrfid);
@@ -719,12 +725,19 @@ static int eigrpd_instance_redistribute_create(struct nb_cb_create_args *args)
        struct eigrp *eigrp;
        uint32_t proto;
        vrf_id_t vrfid;
+       struct vrf *pVrf;
 
        switch (args->event) {
        case NB_EV_VALIDATE:
                proto = yang_dnode_get_enum(args->dnode, "./protocol");
                vrfname = yang_dnode_get_string(args->dnode, "../vrf");
-               vrfid = vrf_name_to_id(vrfname);
+
+               pVrf = vrf_lookup_by_name(vrfname);
+               if (pVrf)
+                       vrfid = pVrf->vrf_id;
+               else
+                       vrfid = VRF_DEFAULT;
+
                if (vrf_bitmap_check(zclient->redist[AFI_IP][proto], vrfid))
                        return NB_ERR_INCONSISTENCY;
                break;
index 39e384c121f56c82fc0cfdb25d23fb4a669ac4e3..529d94567de973212f130455473c5bd0cdebc772 100644 (file)
@@ -340,8 +340,6 @@ int eigrp_write(struct thread *thread)
 #endif /* WANT_EIGRP_WRITE_FRAGMENT */
 #define EIGRP_WRITE_IPHL_SHIFT 2
 
-       eigrp->t_write = NULL;
-
        node = listhead(eigrp->oi_write_q);
        assert(node);
        ei = listgetdata(node);
@@ -470,7 +468,6 @@ out:
 
        /* If packets still remain in queue, call write thread. */
        if (!list_isempty(eigrp->oi_write_q)) {
-               eigrp->t_write = NULL;
                thread_add_write(master, eigrp_write, eigrp, eigrp->fd,
                                 &eigrp->t_write);
        }
@@ -497,7 +494,6 @@ int eigrp_read(struct thread *thread)
        eigrp = THREAD_ARG(thread);
 
        /* prepare for next packet. */
-       eigrp->t_read = NULL;
        thread_add_read(master, eigrp_read, eigrp, eigrp->fd, &eigrp->t_read);
 
        stream_reset(eigrp->ibuf);
@@ -1013,7 +1009,6 @@ int eigrp_unack_packet_retrans(struct thread *thread)
                        return eigrp_retrans_count_exceeded(ep, nbr);
 
                /*Start retransmission timer*/
-               ep->t_retrans_timer = NULL;
                thread_add_timer(master, eigrp_unack_packet_retrans, nbr,
                                 EIGRP_PACKET_RETRANS_TIME,
                                 &ep->t_retrans_timer);
@@ -1049,7 +1044,6 @@ int eigrp_unack_multicast_packet_retrans(struct thread *thread)
                        return eigrp_retrans_count_exceeded(ep, nbr);
 
                /*Start retransmission timer*/
-               ep->t_retrans_timer = NULL;
                thread_add_timer(master, eigrp_unack_multicast_packet_retrans,
                                 nbr, EIGRP_PACKET_RETRANS_TIME,
                                 &ep->t_retrans_timer);
index 0dc509706c91e0af15dd8f5ee3f59945ed10fb5d..8a9eea8a794ddce16fad8401e4ce488480affc06 100644 (file)
@@ -917,12 +917,10 @@ int eigrp_update_send_GR_thread(struct thread *thread)
        /* get argument from thread */
        nbr = THREAD_ARG(thread);
        /* remove this thread pointer */
-       nbr->t_nbr_send_gr = NULL;
 
        /* if there is packet waiting in queue,
         * schedule this thread again with small delay */
        if (nbr->retrans_queue->count > 0) {
-               nbr->t_nbr_send_gr = NULL;
                thread_add_timer_msec(master, eigrp_update_send_GR_thread, nbr,
                                      10, &nbr->t_nbr_send_gr);
                return 0;
@@ -934,7 +932,6 @@ int eigrp_update_send_GR_thread(struct thread *thread)
        /* if it wasn't last chunk, schedule this thread again */
        if (nbr->nbr_gr_packet_type != EIGRP_PACKET_PART_LAST) {
                thread_execute(master, eigrp_update_send_GR_thread, nbr, 0);
-               nbr->t_nbr_send_gr = NULL;
        }
 
        return 0;
@@ -1003,7 +1000,6 @@ void eigrp_update_send_GR(struct eigrp_neighbor *nbr, enum GR_type gr_type,
        nbr->nbr_gr_packet_type = EIGRP_PACKET_PART_FIRST;
        /* execute packet sending in thread */
        thread_execute(master, eigrp_update_send_GR_thread, nbr, 0);
-       nbr->t_nbr_send_gr = NULL;
 }
 
 /**
index 103015490783a2fd548e0e20485f59681888f467..84d4f6aeeb01eb8bf5a8a191864cd7e04fb8e0f0 100644 (file)
@@ -171,7 +171,6 @@ static struct eigrp *eigrp_new(uint16_t as, vrf_id_t vrf_id)
 
        eigrp->ibuf = stream_new(EIGRP_PACKET_MAX_LEN + 1);
 
-       eigrp->t_read = NULL;
        thread_add_read(master, eigrp_read, eigrp, eigrp->fd, &eigrp->t_read);
        eigrp->oi_write_q = list_new();
 
index 20651706d394931f33fd6ef9b40d122f750721a4..0f10a1516a1528afa4763ef2b8b3f6d8f42d90cd 100644 (file)
@@ -413,7 +413,6 @@ static int fabricd_tier_calculation_cb(struct thread *thread)
 {
        struct fabricd *f = THREAD_ARG(thread);
        uint8_t tier = ISIS_TIER_UNDEFINED;
-       f->tier_calculation_timer = NULL;
 
        tier = fabricd_calculate_fabric_tier(f->area);
        if (tier == ISIS_TIER_UNDEFINED)
index 70ec66fd7feb661a629d4d3cfd6f82ec46158fed..f48b142b1a2fbf60ca86e34e5b219d267038f1b5 100644 (file)
@@ -1330,11 +1330,14 @@ void cli_show_isis_def_origin_ipv6(struct vty *vty, struct lyd_node *dnode,
  * XPath: /frr-isisd:isis/instance/redistribute
  */
 DEFPY_YANG(isis_redistribute, isis_redistribute_cmd,
-      "[no] redistribute <ipv4|ipv6>$ip " PROTO_REDIST_STR
-      "$proto <level-1|level-2>$level [{metric (0-16777215)|route-map WORD}]",
+      "[no] redistribute <ipv4$ip " PROTO_IP_REDIST_STR "$proto|ipv6$ip "
+      PROTO_IP6_REDIST_STR "$proto> <level-1|level-2>$level"
+      "[{metric (0-16777215)|route-map WORD}]",
       NO_STR REDIST_STR
       "Redistribute IPv4 routes\n"
-      "Redistribute IPv6 routes\n" PROTO_REDIST_HELP
+      PROTO_IP_REDIST_HELP
+      "Redistribute IPv6 routes\n"
+      PROTO_IP6_REDIST_HELP
       "Redistribute into level-1\n"
       "Redistribute into level-2\n"
       "Metric for redistributed routes\n"
index 2f5e490da1b57abb494287e7eda357e1873a9dcb..45d69bc352df9645ff79ebf2dd59c19c1db7c94f 100644 (file)
@@ -543,12 +543,13 @@ void isis_redist_area_finish(struct isis_area *area)
 #ifdef FABRICD
 DEFUN (isis_redistribute,
        isis_redistribute_cmd,
-       "redistribute <ipv4|ipv6> " PROTO_REDIST_STR
+       "redistribute <ipv4 " PROTO_IP_REDIST_STR "|ipv6 " PROTO_IP6_REDIST_STR ">"
        " [{metric (0-16777215)|route-map WORD}]",
        REDIST_STR
        "Redistribute IPv4 routes\n"
+       PROTO_IP_REDIST_HELP
        "Redistribute IPv6 routes\n"
-       PROTO_REDIST_HELP
+       PROTO_IP6_REDIST_HELP
        "Metric for redistributed routes\n"
        "ISIS default metric\n"
        "Route map reference\n"
@@ -599,12 +600,13 @@ DEFUN (isis_redistribute,
 
 DEFUN (no_isis_redistribute,
        no_isis_redistribute_cmd,
-       "no redistribute <ipv4|ipv6> " PROTO_REDIST_STR,
+       "no redistribute <ipv4 " PROTO_IP_REDIST_STR "|ipv6 " PROTO_IP6_REDIST_STR ">",
        NO_STR
        REDIST_STR
        "Redistribute IPv4 routes\n"
+       PROTO_IP_REDIST_HELP
        "Redistribute IPv6 routes\n"
-       PROTO_REDIST_HELP)
+       PROTO_IP6_REDIST_HELP)
 {
        int idx_afi = 2;
        int idx_protocol = 3;
index d530faa151856aeb4214da66652a4da1ddc5f1df..c530eb9169061a6c7528b575be29dbe15f381a3e 100644 (file)
@@ -283,13 +283,6 @@ SNMP_LOCAL_VARIABLES
  *
  * 2. I could be replaced in unit test environment
  */
-#ifndef ISIS_SNMP_HAVE_TIME_FUNC
-static uint32_t isis_snmp_time(void)
-{
-       return (uint32_t)time(NULL);
-}
-
-#endif
 
 /* ISIS-MIB instances. */
 static oid isis_oid[] = {ISIS_MIB};
@@ -2083,7 +2076,7 @@ static uint8_t *isis_snmp_find_circ(struct variable *v, oid *name,
        struct isis_circuit *circuit;
        uint32_t up_ticks;
        uint32_t delta_ticks;
-       uint32_t now_time;
+       time_t now_time;
        int res;
 
        *write_method = NULL;
@@ -2191,7 +2184,7 @@ static uint8_t *isis_snmp_find_circ(struct variable *v, oid *name,
                        return SNMP_INTEGER(0);
 
                up_ticks = (uint32_t)netsnmp_get_agent_uptime();
-               now_time = isis_snmp_time();
+               now_time = time(NULL);
 
                if (circuit->last_uptime >= now_time)
                        return SNMP_INTEGER(up_ticks);
@@ -2501,11 +2494,11 @@ static uint8_t *isis_snmp_find_isadj(struct variable *v, oid *name,
        oid *oid_idx;
        size_t oid_idx_len;
        int res;
-       uint32_t val;
+       time_t val;
        struct isis_adjacency *adj;
        uint32_t up_ticks;
        uint32_t delta_ticks;
-       uint32_t now_time;
+       time_t now_time;
 
        *write_method = NULL;
 
@@ -2577,7 +2570,7 @@ static uint8_t *isis_snmp_find_isadj(struct variable *v, oid *name,
                 * It seems that we want remaining timer
                 */
                if (adj->last_upd != 0) {
-                       val = isis_snmp_time();
+                       val = time(NULL);
                        if (val < (adj->last_upd + adj->hold_time))
                                return SNMP_INTEGER(adj->last_upd
                                                    + adj->hold_time - val);
@@ -2594,7 +2587,7 @@ static uint8_t *isis_snmp_find_isadj(struct variable *v, oid *name,
 
                up_ticks = (uint32_t)netsnmp_get_agent_uptime();
 
-               now_time = isis_snmp_time();
+               now_time = time(NULL);
 
                if (adj->last_flap >= now_time)
                        return SNMP_INTEGER(up_ticks);
@@ -2853,7 +2846,7 @@ static int isis_snmp_trap_throttle(oid trap_id)
        if (isis == NULL || !isis->snmp_notifications || !smux_enabled())
                return 0;
 
-       time_now = isis_snmp_time();
+       time_now = time(NULL);
 
        if ((isis_snmp_trap_timestamp[trap_id] + 5) > time_now)
                /* Throttle trap rate at 1 in 5 secs */
index c7266152b70697055cf0b2f9263b715e92c46f9c..d3da5b9d39aba480cf7f24a522db253262a493eb 100644 (file)
@@ -119,7 +119,6 @@ static int tx_queue_send_event(struct thread *thread)
        struct isis_tx_queue_entry *e = THREAD_ARG(thread);
        struct isis_tx_queue *queue = e->queue;
 
-       e->retry = NULL;
        thread_add_timer(master, tx_queue_send_event, e, 5, &e->retry);
 
        if (e->is_retry)
index 64fbf78a07377a51e73c7642b042c0fe9d2727d0..3febda1d8724577af1cda733dcd13fd32d937a5e 100644 (file)
@@ -46,7 +46,11 @@ static const bool fabricd = true;
 #define PROTO_NAME "openfabric"
 #define PROTO_HELP "OpenFabric routing protocol\n"
 #define PROTO_REDIST_STR FRR_REDIST_STR_FABRICD
+#define PROTO_IP_REDIST_STR FRR_IP_REDIST_STR_FABRICD
+#define PROTO_IP6_REDIST_STR FRR_IP6_REDIST_STR_FABRICD
 #define PROTO_REDIST_HELP FRR_REDIST_HELP_STR_FABRICD
+#define PROTO_IP_REDIST_HELP FRR_IP_REDIST_HELP_STR_FABRICD
+#define PROTO_IP6_REDIST_HELP FRR_IP6_REDIST_HELP_STR_FABRICD
 #define ROUTER_NODE OPENFABRIC_NODE
 #else
 static const bool fabricd = false;
@@ -54,7 +58,11 @@ static const bool fabricd = false;
 #define PROTO_NAME "isis"
 #define PROTO_HELP "IS-IS routing protocol\n"
 #define PROTO_REDIST_STR FRR_REDIST_STR_ISISD
+#define PROTO_IP_REDIST_STR FRR_IP_REDIST_STR_ISISD
+#define PROTO_IP6_REDIST_STR FRR_IP6_REDIST_STR_ISISD
 #define PROTO_REDIST_HELP FRR_REDIST_HELP_STR_ISISD
+#define PROTO_IP_REDIST_HELP FRR_IP_REDIST_HELP_STR_ISISD
+#define PROTO_IP6_REDIST_HELP FRR_IP6_REDIST_HELP_STR_ISISD
 #define ROUTER_NODE ISIS_NODE
 extern void isis_cli_init(void);
 #endif
@@ -248,7 +256,6 @@ void isis_terminate(void);
 void isis_master_init(struct thread_master *master);
 void isis_vrf_link(struct isis *isis, struct vrf *vrf);
 void isis_vrf_unlink(struct isis *isis, struct vrf *vrf);
-void isis_global_instance_create(const char *vrf_name);
 struct isis *isis_lookup_by_vrfid(vrf_id_t vrf_id);
 struct isis *isis_lookup_by_vrfname(const char *vrfname);
 struct isis *isis_lookup_by_sysid(const uint8_t *sysid);
index 9bba0f5ddd134e217c65adcca8947a86a6d14e80..e8d3976ee9af197f9c003cd2c3232c135d41f998 100644 (file)
@@ -58,7 +58,6 @@ accept_add(int fd, int (*cb)(struct thread *), void *arg)
        av->arg = arg;
        LIST_INSERT_HEAD(&accept_queue.queue, av, entry);
 
-       av->ev = NULL;
        thread_add_read(master, accept_cb, av, av->fd, &av->ev);
 
        log_debug("%s: accepting on fd %d", __func__, fd);
@@ -86,7 +85,6 @@ accept_pause(void)
 {
        log_debug(__func__);
        accept_unarm();
-       accept_queue.evt = NULL;
        thread_add_timer(master, accept_timeout, NULL, 1, &accept_queue.evt);
 }
 
@@ -105,7 +103,6 @@ accept_arm(void)
 {
        struct accept_ev        *av;
        LIST_FOREACH(av, &accept_queue.queue, entry) {
-               av->ev = NULL;
                thread_add_read(master, accept_cb, av, av->fd, &av->ev);
        }
 }
@@ -122,7 +119,6 @@ static int
 accept_cb(struct thread *thread)
 {
        struct accept_ev        *av = THREAD_ARG(thread);
-       av->ev = NULL;
        thread_add_read(master, accept_cb, av, av->fd, &av->ev);
        av->accept_cb(thread);
 
index 3e9f2fa991b095a3806a5715b3f7854df5c5cf6c..5e04eab1b3545fda27f5d9e2d5dd0bbfe690a9b9 100644 (file)
@@ -471,7 +471,6 @@ static void
 if_start_hello_timer(struct iface_af *ia)
 {
        thread_cancel(&ia->hello_timer);
-       ia->hello_timer = NULL;
        thread_add_timer(master, if_hello_timer, ia, if_get_hello_interval(ia),
                         &ia->hello_timer);
 }
index 2d35d097a1cdf57158daea4ff4c5105864afaf69..babadc461fad2c76fffcde90fada2aba3469aba5 100644 (file)
@@ -145,7 +145,6 @@ lde(void)
                fatal(NULL);
        imsg_init(&iev_main->ibuf, LDPD_FD_ASYNC);
        iev_main->handler_read = lde_dispatch_parent;
-       iev_main->ev_read = NULL;
        thread_add_read(master, iev_main->handler_read, iev_main, iev_main->ibuf.fd,
                        &iev_main->ev_read);
        iev_main->handler_write = ldp_write_handler;
@@ -555,7 +554,6 @@ lde_dispatch_parent(struct thread *thread)
                                fatal(NULL);
                        imsg_init(&iev_ldpe->ibuf, fd);
                        iev_ldpe->handler_read = lde_dispatch_imsg;
-                       iev_ldpe->ev_read = NULL;
                        thread_add_read(master, iev_ldpe->handler_read, iev_ldpe, iev_ldpe->ibuf.fd,
                                        &iev_ldpe->ev_read);
                        iev_ldpe->handler_write = ldp_write_handler;
index 0f91f49920ad7d274130c4219e67441e9a525140..33bb6c0fc73b23af94bcf3b007a2522da5a3fdd2 100644 (file)
@@ -1072,7 +1072,6 @@ void
 lde_gc_start_timer(void)
 {
        thread_cancel(&gc_timer);
-       gc_timer = NULL;
        thread_add_timer(master, lde_gc_timer, NULL, LDE_GC_INTERVAL,
                         &gc_timer);
 }
index 000d1a33019202b656bc667ba789e6322798fc1d..9d80bed77f8122432353ec8557c44d8f03c83d23 100644 (file)
@@ -94,10 +94,9 @@ static void ldp_load_module(const char *name)
 {
        const char *dir;
        dir = ldpd_di.module_path ? ldpd_di.module_path : frr_moduledir;
-       char moderr[256];
        struct frrmod_runtime *module;
 
-       module = frrmod_load(name, dir, moderr, sizeof(moderr));
+       module = frrmod_load(name, dir, NULL,NULL);
        if (!module) {
                fprintf(stderr, "%s: failed to load %s", __func__, name);
                log_warnx("%s: failed to load %s", __func__, name);
@@ -404,28 +403,24 @@ main(int argc, char *argv[])
                fatal(NULL);
        imsg_init(&iev_ldpe->ibuf, pipe_parent2ldpe[0]);
        iev_ldpe->handler_read = main_dispatch_ldpe;
-       iev_ldpe->ev_read = NULL;
        thread_add_read(master, iev_ldpe->handler_read, iev_ldpe, iev_ldpe->ibuf.fd,
                        &iev_ldpe->ev_read);
        iev_ldpe->handler_write = ldp_write_handler;
 
        imsg_init(&iev_ldpe_sync->ibuf, pipe_parent2ldpe_sync[0]);
        iev_ldpe_sync->handler_read = main_dispatch_ldpe;
-       iev_ldpe_sync->ev_read = NULL;
        thread_add_read(master, iev_ldpe_sync->handler_read, iev_ldpe_sync, iev_ldpe_sync->ibuf.fd,
                        &iev_ldpe_sync->ev_read);
        iev_ldpe_sync->handler_write = ldp_write_handler;
 
        imsg_init(&iev_lde->ibuf, pipe_parent2lde[0]);
        iev_lde->handler_read = main_dispatch_lde;
-       iev_lde->ev_read = NULL;
        thread_add_read(master, iev_lde->handler_read, iev_lde, iev_lde->ibuf.fd,
                        &iev_lde->ev_read);
        iev_lde->handler_write = ldp_write_handler;
 
        imsg_init(&iev_lde_sync->ibuf, pipe_parent2lde_sync[0]);
        iev_lde_sync->handler_read = main_dispatch_lde;
-       iev_lde_sync->ev_read = NULL;
        thread_add_read(master, iev_lde_sync->handler_read, iev_lde_sync, iev_lde_sync->ibuf.fd,
                        &iev_lde_sync->ev_read);
        iev_lde_sync->handler_write = ldp_write_handler;
index 428d2ab7b49a7fc4d766df6834fd9268311328fe..fff7ee7c67d648c4f46a4740540baef1b66b120c 100644 (file)
@@ -122,7 +122,6 @@ ldpe(void)
                fatal(NULL);
        imsg_init(&iev_main->ibuf, LDPD_FD_ASYNC);
        iev_main->handler_read = ldpe_dispatch_main;
-       iev_main->ev_read = NULL;
        thread_add_read(master, iev_main->handler_read, iev_main, iev_main->ibuf.fd,
                        &iev_main->ev_read);
        iev_main->handler_write = ldp_write_handler;
@@ -149,7 +148,6 @@ ldpe_init(struct ldpd_init *init)
        /* This socket must be open before dropping privileges. */
        global.pfkeysock = pfkey_init();
        if (sysdep.no_pfkey == 0) {
-               pfkey_ev = NULL;
                thread_add_read(master, ldpe_dispatch_pfkey, NULL, global.pfkeysock,
                                &pfkey_ev);
        }
@@ -377,7 +375,6 @@ ldpe_dispatch_main(struct thread *thread)
                                fatal(NULL);
                        imsg_init(&iev_lde->ibuf, fd);
                        iev_lde->handler_read = ldpe_dispatch_lde;
-                       iev_lde->ev_read = NULL;
                        thread_add_read(master, iev_lde->handler_read, iev_lde, iev_lde->ibuf.fd,
                                        &iev_lde->ev_read);
                        iev_lde->handler_write = ldp_write_handler;
@@ -784,7 +781,6 @@ ldpe_dispatch_pfkey(struct thread *thread)
 {
        int      fd = THREAD_FD(thread);
 
-       pfkey_ev = NULL;
        thread_add_read(master, ldpe_dispatch_pfkey, NULL, global.pfkeysock,
                        &pfkey_ev);
 
@@ -805,13 +801,11 @@ ldpe_setup_sockets(int af, int disc_socket, int edisc_socket,
 
        /* discovery socket */
        af_global->ldp_disc_socket = disc_socket;
-       af_global->disc_ev = NULL;
        thread_add_read(master, disc_recv_packet, &af_global->disc_ev, af_global->ldp_disc_socket,
                        &af_global->disc_ev);
 
        /* extended discovery socket */
        af_global->ldp_edisc_socket = edisc_socket;
-       af_global->edisc_ev = NULL;
        thread_add_read(master, disc_recv_packet, &af_global->edisc_ev, af_global->ldp_edisc_socket,
                        &af_global->edisc_ev);
 
index 8735faf3dd1aefd08367833d601d3bc54fdada8b..56af16d28021b72111b7f5c81c9405d4bc30d266 100644 (file)
@@ -141,7 +141,6 @@ disc_recv_packet(struct thread *thread)
        struct in_addr           lsr_id;
 
        /* reschedule read */
-       *threadp = NULL;
        thread_add_read(master, disc_recv_packet, threadp, fd, threadp);
 
        /* setup buffer */
@@ -425,7 +424,6 @@ session_read(struct thread *thread)
        uint16_t         pdu_len, msg_len, msg_size, max_pdu_len;
        int              ret;
 
-       tcp->rev = NULL;
        thread_add_read(master, session_read, nbr, fd, &tcp->rev);
 
        if ((n = read(fd, tcp->rbuf->buf + tcp->rbuf->wpos,
@@ -745,7 +743,6 @@ tcp_new(int fd, struct nbr *nbr)
                if ((tcp->rbuf = calloc(1, sizeof(struct ibuf_read))) == NULL)
                        fatal(__func__);
 
-               tcp->rev = NULL;
                thread_add_read(master, session_read, nbr, tcp->fd, &tcp->rev);
                tcp->nbr = nbr;
        }
index fcaf466c655e73e469943731bcc4921561841880..53aa0647055452824030055d67bc0c71b64dfd42 100644 (file)
@@ -74,6 +74,7 @@ const struct message tokennames[] = {
        item(JOIN_TKN),
        item(START_TKN),
        item(END_TKN),
+       item(NEG_ONLY_TKN),
        {0},
 };
 /* clang-format on */
index c76fc1e8eb5a68d1190446a9a97ab56e91e23e37..8a7c9a2048b47ef2c6cadcbe0ed9d5e1a4da42e4 100644 (file)
@@ -229,6 +229,7 @@ struct cmd_node {
 #define CMD_WARNING_CONFIG_FAILED 13
 #define CMD_NOT_MY_INSTANCE    14
 #define CMD_NO_LEVEL_UP 15
+#define CMD_ERR_NO_DAEMON 16
 
 /* Argc max counts. */
 #define CMD_ARGC_MAX   256
index c6c38404559a4fb58d52ee3bac9e962c8bfc14cd..15c8302e637f785a69733b9646902b01259038c1 100644 (file)
@@ -388,6 +388,7 @@ static void cmd_node_names(struct graph_node *gn, struct graph_node *join,
 
        case START_TKN:
        case JOIN_TKN:
+       case NEG_ONLY_TKN:
                /* "<foo|bar> WORD" -> word is not "bar" or "foo" */
                prevname = NULL;
                break;
@@ -511,6 +512,9 @@ void cmd_graph_node_print_cb(struct graph_node *gn, struct buffer *buf)
        case JOIN_TKN:
                color = "#ddaaff";
                break;
+       case NEG_ONLY_TKN:
+               color = "#ffddaa";
+               break;
        case WORD_TKN:
                color = "#ffffff";
                break;
index 2754dca67d788e64f443b82dabdbc634fec40d2f..86157f872e0d48d8d8d96d8e8c0ea9f0c3966f43 100644 (file)
@@ -64,6 +64,7 @@ enum cmd_token_type {
        JOIN_TKN,  // marks subgraph end
        START_TKN, // first token in line
        END_TKN,   // last token in line
+       NEG_ONLY_TKN,    // filter token, match if "no ..." command
 
        SPECIAL_TKN = FORK_TKN,
 };
@@ -78,11 +79,11 @@ enum { CMD_ATTR_NORMAL,
        CMD_ATTR_YANG,
 };
 
-/* Comamand token struct. */
+/* Command token struct. */
 struct cmd_token {
        enum cmd_token_type type; // token type
        uint8_t attr;             // token attributes
-       bool allowrepeat;        // matcher allowed to match token repetively?
+       bool allowrepeat; // matcher allowed to match token repetitively?
        uint32_t refcnt;
 
        char *text;      // token text
index 9c096995f513770f1b838380fc697e972804df4e..ec366ce7e178919eb91441144f078323b89e4ab6 100644 (file)
@@ -82,6 +82,7 @@ RANGE           \({NUMBER}[ ]?\-[ ]?{NUMBER}\)
 {VARIABLE}      {yylval->string = XSTRDUP(MTYPE_LEX, yytext); return VARIABLE;}
 {WORD}          {yylval->string = XSTRDUP(MTYPE_LEX, yytext); return WORD;}
 {RANGE}         {yylval->string = XSTRDUP(MTYPE_LEX, yytext); return RANGE;}
+!\[             {yylval->string = NULL; return EXCL_BRACKET;}
 .               {return yytext[0];}
 %%
 
index 57035101484127315814e05777ae83744e546d60..f221e0a02ce7ebfc846d93b81dab1a5a0d0de85d 100644 (file)
@@ -42,7 +42,7 @@ DEFINE_MTYPE_STATIC(LIB, CMD_MATCHSTACK, "Command Match Stack");
 
 /* matcher helper prototypes */
 static int add_nexthops(struct list *, struct graph_node *,
-                       struct graph_node **, size_t);
+                       struct graph_node **, size_t, bool);
 
 static enum matcher_rv command_match_r(struct graph_node *, vector,
                                       unsigned int, struct graph_node **,
@@ -79,6 +79,13 @@ static enum match_type match_variable(struct cmd_token *, const char *);
 
 static enum match_type match_mac(const char *, bool);
 
+static bool is_neg(vector vline, size_t idx)
+{
+       if (idx >= vector_active(vline) || !vector_slot(vline, idx))
+               return false;
+       return !strcmp(vector_slot(vline, idx), "no");
+}
+
 enum matcher_rv command_match(struct graph *cmdgraph, vector vline,
                              struct list **argv, const struct cmd_element **el)
 {
@@ -248,7 +255,7 @@ static enum matcher_rv command_match_r(struct graph_node *start, vector vline,
 
        // get all possible nexthops
        struct list *next = list_new();
-       add_nexthops(next, start, NULL, 0);
+       add_nexthops(next, start, NULL, 0, is_neg(vline, 1));
 
        // determine the best match
        for (ALL_LIST_ELEMENTS_RO(next, ln, gn)) {
@@ -349,6 +356,7 @@ enum matcher_rv command_complete(struct graph *graph, vector vline,
 {
        // pointer to next input token to match
        char *input_token;
+       bool neg = is_neg(vline, 0);
 
        struct list *
                current =
@@ -363,7 +371,7 @@ enum matcher_rv command_complete(struct graph *graph, vector vline,
 
        // add all children of start node to list
        struct graph_node *start = vector_slot(graph->nodes, 0);
-       add_nexthops(next, start, &start, 0);
+       add_nexthops(next, start, &start, 0, neg);
 
        unsigned int idx;
        for (idx = 0; idx < vector_active(vline) && next->count > 0; idx++) {
@@ -428,7 +436,7 @@ enum matcher_rv command_complete(struct graph *graph, vector vline,
                                        listnode_add(next, newstack);
                                } else if (matchtype >= minmatch)
                                        add_nexthops(next, gstack[0], gstack,
-                                                    idx + 1);
+                                                    idx + 1, neg);
                                break;
                        default:
                                trace_matcher("no_match\n");
@@ -478,7 +486,7 @@ enum matcher_rv command_complete(struct graph *graph, vector vline,
  * output, instead of direct node pointers!
  */
 static int add_nexthops(struct list *list, struct graph_node *node,
-                       struct graph_node **stack, size_t stackpos)
+                       struct graph_node **stack, size_t stackpos, bool neg)
 {
        int added = 0;
        struct graph_node *child;
@@ -494,8 +502,13 @@ static int add_nexthops(struct list *list, struct graph_node *node,
                        if (j != stackpos)
                                continue;
                }
+
+               if (token->type == NEG_ONLY_TKN && !neg)
+                       continue;
+
                if (token->type >= SPECIAL_TKN && token->type != END_TKN) {
-                       added += add_nexthops(list, child, stack, stackpos);
+                       added +=
+                               add_nexthops(list, child, stack, stackpos, neg);
                } else {
                        if (stack) {
                                nextstack = XMALLOC(
index f5e42cc304898afa6a187e09afd59cf83a83e897..3e2cdc79af9c003128d63a243d44fa64c60c3a23 100644 (file)
 %token <string> MAC
 %token <string> MAC_PREFIX
 
+/* special syntax, value is irrelevant */
+%token <string> EXCL_BRACKET
+
 /* union types for parsed rules */
 %type <node> start
 %type <node> literal_token
@@ -372,6 +375,19 @@ selector: '[' selector_seq_seq ']' varname_token
 }
 ;
 
+/* ![option] productions */
+selector: EXCL_BRACKET selector_seq_seq ']' varname_token
+{
+  struct graph_node *neg_only = new_token_node (ctx, NEG_ONLY_TKN, NULL, NULL);
+
+  $$ = $2;
+  graph_add_edge ($$.start, neg_only);
+  graph_add_edge (neg_only, $$.end);
+  cmd_token_varname_set ($2.end->data, $4);
+  XFREE (MTYPE_LEX, $4);
+}
+;
+
 %%
 
 #undef scanner
index 7f19008fbfa7c6b5f0cc60b1cb8110203eddefcf..90344ae1e599da5c66ab32e84da39a1c2d4bc46b 100644 (file)
@@ -197,21 +197,30 @@ static PyObject *graph_to_pyobj(struct wrap_graph *wgraph,
        if (gn->data) {
                struct cmd_token *tok = gn->data;
                switch (tok->type) {
-#define item(x) case x: wrap->type = #x; break;
-                       item(WORD_TKN)                // words
-                               item(VARIABLE_TKN)    // almost anything
-                               item(RANGE_TKN)       // integer range
-                               item(IPV4_TKN)  // IPV4 addresses
-                               item(IPV4_PREFIX_TKN) // IPV4 network prefixes
-                               item(IPV6_TKN)  // IPV6 prefixes
-                               item(IPV6_PREFIX_TKN) // IPV6 network prefixes
-                               item(MAC_TKN)    // MAC address
-                               item(MAC_PREFIX_TKN)  // MAC address with mask
-
-                               /* plumbing types */
-                               item(FORK_TKN) item(JOIN_TKN) item(START_TKN)
-                                       item(END_TKN) default
-                               : wrap->type = "???";
+#define item(x)                                                                \
+       case x:                                                                \
+               wrap->type = #x;                                               \
+               break /* no semicolon */
+
+                       item(WORD_TKN);        // words
+                       item(VARIABLE_TKN);    // almost anything
+                       item(RANGE_TKN);       // integer range
+                       item(IPV4_TKN);        // IPV4 addresses
+                       item(IPV4_PREFIX_TKN); // IPV4 network prefixes
+                       item(IPV6_TKN);        // IPV6 prefixes
+                       item(IPV6_PREFIX_TKN); // IPV6 network prefixes
+                       item(MAC_TKN);         // MAC address
+                       item(MAC_PREFIX_TKN);  // MAC address with mask
+
+                       /* plumbing types */
+                       item(FORK_TKN);
+                       item(JOIN_TKN);
+                       item(START_TKN);
+                       item(END_TKN);
+                       item(NEG_ONLY_TKN);
+#undef item
+               default:
+                       wrap->type = "???";
                }
 
                wrap->deprecated = (tok->attr == CMD_ATTR_DEPRECATED);
index ea9c828f7c00af80b564912fefa6a223ca7acca5..4e947a8a8429bff87635121b3ce8708dacb427da 100644 (file)
@@ -84,7 +84,10 @@ static int frrzmq_read_msg(struct thread *t)
                        break;
 
                if (cb->read.cb_msg) {
+                       cb->in_cb = true;
                        cb->read.cb_msg(cb->read.arg, cb->zmqsock);
+                       cb->in_cb = false;
+
                        read = 1;
 
                        if (cb->read.cancelled) {
@@ -92,7 +95,8 @@ static int frrzmq_read_msg(struct thread *t)
                                                    ZMQ_POLLOUT);
                                cb->read.thread = NULL;
                                if (cb->write.cancelled && !cb->write.thread)
-                                       XFREE(MTYPE_ZEROMQ_CB, cb);
+                                       XFREE(MTYPE_ZEROMQ_CB, *cbp);
+
                                return 0;
                        }
                        continue;
@@ -112,15 +116,19 @@ static int frrzmq_read_msg(struct thread *t)
                        }
                        read = 1;
 
+                       cb->in_cb = true;
                        cb->read.cb_part(cb->read.arg, cb->zmqsock, &msg,
                                         partno);
+                       cb->in_cb = false;
+
                        if (cb->read.cancelled) {
                                zmq_msg_close(&msg);
                                frrzmq_check_events(cbp, &cb->write,
                                                    ZMQ_POLLOUT);
                                cb->read.thread = NULL;
                                if (cb->write.cancelled && !cb->write.thread)
-                                       XFREE(MTYPE_ZEROMQ_CB, cb);
+                                       XFREE(MTYPE_ZEROMQ_CB, *cbp);
+
                                return 0;
                        }
 
@@ -183,7 +191,6 @@ int _frrzmq_thread_add_read(const struct xref_threadsched *xref,
                cb = *cbp;
        else {
                cb = XCALLOC(MTYPE_ZEROMQ_CB, sizeof(struct frrzmq_cb));
-
                cb->write.cancelled = true;
                *cbp = cb;
        }
@@ -195,6 +202,7 @@ int _frrzmq_thread_add_read(const struct xref_threadsched *xref,
        cb->read.cb_part = partfunc;
        cb->read.cb_error = errfunc;
        cb->read.cancelled = false;
+       cb->in_cb = false;
 
        if (events & ZMQ_POLLIN) {
                thread_cancel(&cb->read.thread);
@@ -232,14 +240,18 @@ static int frrzmq_write_msg(struct thread *t)
                        break;
 
                if (cb->write.cb_msg) {
+                       cb->in_cb = true;
                        cb->write.cb_msg(cb->write.arg, cb->zmqsock);
+                       cb->in_cb = false;
+
                        written = 1;
 
                        if (cb->write.cancelled) {
                                frrzmq_check_events(cbp, &cb->read, ZMQ_POLLIN);
                                cb->write.thread = NULL;
                                if (cb->read.cancelled && !cb->read.thread)
-                                       XFREE(MTYPE_ZEROMQ_CB, cb);
+                                       XFREE(MTYPE_ZEROMQ_CB, *cbp);
+
                                return 0;
                        }
                        continue;
@@ -286,7 +298,6 @@ int _frrzmq_thread_add_write(const struct xref_threadsched *xref,
                cb = *cbp;
        else {
                cb = XCALLOC(MTYPE_ZEROMQ_CB, sizeof(struct frrzmq_cb));
-
                cb->read.cancelled = true;
                *cbp = cb;
        }
@@ -298,6 +309,7 @@ int _frrzmq_thread_add_write(const struct xref_threadsched *xref,
        cb->write.cb_part = NULL;
        cb->write.cb_error = errfunc;
        cb->write.cancelled = false;
+       cb->in_cb = false;
 
        if (events & ZMQ_POLLOUT) {
                thread_cancel(&cb->write.thread);
@@ -317,22 +329,15 @@ void frrzmq_thread_cancel(struct frrzmq_cb **cb, struct cb_core *core)
        core->cancelled = true;
        thread_cancel(&core->thread);
 
-       /*
-        * Looking at this code one would assume that FRR
-        * would want a `!(*cb)->write.thread.  This was
-        * attempted in e08165def1c62beee0e87385 but this
-        * change caused `make check` to stop working
-        * which was not noticed because our CI system
-        * does not build with zeromq.  Put this back
-        * to the code as written in 2017.  e08165de..
-        * was introduced in 2021.  So someone was ok
-        * with frrzmq_thread_cancel for 4 years.  This will
-        * allow those people doing `make check` to continue
-        * working.  In the meantime if the people using
-        * this code see an issue they can fix it
+       /* If cancelled from within a callback, don't try to free memory
+        * in this path.
         */
+       if ((*cb)->in_cb)
+               return;
+
+       /* Ok to free the callback context if no more ... context. */
        if ((*cb)->read.cancelled && !(*cb)->read.thread
-           && (*cb)->write.cancelled && (*cb)->write.thread)
+           && (*cb)->write.cancelled && ((*cb)->write.thread == NULL))
                XFREE(MTYPE_ZEROMQ_CB, *cb);
 }
 
index d30cf8a841520608cc9afdfd8e29c98b068ded27..b3be78cbea7c3129db11b742515025874b9fb961 100644 (file)
@@ -49,10 +49,13 @@ struct cb_core {
                        unsigned partnum);
        void (*cb_error)(void *arg, void *zmqsock);
 };
+
 struct frrzmq_cb {
        void *zmqsock;
        int fd;
 
+       bool in_cb; /* This context is in a read or write callback. */
+
        struct cb_core read;
        struct cb_core write;
 };
index d03437328b83cec356ab58da5994770b7b86668d..9b05bb4fbf96828e733fb04809e39dbe03f1d0cd 100644 (file)
@@ -674,13 +674,19 @@ static void frr_mkdir(const char *path, bool strip)
                         strerror(errno));
 }
 
+static void _err_print(const void *cookie, const char *errstr)
+{
+       const char *prefix = (const char *)cookie;
+
+       fprintf(stderr, "%s: %s\n", prefix, errstr);
+}
+
 static struct thread_master *master;
 struct thread_master *frr_init(void)
 {
        struct option_chain *oc;
        struct frrmod_runtime *module;
        struct zprivs_ids_t ids;
-       char moderr[256];
        char p_instance[16] = "", p_pathspace[256] = "";
        const char *dir;
        dir = di->module_path ? di->module_path : frr_moduledir;
@@ -734,11 +740,9 @@ struct thread_master *frr_init(void)
        frrmod_init(di->module);
        while (modules) {
                modules = (oc = modules)->next;
-               module = frrmod_load(oc->arg, dir, moderr, sizeof(moderr));
-               if (!module) {
-                       fprintf(stderr, "%s\n", moderr);
+               module = frrmod_load(oc->arg, dir, _err_print, __func__);
+               if (!module)
                        exit(1);
-               }
                XFREE(MTYPE_TMP, oc);
        }
 
index 1d51a6396d97efebc105db389aafdb89023f095a..4037bfbeb0202edc6d1661dadc5d03aee1c2b13a 100644 (file)
 #include "module.h"
 #include "memory.h"
 #include "lib/version.h"
+#include "printfrr.h"
 
 DEFINE_MTYPE_STATIC(LIB, MODULE_LOADNAME, "Module loading name");
 DEFINE_MTYPE_STATIC(LIB, MODULE_LOADARGS, "Module loading arguments");
+DEFINE_MTYPE_STATIC(LIB, MODULE_LOAD_ERR, "Module loading error");
 
 static struct frrmod_info frrmod_default_info = {
        .name = "libfrr",
@@ -67,14 +69,64 @@ void frrmod_init(struct frrmod_runtime *modinfo)
        execname = modinfo->info->name;
 }
 
-struct frrmod_runtime *frrmod_load(const char *spec, const char *dir, char *err,
-                                  size_t err_len)
+/*
+ * If caller wants error strings, it should define non-NULL pFerrlog
+ * which will be called with 0-terminated error messages. These
+ * messages will NOT contain newlines, and the (*pFerrlog)() function
+ * could be called multiple times for a single call to frrmod_load().
+ *
+ * The (*pFerrlog)() function may copy these strings if needed, but
+ * should expect them to be freed by frrmod_load() before frrmod_load()
+ * returns.
+ *
+ * frrmod_load() is coded such that (*pFerrlog)() will be called only
+ * in the case where frrmod_load() returns an error.
+ */
+struct frrmod_runtime *frrmod_load(const char *spec, const char *dir,
+                                  void (*pFerrlog)(const void *, const char *),
+                                  const void *pErrlogCookie)
 {
        void *handle = NULL;
        char name[PATH_MAX], fullpath[PATH_MAX * 2], *args;
        struct frrmod_runtime *rtinfo, **rtinfop;
        const struct frrmod_info *info;
 
+#define FRRMOD_LOAD_N_ERRSTR 10
+       char *aErr[FRRMOD_LOAD_N_ERRSTR];
+       unsigned int iErr = 0;
+
+       memset(aErr, 0, sizeof(aErr));
+
+#define ERR_RECORD(...)                                                        \
+       do {                                                                   \
+               if (pFerrlog && (iErr < FRRMOD_LOAD_N_ERRSTR)) {               \
+                       aErr[iErr++] = asprintfrr(MTYPE_MODULE_LOAD_ERR,       \
+                                                 __VA_ARGS__);                \
+               }                                                              \
+       } while (0)
+
+#define ERR_REPORT                                                             \
+       do {                                                                   \
+               if (pFerrlog) {                                                \
+                       unsigned int i;                                        \
+                                                                               \
+                       for (i = 0; i < iErr; ++i) {                           \
+                               (*pFerrlog)(pErrlogCookie, aErr[i]);           \
+                       }                                                      \
+               }                                                              \
+       } while (0)
+
+#define ERR_FREE                                                               \
+       do {                                                                   \
+               unsigned int i;                                                \
+                                                                               \
+               for (i = 0; i < iErr; ++i) {                                   \
+                       XFREE(MTYPE_MODULE_LOAD_ERR, aErr[i]);                 \
+                       aErr[i] = 0;                                           \
+               }                                                              \
+               iErr = 0;                                                      \
+       } while (0)
+
        snprintf(name, sizeof(name), "%s", spec);
        args = strchr(name, ':');
        if (args)
@@ -85,32 +137,41 @@ struct frrmod_runtime *frrmod_load(const char *spec, const char *dir, char *err,
                        snprintf(fullpath, sizeof(fullpath), "%s/%s_%s.so", dir,
                                 execname, name);
                        handle = dlopen(fullpath, RTLD_NOW | RTLD_GLOBAL);
+                       if (!handle)
+                               ERR_RECORD("loader error: dlopen(%s): %s",
+                                          fullpath, dlerror());
                }
                if (!handle) {
                        snprintf(fullpath, sizeof(fullpath), "%s/%s.so", dir,
                                 name);
                        handle = dlopen(fullpath, RTLD_NOW | RTLD_GLOBAL);
+                       if (!handle)
+                               ERR_RECORD("loader error: dlopen(%s): %s",
+                                          fullpath, dlerror());
                }
        }
        if (!handle) {
                snprintf(fullpath, sizeof(fullpath), "%s", name);
                handle = dlopen(fullpath, RTLD_NOW | RTLD_GLOBAL);
+               if (!handle)
+                       ERR_RECORD("loader error: dlopen(%s): %s", fullpath,
+                                  dlerror());
        }
        if (!handle) {
-               if (err)
-                       snprintf(err, err_len,
-                                "loading module \"%s\" failed: %s", name,
-                                dlerror());
+               ERR_REPORT;
+               ERR_FREE;
                return NULL;
        }
 
+       /* previous dlopen() errors are no longer relevant */
+       ERR_FREE;
+
        rtinfop = dlsym(handle, "frr_module");
        if (!rtinfop) {
                dlclose(handle);
-               if (err)
-                       snprintf(err, err_len,
-                                "\"%s\" is not an FRR module: %s", name,
-                                dlerror());
+               ERR_RECORD("\"%s\" is not an FRR module: %s", name, dlerror());
+               ERR_REPORT;
+               ERR_FREE;
                return NULL;
        }
        rtinfo = *rtinfop;
@@ -122,17 +183,13 @@ struct frrmod_runtime *frrmod_load(const char *spec, const char *dir, char *err,
 
        if (rtinfo->finished_loading) {
                dlclose(handle);
-               if (err)
-                       snprintf(err, err_len, "module \"%s\" already loaded",
-                                name);
+               ERR_RECORD("module \"%s\" already loaded", name);
                goto out_fail;
        }
 
        if (info->init && info->init()) {
                dlclose(handle);
-               if (err)
-                       snprintf(err, err_len,
-                                "module \"%s\" initialisation failed", name);
+               ERR_RECORD("module \"%s\" initialisation failed", name);
                goto out_fail;
        }
 
@@ -140,11 +197,14 @@ struct frrmod_runtime *frrmod_load(const char *spec, const char *dir, char *err,
 
        *frrmod_last = rtinfo;
        frrmod_last = &rtinfo->next;
+       ERR_FREE;
        return rtinfo;
 
 out_fail:
        XFREE(MTYPE_MODULE_LOADARGS, rtinfo->load_args);
        XFREE(MTYPE_MODULE_LOADNAME, rtinfo->load_name);
+       ERR_REPORT;
+       ERR_FREE;
        return NULL;
 }
 
index 6275877cb37423e6b9919202f0cafaded6cba5bf..ae1ca2f7579fb30eceb56ea3a208232ad06fd278 100644 (file)
@@ -91,7 +91,9 @@ extern struct frrmod_runtime *frrmod_list;
 
 extern void frrmod_init(struct frrmod_runtime *modinfo);
 extern struct frrmod_runtime *frrmod_load(const char *spec, const char *dir,
-                                         char *err, size_t err_len);
+                                         void (*pFerrlog)(const void *,
+                                                          const char *),
+                                         const void *pErrlogCookie);
 #if 0
 /* not implemented yet */
 extern void frrmod_unload(struct frrmod_runtime *module);
index 23e3a2b7337ab2eecefac78233263ae6a89e0f66..2e09cb4bcc3c0be18b1e4862f396ae42ac5d86f8 100644 (file)
@@ -519,12 +519,13 @@ struct nexthop *nexthop_from_ipv6_ifindex(const struct in6_addr *ipv6,
        return nexthop;
 }
 
-struct nexthop *nexthop_from_blackhole(enum blackhole_type bh_type)
+struct nexthop *nexthop_from_blackhole(enum blackhole_type bh_type,
+                                      vrf_id_t nh_vrf_id)
 {
        struct nexthop *nexthop;
 
        nexthop = nexthop_new();
-       nexthop->vrf_id = VRF_DEFAULT;
+       nexthop->vrf_id = nh_vrf_id;
        nexthop->type = NEXTHOP_TYPE_BLACKHOLE;
        nexthop->bh_type = bh_type;
 
@@ -633,9 +634,6 @@ const char *nexthop2str(const struct nexthop *nexthop, char *str, int size)
        case NEXTHOP_TYPE_BLACKHOLE:
                snprintf(str, size, "blackhole");
                break;
-       default:
-               snprintf(str, size, "unknown");
-               break;
        }
 
        return str;
@@ -938,6 +936,12 @@ int nexthop_str2backups(const char *str, int *num_backups,
  *             unreachable (blackhole)
  *     %pNHs
  *             nexthop2str()
+ *     %pNHcg
+ *             1.2.3.4
+ *             (0-length if no IP address present)
+ *     %pNHci
+ *             eth0
+ *             (0-length if no interface present)
  */
 printfrr_ext_autoreg_p("NH", printfrr_nh)
 static ssize_t printfrr_nh(struct fbuf *buf, struct printfrr_eargs *ea,
@@ -992,12 +996,10 @@ static ssize_t printfrr_nh(struct fbuf *buf, struct printfrr_eargs *ea,
                        case BLACKHOLE_NULL:
                                ret += bputs(buf, " (blackhole)");
                                break;
-                       default:
+                       case BLACKHOLE_UNSPEC:
                                break;
                        }
                        break;
-               default:
-                       break;
                }
                if (do_ifi && nexthop->ifindex)
                        ret += bprintfrr(buf, ", %s%s", v_viaif,
@@ -1028,9 +1030,54 @@ static ssize_t printfrr_nh(struct fbuf *buf, struct printfrr_eargs *ea,
                case NEXTHOP_TYPE_BLACKHOLE:
                        ret += bputs(buf, "blackhole");
                        break;
-               default:
-                       ret += bputs(buf, "unknown");
-                       break;
+               }
+               return ret;
+       case 'c':
+               ea->fmt++;
+               if (*ea->fmt == 'g') {
+                       ea->fmt++;
+                       if (!nexthop)
+                               return bputs(buf, "(null)");
+                       switch (nexthop->type) {
+                       case NEXTHOP_TYPE_IPV4:
+                       case NEXTHOP_TYPE_IPV4_IFINDEX:
+                               ret += bprintfrr(buf, "%pI4",
+                                                &nexthop->gate.ipv4);
+                               break;
+                       case NEXTHOP_TYPE_IPV6:
+                       case NEXTHOP_TYPE_IPV6_IFINDEX:
+                               ret += bprintfrr(buf, "%pI6",
+                                                &nexthop->gate.ipv6);
+                               break;
+                       case NEXTHOP_TYPE_IFINDEX:
+                       case NEXTHOP_TYPE_BLACKHOLE:
+                               break;
+                       }
+               } else if (*ea->fmt == 'i') {
+                       ea->fmt++;
+                       if (!nexthop)
+                               return bputs(buf, "(null)");
+                       switch (nexthop->type) {
+                       case NEXTHOP_TYPE_IFINDEX:
+                               ret += bprintfrr(
+                                       buf, "%s",
+                                       ifindex2ifname(nexthop->ifindex,
+                                                      nexthop->vrf_id));
+                               break;
+                       case NEXTHOP_TYPE_IPV4:
+                       case NEXTHOP_TYPE_IPV4_IFINDEX:
+                       case NEXTHOP_TYPE_IPV6:
+                       case NEXTHOP_TYPE_IPV6_IFINDEX:
+                               if (nexthop->ifindex)
+                                       ret += bprintfrr(
+                                               buf, "%s",
+                                               ifindex2ifname(
+                                                       nexthop->ifindex,
+                                                       nexthop->vrf_id));
+                               break;
+                       case NEXTHOP_TYPE_BLACKHOLE:
+                               break;
+                       }
                }
                return ret;
        }
index dd65509aec5f22f42ad4f3e64b8e1cb43ab4f130..320b46315e1c653ad4fb4fe977d3504338fc98ae 100644 (file)
@@ -182,7 +182,8 @@ struct nexthop *nexthop_from_ipv6(const struct in6_addr *ipv6,
                                  vrf_id_t vrf_id);
 struct nexthop *nexthop_from_ipv6_ifindex(const struct in6_addr *ipv6,
                                          ifindex_t ifindex, vrf_id_t vrf_id);
-struct nexthop *nexthop_from_blackhole(enum blackhole_type bh_type);
+struct nexthop *nexthop_from_blackhole(enum blackhole_type bh_type,
+                                      vrf_id_t nh_vrf_id);
 
 /*
  * Hash a nexthop. Suitable for use with hash tables.
index b74a0e6c2300e3ed3cee8aca8adeef7ef8790cd5..6676c0b072170f5991fb81214e8aff5eaf315be7 100644 (file)
@@ -550,6 +550,13 @@ void nb_cli_show_config_prepare(struct nb_config *config, bool with_defaults)
                                       LYD_VALIDATE_NO_STATE, NULL);
 }
 
+static int lyd_node_cmp(struct lyd_node **dnode1, struct lyd_node **dnode2)
+{
+       struct nb_node *nb_node = (*dnode1)->schema->priv;
+
+       return nb_node->cbs.cli_cmp(*dnode1, *dnode2);
+}
+
 static void show_dnode_children_cmds(struct vty *vty, struct lyd_node *root,
                                     bool with_defaults)
 {
@@ -567,6 +574,10 @@ static void show_dnode_children_cmds(struct vty *vty, struct lyd_node *root,
                 * it's time to print the config.
                 */
                if (sort_node && nb_node != sort_node) {
+                       list_sort(sort_list,
+                                 (int (*)(const void **,
+                                          const void **))lyd_node_cmp);
+
                        for (ALL_LIST_ELEMENTS_RO(sort_list, listnode, data))
                                nb_cli_show_dnode_cmds(vty, data,
                                                       with_defaults);
@@ -584,11 +595,9 @@ static void show_dnode_children_cmds(struct vty *vty, struct lyd_node *root,
                        if (!sort_node) {
                                sort_node = nb_node;
                                sort_list = list_new();
-                               sort_list->cmp = (int (*)(void *, void *))
-                                                nb_node->cbs.cli_cmp;
                        }
 
-                       listnode_add_sort(sort_list, child);
+                       listnode_add(sort_list, child);
                        continue;
                }
 
@@ -596,6 +605,9 @@ static void show_dnode_children_cmds(struct vty *vty, struct lyd_node *root,
        }
 
        if (sort_node) {
+               list_sort(sort_list,
+                         (int (*)(const void **, const void **))lyd_node_cmp);
+
                for (ALL_LIST_ELEMENTS_RO(sort_list, listnode, data))
                        nb_cli_show_dnode_cmds(vty, data, with_defaults);
 
index 71f07dfe86d283697de7eb6e1483ead76707d33d..e227d0385c4c140520247c9e8927d0c7fe44d893 100644 (file)
@@ -344,6 +344,10 @@ static struct lyd_node *get_dnode_config(const std::string &path)
 {
        struct lyd_node *dnode;
 
+       if (!yang_dnode_exists(running_config->dnode,
+                              path.empty() ? NULL : path.c_str()))
+               return NULL;
+
        dnode = yang_dnode_get(running_config->dnode,
                               path.empty() ? NULL : path.c_str());
        if (dnode)
index 944c94f57f8a2a6a93d4ac4772befdadf0694812..c92f5cec5a0d6d1ac7fc5a70e0ba75a1a1ed0127 100644 (file)
@@ -512,7 +512,7 @@ extern char *esi_to_str(const esi_t *esi, char *buf, int size);
 extern char *evpn_es_df_alg2str(uint8_t df_alg, char *buf, int buf_len);
 extern void prefix_evpn_hexdump(const struct prefix_evpn *p);
 
-static inline int ipv6_martian(struct in6_addr *addr)
+static inline int ipv6_martian(const struct in6_addr *addr)
 {
        struct in6_addr localhost_addr;
 
@@ -527,7 +527,7 @@ static inline int ipv6_martian(struct in6_addr *addr)
 extern int macstr2prefix_evpn(const char *str, struct prefix_evpn *p);
 
 /* NOTE: This routine expects the address argument in network byte order. */
-static inline int ipv4_martian(struct in_addr *addr)
+static inline int ipv4_martian(const struct in_addr *addr)
 {
        in_addr_t ip = ntohl(addr->s_addr);
 
index c2153e0a5e4481444e129e252a2ec3269c54c052..4aba909f2555b758ddaae00261dab0d4705bdf20 100644 (file)
@@ -53,14 +53,14 @@ static int resolver_cb_socket_readable(struct thread *t)
 {
        struct resolver_state *r = THREAD_ARG(t);
        int fd = THREAD_FD(t);
+       struct thread **t_ptr;
 
        vector_set_index(r->read_threads, fd, THREAD_RUNNING);
        ares_process_fd(r->channel, fd, ARES_SOCKET_BAD);
        if (vector_lookup(r->read_threads, fd) == THREAD_RUNNING) {
-               t = NULL;
+               t_ptr = (struct thread **)vector_get_index(r->read_threads, fd);
                thread_add_read(r->master, resolver_cb_socket_readable, r, fd,
-                               &t);
-               vector_set_index(r->read_threads, fd, t);
+                               t_ptr);
        }
        resolver_update_timeouts(r);
 
@@ -71,14 +71,14 @@ static int resolver_cb_socket_writable(struct thread *t)
 {
        struct resolver_state *r = THREAD_ARG(t);
        int fd = THREAD_FD(t);
+       struct thread **t_ptr;
 
        vector_set_index(r->write_threads, fd, THREAD_RUNNING);
        ares_process_fd(r->channel, ARES_SOCKET_BAD, fd);
        if (vector_lookup(r->write_threads, fd) == THREAD_RUNNING) {
-               t = NULL;
+               t_ptr = (struct thread **)vector_get_index(r->write_threads, fd);
                thread_add_write(r->master, resolver_cb_socket_writable, r, fd,
-                                &t);
-               vector_set_index(r->write_threads, fd, t);
+                                t_ptr);
        }
        resolver_update_timeouts(r);
 
@@ -105,14 +105,15 @@ static void ares_socket_cb(void *data, ares_socket_t fd, int readable,
                           int writable)
 {
        struct resolver_state *r = (struct resolver_state *)data;
-       struct thread *t;
+       struct thread *t, **t_ptr;
 
        if (readable) {
-               t = vector_lookup_ensure(r->read_threads, fd);
+               t = vector_lookup(r->read_threads, fd);
                if (!t) {
+                       t_ptr = (struct thread **)vector_get_index(
+                               r->read_threads, fd);
                        thread_add_read(r->master, resolver_cb_socket_readable,
-                                       r, fd, &t);
-                       vector_set_index(r->read_threads, fd, t);
+                                       r, fd, t_ptr);
                }
        } else {
                t = vector_lookup(r->read_threads, fd);
@@ -125,11 +126,12 @@ static void ares_socket_cb(void *data, ares_socket_t fd, int readable,
        }
 
        if (writable) {
-               t = vector_lookup_ensure(r->write_threads, fd);
+               t = vector_lookup(r->write_threads, fd);
                if (!t) {
+                       t_ptr = (struct thread **)vector_get_index(
+                               r->write_threads, fd);
                        thread_add_read(r->master, resolver_cb_socket_writable,
-                                       r, fd, &t);
-                       vector_set_index(r->write_threads, fd, t);
+                                       r, fd, t_ptr);
                }
        } else {
                t = vector_lookup(r->write_threads, fd);
index 594dcf97cb8158f21c49d08f54c6cd7dbd7239c7..5c60b7d1c6d42637bf9cd37fdb25d3b742935f40 100644 (file)
@@ -2488,8 +2488,9 @@ void route_map_notify_pentry_dependencies(const char *affected_name,
 
    We need to make sure our route-map processing matches the above
 */
-route_map_result_t route_map_apply(struct route_map *map,
-                                  const struct prefix *prefix, void *object)
+route_map_result_t route_map_apply_ext(struct route_map *map,
+                                      const struct prefix *prefix,
+                                      void *match_object, void *set_object)
 {
        static int recursion = 0;
        enum route_map_cmd_result_t match_ret = RMAP_NOMATCH;
@@ -2516,7 +2517,7 @@ route_map_result_t route_map_apply(struct route_map *map,
 
        if ((!map->optimization_disabled)
            && (map->ipv4_prefix_table || map->ipv6_prefix_table)) {
-               index = route_map_get_index(map, prefix, object,
+               index = route_map_get_index(map, prefix, match_object,
                                            (uint8_t *)&match_ret);
                if (index) {
                        index->applied++;
@@ -2551,7 +2552,7 @@ route_map_result_t route_map_apply(struct route_map *map,
                        index->applied++;
                        /* Apply this index. */
                        match_ret = route_map_apply_match(&index->match_list,
-                                                         prefix, object);
+                                                         prefix, match_object);
                        if (rmap_debug) {
                                zlog_debug(
                                        "Route-map: %s, sequence: %d, prefix: %pFX, result: %s",
@@ -2610,7 +2611,7 @@ route_map_result_t route_map_apply(struct route_map *map,
                                         * return code.
                                         */
                                        (void)(*set->cmd->func_apply)(
-                                               set->value, prefix, object);
+                                               set->value, prefix, set_object);
 
                                /* Call another route-map if available */
                                if (index->nextrm) {
@@ -2622,8 +2623,10 @@ route_map_result_t route_map_apply(struct route_map *map,
                                                       jump to it */
                                        {
                                                recursion++;
-                                               ret = route_map_apply(
-                                                       nextrm, prefix, object);
+                                               ret = route_map_apply_ext(
+                                                       nextrm, prefix,
+                                                       match_object,
+                                                       set_object);
                                                recursion--;
                                        }
 
index b356dbf52e0755dbd56dec268398f00a55c571ab..2c8eb24537083c337d5b3313828a127a0509dc98 100644 (file)
@@ -443,9 +443,12 @@ extern struct route_map *route_map_lookup_by_name(const char *name);
 struct route_map *route_map_lookup_warn_noexist(struct vty *vty, const char *name);
 
 /* Apply route map to the object. */
-extern route_map_result_t route_map_apply(struct route_map *map,
-                                         const struct prefix *prefix,
-                                         void *object);
+extern route_map_result_t route_map_apply_ext(struct route_map *map,
+                                             const struct prefix *prefix,
+                                             void *match_object,
+                                             void *set_object);
+#define route_map_apply(map, prefix, object)                                   \
+       route_map_apply_ext(map, prefix, object, object)
 
 extern void route_map_add_hook(void (*func)(const char *));
 extern void route_map_delete_hook(void (*func)(const char *));
index fc42857418ef1f20e445f4110a0f9938f602320f..c5219f7381f93c81801a7065bccbfcdf9b98a864 100644 (file)
 
 DEFINE_MTYPE_STATIC(LIB, SKIP_LIST, "Skip List");
 DEFINE_MTYPE_STATIC(LIB, SKIP_LIST_NODE, "Skip Node");
+DEFINE_MTYPE_STATIC(LIB, SKIP_LIST_STATS, "Skiplist Counters");
 
 #define BitsInRandom 31
 
 #define MaxNumberOfLevels 16
 #define MaxLevel (MaxNumberOfLevels-1)
-#define newNodeOfLevel(l) XCALLOC(MTYPE_SKIP_LIST_NODE, sizeof(struct skiplistnode)+(l)*sizeof(struct skiplistnode *))
+#define newNodeOfLevel(l)                                                      \
+       XCALLOC(MTYPE_SKIP_LIST_NODE,                                          \
+               sizeof(struct skiplistnode)                                    \
+                       + (l) * sizeof(struct skiplistnode *))
+
+/* XXX must match type of (struct skiplist).level_stats */
+#define newStatsOfLevel(l)                                                     \
+       XCALLOC(MTYPE_SKIP_LIST_STATS, ((l) + 1) * sizeof(int))
 
 static int randomsLeft;
 static int randomBits;
 
-#if 1
+#ifdef SKIPLIST_DEBUG
 #define CHECKLAST(sl)                                                          \
        do {                                                                   \
                if ((sl)->header->forward[0] && !(sl)->last)                   \
@@ -138,7 +146,7 @@ struct skiplist *skiplist_new(int flags,
        new->level = 0;
        new->count = 0;
        new->header = newNodeOfLevel(MaxNumberOfLevels);
-       new->stats = newNodeOfLevel(MaxNumberOfLevels);
+       new->level_stats = newStatsOfLevel(MaxNumberOfLevels);
 
        new->flags = flags;
        if (cmp)
@@ -166,7 +174,7 @@ void skiplist_free(struct skiplist *l)
                p = q;
        } while (p);
 
-       XFREE(MTYPE_SKIP_LIST_NODE, l->stats);
+       XFREE(MTYPE_SKIP_LIST_STATS, l->level_stats);
        XFREE(MTYPE_SKIP_LIST, l);
 }
 
@@ -180,11 +188,13 @@ int skiplist_insert(register struct skiplist *l, register void *key,
 
        CHECKLAST(l);
 
+#ifdef SKIPLIST_DEBUG
        /* DEBUG */
        if (!key) {
                flog_err(EC_LIB_DEVELOPMENT, "%s: key is 0, value is %p",
                         __func__, value);
        }
+#endif
 
        p = l->header;
        k = l->level;
@@ -214,10 +224,10 @@ int skiplist_insert(register struct skiplist *l, register void *key,
        q->flags = SKIPLIST_NODE_FLAG_INSERTED; /* debug */
 #endif
 
-       ++(l->stats->forward[k]);
+       ++(l->level_stats[k]);
 #ifdef SKIPLIST_DEBUG
-       zlog_debug("%s: incremented stats @%p:%d, now %ld", __func__, l, k,
-                  l->stats->forward[k] - (struct skiplistnode *)NULL);
+       zlog_debug("%s: incremented level_stats @%p:%d, now %d", __func__, l, k,
+                  l->level_stats[k]);
 #endif
 
        do {
@@ -298,12 +308,10 @@ int skiplist_delete(register struct skiplist *l, register void *key,
                             k++) {
                                p->forward[k] = q->forward[k];
                        }
-                       --(l->stats->forward[k - 1]);
+                       --(l->level_stats[k - 1]);
 #ifdef SKIPLIST_DEBUG
-                       zlog_debug("%s: decremented stats @%p:%d, now %ld",
-                                  __func__, l, k - 1,
-                                  l->stats->forward[k - 1]
-                                          - (struct skiplistnode *)NULL);
+                       zlog_debug("%s: decremented level_stats @%p:%d, now %d",
+                                  __func__, l, k - 1, l->level_stats[k - 1]);
 #endif
                        if (l->del)
                                (*l->del)(q->value);
@@ -559,11 +567,10 @@ int skiplist_delete_first(register struct skiplist *l)
                l->last = NULL;
        }
 
-       --(l->stats->forward[nodelevel]);
+       --(l->level_stats[nodelevel]);
 #ifdef SKIPLIST_DEBUG
-       zlog_debug("%s: decremented stats @%p:%d, now %ld", __func__, l,
-                  nodelevel,
-                  l->stats->forward[nodelevel] - (struct skiplistnode *)NULL);
+       zlog_debug("%s: decremented level_stats @%p:%d, now %d", __func__, l,
+                  nodelevel, l->level_stats[nodelevel]);
 #endif
 
        if (l->del)
@@ -587,9 +594,7 @@ void skiplist_debug(struct vty *vty, struct skiplist *l)
 
        vty_out(vty, "Skiplist %p has max level %d\n", l, l->level);
        for (i = l->level; i >= 0; --i)
-               vty_out(vty, "  @%d: %ld\n", i,
-                       (long)((l->stats->forward[i])
-                              - (struct skiplistnode *)NULL));
+               vty_out(vty, "  @%d: %d\n", i, l->level_stats[i]);
 }
 
 static void *scramble(int i)
index a106a455d6c271075e754554ed87bc14c734218c..00950e13bbc5fe5292b98b67201e6fe856aecac2 100644 (file)
@@ -60,7 +60,7 @@ struct skiplist {
        int level; /* max lvl (1 + current # of levels in list) */
        unsigned int count;
        struct skiplistnode *header;
-       struct skiplistnode *stats;
+       int *level_stats;
        struct skiplistnode
                *last; /* last real list item (NULL if empty list) */
 
@@ -123,6 +123,7 @@ extern int skiplist_empty(register struct skiplist *l); /* in */
 
 extern unsigned int skiplist_count(register struct skiplist *l); /* in */
 
+struct vty;
 extern void skiplist_debug(struct vty *vty, struct skiplist *l);
 
 extern void skiplist_test(struct vty *vty);
index 565c49fd59a1802cbc4a2e1b7976b8dc656f37bb..4af564a82ff8de47b4cce02a3f12dbf3fba7b9b1 100644 (file)
@@ -123,6 +123,17 @@ int vector_set_index(vector v, unsigned int i, void *val)
        return i;
 }
 
+/* Make a specified index slot active and return its address. */
+void **vector_get_index(vector v, unsigned int i)
+{
+       vector_ensure(v, i);
+
+       if (v->active <= i)
+               v->active = i + 1;
+
+       return &v->index[i];
+}
+
 /* Look up vector.  */
 void *vector_lookup(vector v, unsigned int i)
 {
index d5857eb599d079c625efb47e27bd2277836b5d98..845c8d8b04ef62f9f626385e1dfb7f783d2a26a5 100644 (file)
@@ -54,6 +54,7 @@ extern void vector_ensure(vector v, unsigned int num);
 extern int vector_empty_slot(vector v);
 extern int vector_set(vector v, void *val);
 extern int vector_set_index(vector v, unsigned int i, void *val);
+extern void **vector_get_index(vector v, unsigned int i);
 extern void vector_unset(vector v, unsigned int i);
 extern void vector_unset_value(vector v, void *val);
 extern void vector_remove(vector v, unsigned int ix);
index f9307d303909a41fc5151979b67f4215d033e259..198d5253c8ed20fdcf06ccafb8e3dee28ce63b1c 100644 (file)
--- a/lib/vrf.c
+++ b/lib/vrf.c
@@ -384,21 +384,6 @@ const char *vrf_id_to_name(vrf_id_t vrf_id)
        return VRF_LOGNAME(vrf);
 }
 
-vrf_id_t vrf_name_to_id(const char *name)
-{
-       struct vrf *vrf;
-       vrf_id_t vrf_id = VRF_DEFAULT; // Pending: need a way to return invalid
-                                      // id/ routine not used.
-
-       if (!name)
-               return vrf_id;
-       vrf = vrf_lookup_by_name(name);
-       if (vrf)
-               vrf_id = vrf->vrf_id;
-
-       return vrf_id;
-}
-
 /* Get the data pointer of the specified VRF. If not found, create one. */
 void *vrf_info_get(vrf_id_t vrf_id)
 {
index 9949ec411232a9ebddfa441595d781abf7c2ee84..dab83d42da38d01cd3299a9ad0a13b367b9b02db 100644 (file)
--- a/lib/vrf.h
+++ b/lib/vrf.h
@@ -119,7 +119,6 @@ extern struct vrf *vrf_lookup_by_name(const char *);
 extern struct vrf *vrf_get(vrf_id_t, const char *);
 extern struct vrf *vrf_update(vrf_id_t new_vrf_id, const char *name);
 extern const char *vrf_id_to_name(vrf_id_t vrf_id);
-extern vrf_id_t vrf_name_to_id(const char *);
 
 #define VRF_LOGNAME(V) V ? V->name : "Unknown"
 
index a1e7194890fa69a9bdd4793fb5416567616c96c1..dde60a6c903210cc0f44a75a69b02d7729cb57fb 100644 (file)
@@ -1105,6 +1105,33 @@ stream_failure:
        return -1;
 }
 
+int zapi_srv6_locator_encode(struct stream *s, const struct srv6_locator *l)
+{
+       stream_putw(s, strlen(l->name));
+       stream_put(s, l->name, strlen(l->name));
+       stream_putw(s, l->prefix.prefixlen);
+       stream_put(s, &l->prefix.prefix, sizeof(l->prefix.prefix));
+       return 0;
+}
+
+int zapi_srv6_locator_decode(struct stream *s, struct srv6_locator *l)
+{
+       uint16_t len = 0;
+
+       STREAM_GETW(s, len);
+       if (len > SRV6_LOCNAME_SIZE)
+               goto stream_failure;
+
+       STREAM_GET(l->name, s, len);
+       STREAM_GETW(s, l->prefix.prefixlen);
+       STREAM_GET(&l->prefix.prefix, s, sizeof(l->prefix.prefix));
+       l->prefix.family = AF_INET6;
+       return 0;
+
+stream_failure:
+       return -1;
+}
+
 static int zapi_nhg_encode(struct stream *s, int cmd, struct zapi_nhg *api_nhg)
 {
        int i;
index 71187ccae73cb497b95f7c90da116154898d5f19..f9438d5db71aa07f9f391d5a904667b3b6e78e3a 100644 (file)
@@ -1090,6 +1090,9 @@ extern int zapi_labels_encode(struct stream *s, int cmd,
                              struct zapi_labels *zl);
 extern int zapi_labels_decode(struct stream *s, struct zapi_labels *zl);
 
+extern int zapi_srv6_locator_encode(struct stream *s,
+                                   const struct srv6_locator *l);
+extern int zapi_srv6_locator_decode(struct stream *s, struct srv6_locator *l);
 extern int zapi_srv6_locator_chunk_encode(struct stream *s,
                                          const struct srv6_locator_chunk *c);
 extern int zapi_srv6_locator_chunk_decode(struct stream *s,
index 5fcb31188896fa63dec343e748d67b813c0b53fb..0a618056d5ed1d984b512ff9beb9c481d4c0e2cc 100644 (file)
@@ -107,7 +107,6 @@ static int netlink_log_recv(struct thread *t)
        struct zbuf payload, zb;
        struct nlmsghdr *n;
 
-       netlink_log_thread = NULL;
 
        zbuf_init(&zb, buf, sizeof(buf), 0);
        while (zbuf_recv(&zb, fd) > 0) {
index f784ef22d62f1e4beaa3f45c4fc71ab8be468c77..206b2caccf4da5a282aaf425390a68f1fe2b955f 100644 (file)
@@ -84,7 +84,6 @@ static int evmgr_read(struct thread *t)
        struct zbuf *ibuf = &evmgr->ibuf;
        struct zbuf msg;
 
-       evmgr->t_read = NULL;
        if (zbuf_read(ibuf, evmgr->fd, (size_t)-1) < 0) {
                evmgr_connection_error(evmgr);
                return 0;
@@ -103,7 +102,6 @@ static int evmgr_write(struct thread *t)
        struct event_manager *evmgr = THREAD_ARG(t);
        int r;
 
-       evmgr->t_write = NULL;
        r = zbufq_write(&evmgr->obuf, evmgr->fd);
        if (r > 0) {
                thread_add_write(master, evmgr_write, evmgr, evmgr->fd,
@@ -193,7 +191,6 @@ static int evmgr_reconnect(struct thread *t)
        struct event_manager *evmgr = THREAD_ARG(t);
        int fd;
 
-       evmgr->t_reconnect = NULL;
        if (evmgr->fd >= 0 || !nhrp_event_socket_path)
                return 0;
 
index b78afda2c40bfbe7ab7636aa3e96b889fe1e7434..339b6dfabe274782d56e2aaa0268f5a63db0bc6a 100644 (file)
@@ -149,7 +149,6 @@ static int netlink_mcast_log_recv(struct thread *t)
        struct zbuf payload, zb;
        struct nlmsghdr *n;
 
-       netlink_mcast_log_thread = NULL;
 
        zbuf_init(&zb, buf, sizeof(buf), 0);
        while (zbuf_recv(&zb, fd) > 0) {
index 9dfaf073d85cf2c30a183d9732a834948f4201e1..5179f15ebf8504f65f88efa5983336676f26d016 100644 (file)
@@ -112,7 +112,6 @@ static int nhrp_reg_timeout(struct thread *t)
        struct nhrp_registration *r = THREAD_ARG(t);
        struct nhrp_cache *c;
 
-       r->t_register = NULL;
 
        if (r->timeout >= 16 && sockunion_family(&r->proto_addr) != AF_UNSPEC) {
                nhrp_reqid_free(&nhrp_packet_reqid, &r->reqid);
@@ -176,7 +175,6 @@ static int nhrp_reg_send_req(struct thread *t)
        struct nhrp_extension_header *ext;
        struct nhrp_cie_header *cie;
 
-       r->t_register = NULL;
        if (!nhrp_peer_check(r->peer, 2)) {
                debugf(NHRP_DEBUG_COMMON, "NHS: Waiting link for %pSU",
                       &r->peer->vc->remote.nbma);
@@ -281,7 +279,6 @@ static void nhrp_nhs_resolve_cb(struct resolver_query *q, const char *errstr,
        struct nhrp_registration *reg, *regn;
        int i;
 
-       nhs->t_resolve = NULL;
        if (n < 0) {
                /* Failed, retry in a moment */
                thread_add_timer(master, nhrp_nhs_resolve, nhs, 5,
index 5a7da703acc7c629fe37621c35ae56bb8401794c..030f4c0ff3350498cb32e3bd4101b9e120e8d5f7 100644 (file)
@@ -265,7 +265,6 @@ static int nhrp_peer_request_timeout(struct thread *t)
        struct interface *ifp = p->ifp;
        struct nhrp_interface *nifp = ifp->info;
 
-       p->t_fallback = NULL;
 
        if (p->online)
                return 0;
index 0905ceb72a4bcfa015a67e1d3e1d5e9bee1f4e2b..244273cd5891447f24addceb1b97e9b72b1b6e76 100644 (file)
@@ -39,7 +39,6 @@ static int nhrp_shortcut_do_expire(struct thread *t)
 {
        struct nhrp_shortcut *s = THREAD_ARG(t);
 
-       s->t_timer = NULL;
        thread_add_timer(master, nhrp_shortcut_do_purge, s, s->holding_time / 3,
                         &s->t_timer);
        s->expiring = 1;
index c21e01601c14e4bb6ed7c8ed9e3945d3fe5a6454..8fce828663af5e3ec27f41ffffa7742b219a18f2 100644 (file)
@@ -361,7 +361,6 @@ static int vici_read(struct thread *t)
        struct zbuf *ibuf = &vici->ibuf;
        struct zbuf pktbuf;
 
-       vici->t_read = NULL;
        if (zbuf_read(ibuf, vici->fd, (size_t)-1) < 0) {
                vici_connection_error(vici);
                return 0;
@@ -392,7 +391,6 @@ static int vici_write(struct thread *t)
        struct vici_conn *vici = THREAD_ARG(t);
        int r;
 
-       vici->t_write = NULL;
        r = zbufq_write(&vici->obuf, vici->fd);
        if (r > 0) {
                thread_add_write(master, vici_write, vici, vici->fd,
@@ -509,7 +507,6 @@ static int vici_reconnect(struct thread *t)
        int fd;
        char *file_path;
 
-       vici->t_reconnect = NULL;
        if (vici->fd >= 0)
                return 0;
 
index aa85475678436aa3470d9217ed000db42b0c8ef5..f3e8127a80b64eee8d29d02f426410964020cba0 100644 (file)
 
 unsigned char conf_debug_ospf6_abr;
 
+int ospf6_ls_origin_same(struct ospf6_path *o_path, struct ospf6_path *r_path)
+{
+       if (((o_path->origin.type == r_path->origin.type)
+            && (o_path->origin.id == r_path->origin.id)
+            && (o_path->origin.adv_router == r_path->origin.adv_router)))
+               return 1;
+       else
+               return 0;
+}
+
 bool ospf6_check_and_set_router_abr(struct ospf6 *o)
 {
        struct listnode *node;
@@ -231,6 +241,69 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route,
                return 0;
        }
 
+       if (route->type == OSPF6_DEST_TYPE_NETWORK) {
+               bool filter = false;
+
+               route_area =
+                       ospf6_area_lookup(route->path.area_id, area->ospf6);
+               assert(route_area);
+
+               /* Check export-list */
+               if (EXPORT_LIST(route_area)
+                   && access_list_apply(EXPORT_LIST(route_area),
+                                        &route->prefix)
+                              == FILTER_DENY) {
+                       if (IS_OSPF6_DEBUG_ABR)
+                               zlog_debug(
+                                       "%s: prefix %pFX was denied by export-list",
+                                       __func__, &route->prefix);
+                       filter = true;
+               }
+
+               /* Check output prefix-list */
+               if (PREFIX_LIST_OUT(route_area)
+                   && prefix_list_apply(PREFIX_LIST_OUT(route_area),
+                                        &route->prefix)
+                              != PREFIX_PERMIT) {
+                       if (IS_OSPF6_DEBUG_ABR)
+                               zlog_debug(
+                                       "%s: prefix %pFX was denied by prefix-list out",
+                                       __func__, &route->prefix);
+                       filter = true;
+               }
+
+               /* Check import-list */
+               if (IMPORT_LIST(area)
+                   && access_list_apply(IMPORT_LIST(area), &route->prefix)
+                              == FILTER_DENY) {
+                       if (IS_OSPF6_DEBUG_ABR)
+                               zlog_debug(
+                                       "%s: prefix %pFX was denied by import-list",
+                                       __func__, &route->prefix);
+                       filter = true;
+               }
+
+               /* Check input prefix-list */
+               if (PREFIX_LIST_IN(area)
+                   && prefix_list_apply(PREFIX_LIST_IN(area), &route->prefix)
+                              != PREFIX_PERMIT) {
+                       if (IS_OSPF6_DEBUG_ABR)
+                               zlog_debug(
+                                       "%s: prefix %pFX was denied by prefix-list in",
+                                       __func__, &route->prefix);
+                       filter = true;
+               }
+
+               if (filter) {
+                       if (summary) {
+                               ospf6_route_remove(summary, summary_table);
+                               if (old)
+                                       ospf6_lsa_purge(old);
+                       }
+                       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)
@@ -430,39 +503,6 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route,
                }
        }
 
-       /* Check export list */
-       if (EXPORT_NAME(area)) {
-               if (EXPORT_LIST(area) == NULL)
-                       EXPORT_LIST(area) =
-                               access_list_lookup(AFI_IP6, EXPORT_NAME(area));
-
-               if (EXPORT_LIST(area))
-                       if (access_list_apply(EXPORT_LIST(area), &route->prefix)
-                           == FILTER_DENY) {
-                               if (is_debug)
-                                       zlog_debug(
-                                               "prefix %pFX was denied by export list",
-                                               &route->prefix);
-                               ospf6_abr_delete_route(route, summary,
-                                                      summary_table, old);
-                               return 0;
-                       }
-       }
-
-       /* Check filter-list */
-       if (PREFIX_LIST_OUT(area))
-               if (prefix_list_apply(PREFIX_LIST_OUT(area), &route->prefix)
-                   != PREFIX_PERMIT) {
-                       if (is_debug)
-                               zlog_debug(
-                                       "prefix %pFX was denied by filter-list out",
-                                       &route->prefix);
-                       ospf6_abr_delete_route(route, summary, summary_table,
-                                              old);
-
-                       return 0;
-               }
-
        /* the route is going to be originated. store it in area's summary_table
         */
        if (summary == NULL) {
@@ -785,9 +825,8 @@ void ospf6_abr_old_path_update(struct ospf6_route *old_route,
        struct ospf6_nexthop *nh, *rnh;
 
        for (ALL_LIST_ELEMENTS(old_route->paths, anode, anext, o_path)) {
-               if (o_path->area_id != route->path.area_id ||
-                   (memcmp(&(o_path)->origin, &(route)->path.origin,
-                           sizeof(struct ospf6_ls_origin)) != 0))
+               if (o_path->area_id != route->path.area_id
+                   || !ospf6_ls_origin_same(o_path, &route->path))
                        continue;
 
                if ((o_path->cost == route->path.cost) &&
@@ -1134,39 +1173,6 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
                return;
        }
 
-       /* Check import list */
-       if (IMPORT_NAME(oa)) {
-               if (IMPORT_LIST(oa) == NULL)
-                       IMPORT_LIST(oa) =
-                               access_list_lookup(AFI_IP6, IMPORT_NAME(oa));
-
-               if (IMPORT_LIST(oa))
-                       if (access_list_apply(IMPORT_LIST(oa), &prefix)
-                           == FILTER_DENY) {
-                               if (is_debug)
-                                       zlog_debug(
-                                               "Prefix %pFX was denied by import-list",
-                                               &prefix);
-                               if (old)
-                                       ospf6_route_remove(old, table);
-                               return;
-                       }
-       }
-
-       /* Check input prefix-list */
-       if (PREFIX_LIST_IN(oa)) {
-               if (prefix_list_apply(PREFIX_LIST_IN(oa), &prefix)
-                   != PREFIX_PERMIT) {
-                       if (is_debug)
-                               zlog_debug(
-                                       "Prefix %pFX was denied by prefix-list in",
-                                       &prefix);
-                       if (old)
-                               ospf6_route_remove(old, table);
-                       return;
-               }
-       }
-
        /* (5),(6): the path preference is handled by the sorting
           in the routing table. Always install the path by substituting
           old route (if any). */
@@ -1201,9 +1207,16 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
                                   __func__, &prefix, listcount(old->paths));
        }
        for (old_route = old; old_route; old_route = old_route->next) {
-               if (!ospf6_route_is_same(old_route, route) ||
-                       (old_route->type != route->type) ||
-                       (old_route->path.type != route->path.type))
+
+               /* The route linked-list is grouped in batches of prefix.
+                * If the new prefix is not the same as the one of interest
+                * then we have walked over the end of the batch and so we
+                * should break rather than continuing unnecessarily.
+                */
+               if (!ospf6_route_is_same(old_route, route))
+                       break;
+               if ((old_route->type != route->type)
+                   || (old_route->path.type != route->path.type))
                        continue;
 
                if ((ospf6_route_cmp(route, old_route) != 0)) {
@@ -1228,9 +1241,8 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
 
                for (ALL_LIST_ELEMENTS_RO(old_route->paths, anode,
                                                  o_path)) {
-                       if (o_path->area_id == route->path.area_id &&
-                           (memcmp(&(o_path)->origin, &(route)->path.origin,
-                                   sizeof(struct ospf6_ls_origin)) == 0))
+                       if (o_path->area_id == route->path.area_id
+                           && ospf6_ls_origin_same(o_path, &route->path))
                                break;
                }
 
@@ -1348,35 +1360,6 @@ void ospf6_abr_examin_brouter(uint32_t router_id, struct ospf6_route *route,
                ospf6_abr_examin_summary(lsa, oa);
 }
 
-void ospf6_abr_reimport(struct ospf6_area *oa)
-{
-       struct ospf6_lsa *lsa;
-       uint16_t type;
-
-       type = htons(OSPF6_LSTYPE_INTER_ROUTER);
-       for (ALL_LSDB_TYPED(oa->lsdb, type, lsa))
-               ospf6_abr_examin_summary(lsa, oa);
-
-       type = htons(OSPF6_LSTYPE_INTER_PREFIX);
-       for (ALL_LSDB_TYPED(oa->lsdb, type, lsa))
-               ospf6_abr_examin_summary(lsa, oa);
-}
-
-/* export filter removed so determine if we should reoriginate summary LSAs */
-void ospf6_abr_reexport(struct ospf6_area *oa)
-{
-       struct ospf6_route *route;
-
-       /* if not a ABR return success */
-       if (!ospf6_check_and_set_router_abr(oa->ospf6))
-               return;
-
-       /* Redo summaries if required */
-       for (route = ospf6_route_head(oa->ospf6->route_table); route;
-            route = ospf6_route_next(route))
-               ospf6_abr_originate_summary_to_area(route, oa);
-}
-
 void ospf6_abr_prefix_resummarize(struct ospf6 *o)
 {
        struct ospf6_route *route;
index a5f0f124b9421fa48d503820a3dc4590238ef0e3..a4dc4ddc843e32708ef82de6c7b9e681e5e3d029 100644 (file)
@@ -73,8 +73,6 @@ extern void ospf6_abr_defaults_to_stub(struct ospf6 *ospf6);
 extern void ospf6_abr_examin_brouter(uint32_t router_id,
                                     struct ospf6_route *route,
                                     struct ospf6 *ospf6);
-extern void ospf6_abr_reimport(struct ospf6_area *oa);
-extern void ospf6_abr_reexport(struct ospf6_area *oa);
 extern void ospf6_abr_range_reset_cost(struct ospf6 *ospf6);
 extern void ospf6_abr_prefix_resummarize(struct ospf6 *ospf6);
 
@@ -88,9 +86,10 @@ extern void ospf6_abr_old_path_update(struct ospf6_route *old_route,
                                      struct ospf6_route *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);
+extern int ospf6_ls_origin_same(struct ospf6_path *o_path,
+                               struct ospf6_path *r_path);
 
 #endif /*OSPF6_ABR_H*/
index 71d32b409c260b26bbdda5420a810b6c6f4dc689..999266b8d1ac16192591cc0f53afe45b102a26a9 100644 (file)
@@ -43,6 +43,7 @@
 #include "ospf6_intra.h"
 #include "ospf6_abr.h"
 #include "ospf6_asbr.h"
+#include "ospf6_zebra.h"
 #include "ospf6d.h"
 #include "lib/json.h"
 #include "ospf6_nssa.h"
@@ -234,6 +235,36 @@ static void ospf6_area_no_summary_unset(struct ospf6 *ospf6,
        }
 }
 
+static void ospf6_nssa_default_originate_set(struct ospf6 *ospf6,
+                                            struct ospf6_area *area,
+                                            int metric, int metric_type)
+{
+       if (!area->nssa_default_originate.enabled) {
+               area->nssa_default_originate.enabled = true;
+               if (++ospf6->nssa_default_import_check.refcnt == 1) {
+                       ospf6->nssa_default_import_check.status = false;
+                       ospf6_zebra_import_default_route(ospf6, false);
+               }
+       }
+
+       area->nssa_default_originate.metric_value = metric;
+       area->nssa_default_originate.metric_type = metric_type;
+}
+
+static void ospf6_nssa_default_originate_unset(struct ospf6 *ospf6,
+                                              struct ospf6_area *area)
+{
+       if (area->nssa_default_originate.enabled) {
+               area->nssa_default_originate.enabled = false;
+               if (--ospf6->nssa_default_import_check.refcnt == 0) {
+                       ospf6->nssa_default_import_check.status = false;
+                       ospf6_zebra_import_default_route(ospf6, true);
+               }
+               area->nssa_default_originate.metric_value = -1;
+               area->nssa_default_originate.metric_type = -1;
+       }
+}
+
 /**
  * Make new area structure.
  *
@@ -648,6 +679,17 @@ void ospf6_area_config_write(struct vty *vty, struct ospf6 *ospf6)
                }
                if (IS_AREA_NSSA(oa)) {
                        vty_out(vty, " area %s nssa", oa->name);
+                       if (oa->nssa_default_originate.enabled) {
+                               vty_out(vty, " default-information-originate");
+                               if (oa->nssa_default_originate.metric_value
+                                   != -1)
+                                       vty_out(vty, " metric %d",
+                                               oa->nssa_default_originate
+                                                       .metric_value);
+                               if (oa->nssa_default_originate.metric_type
+                                   != DEFAULT_METRIC_TYPE)
+                                       vty_out(vty, " metric-type 1");
+                       }
                        if (oa->no_summary)
                                vty_out(vty, " no-summary");
                        vty_out(vty, "\n");
@@ -696,17 +738,17 @@ DEFUN (area_filter_list,
                XFREE(MTYPE_OSPF6_PLISTNAME, PREFIX_NAME_IN(area));
                PREFIX_NAME_IN(area) =
                        XSTRDUP(MTYPE_OSPF6_PLISTNAME, plistname);
-               ospf6_abr_reimport(area);
        } else {
                PREFIX_LIST_OUT(area) = plist;
                XFREE(MTYPE_OSPF6_PLISTNAME, PREFIX_NAME_OUT(area));
                PREFIX_NAME_OUT(area) =
                        XSTRDUP(MTYPE_OSPF6_PLISTNAME, plistname);
-
-               /* Redo summaries if required */
-               ospf6_abr_reexport(area);
        }
 
+       /* Redo summaries if required */
+       if (ospf6_check_and_set_router_abr(area->ospf6))
+               ospf6_schedule_abr_task(ospf6);
+
        return CMD_SUCCESS;
 }
 
@@ -739,7 +781,6 @@ DEFUN (no_area_filter_list,
 
                PREFIX_LIST_IN(area) = NULL;
                XFREE(MTYPE_OSPF6_PLISTNAME, PREFIX_NAME_IN(area));
-               ospf6_abr_reimport(area);
        } else {
                if (PREFIX_NAME_OUT(area))
                        if (!strmatch(PREFIX_NAME_OUT(area), plistname))
@@ -747,9 +788,12 @@ DEFUN (no_area_filter_list,
 
                XFREE(MTYPE_OSPF6_PLISTNAME, PREFIX_NAME_OUT(area));
                PREFIX_LIST_OUT(area) = NULL;
-               ospf6_abr_reexport(area);
        }
 
+       /* Redo summaries if required */
+       if (ospf6_check_and_set_router_abr(area->ospf6))
+               ospf6_schedule_abr_task(ospf6);
+
        return CMD_SUCCESS;
 }
 
@@ -760,19 +804,30 @@ void ospf6_filter_update(struct access_list *access)
        struct ospf6 *ospf6;
 
        for (ALL_LIST_ELEMENTS(om6->ospf6, node, nnode, ospf6)) {
+               bool update = false;
+
                for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, n, oa)) {
                        if (IMPORT_NAME(oa)
-                           && strcmp(IMPORT_NAME(oa), access->name) == 0)
-                               ospf6_abr_reimport(oa);
+                           && strcmp(IMPORT_NAME(oa), access->name) == 0) {
+                               IMPORT_LIST(oa) = access_list_lookup(
+                                       AFI_IP6, IMPORT_NAME(oa));
+                               update = true;
+                       }
 
                        if (EXPORT_NAME(oa)
-                           && strcmp(EXPORT_NAME(oa), access->name) == 0)
-                               ospf6_abr_reexport(oa);
+                           && strcmp(EXPORT_NAME(oa), access->name) == 0) {
+                               EXPORT_LIST(oa) = access_list_lookup(
+                                       AFI_IP6, EXPORT_NAME(oa));
+                               update = true;
+                       }
                }
+
+               if (update && ospf6_check_and_set_router_abr(ospf6))
+                       ospf6_schedule_abr_task(ospf6);
        }
 }
 
-void ospf6_area_plist_update(struct prefix_list *plist, int add)
+void ospf6_plist_update(struct prefix_list *plist)
 {
        struct listnode *node, *nnode;
        struct ospf6_area *oa;
@@ -780,23 +835,29 @@ void ospf6_area_plist_update(struct prefix_list *plist, int add)
        const char *name = prefix_list_name(plist);
        struct ospf6 *ospf6 = NULL;
 
-
-       if (!om6->ospf6)
+       if (prefix_list_afi(plist) != AFI_IP6)
                return;
 
        for (ALL_LIST_ELEMENTS(om6->ospf6, node, nnode, ospf6)) {
+               bool update = false;
+
                for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, n, oa)) {
                        if (PREFIX_NAME_IN(oa)
                            && !strcmp(PREFIX_NAME_IN(oa), name)) {
-                               PREFIX_LIST_IN(oa) = add ? plist : NULL;
-                               ospf6_abr_reexport(oa);
+                               PREFIX_LIST_IN(oa) = prefix_list_lookup(
+                                       AFI_IP6, PREFIX_NAME_IN(oa));
+                               update = true;
                        }
                        if (PREFIX_NAME_OUT(oa)
                            && !strcmp(PREFIX_NAME_OUT(oa), name)) {
-                               PREFIX_LIST_OUT(oa) = add ? plist : NULL;
-                               ospf6_abr_reexport(oa);
+                               PREFIX_LIST_OUT(oa) = prefix_list_lookup(
+                                       AFI_IP6, PREFIX_NAME_OUT(oa));
+                               update = true;
                        }
                }
+
+               if (update && ospf6_check_and_set_router_abr(ospf6))
+                       ospf6_schedule_abr_task(ospf6);
        }
 }
 
@@ -826,7 +887,8 @@ DEFUN (area_import_list,
                free(IMPORT_NAME(area));
 
        IMPORT_NAME(area) = strdup(argv[idx_name]->arg);
-       ospf6_abr_reimport(area);
+       if (ospf6_check_and_set_router_abr(area->ospf6))
+               ospf6_schedule_abr_task(ospf6);
 
        return CMD_SUCCESS;
 }
@@ -848,13 +910,14 @@ DEFUN (no_area_import_list,
 
        OSPF6_CMD_AREA_GET(argv[idx_ipv4]->arg, area, ospf6);
 
-       IMPORT_LIST(area) = 0;
+       IMPORT_LIST(area) = NULL;
 
        if (IMPORT_NAME(area))
                free(IMPORT_NAME(area));
 
        IMPORT_NAME(area) = NULL;
-       ospf6_abr_reimport(area);
+       if (ospf6_check_and_set_router_abr(area->ospf6))
+               ospf6_schedule_abr_task(ospf6);
 
        return CMD_SUCCESS;
 }
@@ -887,7 +950,8 @@ DEFUN (area_export_list,
        EXPORT_NAME(area) = strdup(argv[idx_name]->arg);
 
        /* Redo summaries if required */
-       ospf6_abr_reexport(area);
+       if (ospf6_check_and_set_router_abr(area->ospf6))
+               ospf6_schedule_abr_task(ospf6);
 
        return CMD_SUCCESS;
 }
@@ -909,13 +973,14 @@ DEFUN (no_area_export_list,
 
        OSPF6_CMD_AREA_GET(argv[idx_ipv4]->arg, area, ospf6);
 
-       EXPORT_LIST(area) = 0;
+       EXPORT_LIST(area) = NULL;
 
        if (EXPORT_NAME(area))
                free(EXPORT_NAME(area));
 
        EXPORT_NAME(area) = NULL;
-       ospf6_abr_reexport(area);
+       if (ospf6_check_and_set_router_abr(area->ospf6))
+               ospf6_schedule_abr_task(ospf6);
 
        return CMD_SUCCESS;
 }
@@ -988,7 +1053,6 @@ DEFUN(show_ipv6_ospf6_spf_tree, show_ipv6_ospf6_spf_tree_cmd,
        int idx_vrf = 0;
        bool uj = use_json(argc, argv);
 
-       OSPF6_CMD_CHECK_RUNNING();
        OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
 
        for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) {
@@ -1048,7 +1112,6 @@ DEFUN(show_ipv6_ospf6_area_spf_tree, show_ipv6_ospf6_area_spf_tree_cmd,
        bool all_vrf = false;
        int idx_vrf = 0;
 
-       OSPF6_CMD_CHECK_RUNNING();
        OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
        if (idx_vrf > 0)
                idx_ipv4 += 2;
@@ -1132,7 +1195,6 @@ DEFUN(show_ipv6_ospf6_simulate_spf_tree_root,
        bool all_vrf = false;
        int idx_vrf = 0;
 
-       OSPF6_CMD_CHECK_RUNNING();
        OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
        if (idx_vrf > 0) {
                idx_ipv4 += 2;
@@ -1258,11 +1320,20 @@ DEFUN (no_ospf6_area_stub_no_summary,
 }
 
 DEFPY(ospf6_area_nssa, ospf6_area_nssa_cmd,
-      "area <A.B.C.D|(0-4294967295)>$area_str nssa [no-summary$no_summary]",
+      "area <A.B.C.D|(0-4294967295)>$area_str nssa\
+        [{\
+         default-information-originate$dflt_originate [{metric (0-16777214)$mval|metric-type (1-2)$mtype}]\
+         |no-summary$no_summary\
+        }]",
       "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"
+      "Originate Type 7 default into NSSA area\n"
+      "OSPFv3 default metric\n"
+      "OSPFv3 metric\n"
+      "OSPFv3 metric type for default routes\n"
+      "Set OSPFv3 External Type 1/2 metrics\n"
       "Do not inject inter-area routes into area\n")
 {
        struct ospf6_area *area;
@@ -1276,23 +1347,44 @@ DEFPY(ospf6_area_nssa, ospf6_area_nssa_cmd,
                return CMD_WARNING_CONFIG_FAILED;
        }
 
+       if (dflt_originate) {
+               if (mval_str == NULL)
+                       mval = -1;
+               if (mtype_str == NULL)
+                       mtype = DEFAULT_METRIC_TYPE;
+               ospf6_nssa_default_originate_set(ospf6, area, mval, mtype);
+       } else
+               ospf6_nssa_default_originate_unset(ospf6, area);
+
        if (no_summary)
                ospf6_area_no_summary_set(ospf6, area);
        else
                ospf6_area_no_summary_unset(ospf6, area);
-       if (ospf6_check_and_set_router_abr(ospf6))
+
+       if (ospf6_check_and_set_router_abr(ospf6)) {
                ospf6_abr_defaults_to_stub(ospf6);
+               ospf6_abr_nssa_type_7_defaults(ospf6);
+       }
 
        return CMD_SUCCESS;
 }
 
 DEFPY(no_ospf6_area_nssa, no_ospf6_area_nssa_cmd,
-      "no area <A.B.C.D|(0-4294967295)>$area_str nssa [no-summary$no_summary]",
+      "no area <A.B.C.D|(0-4294967295)>$area_str nssa\
+        [{\
+         default-information-originate [{metric (0-16777214)|metric-type (1-2)}]\
+         |no-summary\
+        }]",
       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"
+      "Originate Type 7 default into NSSA area\n"
+      "OSPFv3 default metric\n"
+      "OSPFv3 metric\n"
+      "OSPFv3 metric type for default routes\n"
+      "Set OSPFv3 External Type 1/2 metrics\n"
       "Do not inject inter-area routes into area\n")
 {
        struct ospf6_area *area;
@@ -1302,6 +1394,7 @@ DEFPY(no_ospf6_area_nssa, no_ospf6_area_nssa_cmd,
 
        ospf6_area_nssa_unset(ospf6, area);
        ospf6_area_no_summary_unset(ospf6, area);
+       ospf6_nssa_default_originate_unset(ospf6, area);
 
        return CMD_SUCCESS;
 }
@@ -1340,8 +1433,6 @@ void ospf6_area_interface_delete(struct ospf6_interface *oi)
        struct listnode *node, *nnode;
        struct ospf6 *ospf6;
 
-       if (!om6->ospf6)
-               return;
        for (ALL_LIST_ELEMENTS(om6->ospf6, node, nnode, ospf6)) {
                for (ALL_LIST_ELEMENTS(ospf6->area_list, node, nnode, oa))
                        if (listnode_lookup(oa->if_list, oi))
index b2a275d745bedb0a5e27804de516e74b0bcf9704..77cbad8b9ea55f1a151661afb2f117825608bea6 100644 (file)
@@ -52,8 +52,15 @@ struct ospf6_area {
        /* Area type */
        int no_summary;
 
+       /* NSSA default-information-originate */
+       struct {
+               bool enabled;
+               int metric_type;
+               int metric_value;
+       } nssa_default_originate;
+
        /* Brouter traversal protection */
-       int intra_brouter_calc;
+       bool intra_brouter_calc;
 
        /* OSPF interface list */
        struct list *if_list;
@@ -149,19 +156,21 @@ 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);
-extern void ospf6_area_delete(struct ospf6_area *);
-extern struct ospf6_area *ospf6_area_lookup(uint32_t, struct ospf6 *);
+extern struct ospf6_area *ospf6_area_create(uint32_t area_id,
+                                           struct ospf6 *ospf6, int df);
+extern void ospf6_area_delete(struct ospf6_area *oa);
+extern struct ospf6_area *ospf6_area_lookup(uint32_t area_id,
+                                           struct ospf6 *ospf6);
 extern struct ospf6_area *ospf6_area_lookup_by_area_id(uint32_t area_id);
 
 extern void ospf6_area_stub_unset(struct ospf6 *ospf6, struct ospf6_area *area);
-extern void ospf6_area_enable(struct ospf6_area *);
-extern void ospf6_area_disable(struct ospf6_area *);
+extern void ospf6_area_enable(struct ospf6_area *oa);
+extern void ospf6_area_disable(struct ospf6_area *oa);
 
-extern void ospf6_area_show(struct vty *, struct ospf6_area *,
+extern void ospf6_area_show(struct vty *vty, struct ospf6_area *oa,
                            json_object *json_areas, bool use_json);
 
-extern void ospf6_area_plist_update(struct prefix_list *plist, int add);
+extern void ospf6_plist_update(struct prefix_list *plist);
 extern void ospf6_filter_update(struct access_list *access);
 extern void ospf6_area_config_write(struct vty *vty, struct ospf6 *ospf6);
 extern void ospf6_area_init(void);
index b5bf81c2131579ef8f82f04c8669511285ce1797..733f4ba1fb71df45b6b5fd279b5e1ab3ab50b9a1 100644 (file)
 #include "ospf6_abr.h"
 #include "ospf6_intra.h"
 #include "ospf6_flood.h"
+#include "ospf6_nssa.h"
 #include "ospf6d.h"
 #include "ospf6_spf.h"
 #include "ospf6_nssa.h"
+#include "ospf6_gr.h"
 #include "lib/json.h"
 
 DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_EXTERNAL_INFO, "OSPF6 ext. info");
@@ -84,7 +86,7 @@ static struct ospf6_lsa *ospf6_originate_type5_type7_lsas(
 
        for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, lnode, oa)) {
                if (IS_AREA_NSSA(oa))
-                       ospf6_nssa_lsa_originate(route, oa);
+                       ospf6_nssa_lsa_originate(route, oa, true);
        }
 
        return lsa;
@@ -102,6 +104,13 @@ struct ospf6_lsa *ospf6_as_external_lsa_originate(struct ospf6_route *route,
        struct ospf6_as_external_lsa *as_external_lsa;
        caddr_t p;
 
+       if (ospf6->gr_info.restart_in_progress) {
+               if (IS_DEBUG_OSPF6_GR)
+                       zlog_debug(
+                               "Graceful Restart in progress, don't originate LSA");
+               return NULL;
+       }
+
        if (IS_OSPF6_DEBUG_ASBR || IS_OSPF6_DEBUG_ORIGINATE(AS_EXTERNAL))
                zlog_debug("Originate AS-External-LSA for %pFX",
                           &route->prefix);
@@ -262,8 +271,14 @@ void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old,
 
                next_route = old_route->next;
 
-               if (!ospf6_route_is_same(old_route, route)
-                   || (old_route->path.type != route->path.type))
+               /* The route linked-list is grouped in batches of prefix.
+                * If the new prefix is not the same as the one of interest
+                * then we have walked over the end of the batch and so we
+                * should break rather than continuing unnecessarily.
+                */
+               if (!ospf6_route_is_same(old_route, route))
+                       break;
+               if (old_route->path.type != route->path.type)
                        continue;
 
                /* Current and New route has same origin,
@@ -275,9 +290,7 @@ void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old,
                         * origin.
                         */
                        if (o_path->area_id != route->path.area_id
-                           || (memcmp(&(o_path)->origin, &(route)->path.origin,
-                                      sizeof(struct ospf6_ls_origin))
-                               != 0))
+                           || !ospf6_ls_origin_same(o_path, &route->path))
                                continue;
 
                        /* Cost is not same then delete current path */
@@ -367,11 +380,14 @@ void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old,
        /* Add new route */
        for (old_route = old; old_route; old_route = old_route->next) {
 
-               /* Current and New Route prefix or route type
-                * is not same skip this current node.
+               /* The route linked-list is grouped in batches of prefix.
+                * If the new prefix is not the same as the one of interest
+                * then we have walked over the end of the batch and so we
+                * should break rather than continuing unnecessarily.
                 */
-               if (!ospf6_route_is_same(old_route, route)
-                   || (old_route->path.type != route->path.type))
+               if (!ospf6_route_is_same(old_route, route))
+                       break;
+               if (old_route->path.type != route->path.type)
                        continue;
 
                /* Old Route and New Route have Equal Cost, Merge NHs */
@@ -393,10 +409,7 @@ void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old,
                        for (ALL_LIST_ELEMENTS_RO(old_route->paths, anode,
                                                  o_path)) {
                                if (o_path->area_id == route->path.area_id
-                                   && (memcmp(&(o_path)->origin,
-                                              &(route)->path.origin,
-                                              sizeof(struct ospf6_ls_origin))
-                                       == 0))
+                                   && ospf6_ls_origin_same(o_path, &route->path))
                                        break;
                        }
                        /* If path is not found in old_route paths's list,
@@ -1121,7 +1134,6 @@ void ospf6_asbr_distribute_list_update(struct ospf6 *ospf6,
        if (IS_OSPF6_DEBUG_ASBR)
                zlog_debug("%s: trigger redistribute reset thread", __func__);
 
-       ospf6->t_distribute_update = NULL;
        thread_add_timer_msec(master, ospf6_asbr_routemap_update_timer, ospf6,
                              OSPF_MIN_LS_INTERVAL,
                              &ospf6->t_distribute_update);
@@ -1416,7 +1428,10 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex,
        memset(&tinfo, 0, sizeof(tinfo));
 
        if (IS_OSPF6_DEBUG_ASBR)
-               zlog_debug("Redistribute %pFX (%s)", prefix, ZROUTE_NAME(type));
+               zlog_debug("Redistribute %pFX (%s)", prefix,
+                          type == DEFAULT_ROUTE
+                                  ? "default-information-originate"
+                                  : ZROUTE_NAME(type));
 
        /* if route-map was specified but not found, do not advertise */
        if (ROUTEMAP_NAME(red)) {
@@ -1770,7 +1785,7 @@ int ospf6_redistribute_config_write(struct vty *vty, struct ospf6 *ospf6)
                vty_out(vty, " redistribute %s", ZROUTE_NAME(type));
                if (red->dmetric.value >= 0)
                        vty_out(vty, " metric %d", red->dmetric.value);
-               if (red->dmetric.type != DEFAULT_METRIC_TYPE)
+               if (red->dmetric.type == 1)
                        vty_out(vty, " metric-type 1");
                if (ROUTEMAP_NAME(red))
                        vty_out(vty, " route-map %s", ROUTEMAP_NAME(red));
@@ -2513,7 +2528,6 @@ DEFUN(show_ipv6_ospf6_redistribute, show_ipv6_ospf6_redistribute_cmd,
        json_object *json_array_routes = NULL;
        json_object *json_array_redistribute = NULL;
 
-       OSPF6_CMD_CHECK_RUNNING();
        OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
 
        if (uj) {
index f13ed3e3bbf2fed816008c873c8f58f519fdbb24..150903a56af434d73f747e4bff6b9cf008424c99 100644 (file)
@@ -85,7 +85,7 @@ struct ospf6_lsdb *ospf6_get_scoped_lsdb_self(struct ospf6_lsa *lsa)
        return lsdb_self;
 }
 
-void ospf6_lsa_originate(struct ospf6_lsa *lsa)
+void ospf6_lsa_originate(struct ospf6 *ospf6, struct ospf6_lsa *lsa)
 {
        struct ospf6_lsa *old;
        struct ospf6_lsdb *lsdb_self;
@@ -106,7 +106,8 @@ void ospf6_lsa_originate(struct ospf6_lsa *lsa)
 
        /* if the new LSA does not differ from previous,
           suppress this update of the LSA */
-       if (old && !OSPF6_LSA_IS_DIFFER(lsa, old)) {
+       if (old && !OSPF6_LSA_IS_DIFFER(lsa, old)
+           && !ospf6->gr_info.finishing_restart) {
                if (IS_OSPF6_DEBUG_ORIGINATE_TYPE(lsa->header->type))
                        zlog_debug("Suppress updating LSA: %s", lsa->name);
                ospf6_lsa_delete(lsa);
@@ -134,20 +135,20 @@ void ospf6_lsa_originate(struct ospf6_lsa *lsa)
 void ospf6_lsa_originate_process(struct ospf6_lsa *lsa, struct ospf6 *process)
 {
        lsa->lsdb = process->lsdb;
-       ospf6_lsa_originate(lsa);
+       ospf6_lsa_originate(process, lsa);
 }
 
 void ospf6_lsa_originate_area(struct ospf6_lsa *lsa, struct ospf6_area *oa)
 {
        lsa->lsdb = oa->lsdb;
-       ospf6_lsa_originate(lsa);
+       ospf6_lsa_originate(oa->ospf6, lsa);
 }
 
 void ospf6_lsa_originate_interface(struct ospf6_lsa *lsa,
                                   struct ospf6_interface *oi)
 {
        lsa->lsdb = oi->lsdb;
-       ospf6_lsa_originate(lsa);
+       ospf6_lsa_originate(oi->area->ospf6, lsa);
 }
 
 void ospf6_remove_id_from_external_id_table(struct ospf6 *ospf6,
@@ -287,7 +288,6 @@ void ospf6_install_lsa(struct ospf6_lsa *lsa)
 
        monotime(&now);
        if (!OSPF6_LSA_IS_MAXAGE(lsa)) {
-               lsa->expire = NULL;
                thread_add_timer(master, ospf6_lsa_expire, lsa,
                                 OSPF_LSA_MAXAGE + lsa->birth.tv_sec
                                         - now.tv_sec,
@@ -326,7 +326,8 @@ void ospf6_install_lsa(struct ospf6_lsa *lsa)
        lsa->installed = now;
 
        /* Topo change handling */
-       if (CHECK_LSA_TOPO_CHG_ELIGIBLE(ntohs(lsa->header->type))) {
+       if (CHECK_LSA_TOPO_CHG_ELIGIBLE(ntohs(lsa->header->type))
+           && !CHECK_FLAG(lsa->flag, OSPF6_LSA_DUPLICATE)) {
 
                /* check if it is new lsa ? or existing lsa got modified ?*/
                if (!old || OSPF6_LSA_IS_CHANGED(old, lsa)) {
@@ -545,7 +546,6 @@ void ospf6_flood_interface(struct ospf6_neighbor *from, struct ospf6_lsa *lsa,
                /* reschedule retransmissions to all neighbors */
                for (ALL_LIST_ELEMENTS(oi->neighbor_list, node, nnode, on)) {
                        THREAD_OFF(on->thread_send_lsupdate);
-                       on->thread_send_lsupdate = NULL;
                        thread_add_event(master, ospf6_lsupdate_send_neighbor,
                                         on, 0, &on->thread_send_lsupdate);
                }
@@ -991,6 +991,8 @@ void ospf6_receive_lsa(struct ospf6_neighbor *from,
 
        /* if no database copy or received is more recent */
        if (old == NULL || ismore_recent < 0) {
+               bool self_originated;
+
                /* in case we have no database copy */
                ismore_recent = -1;
 
@@ -1024,17 +1026,11 @@ void ospf6_receive_lsa(struct ospf6_neighbor *from,
                if (old)
                        ospf6_flood_clear(old);
 
-               /* (b) immediately flood and (c) remove from all retrans-list */
-               /* Prevent self-originated LSA to be flooded. this is to make
-               reoriginated instance of the LSA not to be rejected by other
-               routers
-               due to MinLSArrival. */
-               if (new->header->adv_router
-                   != from->ospf6_if->area->ospf6->router_id)
-                       ospf6_flood(from, new);
+               self_originated = (new->header->adv_router
+                                  == from->ospf6_if->area->ospf6->router_id);
 
-               /* Received Grace-LSA */
-               if (IS_GRACE_LSA(new)) {
+               /* Received non-self-originated Grace LSA. */
+               if (IS_GRACE_LSA(new) && !self_originated) {
                        struct ospf6 *ospf6;
 
                        ospf6 = ospf6_get_by_lsdb(new);
@@ -1077,6 +1073,14 @@ void ospf6_receive_lsa(struct ospf6_neighbor *from,
                        }
                }
 
+               /* (b) immediately flood and (c) remove from all retrans-list */
+               /* Prevent self-originated LSA to be flooded. this is to make
+                * reoriginated instance of the LSA not to be rejected by other
+                * routers due to MinLSArrival.
+                */
+               if (!self_originated)
+                       ospf6_flood(from, new);
+
                /* (d), installing lsdb, which may cause routing
                        table calculation (replacing database copy) */
                ospf6_install_lsa(new);
@@ -1088,8 +1092,16 @@ void ospf6_receive_lsa(struct ospf6_neighbor *from,
                ospf6_acknowledge_lsa(new, ismore_recent, from);
 
                /* (f) Self Originated LSA, section 13.4 */
-               if (new->header->adv_router
-                   == from->ospf6_if->area->ospf6->router_id) {
+               if (self_originated) {
+                       if (from->ospf6_if->area->ospf6->gr_info
+                                   .restart_in_progress) {
+                               if (IS_DEBUG_OSPF6_GR)
+                                       zlog_debug(
+                                               "Graceful Restart in progress -- not flushing self-originated LSA: %s",
+                                               new->name);
+                               return;
+                       }
+
                        /* Self-originated LSA (newer than ours) is received
                           from
                           another router. We have to make a new instance of the
@@ -1100,11 +1112,15 @@ void ospf6_receive_lsa(struct ospf6_neighbor *from,
                                        "Newer instance of the self-originated LSA");
                                zlog_debug("Schedule reorigination");
                        }
-                       new->refresh = NULL;
                        thread_add_event(master, ospf6_lsa_refresh, new, 0,
                                         &new->refresh);
                }
 
+               struct ospf6 *ospf6 = from->ospf6_if->area->ospf6;
+               struct ospf6_area *area = from->ospf6_if->area;
+               if (ospf6->gr_info.restart_in_progress)
+                       ospf6_gr_check_lsdb_consistency(ospf6, area);
+
                return;
        }
 
@@ -1221,7 +1237,6 @@ void ospf6_receive_lsa(struct ospf6_neighbor *from,
                        ospf6_lsa_delete(new);
                        return;
                }
-               return;
        }
 }
 
index 4e4fc55ed4a501efa797c518c948d1b4706aae92..775d0d289d34ed0e3a5b54fcab355c1e6cbffe9b 100644 (file)
@@ -32,7 +32,7 @@ extern struct ospf6_lsdb *ospf6_get_scoped_lsdb(struct ospf6_lsa *lsa);
 extern struct ospf6_lsdb *ospf6_get_scoped_lsdb_self(struct ospf6_lsa *lsa);
 
 /* origination & purging */
-extern void ospf6_lsa_originate(struct ospf6_lsa *lsa);
+extern void ospf6_lsa_originate(struct ospf6 *ospf6, struct ospf6_lsa *lsa);
 extern void ospf6_lsa_originate_process(struct ospf6_lsa *lsa,
                                        struct ospf6 *process);
 extern void ospf6_lsa_originate_area(struct ospf6_lsa *lsa,
diff --git a/ospf6d/ospf6_gr.c b/ospf6d/ospf6_gr.c
new file mode 100644 (file)
index 0000000..40893ed
--- /dev/null
@@ -0,0 +1,749 @@
+/*
+ * This is an implementation of RFC 5187 Graceful Restart.
+ *
+ * Copyright 2021 NetDEF (c), All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <zebra.h>
+
+#include "memory.h"
+#include "command.h"
+#include "table.h"
+#include "vty.h"
+#include "log.h"
+#include "hook.h"
+#include "printfrr.h"
+
+#include "ospf6d/ospf6_lsa.h"
+#include "ospf6d/ospf6_lsdb.h"
+#include "ospf6d/ospf6_route.h"
+#include "ospf6d/ospf6_area.h"
+#include "ospf6d/ospf6_interface.h"
+#include "ospf6d/ospf6d.h"
+#include "ospf6d/ospf6_asbr.h"
+#include "ospf6d/ospf6_zebra.h"
+#include "ospf6d/ospf6_message.h"
+#include "ospf6d/ospf6_neighbor.h"
+#include "ospf6d/ospf6_flood.h"
+#include "ospf6d/ospf6_intra.h"
+#include "ospf6d/ospf6_spf.h"
+#include "ospf6d/ospf6_gr.h"
+#ifndef VTYSH_EXTRACT_PL
+#include "ospf6d/ospf6_gr_clippy.c"
+#endif
+
+static void ospf6_gr_nvm_delete(struct ospf6 *ospf6);
+
+/* Originate and install Grace-LSA for a given interface. */
+static int ospf6_gr_lsa_originate(struct ospf6_interface *oi)
+{
+       struct ospf6_gr_info *gr_info = &oi->area->ospf6->gr_info;
+       struct ospf6_lsa_header *lsa_header;
+       struct ospf6_grace_lsa *grace_lsa;
+       struct ospf6_lsa *lsa;
+       char buffer[OSPF6_MAX_LSASIZE];
+
+       if (IS_OSPF6_DEBUG_ORIGINATE(LINK))
+               zlog_debug("Originate Link-LSA for Interface %s",
+                          oi->interface->name);
+
+       /* prepare buffer */
+       memset(buffer, 0, sizeof(buffer));
+       lsa_header = (struct ospf6_lsa_header *)buffer;
+       grace_lsa =
+               (struct ospf6_grace_lsa *)((caddr_t)lsa_header
+                                          + sizeof(struct ospf6_lsa_header));
+
+       /* Put grace period. */
+       grace_lsa->tlv_period.header.type = htons(GRACE_PERIOD_TYPE);
+       grace_lsa->tlv_period.header.length = htons(GRACE_PERIOD_LENGTH);
+       grace_lsa->tlv_period.interval = htonl(gr_info->grace_period);
+
+       /* Put restart reason. */
+       grace_lsa->tlv_reason.header.type = htons(RESTART_REASON_TYPE);
+       grace_lsa->tlv_reason.header.length = htons(RESTART_REASON_LENGTH);
+       if (gr_info->restart_support)
+               grace_lsa->tlv_reason.reason = OSPF6_GR_SW_RESTART;
+       else
+               grace_lsa->tlv_reason.reason = OSPF6_GR_UNKNOWN_RESTART;
+
+       /* Fill LSA Header */
+       lsa_header->age = 0;
+       lsa_header->type = htons(OSPF6_LSTYPE_GRACE_LSA);
+       lsa_header->id = htonl(oi->interface->ifindex);
+       lsa_header->adv_router = oi->area->ospf6->router_id;
+       lsa_header->seqnum =
+               ospf6_new_ls_seqnum(lsa_header->type, lsa_header->id,
+                                   lsa_header->adv_router, oi->lsdb);
+       lsa_header->length = htons(sizeof(*lsa_header) + sizeof(*grace_lsa));
+
+       /* LSA checksum */
+       ospf6_lsa_checksum(lsa_header);
+
+       /* create LSA */
+       lsa = ospf6_lsa_create(lsa_header);
+
+       /* Originate */
+       ospf6_lsa_originate_interface(lsa, oi);
+
+       return 0;
+}
+
+/* Flush all self-originated Grace-LSAs. */
+static void ospf6_gr_flush_grace_lsas(struct ospf6 *ospf6)
+{
+       struct ospf6_area *area;
+       struct listnode *anode;
+
+       for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, anode, area)) {
+               struct ospf6_lsa *lsa;
+               struct ospf6_interface *oi;
+               struct listnode *inode;
+
+               if (IS_DEBUG_OSPF6_GR)
+                       zlog_debug(
+                               "GR: flushing self-originated Grace-LSAs [area %pI4]",
+                               &area->area_id);
+
+               for (ALL_LIST_ELEMENTS_RO(area->if_list, inode, oi)) {
+                       lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_GRACE_LSA),
+                                               htonl(oi->interface->ifindex),
+                                               oi->area->ospf6->router_id,
+                                               oi->lsdb);
+                       if (!lsa) {
+                               zlog_warn(
+                                       "%s: Grace-LSA not found [interface %s] [area %pI4]",
+                                       __func__, oi->interface->name,
+                                       &area->area_id);
+                               continue;
+                       }
+
+                       ospf6_lsa_purge(lsa);
+               }
+       }
+}
+
+/* Exit from the Graceful Restart mode. */
+static void ospf6_gr_restart_exit(struct ospf6 *ospf6, const char *reason)
+{
+       struct ospf6_area *area;
+       struct listnode *onode, *anode;
+
+       if (IS_DEBUG_OSPF6_GR)
+               zlog_debug("GR: exiting graceful restart: %s", reason);
+
+       ospf6->gr_info.restart_in_progress = false;
+       ospf6->gr_info.finishing_restart = true;
+       THREAD_OFF(ospf6->gr_info.t_grace_period);
+
+       /* Record in non-volatile memory that the restart is complete. */
+       ospf6_gr_nvm_delete(ospf6);
+
+       for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, onode, area)) {
+               struct ospf6_interface *oi;
+
+               /*
+                * 1) The router should reoriginate its router-LSAs for all
+                *    attached areas in order to make sure they have the correct
+                *    contents.
+                */
+               OSPF6_ROUTER_LSA_EXECUTE(area);
+
+               for (ALL_LIST_ELEMENTS_RO(area->if_list, anode, oi)) {
+                       OSPF6_LINK_LSA_EXECUTE(oi);
+
+                       /*
+                        * 2) The router should reoriginate network-LSAs on all
+                        * segments where it is the Designated Router.
+                        */
+                       if (oi->state == OSPF6_INTERFACE_DR)
+                               OSPF6_NETWORK_LSA_EXECUTE(oi);
+               }
+       }
+
+       /*
+        * 3) The router reruns its OSPF routing calculations, this time
+        *    installing the results into the system forwarding table, and
+        *    originating summary-LSAs, Type-7 LSAs and AS-external-LSAs as
+        *    necessary.
+        *
+        * 4) Any remnant entries in the system forwarding table that were
+        *    installed before the restart, but that are no longer valid,
+        *    should be removed.
+        */
+       ospf6_spf_schedule(ospf6, OSPF6_SPF_FLAGS_GR_FINISH);
+
+       /* 6) Any grace-LSAs that the router originated should be flushed. */
+       ospf6_gr_flush_grace_lsas(ospf6);
+}
+
+#define RTR_LSA_MISSING 0
+#define RTR_LSA_ADJ_FOUND 1
+#define RTR_LSA_ADJ_NOT_FOUND 2
+
+/* Check if a Router-LSA exists and if it contains a given link. */
+static int ospf6_router_lsa_contains_adj(struct ospf6_area *area,
+                                        in_addr_t adv_router,
+                                        in_addr_t neighbor_router_id)
+{
+       uint16_t type;
+       struct ospf6_lsa *lsa;
+       bool empty = true;
+
+       type = ntohs(OSPF6_LSTYPE_ROUTER);
+       for (ALL_LSDB_TYPED_ADVRTR(area->lsdb, type, adv_router, lsa)) {
+               struct ospf6_router_lsa *router_lsa;
+               char *start, *end, *current;
+
+               empty = false;
+               router_lsa = (struct ospf6_router_lsa
+                                     *)((char *)lsa->header
+                                        + sizeof(struct ospf6_lsa_header));
+
+               /* Iterate over all interfaces in the Router-LSA. */
+               start = (char *)router_lsa + sizeof(struct ospf6_router_lsa);
+               end = (char *)lsa->header + ntohs(lsa->header->length);
+               for (current = start;
+                    current + sizeof(struct ospf6_router_lsdesc) <= end;
+                    current += sizeof(struct ospf6_router_lsdesc)) {
+                       struct ospf6_router_lsdesc *lsdesc;
+
+                       lsdesc = (struct ospf6_router_lsdesc *)current;
+                       if (lsdesc->type != OSPF6_ROUTER_LSDESC_POINTTOPOINT)
+                               continue;
+
+                       if (lsdesc->neighbor_router_id == neighbor_router_id)
+                               return RTR_LSA_ADJ_FOUND;
+               }
+       }
+
+       if (empty)
+               return RTR_LSA_MISSING;
+
+       return RTR_LSA_ADJ_NOT_FOUND;
+}
+
+static bool ospf6_gr_check_router_lsa_consistency(struct ospf6 *ospf6,
+                                                 struct ospf6_area *area,
+                                                 struct ospf6_lsa *lsa)
+{
+       if (lsa->header->adv_router == ospf6->router_id) {
+               struct ospf6_router_lsa *router_lsa;
+               char *start, *end, *current;
+
+               router_lsa = (struct ospf6_router_lsa
+                                     *)((char *)lsa->header
+                                        + sizeof(struct ospf6_lsa_header));
+
+               /* Iterate over all interfaces in the Router-LSA. */
+               start = (char *)router_lsa + sizeof(struct ospf6_router_lsa);
+               end = (char *)lsa->header + ntohs(lsa->header->length);
+               for (current = start;
+                    current + sizeof(struct ospf6_router_lsdesc) <= end;
+                    current += sizeof(struct ospf6_router_lsdesc)) {
+                       struct ospf6_router_lsdesc *lsdesc;
+
+                       lsdesc = (struct ospf6_router_lsdesc *)current;
+                       if (lsdesc->type != OSPF6_ROUTER_LSDESC_POINTTOPOINT)
+                               continue;
+
+                       if (ospf6_router_lsa_contains_adj(
+                                   area, lsdesc->neighbor_router_id,
+                                   ospf6->router_id)
+                           == RTR_LSA_ADJ_NOT_FOUND)
+                               return false;
+               }
+       } else {
+               int adj1, adj2;
+
+               adj1 = ospf6_router_lsa_contains_adj(area, ospf6->router_id,
+                                                    lsa->header->adv_router);
+               adj2 = ospf6_router_lsa_contains_adj(
+                       area, lsa->header->adv_router, ospf6->router_id);
+               if ((adj1 == RTR_LSA_ADJ_FOUND && adj2 == RTR_LSA_ADJ_NOT_FOUND)
+                   || (adj1 == RTR_LSA_ADJ_NOT_FOUND
+                       && adj2 == RTR_LSA_ADJ_FOUND))
+                       return false;
+       }
+
+       return true;
+}
+
+/*
+ * Check for LSAs that are inconsistent with the pre-restart LSAs, and abort the
+ * ongoing graceful restart when that's the case.
+ */
+void ospf6_gr_check_lsdb_consistency(struct ospf6 *ospf6,
+                                    struct ospf6_area *area)
+{
+       uint16_t type;
+       struct ospf6_lsa *lsa;
+
+       type = ntohs(OSPF6_LSTYPE_ROUTER);
+       for (ALL_LSDB_TYPED(area->lsdb, type, lsa)) {
+               if (!ospf6_gr_check_router_lsa_consistency(ospf6, area, lsa)) {
+                       char reason[256];
+
+                       snprintfrr(reason, sizeof(reason),
+                                  "detected inconsistent LSA %s [area %pI4]",
+                                  lsa->name, &area->area_id);
+                       ospf6_gr_restart_exit(ospf6, reason);
+                       return;
+               }
+       }
+}
+
+/* Check if there's a fully formed adjacency with the given neighbor ID. */
+static bool ospf6_gr_check_adj_id(struct ospf6_area *area,
+                                 in_addr_t neighbor_router_id)
+{
+       struct ospf6_neighbor *nbr;
+
+       nbr = ospf6_area_neighbor_lookup(area, neighbor_router_id);
+       if (!nbr || nbr->state < OSPF6_NEIGHBOR_FULL) {
+               if (IS_DEBUG_OSPF6_GR)
+                       zlog_debug("GR: missing adjacency to router %pI4",
+                                  &neighbor_router_id);
+               return false;
+       }
+
+       return true;
+}
+
+static bool ospf6_gr_check_adjs_lsa_transit(struct ospf6_area *area,
+                                           in_addr_t neighbor_router_id,
+                                           uint32_t neighbor_interface_id)
+{
+       struct ospf6 *ospf6 = area->ospf6;
+
+       /* Check if we are the DR. */
+       if (neighbor_router_id == ospf6->router_id) {
+               struct ospf6_lsa *lsa;
+               char *start, *end, *current;
+               struct ospf6_network_lsa *network_lsa;
+               struct ospf6_network_lsdesc *lsdesc;
+
+               /* Lookup Network LSA corresponding to this interface. */
+               lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_NETWORK),
+                                       neighbor_interface_id,
+                                       neighbor_router_id, area->lsdb);
+               if (!lsa)
+                       return false;
+
+               /* Iterate over all routers present in the network. */
+               network_lsa = (struct ospf6_network_lsa
+                                      *)((char *)lsa->header
+                                         + sizeof(struct ospf6_lsa_header));
+               start = (char *)network_lsa + sizeof(struct ospf6_network_lsa);
+               end = (char *)lsa->header + ntohs(lsa->header->length);
+               for (current = start;
+                    current + sizeof(struct ospf6_network_lsdesc) <= end;
+                    current += sizeof(struct ospf6_network_lsdesc)) {
+                       lsdesc = (struct ospf6_network_lsdesc *)current;
+
+                       /* Skip self in the pseudonode. */
+                       if (lsdesc->router_id == ospf6->router_id)
+                               continue;
+
+                       /*
+                        * Check if there's a fully formed adjacency with this
+                        * router.
+                        */
+                       if (!ospf6_gr_check_adj_id(area, lsdesc->router_id))
+                               return false;
+               }
+       } else {
+               struct ospf6_neighbor *nbr;
+
+               /* Check if there's a fully formed adjacency with the DR. */
+               nbr = ospf6_area_neighbor_lookup(area, neighbor_router_id);
+               if (!nbr || nbr->state < OSPF6_NEIGHBOR_FULL) {
+                       if (IS_DEBUG_OSPF6_GR)
+                               zlog_debug(
+                                       "GR: missing adjacency to DR router %pI4",
+                                       &neighbor_router_id);
+                       return false;
+               }
+       }
+
+       return true;
+}
+
+static bool ospf6_gr_check_adjs_lsa(struct ospf6_area *area,
+                                   struct ospf6_lsa *lsa)
+{
+       struct ospf6_router_lsa *router_lsa;
+       char *start, *end, *current;
+
+       router_lsa =
+               (struct ospf6_router_lsa *)((char *)lsa->header
+                                           + sizeof(struct ospf6_lsa_header));
+
+       /* Iterate over all interfaces in the Router-LSA. */
+       start = (char *)router_lsa + sizeof(struct ospf6_router_lsa);
+       end = (char *)lsa->header + ntohs(lsa->header->length);
+       for (current = start;
+            current + sizeof(struct ospf6_router_lsdesc) <= end;
+            current += sizeof(struct ospf6_router_lsdesc)) {
+               struct ospf6_router_lsdesc *lsdesc;
+
+               lsdesc = (struct ospf6_router_lsdesc *)current;
+               switch (lsdesc->type) {
+               case OSPF6_ROUTER_LSDESC_POINTTOPOINT:
+                       if (!ospf6_gr_check_adj_id(area,
+                                                  lsdesc->neighbor_router_id))
+                               return false;
+                       break;
+               case OSPF6_ROUTER_LSDESC_TRANSIT_NETWORK:
+                       if (!ospf6_gr_check_adjs_lsa_transit(
+                                   area, lsdesc->neighbor_router_id,
+                                   lsdesc->neighbor_interface_id))
+                               return false;
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       return true;
+}
+
+/*
+ * Check if all adjacencies prior to the restart were reestablished.
+ *
+ * This is done using pre-restart Router LSAs and pre-restart Network LSAs
+ * received from the helping neighbors.
+ */
+static bool ospf6_gr_check_adjs(struct ospf6 *ospf6)
+{
+       struct ospf6_area *area;
+       struct listnode *node;
+
+       for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, area)) {
+               uint16_t type;
+               uint32_t router;
+               struct ospf6_lsa *lsa_self;
+               bool found = false;
+
+               type = ntohs(OSPF6_LSTYPE_ROUTER);
+               router = ospf6->router_id;
+               for (ALL_LSDB_TYPED_ADVRTR(area->lsdb, type, router,
+                                          lsa_self)) {
+                       found = true;
+                       if (!ospf6_gr_check_adjs_lsa(area, lsa_self))
+                               return false;
+               }
+               if (!found)
+                       return false;
+       }
+
+       return true;
+}
+
+/* Handling of grace period expiry. */
+static int ospf6_gr_grace_period_expired(struct thread *thread)
+{
+       struct ospf6 *ospf6 = THREAD_ARG(thread);
+
+       ospf6->gr_info.t_grace_period = NULL;
+       ospf6_gr_restart_exit(ospf6, "grace period has expired");
+
+       return 0;
+}
+
+/*
+ * Record in non-volatile memory that the given OSPF instance is attempting to
+ * perform a graceful restart.
+ */
+static void ospf6_gr_nvm_update(struct ospf6 *ospf6)
+{
+       const char *inst_name;
+       json_object *json;
+       json_object *json_instances;
+       json_object *json_instance;
+
+       inst_name = ospf6->name ? ospf6->name : VRF_DEFAULT_NAME;
+
+       json = json_object_from_file((char *)OSPF6D_GR_STATE);
+       if (json == NULL)
+               json = json_object_new_object();
+
+       json_object_object_get_ex(json, "instances", &json_instances);
+       if (!json_instances) {
+               json_instances = json_object_new_object();
+               json_object_object_add(json, "instances", json_instances);
+       }
+
+       json_object_object_get_ex(json_instances, inst_name, &json_instance);
+       if (!json_instance) {
+               json_instance = json_object_new_object();
+               json_object_object_add(json_instances, inst_name,
+                                      json_instance);
+       }
+
+       /*
+        * Record not only the grace period, but also a UNIX timestamp
+        * corresponding to the end of that period. That way, once ospf6d is
+        * restarted, it will be possible to take into account the time that
+        * passed while ospf6d wasn't running.
+        */
+       json_object_int_add(json_instance, "gracePeriod",
+                           ospf6->gr_info.grace_period);
+       json_object_int_add(json_instance, "timestamp",
+                           time(NULL) + ospf6->gr_info.grace_period);
+
+       json_object_to_file_ext((char *)OSPF6D_GR_STATE, json,
+                               JSON_C_TO_STRING_PRETTY);
+       json_object_free(json);
+}
+
+/*
+ * Delete GR status information about the given OSPF instance from non-volatile
+ * memory.
+ */
+static void ospf6_gr_nvm_delete(struct ospf6 *ospf6)
+{
+       const char *inst_name;
+       json_object *json;
+       json_object *json_instances;
+
+       inst_name = ospf6->name ? ospf6->name : VRF_DEFAULT_NAME;
+
+       json = json_object_from_file((char *)OSPF6D_GR_STATE);
+       if (json == NULL)
+               json = json_object_new_object();
+
+       json_object_object_get_ex(json, "instances", &json_instances);
+       if (!json_instances) {
+               json_instances = json_object_new_object();
+               json_object_object_add(json, "instances", json_instances);
+       }
+
+       json_object_object_del(json_instances, inst_name);
+
+       json_object_to_file_ext((char *)OSPF6D_GR_STATE, json,
+                               JSON_C_TO_STRING_PRETTY);
+       json_object_free(json);
+}
+
+/*
+ * Fetch from non-volatile memory whether the given OSPF instance is performing
+ * a graceful shutdown or not.
+ */
+void ospf6_gr_nvm_read(struct ospf6 *ospf6)
+{
+       const char *inst_name;
+       json_object *json;
+       json_object *json_instances;
+       json_object *json_instance;
+       json_object *json_timestamp;
+       time_t timestamp = 0;
+
+       inst_name = ospf6->name ? ospf6->name : VRF_DEFAULT_NAME;
+
+       json = json_object_from_file((char *)OSPF6D_GR_STATE);
+       if (json == NULL)
+               json = json_object_new_object();
+
+       json_object_object_get_ex(json, "instances", &json_instances);
+       if (!json_instances) {
+               json_instances = json_object_new_object();
+               json_object_object_add(json, "instances", json_instances);
+       }
+
+       json_object_object_get_ex(json_instances, inst_name, &json_instance);
+       if (!json_instance) {
+               json_instance = json_object_new_object();
+               json_object_object_add(json_instances, inst_name,
+                                      json_instance);
+       }
+
+       json_object_object_get_ex(json_instance, "timestamp", &json_timestamp);
+       if (json_timestamp) {
+               time_t now;
+               unsigned long remaining_time;
+
+               /* Check if the grace period has already expired. */
+               now = time(NULL);
+               timestamp = json_object_get_int(json_timestamp);
+               if (now > timestamp) {
+                       ospf6_gr_restart_exit(
+                               ospf6, "grace period has expired already");
+               } else {
+                       /* Schedule grace period timeout. */
+                       ospf6->gr_info.restart_in_progress = true;
+                       remaining_time = timestamp - time(NULL);
+                       if (IS_DEBUG_OSPF6_GR)
+                               zlog_debug(
+                                       "GR: remaining time until grace period expires: %lu(s)",
+                                       remaining_time);
+                       thread_add_timer(master, ospf6_gr_grace_period_expired,
+                                        ospf6, remaining_time,
+                                        &ospf6->gr_info.t_grace_period);
+               }
+       }
+
+       json_object_object_del(json_instances, inst_name);
+
+       json_object_to_file_ext((char *)OSPF6D_GR_STATE, json,
+                               JSON_C_TO_STRING_PRETTY);
+       json_object_free(json);
+}
+
+/* Prepare to start a Graceful Restart. */
+static void ospf6_gr_prepare(void)
+{
+       struct ospf6 *ospf6;
+       struct ospf6_interface *oi;
+       struct listnode *onode, *anode, *inode;
+
+       for (ALL_LIST_ELEMENTS_RO(om6->ospf6, onode, ospf6)) {
+               struct ospf6_area *area;
+
+               if (!ospf6->gr_info.restart_support
+                   || ospf6->gr_info.prepare_in_progress)
+                       continue;
+
+               if (IS_DEBUG_OSPF6_GR)
+                       zlog_debug(
+                               "GR: preparing to perform a graceful restart [period %u second(s)] [vrf %s]",
+                               ospf6->gr_info.grace_period,
+                               ospf6_vrf_id_to_name(ospf6->vrf_id));
+
+               /* Freeze OSPF routes in the RIB. */
+               if (ospf6_zebra_gr_enable(ospf6, ospf6->gr_info.grace_period)) {
+                       zlog_warn(
+                               "%s: failed to activate graceful restart: not connected to zebra",
+                               __func__);
+                       continue;
+               }
+
+               /* Send a Grace-LSA to all neighbors. */
+               for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, anode, area)) {
+                       for (ALL_LIST_ELEMENTS_RO(area->if_list, inode, oi)) {
+                               if (oi->state < OSPF6_INTERFACE_POINTTOPOINT)
+                                       continue;
+                               ospf6_gr_lsa_originate(oi);
+                       }
+               }
+
+               /* Record end of the grace period in non-volatile memory. */
+               ospf6_gr_nvm_update(ospf6);
+
+               /*
+                * Mark that a Graceful Restart preparation is in progress, to
+                * prevent ospf6d from flushing its self-originated LSAs on
+                * exit.
+                */
+               ospf6->gr_info.prepare_in_progress = true;
+       }
+}
+
+static int ospf6_gr_neighbor_change(struct ospf6_neighbor *on, int next_state,
+                                   int prev_state)
+{
+       struct ospf6 *ospf6 = on->ospf6_if->area->ospf6;
+
+       if (next_state == OSPF6_NEIGHBOR_FULL
+           && ospf6->gr_info.restart_in_progress) {
+               if (ospf6_gr_check_adjs(ospf6)) {
+                       ospf6_gr_restart_exit(
+                               ospf6, "all adjacencies were reestablished");
+               } else {
+                       if (IS_DEBUG_OSPF6_GR)
+                               zlog_debug(
+                                       "GR: not all adjacencies were reestablished yet");
+               }
+       }
+
+       return 0;
+}
+
+int config_write_ospf6_gr(struct vty *vty, struct ospf6 *ospf6)
+{
+       if (!ospf6->gr_info.restart_support)
+               return 0;
+
+       if (ospf6->gr_info.grace_period == OSPF6_DFLT_GRACE_INTERVAL)
+               vty_out(vty, " graceful-restart\n");
+       else
+               vty_out(vty, " graceful-restart grace-period %u\n",
+                       ospf6->gr_info.grace_period);
+
+       return 0;
+}
+
+DEFPY(ospf6_graceful_restart_prepare, ospf6_graceful_restart_prepare_cmd,
+      "graceful-restart prepare ipv6 ospf",
+      "Graceful Restart commands\n"
+      "Prepare upcoming graceful restart\n" IPV6_STR
+      "Prepare to restart the OSPFv3 process")
+{
+       ospf6_gr_prepare();
+
+       return CMD_SUCCESS;
+}
+
+DEFPY(ospf6_graceful_restart, ospf6_graceful_restart_cmd,
+      "graceful-restart [grace-period (1-1800)$grace_period]",
+      OSPF_GR_STR
+      "Maximum length of the 'grace period'\n"
+      "Maximum length of the 'grace period' in seconds\n")
+{
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf6, ospf6);
+
+       /* Check and get restart period if present. */
+       if (!grace_period_str)
+               grace_period = OSPF6_DFLT_GRACE_INTERVAL;
+
+       ospf6->gr_info.restart_support = true;
+       ospf6->gr_info.grace_period = grace_period;
+
+       return CMD_SUCCESS;
+}
+
+DEFPY(ospf6_no_graceful_restart, ospf6_no_graceful_restart_cmd,
+      "no graceful-restart [period (1-1800)]",
+      NO_STR OSPF_GR_STR
+      "Maximum length of the 'grace period'\n"
+      "Maximum length of the 'grace period' in seconds\n")
+{
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf6, ospf6);
+
+       if (!ospf6->gr_info.restart_support)
+               return CMD_SUCCESS;
+
+       if (ospf6->gr_info.prepare_in_progress) {
+               vty_out(vty,
+                       "%% Error: Graceful Restart preparation in progress\n");
+               return CMD_WARNING;
+       }
+
+       ospf6->gr_info.restart_support = false;
+       ospf6->gr_info.grace_period = OSPF6_DFLT_GRACE_INTERVAL;
+
+       return CMD_SUCCESS;
+}
+
+void ospf6_gr_init(void)
+{
+       hook_register(ospf6_neighbor_change, ospf6_gr_neighbor_change);
+
+       install_element(ENABLE_NODE, &ospf6_graceful_restart_prepare_cmd);
+       install_element(OSPF6_NODE, &ospf6_graceful_restart_cmd);
+       install_element(OSPF6_NODE, &ospf6_no_graceful_restart_cmd);
+}
index 378b7193cdba041b4d3c3924e6752b739c2fc7ca..6406e8efee15deeb24217317d82dc12032ee0192 100644 (file)
 
 #define OSPF6_MAX_GRACE_INTERVAL 1800
 #define OSPF6_MIN_GRACE_INTERVAL 1
+#define OSPF6_DFLT_GRACE_INTERVAL 120
+
+/* Forward declaration(s). */
+struct ospf6_neighbor;
 
 /* Debug option */
 extern unsigned char conf_debug_ospf6_gr;
@@ -67,7 +71,8 @@ enum ospf6_gr_helper_rejected_reason {
        OSPF6_HELPER_NOT_A_VALID_NEIGHBOUR,
        OSPF6_HELPER_PLANNED_ONLY_RESTART,
        OSPF6_HELPER_TOPO_CHANGE_RTXMT_LIST,
-       OSPF6_HELPER_LSA_AGE_MORE
+       OSPF6_HELPER_LSA_AGE_MORE,
+       OSPF6_HELPER_RESTARTING,
 };
 
 #ifdef roundup
@@ -119,6 +124,11 @@ struct grace_tlv_restart_reason {
 #define OSPF6_GRACE_LSA_MIN_SIZE                                               \
        GRACE_PERIOD_TLV_SIZE + GRACE_RESTART_REASON_TLV_SIZE
 
+struct ospf6_grace_lsa {
+       struct grace_tlv_graceperiod tlv_period;
+       struct grace_tlv_restart_reason tlv_reason;
+};
+
 struct advRtr {
        in_addr_t advRtrAddr;
 };
@@ -156,6 +166,13 @@ extern void ospf6_process_maxage_grace_lsa(struct ospf6 *ospf,
                                           struct ospf6_neighbor *nbr);
 extern void ospf6_helper_handle_topo_chg(struct ospf6 *ospf6,
                                         struct ospf6_lsa *lsa);
+extern int config_write_ospf6_gr(struct vty *vty, struct ospf6 *ospf6);
 extern int config_write_ospf6_gr_helper(struct vty *vty, struct ospf6 *ospf6);
 extern int config_write_ospf6_debug_gr_helper(struct vty *vty);
+
+extern void ospf6_gr_check_lsdb_consistency(struct ospf6 *ospf,
+                                           struct ospf6_area *area);
+extern void ospf6_gr_nvm_read(struct ospf6 *ospf);
+extern void ospf6_gr_init(void);
+
 #endif /* OSPF6_GR_H */
index 76496c050f58e74494374ef74ee0301f93804378..ad8998b1edc0043837f4e0d5bc54eb375e15ecef 100644 (file)
@@ -360,6 +360,16 @@ int ospf6_process_grace_lsa(struct ospf6 *ospf6, struct ospf6_lsa *lsa,
                return OSPF6_GR_NOT_HELPER;
        }
 
+       if (ospf6->gr_info.restart_in_progress) {
+               if (IS_DEBUG_OSPF6_GR)
+                       zlog_debug(
+                               "%s: router is in the process of graceful restart",
+                               __func__);
+               restarter->gr_helper_info.rejected_reason =
+                       OSPF6_HELPER_RESTARTING;
+               return OSPF6_GR_NOT_HELPER;
+       }
+
        /* check supported grace period configured
         * if configured, use this to start the grace
         * timer otherwise use the interval received
@@ -1009,10 +1019,11 @@ static void show_ospf6_gr_helper_details(struct vty *vty, struct ospf6 *ospf6,
 /* Graceful Restart HELPER  config Commands */
 DEFPY(ospf6_gr_helper_enable,
       ospf6_gr_helper_enable_cmd,
-      "graceful-restart helper-only [A.B.C.D$rtr_id]",
+      "graceful-restart helper enable [A.B.C.D$rtr_id]",
       "ospf6 graceful restart\n"
+      "ospf6 GR Helper\n"
       "Enable Helper support\n"
-      "Advertisement RouterId\n")
+      "Advertisement Router-ID\n")
 {
        VTY_DECLVAR_CONTEXT(ospf6, ospf6);
 
@@ -1031,11 +1042,12 @@ DEFPY(ospf6_gr_helper_enable,
 
 DEFPY(ospf6_gr_helper_disable,
       ospf6_gr_helper_disable_cmd,
-      "no graceful-restart helper-only [A.B.C.D$rtr_id]",
+      "no graceful-restart helper enable [A.B.C.D$rtr_id]",
       NO_STR
       "ospf6 graceful restart\n"
-      "Disable Helper support\n"
-      "Advertisement RouterId\n")
+      "ospf6 GR Helper\n"
+      "Enable Helper support\n"
+      "Advertisement Router-ID\n")
 {
        VTY_DECLVAR_CONTEXT(ospf6, ospf6);
 
@@ -1155,7 +1167,10 @@ DEFPY(show_ipv6_ospf6_gr_helper,
        bool detail = false;
 
        ospf6 = ospf6_lookup_by_vrf_name(VRF_DEFAULT_NAME);
-       OSPF6_CMD_CHECK_RUNNING();
+       if (ospf6 == NULL) {
+               vty_out(vty, "OSPFv3 is not configured\n");
+               return CMD_SUCCESS;
+       }
 
        if (argv_find(argv, argc, "detail", &idx))
                detail = true;
@@ -1341,14 +1356,14 @@ static int ospf6_cfg_write_helper_enable_rtr_walkcb(struct hash_bucket *backet,
        struct advRtr *rtr = backet->data;
        struct vty *vty = (struct vty *)arg;
 
-       vty_out(vty, " graceful-restart helper-only %pI4\n", &rtr->advRtrAddr);
+       vty_out(vty, " graceful-restart helper enable %pI4\n", &rtr->advRtrAddr);
        return HASHWALK_CONTINUE;
 }
 
 int config_write_ospf6_gr_helper(struct vty *vty, struct ospf6 *ospf6)
 {
        if (ospf6->ospf6_helper_cfg.is_helper_supported)
-               vty_out(vty, " graceful-restart helper-only\n");
+               vty_out(vty, " graceful-restart helper enable\n");
 
        if (!ospf6->ospf6_helper_cfg.strict_lsa_check)
                vty_out(vty, " graceful-restart helper lsa-check-disable\n");
index b427a0c9bde3ed34cb966487df1e4560e445f407..a3eb1445f187a0d6b564835db23124fbfcf6fb6a 100644 (file)
@@ -819,7 +819,6 @@ int interface_up(struct thread *thread)
        /* Schedule Hello */
        if (!CHECK_FLAG(oi->flag, OSPF6_INTERFACE_PASSIVE)
            && !if_is_loopback_or_vrf(oi->interface)) {
-               oi->thread_send_hello = NULL;
                thread_add_event(master, ospf6_hello_send, oi, 0,
                                 &oi->thread_send_hello);
        }
@@ -1330,7 +1329,6 @@ DEFUN(show_ipv6_ospf6_interface, show_ipv6_ospf6_interface_ifname_cmd,
        bool all_vrf = false;
        int idx_vrf = 0;
 
-       OSPF6_CMD_CHECK_RUNNING();
        OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
        if (idx_vrf > 0) {
                idx_ifname += 2;
@@ -1547,7 +1545,6 @@ DEFUN(show_ipv6_ospf6_interface_traffic, show_ipv6_ospf6_interface_traffic_cmd,
        bool all_vrf = false;
        int idx_vrf = 0;
 
-       OSPF6_CMD_CHECK_RUNNING();
        OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
 
        for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) {
@@ -1590,7 +1587,6 @@ DEFUN(show_ipv6_ospf6_interface_ifname_prefix,
        bool all_vrf = false;
        int idx_vrf = 0;
 
-       OSPF6_CMD_CHECK_RUNNING();
        OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
        if (idx_vrf > 0) {
                idx_ifname += 2;
@@ -1651,7 +1647,6 @@ DEFUN(show_ipv6_ospf6_interface_prefix, show_ipv6_ospf6_interface_prefix_cmd,
        bool all_vrf = false;
        int idx_vrf = 0;
 
-       OSPF6_CMD_CHECK_RUNNING();
        OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
        if (idx_vrf > 0)
                idx_prefix += 2;
index ccdf8b1c8fc7d0424ef32f15483ef3906d5c4749..ee24b989bdb1be5401d4e81d0b03d62436299481 100644 (file)
@@ -193,23 +193,23 @@ 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 *);
-extern void ospf6_interface_delete(struct ospf6_interface *);
+extern struct ospf6_interface *ospf6_interface_create(struct interface *ifp);
+extern void ospf6_interface_delete(struct ospf6_interface *oi);
 
-extern void ospf6_interface_enable(struct ospf6_interface *);
-extern void ospf6_interface_disable(struct ospf6_interface *);
+extern void ospf6_interface_enable(struct ospf6_interface *oi);
+extern void ospf6_interface_disable(struct ospf6_interface *oi);
 
-extern void ospf6_interface_state_update(struct interface *);
-extern void ospf6_interface_connected_route_update(struct interface *);
+extern void ospf6_interface_state_update(struct interface *ifp);
+extern void ospf6_interface_connected_route_update(struct interface *ifp);
 extern struct in6_addr *
 ospf6_interface_get_global_address(struct interface *ifp);
 
 /* interface event */
-extern int interface_up(struct thread *);
-extern int interface_down(struct thread *);
-extern int wait_timer(struct thread *);
-extern int backup_seen(struct thread *);
-extern int neighbor_change(struct thread *);
+extern int interface_up(struct thread *thread);
+extern int interface_down(struct thread *thread);
+extern int wait_timer(struct thread *thread);
+extern int backup_seen(struct thread *thread);
+extern int neighbor_change(struct thread *thread);
 
 extern void ospf6_interface_init(void);
 extern void ospf6_interface_clear(struct interface *ifp);
index e4db8f3a026e5cc24e43ee0ce586369a57f52e2a..2d82ff7ce81748b45a81f2532296e39e8b69675f 100644 (file)
@@ -47,6 +47,7 @@
 #include "ospf6_flood.h"
 #include "ospf6d.h"
 #include "ospf6_spf.h"
+#include "ospf6_gr.h"
 
 unsigned char conf_debug_ospf6_brouter = 0;
 uint32_t conf_debug_ospf6_brouter_specific_router_id;
@@ -249,6 +250,13 @@ int ospf6_router_lsa_originate(struct thread *thread)
        oa = (struct ospf6_area *)THREAD_ARG(thread);
        oa->thread_router_lsa = NULL;
 
+       if (oa->ospf6->gr_info.restart_in_progress) {
+               if (IS_DEBUG_OSPF6_GR)
+                       zlog_debug(
+                               "Graceful Restart in progress, don't originate LSA");
+               return 0;
+       }
+
        if (IS_OSPF6_DEBUG_ORIGINATE(ROUTER))
                zlog_debug("Originate Router-LSA for Area %s", oa->name);
 
@@ -532,6 +540,13 @@ int ospf6_network_lsa_originate(struct thread *thread)
           by ospf6_lsa_refresh (), and does not come here. */
        assert(oi->area);
 
+       if (oi->area->ospf6->gr_info.restart_in_progress) {
+               if (IS_DEBUG_OSPF6_GR)
+                       zlog_debug(
+                               "Graceful Restart in progress, don't originate LSA");
+               return 0;
+       }
+
        old = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_NETWORK),
                                htonl(oi->interface->ifindex),
                                oi->area->ospf6->router_id, oi->area->lsdb);
@@ -773,6 +788,14 @@ int ospf6_link_lsa_originate(struct thread *thread)
 
        assert(oi->area);
 
+       if (oi->area->ospf6->gr_info.restart_in_progress) {
+               if (IS_DEBUG_OSPF6_GR)
+                       zlog_debug(
+                               "Graceful Restart in progress, don't originate LSA");
+               return 0;
+       }
+
+
        /* find previous LSA */
        old = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_LINK),
                                htonl(oi->interface->ifindex),
@@ -1009,6 +1032,13 @@ int ospf6_intra_prefix_lsa_originate_stub(struct thread *thread)
        oa = (struct ospf6_area *)THREAD_ARG(thread);
        oa->thread_intra_prefix_lsa = NULL;
 
+       if (oa->ospf6->gr_info.restart_in_progress) {
+               if (IS_DEBUG_OSPF6_GR)
+                       zlog_debug(
+                               "Graceful Restart in progress, don't originate LSA");
+               return 0;
+       }
+
        /* find previous LSA */
        old = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_INTRA_PREFIX), htonl(0),
                                oa->ospf6->router_id, oa->lsdb);
@@ -1243,6 +1273,13 @@ int ospf6_intra_prefix_lsa_originate_transit(struct thread *thread)
 
        assert(oi->area);
 
+       if (oi->area->ospf6->gr_info.restart_in_progress) {
+               if (IS_DEBUG_OSPF6_GR)
+                       zlog_debug(
+                               "Graceful Restart in progress, don't originate LSA");
+               return 0;
+       }
+
        /* find previous LSA */
        old = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_INTRA_PREFIX),
                                htonl(oi->interface->ifindex),
@@ -1458,7 +1495,6 @@ void ospf6_intra_prefix_route_ecmp_path(struct ospf6_area *oa,
        struct listnode *anode, *anext;
        struct listnode *nnode, *rnode, *rnext;
        struct ospf6_nexthop *nh, *rnh;
-       char buf[PREFIX2STR_BUFFER];
        bool route_found = false;
        struct interface *ifp = NULL;
        struct ospf6_lsa *lsa;
@@ -1470,8 +1506,14 @@ void ospf6_intra_prefix_route_ecmp_path(struct ospf6_area *oa,
        for (old_route = old; old_route; old_route = old_route->next) {
                bool route_updated = false;
 
-               if (!ospf6_route_is_same(old_route, route) ||
-                       (old_route->path.type != route->path.type))
+               /* The route linked-list is grouped in batches of prefix.
+                * If the new prefix is not the same as the one of interest
+                * then we have walked over the end of the batch and so we
+                * should break rather than continuing unnecessarily.
+                */
+               if (!ospf6_route_is_same(old_route, route))
+                       break;
+               if (old_route->path.type != route->path.type)
                        continue;
 
                /* Current and New route has same origin,
@@ -1482,9 +1524,8 @@ void ospf6_intra_prefix_route_ecmp_path(struct ospf6_area *oa,
                        /* Check old route path and route has same
                         * origin.
                         */
-                       if (o_path->area_id != route->path.area_id ||
-                           (memcmp(&(o_path)->origin, &(route)->path.origin,
-                                  sizeof(struct ospf6_ls_origin)) != 0))
+                       if (o_path->area_id != route->path.area_id
+                           || !ospf6_ls_origin_same(o_path, &route->path))
                                continue;
 
                        /* Cost is not same then delete current path */
@@ -1569,8 +1610,14 @@ void ospf6_intra_prefix_route_ecmp_path(struct ospf6_area *oa,
 
        for (old_route = old; old_route; old_route = old_route->next) {
 
-               if (!ospf6_route_is_same(old_route, route) ||
-                       (old_route->path.type != route->path.type))
+               /* The route linked-list is grouped in batches of prefix.
+                * If the new prefix is not the same as the one of interest
+                * then we have walked over the end of the batch and so we
+                * should break rather than continuing unnecessarily.
+                */
+               if (!ospf6_route_is_same(old_route, route))
+                       break;
+               if (old_route->path.type != route->path.type)
                        continue;
 
                /* Old Route and New Route have Equal Cost, Merge NHs */
@@ -1582,10 +1629,8 @@ void ospf6_intra_prefix_route_ecmp_path(struct ospf6_area *oa,
                         */
                        for (ALL_LIST_ELEMENTS_RO(old_route->paths, anode,
                                                  o_path)) {
-                               if (o_path->area_id == route->path.area_id &&
-                                   (memcmp(&(o_path)->origin,
-                                       &(route)->path.origin,
-                                       sizeof(struct ospf6_ls_origin)) == 0))
+                               if (o_path->area_id == route->path.area_id
+                                   && ospf6_ls_origin_same(o_path, &route->path))
                                        break;
                        }
                        /* If path is not found in old_route paths's list,
@@ -1630,8 +1675,9 @@ void ospf6_intra_prefix_route_ecmp_path(struct ospf6_area *oa,
                                if (ls_entry == NULL) {
                                        if (IS_OSPF6_DEBUG_EXAMIN(INTRA_PREFIX))
                                                zlog_debug(
-                                                       "%s: ls_prfix %s ls_entry not found.",
-                                                       __func__, buf);
+                                                       "%s: ls_prfix %pFX ls_entry not found.",
+                                                       __func__,
+                                                       &o_path->ls_prefix);
                                        continue;
                                }
                                lsa = ospf6_lsdb_lookup(o_path->origin.type,
@@ -2304,7 +2350,7 @@ void ospf6_intra_brouter_calculation(struct ospf6_area *oa)
                         * the table. For an example, ospf6_abr_examin_summary,
                         * removes brouters which are marked for remove.
                         */
-                       oa->intra_brouter_calc = 1;
+                       oa->intra_brouter_calc = true;
                        ospf6_route_remove(brouter, oa->ospf6->brouter_table);
                        brouter = NULL;
                } else if (CHECK_FLAG(brouter->flag, OSPF6_ROUTE_ADD)
@@ -2337,7 +2383,7 @@ void ospf6_intra_brouter_calculation(struct ospf6_area *oa)
                        UNSET_FLAG(brouter->flag, OSPF6_ROUTE_CHANGE);
                }
                /* Reset for nbrouter */
-               oa->intra_brouter_calc = 0;
+               oa->intra_brouter_calc = false;
        }
 
        if (IS_OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_ID(oa->area_id) ||
@@ -2430,12 +2476,13 @@ DEFUN (debug_ospf6_brouter_router,
 
 DEFUN (no_debug_ospf6_brouter_router,
        no_debug_ospf6_brouter_router_cmd,
-       "no debug ospf6 border-routers router-id",
+       "no debug ospf6 border-routers router-id [A.B.C.D]",
        NO_STR
        DEBUG_STR
        OSPF6_STR
        "Debug border router\n"
        "Debug specific border router\n"
+       "Specify border-router's router-id\n"
       )
 {
        OSPF6_DEBUG_BROUTER_SPECIFIC_ROUTER_OFF();
@@ -2461,12 +2508,13 @@ DEFUN (debug_ospf6_brouter_area,
 
 DEFUN (no_debug_ospf6_brouter_area,
        no_debug_ospf6_brouter_area_cmd,
-       "no debug ospf6 border-routers area-id",
+       "no debug ospf6 border-routers area-id [A.B.C.D]",
        NO_STR
        DEBUG_STR
        OSPF6_STR
        "Debug border router\n"
        "Debug border routers in specific Area\n"
+       "Specify Area-ID\n"
       )
 {
        OSPF6_DEBUG_BROUTER_SPECIFIC_AREA_OFF();
index 9c29681dee56426995dc27e38a6c5907e3a7eacc..f15bf0b9b4fa6d9ef6379e10f9745587932f8e8d 100644 (file)
@@ -192,12 +192,26 @@ struct ospf6_intra_prefix_lsa {
                                         oi, 0, &(oi)->thread_as_extern_lsa);  \
        } while (0)
 
+#define OSPF6_ROUTER_LSA_EXECUTE(oa)                                           \
+       do {                                                                   \
+               if (CHECK_FLAG((oa)->flag, OSPF6_AREA_ENABLE))                 \
+                       thread_execute(master, ospf6_router_lsa_originate, oa, \
+                                      0);                                     \
+       } while (0)
+
 #define OSPF6_NETWORK_LSA_EXECUTE(oi)                                          \
        do {                                                                   \
                THREAD_OFF((oi)->thread_network_lsa);                          \
                thread_execute(master, ospf6_network_lsa_originate, oi, 0);    \
        } while (0)
 
+#define OSPF6_LINK_LSA_EXECUTE(oi)                                             \
+       do {                                                                   \
+               if (!CHECK_FLAG((oi)->flag, OSPF6_INTERFACE_DISABLE))          \
+                       thread_execute(master, ospf6_link_lsa_originate, oi,   \
+                                      0);                                     \
+       } while (0)
+
 #define OSPF6_INTRA_PREFIX_LSA_EXECUTE_TRANSIT(oi)                             \
        do {                                                                   \
                THREAD_OFF((oi)->thread_intra_prefix_lsa);                     \
@@ -221,11 +235,11 @@ extern char *ospf6_network_lsdesc_lookup(uint32_t router_id,
                                         struct ospf6_lsa *lsa);
 
 extern int ospf6_router_is_stub_router(struct ospf6_lsa *lsa);
-extern int ospf6_router_lsa_originate(struct thread *);
-extern int ospf6_network_lsa_originate(struct thread *);
-extern int ospf6_link_lsa_originate(struct thread *);
-extern int ospf6_intra_prefix_lsa_originate_transit(struct thread *);
-extern int ospf6_intra_prefix_lsa_originate_stub(struct thread *);
+extern int ospf6_router_lsa_originate(struct thread *thread);
+extern int ospf6_network_lsa_originate(struct thread *thread);
+extern int ospf6_link_lsa_originate(struct thread *thread);
+extern int ospf6_intra_prefix_lsa_originate_transit(struct thread *thread);
+extern int ospf6_intra_prefix_lsa_originate_stub(struct thread *thread);
 extern void ospf6_intra_prefix_lsa_add(struct ospf6_lsa *lsa);
 extern void ospf6_intra_prefix_lsa_remove(struct ospf6_lsa *lsa);
 extern int ospf6_orig_as_external_lsa(struct thread *thread);
index 1bc1ce9cdf7c00c9edecdcac34fce281feadf7e6..f406e828e1c1721a8e84803f3878c946eb3e2b9c 100644 (file)
@@ -891,7 +891,6 @@ int ospf6_lsa_refresh(struct thread *thread)
 
        new = ospf6_lsa_create(self->header);
        new->lsdb = old->lsdb;
-       new->refresh = NULL;
        thread_add_timer(master, ospf6_lsa_refresh, new, OSPF_LS_REFRESH_TIME,
                         &new->refresh);
 
@@ -1021,6 +1020,30 @@ static char *ospf6_lsa_handler_name(const struct ospf6_lsa_handler *h)
        return buf;
 }
 
+DEFPY (debug_ospf6_lsa_all,
+       debug_ospf6_lsa_all_cmd,
+       "[no$no] debug ospf6 lsa all",
+       NO_STR
+       DEBUG_STR
+       OSPF6_STR
+       "Debug Link State Advertisements (LSAs)\n"
+       "Display for all types of LSAs\n")
+{
+       unsigned int i;
+       struct ospf6_lsa_handler *handler = NULL;
+
+       for (i = 0; i < vector_active(ospf6_lsa_handler_vector); i++) {
+               handler = vector_slot(ospf6_lsa_handler_vector, i);
+               if (handler == NULL)
+                       continue;
+               if (!no)
+                       SET_FLAG(handler->lh_debug, OSPF6_LSA_DEBUG_ALL);
+               else
+                       UNSET_FLAG(handler->lh_debug, OSPF6_LSA_DEBUG_ALL);
+       }
+       return CMD_SUCCESS;
+}
+
 DEFPY (debug_ospf6_lsa_aggregation,
        debug_ospf6_lsa_aggregation_cmd,
        "[no] debug ospf6 lsa aggregation",
@@ -1152,6 +1175,8 @@ DEFUN (no_debug_ospf6_lsa_type,
 
 void install_element_ospf6_debug_lsa(void)
 {
+       install_element(ENABLE_NODE, &debug_ospf6_lsa_all_cmd);
+       install_element(CONFIG_NODE, &debug_ospf6_lsa_all_cmd);
        install_element(ENABLE_NODE, &debug_ospf6_lsa_hex_cmd);
        install_element(ENABLE_NODE, &no_debug_ospf6_lsa_hex_cmd);
        install_element(CONFIG_NODE, &debug_ospf6_lsa_hex_cmd);
@@ -1165,6 +1190,23 @@ int config_write_ospf6_debug_lsa(struct vty *vty)
 {
        unsigned int i;
        const struct ospf6_lsa_handler *handler;
+       bool debug_all = true;
+
+       for (i = 0; i < vector_active(ospf6_lsa_handler_vector); i++) {
+               handler = vector_slot(ospf6_lsa_handler_vector, i);
+               if (handler == NULL)
+                       continue;
+               if (CHECK_FLAG(handler->lh_debug, OSPF6_LSA_DEBUG_ALL)
+                   < OSPF6_LSA_DEBUG_ALL) {
+                       debug_all = false;
+                       break;
+               }
+       }
+
+       if (debug_all) {
+               vty_out(vty, "debug ospf6 lsa all\n");
+               return 0;
+       }
 
        for (i = 0; i < vector_active(ospf6_lsa_handler_vector); i++) {
                handler = vector_slot(ospf6_lsa_handler_vector, i);
index a8ed9132dd9b1ca1cc360d2ce640ad549742350c..2316040694a4b1ba4afd9d230cff1f72b4278d7b 100644 (file)
@@ -28,6 +28,9 @@
 #define OSPF6_LSA_DEBUG_ORIGINATE 0x02
 #define OSPF6_LSA_DEBUG_EXAMIN    0x04
 #define OSPF6_LSA_DEBUG_FLOOD     0x08
+#define OSPF6_LSA_DEBUG_ALL                                                    \
+       (OSPF6_LSA_DEBUG | OSPF6_LSA_DEBUG_ORIGINATE | OSPF6_LSA_DEBUG_EXAMIN  \
+        | OSPF6_LSA_DEBUG_FLOOD)
 #define OSPF6_LSA_DEBUG_AGGR      0x10
 
 /* OSPF LSA Default metric values */
@@ -231,10 +234,11 @@ extern int metric_type(struct ospf6 *ospf6, int type, uint8_t instance);
 extern int metric_value(struct ospf6 *ospf6, int type, uint8_t instance);
 extern int ospf6_lsa_is_differ(struct ospf6_lsa *lsa1, struct ospf6_lsa *lsa2);
 extern int ospf6_lsa_is_changed(struct ospf6_lsa *lsa1, struct ospf6_lsa *lsa2);
-extern uint16_t ospf6_lsa_age_current(struct ospf6_lsa *);
-extern void ospf6_lsa_age_update_to_send(struct ospf6_lsa *, uint32_t);
-extern void ospf6_lsa_premature_aging(struct ospf6_lsa *);
-extern int ospf6_lsa_compare(struct ospf6_lsa *, struct ospf6_lsa *);
+extern uint16_t ospf6_lsa_age_current(struct ospf6_lsa *lsa);
+extern void ospf6_lsa_age_update_to_send(struct ospf6_lsa *lsa,
+                                        uint32_t transdelay);
+extern void ospf6_lsa_premature_aging(struct ospf6_lsa *lsa);
+extern int ospf6_lsa_compare(struct ospf6_lsa *lsa1, struct ospf6_lsa *lsa2);
 
 extern char *ospf6_lsa_printbuf(struct ospf6_lsa *lsa, char *buf, int size);
 extern void ospf6_lsa_header_print_raw(struct ospf6_lsa_header *header);
@@ -254,16 +258,16 @@ extern struct ospf6_lsa *ospf6_lsa_create(struct ospf6_lsa_header *header);
 extern struct ospf6_lsa *
 ospf6_lsa_create_headeronly(struct ospf6_lsa_header *header);
 extern void ospf6_lsa_delete(struct ospf6_lsa *lsa);
-extern struct ospf6_lsa *ospf6_lsa_copy(struct ospf6_lsa *);
+extern struct ospf6_lsa *ospf6_lsa_copy(struct ospf6_lsa *lsa);
 
 extern struct ospf6_lsa *ospf6_lsa_lock(struct ospf6_lsa *lsa);
 extern struct ospf6_lsa *ospf6_lsa_unlock(struct ospf6_lsa *lsa);
 
-extern int ospf6_lsa_expire(struct thread *);
-extern int ospf6_lsa_refresh(struct thread *);
+extern int ospf6_lsa_expire(struct thread *thread);
+extern int ospf6_lsa_refresh(struct thread *thread);
 
-extern unsigned short ospf6_lsa_checksum(struct ospf6_lsa_header *);
-extern int ospf6_lsa_checksum_valid(struct ospf6_lsa_header *);
+extern unsigned short ospf6_lsa_checksum(struct ospf6_lsa_header *lsah);
+extern int ospf6_lsa_checksum_valid(struct ospf6_lsa_header *lsah);
 extern int ospf6_lsa_prohibited_duration(uint16_t type, uint32_t id,
                                         uint32_t adv_router, void *scope);
 
index 3dcc74589adddffa32859352127857dc3d228bca..a81c3e728f5bb6e30fca297c1969dc83f79ba840 100644 (file)
@@ -553,6 +553,21 @@ static void ospf6_hello_recv(struct in6_addr *src, struct in6_addr *dst,
                return;
        }
 
+       /*
+        * RFC 3623 - Section 2:
+        * "If the restarting router determines that it was the Designated
+        * Router on a given segment prior to the restart, it elects
+        * itself as the Designated Router again.  The restarting router
+        * knows that it was the Designated Router if, while the
+        * associated interface is in Waiting state, a Hello packet is
+        * received from a neighbor listing the router as the Designated
+        * Router".
+        */
+       if (oi->area->ospf6->gr_info.restart_in_progress
+           && oi->state == OSPF6_INTERFACE_WAITING
+           && hello->drouter == oi->area->ospf6->router_id)
+               oi->drouter = hello->drouter;
+
        /* Schedule interface events */
        if (backupseen)
                thread_add_event(master, backup_seen, oi, 0, NULL);
@@ -711,7 +726,6 @@ static void ospf6_dbdesc_recv_master(struct ospf6_header *oh,
                                zlog_debug("Ignoring LSA of reserved scope");
                        ospf6_lsa_delete(his);
                        continue;
-                       break;
                }
 
                if (ntohs(his->header->type) == OSPF6_LSTYPE_AS_EXTERNAL
@@ -760,7 +774,6 @@ static void ospf6_dbdesc_recv_master(struct ospf6_header *oh,
            && !CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MBIT))
                thread_add_event(master, exchange_done, on, 0, NULL);
        else {
-               on->thread_send_dbdesc = NULL;
                thread_add_event(master, ospf6_dbdesc_send_newone, on, 0,
                                 &on->thread_send_dbdesc);
        }
@@ -841,7 +854,6 @@ static void ospf6_dbdesc_recv_slave(struct ospf6_header *oh,
                                zlog_debug(
                                        "Duplicated dbdesc causes retransmit");
                        THREAD_OFF(on->thread_send_dbdesc);
-                       on->thread_send_dbdesc = NULL;
                        thread_add_event(master, ospf6_dbdesc_send, on, 0,
                                         &on->thread_send_dbdesc);
                        return;
@@ -934,7 +946,6 @@ static void ospf6_dbdesc_recv_slave(struct ospf6_header *oh,
                                zlog_debug("Ignoring LSA of reserved scope");
                        ospf6_lsa_delete(his);
                        continue;
-                       break;
                }
 
                if (OSPF6_LSA_SCOPE(his->header->type) == OSPF6_SCOPE_AS
@@ -1069,7 +1080,6 @@ static void ospf6_lsreq_recv(struct in6_addr *src, struct in6_addr *dst,
                        if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
                                zlog_debug("Ignoring LSA of reserved scope");
                        continue;
-                       break;
                }
 
                /* Find database copy */
@@ -1621,7 +1631,6 @@ static void ospf6_lsack_recv(struct in6_addr *src, struct in6_addr *dst,
                                zlog_debug("Ignoring LSA of reserved scope");
                        ospf6_lsa_delete(his);
                        continue;
-                       break;
                }
 
                if (IS_OSPF6_DEBUG_MESSAGE(oh->type, RECV))
@@ -1863,11 +1872,13 @@ static void ospf6_make_header(uint8_t type, struct ospf6_interface *oi,
 
        oh->version = (uint8_t)OSPFV3_VERSION;
        oh->type = type;
-
+       oh->length = 0;
        oh->router_id = oi->area->ospf6->router_id;
        oh->area_id = oi->area->area_id;
+       oh->checksum = 0;
        oh->instance_id = oi->instance_id;
        oh->reserved = 0;
+
        stream_forward_endp(s, OSPF6_HEADER_SIZE);
 }
 
@@ -2382,7 +2393,6 @@ int ospf6_lsreq_send(struct thread *thread)
 
        /* set next thread */
        if (on->request_list->count != 0) {
-               on->thread_send_lsreq = NULL;
                thread_add_timer(master, ospf6_lsreq_send, on,
                                 on->ospf6_if->rxmt_interval,
                                 &on->thread_send_lsreq);
@@ -2568,11 +2578,9 @@ int ospf6_lsupdate_send_neighbor(struct thread *thread)
                ospf6_packet_free(op);
 
        if (on->lsupdate_list->count != 0) {
-               on->thread_send_lsupdate = NULL;
                thread_add_event(master, ospf6_lsupdate_send_neighbor, on, 0,
                                 &on->thread_send_lsupdate);
        } else if (on->retrans_list->count != 0) {
-               on->thread_send_lsupdate = NULL;
                thread_add_timer(master, ospf6_lsupdate_send_neighbor, on,
                                 on->ospf6_if->rxmt_interval,
                                 &on->thread_send_lsupdate);
@@ -2686,7 +2694,6 @@ int ospf6_lsupdate_send_interface(struct thread *thread)
                ospf6_packet_free(op);
 
        if (oi->lsupdate_list->count > 0) {
-               oi->thread_send_lsupdate = NULL;
                thread_add_event(master, ospf6_lsupdate_send_interface, oi, 0,
                                 &oi->thread_send_lsupdate);
        }
index 4ea615f32b7f5923bb84ba44bfe5a7dbb3b6b18a..6f2795a56d57231d0617b1187d2a46b1564d4dfe 100644 (file)
@@ -90,6 +90,22 @@ struct ospf6_neighbor *ospf6_neighbor_lookup(uint32_t router_id,
        return (struct ospf6_neighbor *)NULL;
 }
 
+struct ospf6_neighbor *ospf6_area_neighbor_lookup(struct ospf6_area *area,
+                                                 uint32_t router_id)
+{
+       struct ospf6_interface *oi;
+       struct ospf6_neighbor *nbr;
+       struct listnode *node;
+
+       for (ALL_LIST_ELEMENTS_RO(area->if_list, node, oi)) {
+               nbr = ospf6_neighbor_lookup(router_id, oi);
+               if (nbr)
+                       return nbr;
+       }
+
+       return NULL;
+}
+
 /* create ospf6_neighbor */
 struct ospf6_neighbor *ospf6_neighbor_create(uint32_t router_id,
                                             struct ospf6_interface *oi)
@@ -257,7 +273,6 @@ int hello_received(struct thread *thread)
 
        /* reset Inactivity Timer */
        THREAD_OFF(on->inactivity_timer);
-       on->inactivity_timer = NULL;
        thread_add_timer(master, inactivity_timer, on,
                         on->ospf6_if->dead_interval, &on->inactivity_timer);
 
@@ -296,7 +311,6 @@ int twoway_received(struct thread *thread)
        SET_FLAG(on->dbdesc_bits, OSPF6_DBDESC_IBIT);
 
        THREAD_OFF(on->thread_send_dbdesc);
-       on->thread_send_dbdesc = NULL;
        thread_add_event(master, ospf6_dbdesc_send, on, 0,
                         &on->thread_send_dbdesc);
 
@@ -422,7 +436,6 @@ void ospf6_check_nbr_loading(struct ospf6_neighbor *on)
                else if (on->last_ls_req == NULL) {
                        if (on->thread_send_lsreq != NULL)
                                THREAD_OFF(on->thread_send_lsreq);
-                       on->thread_send_lsreq = NULL;
                        thread_add_event(master, ospf6_lsreq_send, on, 0,
                                         &on->thread_send_lsreq);
                }
@@ -604,7 +617,6 @@ int inactivity_timer(struct thread *thread)
        if (IS_OSPF6_DEBUG_NEIGHBOR(EVENT))
                zlog_debug("Neighbor Event %s: *InactivityTimer*", on->name);
 
-       on->inactivity_timer = NULL;
        on->drouter = on->prev_drouter = 0;
        on->bdrouter = on->prev_bdrouter = 0;
 
@@ -1081,7 +1093,6 @@ DEFUN(show_ipv6_ospf6_neighbor, show_ipv6_ospf6_neighbor_cmd,
        bool detail = false;
        bool drchoice = false;
 
-       OSPF6_CMD_CHECK_RUNNING();
        OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
 
        if (argv_find(argv, argc, "detail", &idx_type))
@@ -1156,7 +1167,6 @@ DEFUN(show_ipv6_ospf6_neighbor_one, show_ipv6_ospf6_neighbor_one_cmd,
        bool all_vrf = false;
        int idx_vrf = 0;
 
-       OSPF6_CMD_CHECK_RUNNING();
        OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
        if (idx_vrf > 0)
                idx_ipv4 += 2;
index a229897226be6e95517b7cd2101959d2e223402b..f7735b87b9b3cdcd770c580518c656715e870ca2 100644 (file)
@@ -23,6 +23,9 @@
 
 #include "hook.h"
 
+/* Forward declaration(s). */
+struct ospf6_area;
+
 /* Debug option */
 extern unsigned char conf_debug_ospf6_neighbor;
 #define OSPF6_DEBUG_NEIGHBOR_STATE   0x01
@@ -183,24 +186,26 @@ extern const char *const ospf6_neighbor_state_str[];
 int ospf6_neighbor_cmp(void *va, void *vb);
 void ospf6_neighbor_dbex_init(struct ospf6_neighbor *on);
 
-struct ospf6_neighbor *ospf6_neighbor_lookup(uint32_t,
-                                            struct ospf6_interface *);
-struct ospf6_neighbor *ospf6_neighbor_create(uint32_t,
-                                            struct ospf6_interface *);
-void ospf6_neighbor_delete(struct ospf6_neighbor *);
+struct ospf6_neighbor *ospf6_neighbor_lookup(uint32_t router_id,
+                                            struct ospf6_interface *oi);
+struct ospf6_neighbor *ospf6_area_neighbor_lookup(struct ospf6_area *area,
+                                                 uint32_t router_id);
+struct ospf6_neighbor *ospf6_neighbor_create(uint32_t router_id,
+                                            struct ospf6_interface *oi);
+void ospf6_neighbor_delete(struct ospf6_neighbor *on);
 
 /* Neighbor event */
-extern int hello_received(struct thread *);
-extern int twoway_received(struct thread *);
-extern int negotiation_done(struct thread *);
-extern int exchange_done(struct thread *);
-extern int loading_done(struct thread *);
-extern int adj_ok(struct thread *);
-extern int seqnumber_mismatch(struct thread *);
-extern int bad_lsreq(struct thread *);
-extern int oneway_received(struct thread *);
-extern int inactivity_timer(struct thread *);
-extern void ospf6_check_nbr_loading(struct ospf6_neighbor *);
+extern int hello_received(struct thread *thread);
+extern int twoway_received(struct thread *thread);
+extern int negotiation_done(struct thread *thread);
+extern int exchange_done(struct thread *thread);
+extern int loading_done(struct thread *thread);
+extern int adj_ok(struct thread *thread);
+extern int seqnumber_mismatch(struct thread *thread);
+extern int bad_lsreq(struct thread *thread);
+extern int oneway_received(struct thread *thread);
+extern int inactivity_timer(struct thread *thread);
+extern void ospf6_check_nbr_loading(struct ospf6_neighbor *on);
 
 extern void ospf6_neighbor_init(void);
 extern int config_write_ospf6_debug_neighbor(struct vty *vty);
index 10b7d2d9f65addd7f2d75e74f20818be02f0dfd5..809768fb5ca9396ee9364d4e8a574ceb36005327 100644 (file)
@@ -304,24 +304,16 @@ void ospf6_abr_remove_unapproved_summaries(struct ospf6 *ospf6)
                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);
-                       }
+                       if (CHECK_FLAG(lsa->flag, OSPF6_LSA_UNAPPROVED))
+                               ospf6_lsa_premature_aging(lsa);
                }
 
                /* 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 (CHECK_FLAG(lsa->flag, OSPF6_LSA_UNAPPROVED))
+                               ospf6_lsa_premature_aging(lsa);
                }
        }
 
@@ -368,6 +360,11 @@ static void ospf6_abr_task(struct ospf6 *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 : announce NSSA Type-7 defaults",
+                                  __func__);
+               ospf6_abr_nssa_type_7_defaults(ospf6);
        }
 
        if (IS_OSPF6_DEBUG_ABR)
@@ -872,6 +869,83 @@ static void ospf6_abr_remove_unapproved_translates(struct ospf6 *ospf6)
                zlog_debug("ospf_abr_remove_unapproved_translates(): Stop");
 }
 
+static void ospf6_abr_nssa_type_7_default_create(struct ospf6 *ospf6,
+                                                struct ospf6_area *oa)
+{
+       struct ospf6_route *def;
+       int metric;
+       int metric_type;
+
+       if (IS_OSPF6_DEBUG_NSSA)
+               zlog_debug("Announcing Type-7 default route into NSSA area %s",
+                          oa->name);
+
+       def = ospf6_route_create(ospf6);
+       def->type = OSPF6_DEST_TYPE_NETWORK;
+       def->prefix.family = AF_INET6;
+       def->prefix.prefixlen = 0;
+       memset(&def->prefix.u.prefix6, 0, sizeof(struct in6_addr));
+       def->type = OSPF6_DEST_TYPE_NETWORK;
+       def->path.subtype = OSPF6_PATH_SUBTYPE_DEFAULT_RT;
+       if (CHECK_FLAG(ospf6->flag, OSPF6_FLAG_ABR))
+               def->path.area_id = ospf6->backbone->area_id;
+       else
+               def->path.area_id = oa->area_id;
+
+       /* Compute default route type and metric. */
+       if (oa->nssa_default_originate.metric_value != -1)
+               metric = oa->nssa_default_originate.metric_value;
+       else
+               metric = DEFAULT_DEFAULT_ALWAYS_METRIC;
+       if (oa->nssa_default_originate.metric_type != -1)
+               metric_type = oa->nssa_default_originate.metric_type;
+       else
+               metric_type = DEFAULT_METRIC_TYPE;
+       def->path.metric_type = metric_type;
+       def->path.cost = metric;
+       if (metric_type == 1)
+               def->path.type = OSPF6_PATH_TYPE_EXTERNAL1;
+       else
+               def->path.type = OSPF6_PATH_TYPE_EXTERNAL2;
+
+       ospf6_nssa_lsa_originate(def, oa, false);
+       ospf6_route_delete(def);
+}
+
+static void ospf6_abr_nssa_type_7_default_delete(struct ospf6 *ospf6,
+                                                struct ospf6_area *oa)
+{
+       struct ospf6_lsa *lsa;
+
+       lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_TYPE_7), 0,
+                               oa->ospf6->router_id, oa->lsdb);
+       if (lsa && !OSPF6_LSA_IS_MAXAGE(lsa)) {
+               if (IS_OSPF6_DEBUG_NSSA)
+                       zlog_debug(
+                               "Withdrawing Type-7 default route from area %s",
+                               oa->name);
+
+               ospf6_lsa_purge(lsa);
+       }
+}
+
+/* NSSA Type-7 default route. */
+void ospf6_abr_nssa_type_7_defaults(struct ospf6 *ospf6)
+{
+       struct listnode *node;
+       struct ospf6_area *oa;
+
+       for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, oa)) {
+               if (IS_AREA_NSSA(oa) && oa->nssa_default_originate.enabled
+                   && (IS_OSPF6_ABR(ospf6)
+                       || (IS_OSPF6_ASBR(ospf6)
+                           && ospf6->nssa_default_import_check.status)))
+                       ospf6_abr_nssa_type_7_default_create(ospf6, oa);
+               else
+                       ospf6_abr_nssa_type_7_default_delete(ospf6, oa);
+       }
+}
+
 static void ospf6_abr_nssa_task(struct ospf6 *ospf6)
 {
        /* called only if any_nssa */
@@ -1169,10 +1243,11 @@ static void ospf6_check_and_originate_type7_lsa(struct ospf6_area *area)
        for (route = ospf6_route_head(
                     area->ospf6->external_table);
             route; route = ospf6_route_next(route)) {
-               /* This means the Type-5 LSA was originated for this route */
-               if (route->path.origin.id != 0)
-                       ospf6_nssa_lsa_originate(route, area);
+               struct ospf6_external_info *info = route->route_option;
 
+               /* This means the Type-5 LSA was originated for this route */
+               if (route->path.origin.id != 0 && info->type != DEFAULT_ROUTE)
+                       ospf6_nssa_lsa_originate(route, area, true);
        }
 
        /* Loop through the aggregation table to originate type-7 LSAs
@@ -1192,7 +1267,7 @@ static void ospf6_check_and_originate_type7_lsa(struct ospf6_area *area)
                                        "Originating Type-7 LSAs for area %s",
                                        area->name);
 
-                       ospf6_nssa_lsa_originate(aggr->route, area);
+                       ospf6_nssa_lsa_originate(aggr->route, area, true);
                }
        }
 
@@ -1286,7 +1361,7 @@ static struct in6_addr *ospf6_get_nssa_fwd_addr(struct ospf6_area *oa)
 }
 
 void ospf6_nssa_lsa_originate(struct ospf6_route *route,
-                             struct ospf6_area *area)
+                             struct ospf6_area *area, bool p_bit)
 {
        char buffer[OSPF6_MAX_LSASIZE];
        struct ospf6_lsa_header *lsa_header;
@@ -1311,13 +1386,13 @@ void ospf6_nssa_lsa_originate(struct ospf6_route *route,
 
        /* Fill AS-External-LSA */
        /* Metric type */
-       if (route->path.metric_type == OSPF6_PATH_TYPE_EXTERNAL2)
+       if (route->path.metric_type == 2)
                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)
+       if (info && 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);
@@ -1332,7 +1407,8 @@ void ospf6_nssa_lsa_originate(struct ospf6_route *route,
        as_external_lsa->prefix.prefix_options = route->prefix_options;
 
        /* Set the P bit */
-       as_external_lsa->prefix.prefix_options |= OSPF6_PREFIX_OPTION_P;
+       if (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);
@@ -1353,7 +1429,8 @@ void ospf6_nssa_lsa_originate(struct ospf6_route *route,
                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)) {
+       if (info
+           && 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));
index 454bdd7fe2eb692185b5dbbea599e7d48abd85e3..99cb04c0031f5baee30fb1087382e1094f09bc44 100644 (file)
@@ -52,11 +52,11 @@ 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 struct ospf6_lsa *ospf6_translated_nssa_refresh(struct ospf6_area *oa,
+                                                      struct ospf6_lsa *type7,
+                                                      struct ospf6_lsa *type5);
+extern struct ospf6_lsa *
+ospf6_translated_nssa_originate(struct ospf6_area *oa, struct ospf6_lsa *type7);
 
 extern void ospf6_asbr_nssa_redist_task(struct ospf6 *ospf6);
 
@@ -64,8 +64,9 @@ extern void ospf6_schedule_abr_task(struct ospf6 *ospf6);
 extern void ospf6_area_nssa_update(struct ospf6_area *area);
 void ospf6_asbr_prefix_readvertise(struct ospf6 *ospf6);
 extern void ospf6_nssa_lsa_originate(struct ospf6_route *route,
-                                    struct ospf6_area *area);
+                                    struct ospf6_area *area, bool p_bit);
 extern void install_element_ospf6_debug_nssa(void);
+extern void ospf6_abr_nssa_type_7_defaults(struct ospf6 *osof6);
 int ospf6_redistribute_check(struct ospf6 *ospf6, struct ospf6_route *route,
                             int type);
 extern int ospf6_abr_translate_nssa(struct ospf6_area *area,
index 13003b4151802cc50e29130936068260b8140613..4b87c4cf3089b44f612f81a6a00ecd50f1967d93 100644 (file)
@@ -37,6 +37,9 @@
 #include "ospf6_interface.h"
 #include "ospf6d.h"
 #include "ospf6_zebra.h"
+#ifndef VTYSH_EXTRACT_PL
+#include "ospf6d/ospf6_route_clippy.c"
+#endif
 
 DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_ROUTE,   "OSPF6 route");
 DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_ROUTE_TABLE, "OSPF6 route table");
@@ -405,8 +408,6 @@ int ospf6_nexthop_cmp(struct ospf6_nexthop *a, struct ospf6_nexthop *b)
        else
                return memcmp(&a->address, &b->address,
                              sizeof(struct in6_addr));
-
-       return 0;
 }
 
 static int ospf6_path_cmp(struct ospf6_path *a, struct ospf6_path *b)
@@ -1117,11 +1118,6 @@ void ospf6_route_show(struct vty *vty, struct ospf6_route *route,
        json_object *json_array_next_hops = NULL;
        json_object *json_next_hop;
 
-       if (om6->ospf6 == NULL) {
-               vty_out(vty, "OSPFv3 is not running\n");
-               return;
-       }
-
        monotime(&now);
        timersub(&now, &route->changed, &res);
        timerstring(&res, duration, sizeof(duration));
@@ -1205,11 +1201,6 @@ void ospf6_route_show_detail(struct vty *vty, struct ospf6_route *route,
        json_object *json_array_next_hops = NULL;
        json_object *json_next_hop;
 
-       if (om6->ospf6 == NULL) {
-               vty_out(vty, "OSPFv3 is not running\n");
-               return;
-       }
-
        monotime(&now);
 
        /* destination */
@@ -1837,49 +1828,27 @@ void ospf6_brouter_show(struct vty *vty, struct ospf6_route *route)
                OSPF6_PATH_TYPE_NAME(route->path.type), area);
 }
 
-DEFUN (debug_ospf6_route,
-       debug_ospf6_route_cmd,
-       "debug ospf6 route <table|intra-area|inter-area|memory>",
-       DEBUG_STR
-       OSPF6_STR
-       "Debug routes\n"
-       "Debug route table calculation\n"
-       "Debug intra-area route calculation\n"
-       "Debug inter-area route calculation\n"
-       "Debug route memory use\n"
-       )
+DEFPY(debug_ospf6_route,
+      debug_ospf6_route_cmd,
+      "[no$no] debug ospf6 route <all|table|intra-area|inter-area|memory>",
+      NO_STR
+      DEBUG_STR
+      OSPF6_STR
+      "Debug routes\n"
+      "Debug for all types of route calculation\n"
+      "Debug route table calculation\n"
+      "Debug intra-area route calculation\n"
+      "Debug inter-area route calculation\n"
+      "Debug route memory use\n")
 {
-       int idx_type = 3;
+       int idx_type;
        unsigned char level = 0;
 
-       if (!strcmp(argv[idx_type]->text, "table"))
-               level = OSPF6_DEBUG_ROUTE_TABLE;
-       else if (!strcmp(argv[idx_type]->text, "intra-area"))
-               level = OSPF6_DEBUG_ROUTE_INTRA;
-       else if (!strcmp(argv[idx_type]->text, "inter-area"))
-               level = OSPF6_DEBUG_ROUTE_INTER;
-       else if (!strcmp(argv[idx_type]->text, "memory"))
-               level = OSPF6_DEBUG_ROUTE_MEMORY;
-       OSPF6_DEBUG_ROUTE_ON(level);
-       return CMD_SUCCESS;
-}
-
-DEFUN (no_debug_ospf6_route,
-       no_debug_ospf6_route_cmd,
-       "no debug ospf6 route <table|intra-area|inter-area|memory>",
-       NO_STR
-       DEBUG_STR
-       OSPF6_STR
-       "Debug routes\n"
-       "Debug route table calculation\n"
-       "Debug intra-area route calculation\n"
-       "Debug inter-area route calculation\n"
-       "Debug route memory use\n")
-{
-       int idx_type = 4;
-       unsigned char level = 0;
+       idx_type = ((no) ? 4 : 3);
 
-       if (!strcmp(argv[idx_type]->text, "table"))
+       if (!strcmp(argv[idx_type]->text, "all"))
+               level = OSPF6_DEBUG_ROUTE_ALL;
+       else if (!strcmp(argv[idx_type]->text, "table"))
                level = OSPF6_DEBUG_ROUTE_TABLE;
        else if (!strcmp(argv[idx_type]->text, "intra-area"))
                level = OSPF6_DEBUG_ROUTE_INTRA;
@@ -1887,12 +1856,20 @@ DEFUN (no_debug_ospf6_route,
                level = OSPF6_DEBUG_ROUTE_INTER;
        else if (!strcmp(argv[idx_type]->text, "memory"))
                level = OSPF6_DEBUG_ROUTE_MEMORY;
-       OSPF6_DEBUG_ROUTE_OFF(level);
+
+       if (no)
+               OSPF6_DEBUG_ROUTE_OFF(level);
+       else
+               OSPF6_DEBUG_ROUTE_ON(level);
        return CMD_SUCCESS;
 }
 
 int config_write_ospf6_debug_route(struct vty *vty)
 {
+       if (IS_OSPF6_DEBUG_ROUTE(ALL) == OSPF6_DEBUG_ROUTE_ALL) {
+               vty_out(vty, "debug ospf6 route all\n");
+               return 0;
+       }
        if (IS_OSPF6_DEBUG_ROUTE(TABLE))
                vty_out(vty, "debug ospf6 route table\n");
        if (IS_OSPF6_DEBUG_ROUTE(INTRA))
@@ -1908,7 +1885,5 @@ int config_write_ospf6_debug_route(struct vty *vty)
 void install_element_ospf6_debug_route(void)
 {
        install_element(ENABLE_NODE, &debug_ospf6_route_cmd);
-       install_element(ENABLE_NODE, &no_debug_ospf6_route_cmd);
        install_element(CONFIG_NODE, &debug_ospf6_route_cmd);
-       install_element(CONFIG_NODE, &no_debug_ospf6_route_cmd);
 }
index 991720ec2e6ed1446cd191209adc45c2d6031db7..e29439b95e676c282d65f3a46819a028bd51c75b 100644 (file)
@@ -33,7 +33,10 @@ extern unsigned char conf_debug_ospf6_route;
 #define OSPF6_DEBUG_ROUTE_TABLE   0x01
 #define OSPF6_DEBUG_ROUTE_INTRA   0x02
 #define OSPF6_DEBUG_ROUTE_INTER   0x04
-#define OSPF6_DEBUG_ROUTE_MEMORY  0x80
+#define OSPF6_DEBUG_ROUTE_MEMORY  0x08
+#define OSPF6_DEBUG_ROUTE_ALL                                                  \
+       (OSPF6_DEBUG_ROUTE_TABLE | OSPF6_DEBUG_ROUTE_INTRA                     \
+        | OSPF6_DEBUG_ROUTE_INTER | OSPF6_DEBUG_ROUTE_MEMORY)
 #define OSPF6_DEBUG_ROUTE_ON(level) (conf_debug_ospf6_route |= (level))
 #define OSPF6_DEBUG_ROUTE_OFF(level) (conf_debug_ospf6_route &= ~(level))
 #define IS_OSPF6_DEBUG_ROUTE(e) (conf_debug_ospf6_route & OSPF6_DEBUG_ROUTE_##e)
@@ -343,7 +346,7 @@ extern int ospf6_route_get_first_nh_index(struct ospf6_route *route);
        ospf6_add_nexthop(route->nh_list, ifindex, addr)
 
 extern struct ospf6_route *ospf6_route_create(struct ospf6 *ospf6);
-extern void ospf6_route_delete(struct ospf6_route *);
+extern void ospf6_route_delete(struct ospf6_route *route);
 extern struct ospf6_route *ospf6_route_copy(struct ospf6_route *route);
 extern int ospf6_route_cmp(struct ospf6_route *ra, struct ospf6_route *rb);
 
@@ -384,8 +387,10 @@ extern void ospf6_route_show_detail(struct vty *vty, struct ospf6_route *route,
                                    json_object *json, bool use_json);
 
 
-extern int ospf6_route_table_show(struct vty *, int, int, struct cmd_token **,
-                                 struct ospf6_route_table *, bool use_json);
+extern int ospf6_route_table_show(struct vty *vty, int argc_start, int argc,
+                                 struct cmd_token **argv,
+                                 struct ospf6_route_table *table,
+                                 bool use_json);
 extern int ospf6_linkstate_table_show(struct vty *vty, int idx_ipv4, int argc,
                                      struct cmd_token **argv,
                                      struct ospf6_route_table *table);
index 14122988025e369619bfecf0c54f880379b1023a..a9bd7febcf23245ebe3faa533bf859bd7782f773 100644 (file)
@@ -44,6 +44,7 @@
 #include "ospf6d.h"
 #include "ospf6_abr.h"
 #include "ospf6_nssa.h"
+#include "ospf6_zebra.h"
 
 DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_VERTEX, "OSPF6 vertex");
 
@@ -438,12 +439,23 @@ void ospf6_spf_table_finish(struct ospf6_route_table *result_table)
        }
 }
 
-static const char *const ospf6_spf_reason_str[] = {"R+", "R-", "N+", "N-", "L+",
-                                                  "L-", "R*", "N*", "C"};
-
-void ospf6_spf_reason_string(unsigned int reason, char *buf, int size)
+static const char *const ospf6_spf_reason_str[] = {
+       "R+", /* OSPF6_SPF_FLAGS_ROUTER_LSA_ADDED */
+       "R-", /* OSPF6_SPF_FLAGS_ROUTER_LSA_REMOVED */
+       "N+", /* OSPF6_SPF_FLAGS_NETWORK_LSA_ADDED */
+       "N-", /* OSPF6_SPF_FLAGS_NETWORK_LSA_REMOVED */
+       "L+", /* OSPF6_SPF_FLAGS_NETWORK_LINK_LSA_ADDED */
+       "L-", /* OSPF6_SPF_FLAGS_NETWORK_LINK_LSA_REMOVED */
+       "R*", /* OSPF6_SPF_FLAGS_ROUTER_LSA_ORIGINATED */
+       "N*", /* OSPF6_SPF_FLAGS_NETWORK_LSA_ORIGINATED */
+       "C",  /* OSPF6_SPF_FLAGS_CONFIG_CHANGE */
+       "A",  /* OSPF6_SPF_FLAGS_ASBR_STATUS_CHANGE */
+       "GR", /* OSPF6_SPF_FLAGS_GR_FINISH */
+};
+
+void ospf6_spf_reason_string(uint32_t reason, char *buf, int size)
 {
-       unsigned int bit;
+       uint32_t bit;
        int len = 0;
 
        if (!buf)
@@ -645,8 +657,10 @@ static int ospf6_spf_calculation_thread(struct thread *t)
        /* External LSA calculation */
        ospf6_ase_calculate_timer_add(ospf6);
 
-       if (ospf6_check_and_set_router_abr(ospf6))
+       if (ospf6_check_and_set_router_abr(ospf6)) {
                ospf6_abr_defaults_to_stub(ospf6);
+               ospf6_abr_nssa_type_7_defaults(ospf6);
+       }
 
        monotime(&end);
        timersub(&end, &start, &runtime);
@@ -1255,6 +1269,17 @@ static int ospf6_ase_calculate_timer(struct thread *t)
                                ospf6_ase_calculate_route(ospf6, lsa, area);
                }
        }
+
+       if (ospf6->gr_info.finishing_restart) {
+               /*
+                * The routing table computation is complete. Uninstall remnant
+                * routes that were installed before the restart, but that are
+                * no longer valid.
+                */
+               ospf6_zebra_gr_disable(ospf6);
+               ospf6->gr_info.finishing_restart = false;
+       }
+
        return 0;
 }
 
index d6fbc5c13b74ed6201091ead73daa2fab9bc8e45..cc52d168614e8086dda7c53a3c5ababe01101b37 100644 (file)
@@ -93,6 +93,7 @@ struct ospf6_vertex {
 #define OSPF6_SPF_FLAGS_NETWORK_LSA_ORIGINATED   (1 << 7)
 #define OSPF6_SPF_FLAGS_CONFIG_CHANGE            (1 << 8)
 #define OSPF6_SPF_FLAGS_ASBR_STATUS_CHANGE       (1 << 9)
+#define OSPF6_SPF_FLAGS_GR_FINISH                (1 << 10)
 
 static inline void ospf6_set_spf_reason(struct ospf6 *ospf, unsigned int reason)
 {
index 6ff3789a804ac00bf126250c1f8734cb5f6c403b..6fe70552027ba545cd8c571b1d00135be1ec86a6 100644 (file)
@@ -226,7 +226,7 @@ static int ospf6_vrf_enable(struct vrf *vrf)
                        thread_add_read(master, ospf6_receive, ospf6, ospf6->fd,
                                        &ospf6->t_ospf6_receive);
 
-                       ospf6_router_id_update(ospf6);
+                       ospf6_router_id_update(ospf6, true);
                }
        }
 
@@ -460,7 +460,7 @@ struct ospf6 *ospf6_instance_create(const char *name)
        if (DFLT_OSPF6_LOG_ADJACENCY_CHANGES)
                SET_FLAG(ospf6->config_flags, OSPF6_LOG_ADJACENCY_CHANGES);
        if (ospf6->router_id == 0)
-               ospf6_router_id_update(ospf6);
+               ospf6_router_id_update(ospf6, true);
        ospf6_add(ospf6);
        if (ospf6->vrf_id != VRF_UNKNOWN) {
                vrf = vrf_lookup_by_id(ospf6->vrf_id);
@@ -472,6 +472,12 @@ struct ospf6 *ospf6_instance_create(const char *name)
        if (ospf6->fd < 0)
                return ospf6;
 
+       /*
+        * Read from non-volatile memory whether this instance is performing a
+        * graceful restart or not.
+        */
+       ospf6_gr_nvm_read(ospf6);
+
        thread_add_read(master, ospf6_receive, ospf6, ospf6->fd,
                        &ospf6->t_ospf6_receive);
 
@@ -488,7 +494,8 @@ void ospf6_delete(struct ospf6 *o)
        QOBJ_UNREG(o);
 
        ospf6_gr_helper_deinit(o);
-       ospf6_flush_self_originated_lsas_now(o);
+       if (!o->gr_info.prepare_in_progress)
+               ospf6_flush_self_originated_lsas_now(o);
        ospf6_disable(o);
        ospf6_del(o);
 
@@ -555,6 +562,7 @@ static void ospf6_disable(struct ospf6 *o)
                THREAD_OFF(o->t_distribute_update);
                THREAD_OFF(o->t_ospf6_receive);
                THREAD_OFF(o->t_external_aggr);
+               THREAD_OFF(o->gr_info.t_grace_period);
        }
 }
 
@@ -622,15 +630,35 @@ void ospf6_maxage_remove(struct ospf6 *o)
                                 &o->maxage_remover);
 }
 
-void ospf6_router_id_update(struct ospf6 *ospf6)
+bool ospf6_router_id_update(struct ospf6 *ospf6, bool init)
 {
+       in_addr_t new_router_id;
+       struct listnode *node;
+       struct ospf6_area *oa;
+
        if (!ospf6)
-               return;
+               return true;
 
        if (ospf6->router_id_static != 0)
-               ospf6->router_id = ospf6->router_id_static;
+               new_router_id = ospf6->router_id_static;
        else
-               ospf6->router_id = ospf6->router_id_zebra;
+               new_router_id = ospf6->router_id_zebra;
+
+       if (ospf6->router_id == new_router_id)
+               return true;
+
+       if (!init)
+               for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, oa)) {
+                       if (oa->full_nbrs) {
+                               zlog_err(
+                                       "%s: cannot update router-id. Run the \"clear ipv6 ospf6 process\" command",
+                                       __func__);
+                               return false;
+                       }
+               }
+
+       ospf6->router_id = new_router_id;
+       return true;
 }
 
 /* start ospf6 */
@@ -723,8 +751,6 @@ static void ospf6_process_reset(struct ospf6 *ospf6)
        ospf6->inst_shutdown = 0;
        ospf6_db_clear(ospf6);
 
-       ospf6_router_id_update(ospf6);
-
        ospf6_asbr_redistribute_reset(ospf6);
        FOR_ALL_INTERFACES (vrf, ifp)
                ospf6_interface_clear(ifp);
@@ -746,10 +772,12 @@ DEFPY (clear_router_ospf6,
                vrf_name = name;
 
        ospf6 = ospf6_lookup_by_vrf_name(vrf_name);
-       if (ospf6 == NULL)
+       if (ospf6 == NULL) {
                vty_out(vty, "OSPFv3 is not configured\n");
-       else
+       } else {
+               ospf6_router_id_update(ospf6, true);
                ospf6_process_reset(ospf6);
+       }
 
        return CMD_SUCCESS;
 }
@@ -767,8 +795,6 @@ DEFUN(ospf6_router_id,
        int ret;
        const char *router_id_str;
        uint32_t router_id;
-       struct ospf6_area *oa;
-       struct listnode *node;
 
        argv_find(argv, argc, "A.B.C.D", &idx);
        router_id_str = argv[idx]->arg;
@@ -781,15 +807,11 @@ DEFUN(ospf6_router_id,
 
        o->router_id_static = router_id;
 
-       for (ALL_LIST_ELEMENTS_RO(o->area_list, node, oa)) {
-               if (oa->full_nbrs) {
-                       vty_out(vty,
-                               "For this router-id change to take effect, run the \"clear ipv6 ospf6 process\" command\n");
-                       return CMD_SUCCESS;
-               }
-       }
-
-       o->router_id = router_id;
+       if (ospf6_router_id_update(o, false))
+               ospf6_process_reset(o);
+       else
+               vty_out(vty,
+                       "For this router-id change to take effect run the \"clear ipv6 ospf6 process\" command\n");
 
        return CMD_SUCCESS;
 }
@@ -802,21 +824,15 @@ DEFUN(no_ospf6_router_id,
       V4NOTATION_STR)
 {
        VTY_DECLVAR_CONTEXT(ospf6, o);
-       struct ospf6_area *oa;
-       struct listnode *node;
 
        o->router_id_static = 0;
 
-       for (ALL_LIST_ELEMENTS_RO(o->area_list, node, oa)) {
-               if (oa->full_nbrs) {
-                       vty_out(vty,
-                               "For this router-id change to take effect, run the \"clear ipv6 ospf6 process\" command\n");
-                       return CMD_SUCCESS;
-               }
-       }
-       o->router_id = 0;
-       if (o->router_id_zebra)
-               o->router_id = o->router_id_zebra;
+
+       if (ospf6_router_id_update(o, false))
+               ospf6_process_reset(o);
+       else
+               vty_out(vty,
+                       "For this router-id change to take effect run the \"clear ipv6 ospf6 process\" command\n");
 
        return CMD_SUCCESS;
 }
@@ -1519,7 +1535,6 @@ DEFUN(show_ipv6_ospf6, show_ipv6_ospf6_cmd,
        bool uj = use_json(argc, argv);
        json_object *json = NULL;
 
-       OSPF6_CMD_CHECK_RUNNING();
        OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
 
        for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) {
@@ -1560,7 +1575,6 @@ DEFUN(show_ipv6_ospf6_route, show_ipv6_ospf6_route_cmd,
        int idx_arg_start = 4;
        bool uj = use_json(argc, argv);
 
-       OSPF6_CMD_CHECK_RUNNING();
        OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
        if (idx_vrf > 0)
                idx_arg_start += 2;
@@ -1594,7 +1608,6 @@ DEFUN(show_ipv6_ospf6_route_match, show_ipv6_ospf6_route_match_cmd,
        int idx_start_arg = 4;
        bool uj = use_json(argc, argv);
 
-       OSPF6_CMD_CHECK_RUNNING();
        OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
        if (idx_vrf > 0)
                idx_start_arg += 2;
@@ -1629,7 +1642,6 @@ DEFUN(show_ipv6_ospf6_route_match_detail,
        int idx_start_arg = 4;
        bool uj = use_json(argc, argv);
 
-       OSPF6_CMD_CHECK_RUNNING();
        OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
        if (idx_vrf > 0)
                idx_start_arg += 2;
@@ -1665,7 +1677,6 @@ DEFUN(show_ipv6_ospf6_route_type_detail, show_ipv6_ospf6_route_type_detail_cmd,
        int idx_start_arg = 4;
        bool uj = use_json(argc, argv);
 
-       OSPF6_CMD_CHECK_RUNNING();
        OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
        if (idx_vrf > 0)
                idx_start_arg += 2;
@@ -2078,7 +2089,6 @@ DEFPY (show_ipv6_ospf6_external_aggregator,
        if (uj)
                json = json_object_new_object();
 
-       OSPF6_CMD_CHECK_RUNNING();
        OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
 
        for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) {
@@ -2236,6 +2246,7 @@ static int config_write_ospf6(struct vty *vty)
                ospf6_distance_config_write(vty, ospf6);
                ospf6_distribute_config_write(vty, ospf6);
                ospf6_asbr_summary_config_write(vty, ospf6);
+               config_write_ospf6_gr(vty, ospf6);
                config_write_ospf6_gr_helper(vty, ospf6);
 
                vty_out(vty, "exit\n");
index 58ecf08495b9413ff9e36bb8b97b76587fae7a48..55cab72307e042e678ecbd4fa66bf3d96d08b976 100644 (file)
@@ -60,6 +60,15 @@ struct ospf6_redist {
 #define ROUTEMAP(R) (R->route_map.map)
 };
 
+struct ospf6_gr_info {
+       bool restart_support;
+       bool restart_in_progress;
+       bool prepare_in_progress;
+       bool finishing_restart;
+       uint32_t grace_period;
+       struct thread *t_grace_period;
+};
+
 struct ospf6_gr_helper {
        /* Gracefull restart Helper supported configs*/
        /* Supported grace interval*/
@@ -134,6 +143,18 @@ struct ospf6 {
        /* OSPF6 redistribute configuration */
        struct list *redist[ZEBRA_ROUTE_MAX + 1];
 
+       /* NSSA default-information-originate */
+       struct {
+               /* # of NSSA areas requesting default information */
+               uint16_t refcnt;
+
+               /*
+                * Whether a default route known through non-OSPF protocol is
+                * present in the RIB.
+                */
+               bool status;
+       } nssa_default_import_check;
+
        uint8_t flag;
 #define OSPF6_FLAG_ABR          0x04
 #define OSPF6_FLAG_ASBR         0x08
@@ -192,6 +213,9 @@ struct ospf6 {
         */
        uint16_t max_multipath;
 
+       /* OSPF Graceful Restart info (restarting mode) */
+       struct ospf6_gr_info gr_info;
+
        /*ospf6 Graceful restart helper info */
        struct ospf6_gr_helper ospf6_helper_cfg;
 
@@ -227,7 +251,7 @@ extern void ospf6_master_init(struct thread_master *master);
 extern void install_element_ospf6_clear_process(void);
 extern void ospf6_top_init(void);
 extern void ospf6_delete(struct ospf6 *o);
-extern void ospf6_router_id_update(struct ospf6 *ospf6);
+extern bool ospf6_router_id_update(struct ospf6 *ospf6, bool init);
 
 extern void ospf6_maxage_remove(struct ospf6 *o);
 extern struct ospf6 *ospf6_instance_create(const char *name);
index 5403e643dc664b542d7ed1b13a71695355f576f0..1a0c5a9971edd079941f5dab625f7484e0eeacff 100644 (file)
 #include "ospf6_lsa.h"
 #include "ospf6_lsdb.h"
 #include "ospf6_asbr.h"
+#include "ospf6_nssa.h"
 #include "ospf6_zebra.h"
 #include "ospf6d.h"
 #include "ospf6_area.h"
+#include "ospf6_gr.h"
 #include "lib/json.h"
 
 DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_DISTANCE, "OSPF6 distance");
@@ -101,7 +103,7 @@ static int ospf6_router_id_update_zebra(ZAPI_CALLBACK_ARGS)
 
        o->router_id_zebra = router_id.u.prefix4.s_addr;
 
-       ospf6_router_id_update(o);
+       ospf6_router_id_update(o, false);
 
        return 0;
 }
@@ -128,6 +130,61 @@ void ospf6_zebra_no_redistribute(int type, vrf_id_t vrf_id)
                                        AFI_IP6, type, 0, vrf_id);
 }
 
+void ospf6_zebra_import_default_route(struct ospf6 *ospf6, bool unreg)
+{
+       struct prefix prefix = {};
+       int command;
+
+       if (zclient->sock < 0) {
+               if (IS_OSPF6_DEBUG_ZEBRA(SEND))
+                       zlog_debug("  Not connected to Zebra");
+               return;
+       }
+
+       prefix.family = AF_INET6;
+       prefix.prefixlen = 0;
+
+       if (unreg)
+               command = ZEBRA_IMPORT_ROUTE_UNREGISTER;
+       else
+               command = ZEBRA_IMPORT_ROUTE_REGISTER;
+
+       if (IS_OSPF6_DEBUG_ZEBRA(SEND))
+               zlog_debug("%s: sending cmd %s for %pFX (vrf %u)", __func__,
+                          zserv_command_string(command), &prefix,
+                          ospf6->vrf_id);
+
+       if (zclient_send_rnh(zclient, command, &prefix, true, ospf6->vrf_id)
+           == ZCLIENT_SEND_FAILURE)
+               flog_err(EC_LIB_ZAPI_SOCKET, "%s: zclient_send_rnh() failed",
+                        __func__);
+}
+
+static int ospf6_zebra_import_check_update(ZAPI_CALLBACK_ARGS)
+{
+       struct ospf6 *ospf6;
+       struct zapi_route nhr;
+
+       ospf6 = ospf6_lookup_by_vrf_id(vrf_id);
+       if (ospf6 == NULL || !IS_OSPF6_ASBR(ospf6))
+               return 0;
+
+       if (!zapi_nexthop_update_decode(zclient->ibuf, &nhr)) {
+               zlog_err("%s[%u]: Failure to decode route", __func__,
+                        ospf6->vrf_id);
+               return -1;
+       }
+
+       if (nhr.prefix.family != AF_INET6 || nhr.prefix.prefixlen != 0
+           || nhr.type == ZEBRA_ROUTE_OSPF6)
+               return 0;
+
+       ospf6->nssa_default_import_check.status = !!nhr.nexthop_num;
+       ospf6_abr_nssa_type_7_defaults(ospf6);
+
+       return 0;
+}
+
 static int ospf6_zebra_if_address_update_add(ZAPI_CALLBACK_ARGS)
 {
        struct connected *c;
@@ -173,6 +230,36 @@ static int ospf6_zebra_if_address_update_delete(ZAPI_CALLBACK_ARGS)
        return 0;
 }
 
+static int ospf6_zebra_gr_update(struct ospf6 *ospf6, int command,
+                                uint32_t stale_time)
+{
+       struct zapi_cap api;
+
+       if (!zclient || zclient->sock < 0 || !ospf6)
+               return 1;
+
+       memset(&api, 0, sizeof(struct zapi_cap));
+       api.cap = command;
+       api.stale_removal_time = stale_time;
+       api.vrf_id = ospf6->vrf_id;
+
+       (void)zclient_capabilities_send(ZEBRA_CLIENT_CAPABILITIES, zclient,
+                                       &api);
+
+       return 0;
+}
+
+int ospf6_zebra_gr_enable(struct ospf6 *ospf6, uint32_t stale_time)
+{
+       return ospf6_zebra_gr_update(ospf6, ZEBRA_CLIENT_GR_CAPABILITIES,
+                                    stale_time);
+}
+
+int ospf6_zebra_gr_disable(struct ospf6 *ospf6)
+{
+       return ospf6_zebra_gr_update(ospf6, ZEBRA_CLIENT_GR_DISABLE, 0);
+}
+
 static int ospf6_zebra_read_route(ZAPI_CALLBACK_ARGS)
 {
        struct zapi_route api;
@@ -384,12 +471,30 @@ static void ospf6_zebra_route_update(int type, struct ospf6_route *request,
 void ospf6_zebra_route_update_add(struct ospf6_route *request,
                                  struct ospf6 *ospf6)
 {
+       if (ospf6->gr_info.restart_in_progress
+           || ospf6->gr_info.prepare_in_progress) {
+               if (IS_DEBUG_OSPF6_GR)
+                       zlog_debug(
+                               "Zebra: Graceful Restart in progress -- not installing %pFX",
+                               &request->prefix);
+               return;
+       }
+
        ospf6_zebra_route_update(ADD, request, ospf6);
 }
 
 void ospf6_zebra_route_update_remove(struct ospf6_route *request,
                                     struct ospf6 *ospf6)
 {
+       if (ospf6->gr_info.restart_in_progress
+           || ospf6->gr_info.prepare_in_progress) {
+               if (IS_DEBUG_OSPF6_GR)
+                       zlog_debug(
+                               "Zebra: Graceful Restart in progress -- not uninstalling %pFX",
+                               &request->prefix);
+               return;
+       }
+
        ospf6_zebra_route_update(REM, request, ospf6);
 }
 
@@ -398,6 +503,15 @@ void ospf6_zebra_add_discard(struct ospf6_route *request, struct ospf6 *ospf6)
        struct zapi_route api;
        struct prefix *dest = &request->prefix;
 
+       if (ospf6->gr_info.restart_in_progress
+           || ospf6->gr_info.prepare_in_progress) {
+               if (IS_DEBUG_OSPF6_GR)
+                       zlog_debug(
+                               "Zebra: Graceful Restart in progress -- not installing %pFX",
+                               &request->prefix);
+               return;
+       }
+
        if (!CHECK_FLAG(request->flag, OSPF6_ROUTE_BLACKHOLE_ADDED)) {
                memset(&api, 0, sizeof(api));
                api.vrf_id = ospf6->vrf_id;
@@ -426,6 +540,15 @@ void ospf6_zebra_delete_discard(struct ospf6_route *request,
        struct zapi_route api;
        struct prefix *dest = &request->prefix;
 
+       if (ospf6->gr_info.restart_in_progress
+           || ospf6->gr_info.prepare_in_progress) {
+               if (IS_DEBUG_OSPF6_GR)
+                       zlog_debug(
+                               "Zebra: Graceful Restart in progress -- not uninstalling %pFX",
+                               &request->prefix);
+               return;
+       }
+
        if (CHECK_FLAG(request->flag, OSPF6_ROUTE_BLACKHOLE_ADDED)) {
                memset(&api, 0, sizeof(api));
                api.vrf_id = ospf6->vrf_id;
@@ -597,6 +720,7 @@ void ospf6_zebra_init(struct thread_master *master)
                ospf6_zebra_if_address_update_delete;
        zclient->redistribute_route_add = ospf6_zebra_read_route;
        zclient->redistribute_route_del = ospf6_zebra_read_route;
+       zclient->import_check_update = ospf6_zebra_import_check_update;
 
        /* Install command element for zebra node. */
        install_element(VIEW_NODE, &show_ospf6_zebra_cmd);
index a3ccc3d38db5287dcb228b94bee2860d27dd05ed..572bed9f599753e31b364f5ee8517f1f1b268c93 100644 (file)
@@ -54,20 +54,26 @@ extern void ospf6_zebra_redistribute(int, vrf_id_t vrf_id);
 extern void ospf6_zebra_no_redistribute(int, vrf_id_t vrf_id);
 #define ospf6_zebra_is_redistribute(type, vrf_id)                              \
        vrf_bitmap_check(zclient->redist[AFI_IP6][type], vrf_id)
-extern void ospf6_zebra_init(struct thread_master *);
+extern void ospf6_zebra_init(struct thread_master *tm);
+extern void ospf6_zebra_import_default_route(struct ospf6 *ospf6, bool unreg);
 extern void ospf6_zebra_add_discard(struct ospf6_route *request,
                                    struct ospf6 *ospf6);
 extern void ospf6_zebra_delete_discard(struct ospf6_route *request,
                                       struct ospf6 *ospf6);
 
-extern void ospf6_distance_reset(struct ospf6 *);
-extern uint8_t ospf6_distance_apply(struct prefix_ipv6 *, struct ospf6_route *,
-                                   struct ospf6 *);
+extern void ospf6_distance_reset(struct ospf6 *ospf6);
+extern uint8_t ospf6_distance_apply(struct prefix_ipv6 *p,
+                                   struct ospf6_route * or,
+                                   struct ospf6 *ospf6);
 
-extern int ospf6_distance_set(struct vty *, struct ospf6 *, const char *,
-                             const char *, const char *);
-extern int ospf6_distance_unset(struct vty *, struct ospf6 *, const char *,
-                               const char *, const char *);
+extern int ospf6_zebra_gr_enable(struct ospf6 *ospf6, uint32_t stale_time);
+extern int ospf6_zebra_gr_disable(struct ospf6 *ospf6);
+extern int ospf6_distance_set(struct vty *vty, struct ospf6 *ospf6,
+                             const char *distance_str, const char *ip_str,
+                             const char *access_list_str);
+extern int ospf6_distance_unset(struct vty *vty, struct ospf6 *ospf6,
+                               const char *distance_str, const char *ip_str,
+                               const char *access_list_str);
 
 extern int config_write_ospf6_debug_zebra(struct vty *vty);
 extern void install_element_ospf6_debug_zebra(void);
index 0e8185cfeb81415a9ee48be13b03407e57f68ba7..5e6dcde991b5fbc77d3fdf5f428ed3f5121fa2a8 100644 (file)
@@ -413,7 +413,6 @@ DEFUN(show_ipv6_ospf6_database, show_ipv6_ospf6_database_cmd,
        int idx_vrf = 0;
        bool uj = use_json(argc, argv);
 
-       OSPF6_CMD_CHECK_RUNNING();
        OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
        if (idx_vrf > 0)
                idx_level += 2;
@@ -460,7 +459,6 @@ DEFUN(show_ipv6_ospf6_database_type, show_ipv6_ospf6_database_type_cmd,
        bool all_vrf = false;
        int idx_vrf = 0;
 
-       OSPF6_CMD_CHECK_RUNNING();
        OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
        if (idx_vrf > 0) {
                idx_lsa += 2;
@@ -505,7 +503,6 @@ DEFUN(show_ipv6_ospf6_database_id, show_ipv6_ospf6_database_id_cmd,
        bool all_vrf = false;
        int idx_vrf = 0;
 
-       OSPF6_CMD_CHECK_RUNNING();
        OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
        if (argv[idx_ipv4]->type == IPV4_TKN)
                inet_pton(AF_INET, argv[idx_ipv4]->arg, &id);
@@ -548,7 +545,6 @@ DEFUN(show_ipv6_ospf6_database_router, show_ipv6_ospf6_database_router_cmd,
        int idx_vrf = 0;
        bool uj = use_json(argc, argv);
 
-       OSPF6_CMD_CHECK_RUNNING();
        OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
        if (idx_vrf > 0) {
                idx_ipv4 += 2;
@@ -619,7 +615,6 @@ DEFUN_HIDDEN(
        bool all_vrf = false;
        int idx_vrf = 0;
 
-       OSPF6_CMD_CHECK_RUNNING();
        OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
        if (idx_vrf > 0)
                idx_ipv4 += 2;
@@ -672,7 +667,6 @@ DEFUN(show_ipv6_ospf6_database_type_id, show_ipv6_ospf6_database_type_id_cmd,
        bool all_vrf = false;
        int idx_vrf = 0;
 
-       OSPF6_CMD_CHECK_RUNNING();
        OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
        if (idx_vrf > 0) {
                idx_lsa += 2;
@@ -731,7 +725,6 @@ DEFUN(show_ipv6_ospf6_database_type_router,
        bool all_vrf = false;
        int idx_vrf = 0;
 
-       OSPF6_CMD_CHECK_RUNNING();
        OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
        if (idx_vrf > 0) {
                idx_lsa += 2;
@@ -782,7 +775,6 @@ DEFUN(show_ipv6_ospf6_database_id_router,
        bool all_vrf = false;
        int idx_vrf = 0;
 
-       OSPF6_CMD_CHECK_RUNNING();
        OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
        if (idx_vrf > 0) {
                idx_ls_id += 2;
@@ -833,7 +825,6 @@ DEFUN(show_ipv6_ospf6_database_adv_router_linkstate_id,
        bool all_vrf = false;
        int idx_vrf = 0;
 
-       OSPF6_CMD_CHECK_RUNNING();
        OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
        if (idx_vrf > 0) {
                idx_adv_rtr += 2;
@@ -891,7 +882,6 @@ DEFUN(show_ipv6_ospf6_database_type_id_router,
        bool all_vrf = false;
        int idx_vrf = 0;
 
-       OSPF6_CMD_CHECK_RUNNING();
        OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
        if (idx_vrf > 0) {
                idx_lsa += 2;
@@ -960,7 +950,6 @@ DEFUN (show_ipv6_ospf6_database_type_adv_router_linkstate_id,
        bool all_vrf = false;
        int idx_vrf = 0;
 
-       OSPF6_CMD_CHECK_RUNNING();
        OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
        if (idx_vrf > 0) {
                idx_lsa += 2;
@@ -1008,7 +997,6 @@ DEFUN(show_ipv6_ospf6_database_self_originated,
        uint32_t adv_router = 0;
        bool uj = use_json(argc, argv);
 
-       OSPF6_CMD_CHECK_RUNNING();
        OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
        if (idx_vrf > 0)
                idx_level += 2;
@@ -1063,7 +1051,6 @@ DEFUN(show_ipv6_ospf6_database_type_self_originated,
        bool all_vrf = false;
        int idx_vrf = 0;
 
-       OSPF6_CMD_CHECK_RUNNING();
        OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
        if (idx_vrf > 0) {
                idx_lsa += 2;
@@ -1123,7 +1110,6 @@ DEFUN(show_ipv6_ospf6_database_type_self_originated_linkstate_id,
        bool all_vrf = false;
        int idx_vrf = 0;
 
-       OSPF6_CMD_CHECK_RUNNING();
        OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
        if (idx_vrf > 0) {
                idx_lsa += 2;
@@ -1185,7 +1171,6 @@ DEFUN(show_ipv6_ospf6_database_type_id_self_originated,
        bool all_vrf = false;
        int idx_vrf = 0;
 
-       OSPF6_CMD_CHECK_RUNNING();
        OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
        if (idx_vrf > 0) {
                idx_lsa += 2;
@@ -1268,7 +1253,6 @@ DEFUN(show_ipv6_ospf6_border_routers, show_ipv6_ospf6_border_routers_cmd,
        int idx_vrf = 0;
        int idx_argc = 5;
 
-       OSPF6_CMD_CHECK_RUNNING();
        OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
        if (idx_vrf > 0) {
                idx_argc += 2;
@@ -1308,7 +1292,6 @@ DEFUN(show_ipv6_ospf6_linkstate, show_ipv6_ospf6_linkstate_cmd,
        bool all_vrf = false;
        int idx_vrf = 0;
 
-       OSPF6_CMD_CHECK_RUNNING();
        OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
        if (idx_vrf > 0)
                idx_ipv4 += 2;
@@ -1348,8 +1331,6 @@ DEFUN(show_ipv6_ospf6_linkstate_detail, show_ipv6_ospf6_linkstate_detail_cmd,
        bool all_vrf = false;
        int idx_vrf = 0;
 
-
-       OSPF6_CMD_CHECK_RUNNING();
        OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
        if (idx_vrf > 0)
                idx_detail += 2;
@@ -1374,20 +1355,6 @@ DEFUN(show_ipv6_ospf6_linkstate_detail, show_ipv6_ospf6_linkstate_detail_cmd,
        return CMD_SUCCESS;
 }
 
-static void ospf6_plist_add(struct prefix_list *plist)
-{
-       if (prefix_list_afi(plist) != AFI_IP6)
-               return;
-       ospf6_area_plist_update(plist, 1);
-}
-
-static void ospf6_plist_del(struct prefix_list *plist)
-{
-       if (prefix_list_afi(plist) != AFI_IP6)
-               return;
-       ospf6_area_plist_update(plist, 0);
-}
-
 /* Install ospf related commands. */
 void ospf6_init(struct thread_master *master)
 {
@@ -1402,11 +1369,12 @@ void ospf6_init(struct thread_master *master)
        ospf6_intra_init();
        ospf6_asbr_init();
        ospf6_abr_init();
+       ospf6_gr_init();
        ospf6_gr_helper_config_init();
 
        /* initialize hooks for modifying filter rules */
-       prefix_list_add_hook(ospf6_plist_add);
-       prefix_list_delete_hook(ospf6_plist_del);
+       prefix_list_add_hook(ospf6_plist_update);
+       prefix_list_delete_hook(ospf6_plist_update);
        access_list_add_hook(ospf6_filter_update);
        access_list_delete_hook(ospf6_filter_update);
 
index d5170be7cc8a6d28817386ac4c19bd325a767021..041a9b1df98cf82624320a997a954352eb2b3019 100644 (file)
@@ -93,12 +93,6 @@ extern struct thread_master *master;
 #define OSPF6_ROUTER_ID_STR "Specify Router-ID\n"
 #define OSPF6_LS_ID_STR     "Specify Link State ID\n"
 
-#define OSPF6_CMD_CHECK_RUNNING()                                              \
-       if (om6->ospf6 == NULL) {                                              \
-               vty_out(vty, "OSPFv3 is not running\n");                       \
-               return CMD_SUCCESS;                                            \
-       }
-
 #define IS_OSPF6_ASBR(O) ((O)->flag & OSPF6_FLAG_ASBR)
 #define OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf)            \
        if (argv_find(argv, argc, "vrf", &idx_vrf)) {                          \
index 5a4e4db69beb8a7080a3e4337880280fe25acc44..be626646a000ece7b415e8d31955518f2c8276c8 100644 (file)
@@ -12,6 +12,7 @@ vtysh_scan += \
        ospf6d/ospf6_area.c \
        ospf6d/ospf6_bfd.c \
        ospf6d/ospf6_flood.c \
+       ospf6d/ospf6_gr.c \
        ospf6d/ospf6_gr_helper.c \
        ospf6d/ospf6_interface.c \
        ospf6d/ospf6_intra.c \
@@ -40,6 +41,7 @@ ospf6d_libospf6_a_SOURCES = \
        ospf6d/ospf6_routemap_nb_config.c \
        ospf6d/ospf6_bfd.c \
        ospf6d/ospf6_flood.c \
+       ospf6d/ospf6_gr.c \
        ospf6d/ospf6_gr_helper.c \
        ospf6d/ospf6_interface.c \
        ospf6d/ospf6_intra.c \
@@ -96,6 +98,8 @@ clippy_scan += \
        ospf6d/ospf6_asbr.c \
        ospf6d/ospf6_lsa.c \
        ospf6d/ospf6_gr_helper.c \
+       ospf6d/ospf6_gr.c \
+       ospf6d/ospf6_route.c \
        # end
 
 nodist_ospf6d_ospf6d_SOURCES = \
index 11ad45d30f7a627f9c5e3a65efd433126df35444..b3eaf7bbdbb69137b0b7343ec64f6ec3b6b1d2d9 100644 (file)
@@ -723,14 +723,10 @@ void ospf_gr_helper_exit(struct ospf_neighbor *nbr,
 
        /* check exit triggered due to successful completion
         * of graceful restart.
-        * If no, bring down the neighbour.
         */
        if (reason != OSPF_GR_HELPER_COMPLETED) {
                if (IS_DEBUG_OSPF_GR)
-                       zlog_debug(
-                               "%s, Failed GR exit, so bringing down the neighbour",
-                               __func__);
-               OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_KillNbr);
+                       zlog_debug("%s, Unsuccessful GR exit", __func__);
        }
 
        /*Recalculate the DR for the network segment */
index eb7a8348e832e0452953229f137dc0dee754067c..81cc34600047b508f4156e0f499e1863d1f7bca0 100644 (file)
@@ -477,7 +477,7 @@ struct ospf_interface *ospf_if_lookup_recv_if(struct ospf *ospf,
                if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
                        continue;
 
-               if (if_is_loopback(oi->ifp) || if_is_vrf(oi->ifp))
+               if (if_is_loopback_or_vrf(oi->ifp))
                        continue;
 
                if (CHECK_FLAG(oi->connected->flags, ZEBRA_IFA_UNNUMBERED))
@@ -719,7 +719,7 @@ static int ospf_if_delete_hook(struct interface *ifp)
 
 int ospf_if_is_enable(struct ospf_interface *oi)
 {
-       if (!(if_is_loopback(oi->ifp) || if_is_vrf(oi->ifp)))
+       if (!(if_is_loopback_or_vrf(oi->ifp)))
                if (if_is_up(oi->ifp))
                        return 1;
 
@@ -1291,7 +1291,7 @@ uint8_t ospf_default_iftype(struct interface *ifp)
 {
        if (if_is_pointopoint(ifp))
                return OSPF_IFTYPE_POINTOPOINT;
-       else if (if_is_loopback(ifp) || if_is_vrf(ifp))
+       else if (if_is_loopback_or_vrf(ifp))
                return OSPF_IFTYPE_LOOPBACK;
        else
                return OSPF_IFTYPE_BROADCAST;
index 268fb81e52a9fd97d5c7b30e6d302f655df041a0..dee25275d69495fee364717007914b8e153f1607 100644 (file)
@@ -76,10 +76,13 @@ static int ospf_inactivity_timer(struct thread *thread)
         */
        if (!OSPF_GR_IS_ACTIVE_HELPER(nbr))
                OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_InactivityTimer);
-       else if (IS_DEBUG_OSPF_GR)
+       else if (IS_DEBUG_OSPF_GR) {
                zlog_debug(
-                       "%s, Acting as HELPER for this neighbour, So inactivitytimer event will not be fired.",
+                       "%s, Acting as HELPER for this neighbour, So restart the dead timer",
                        __func__);
+               OSPF_NSM_TIMER_ON(nbr->t_inactivity, ospf_inactivity_timer,
+                                 nbr->v_inactivity);
+       }
 
        return 0;
 }
index 3ae9707f5f95c46e31d455ec2007cfea0ca1c12b..4109ada64a198b1a28f81e1ed8613a8a30ce6ffe 100644 (file)
@@ -9894,24 +9894,17 @@ DEFUN (no_ospf_proactive_arp,
 
 /* Graceful Restart HELPER Commands */
 DEFPY(ospf_gr_helper_enable, ospf_gr_helper_enable_cmd,
-      "graceful-restart helper-only [A.B.C.D]",
+      "graceful-restart helper enable [A.B.C.D$address]",
       "OSPF Graceful Restart\n"
+      "OSPF GR Helper\n"
       "Enable Helper support\n"
-      "Advertising router id\n")
+      "Advertising Router-ID\n")
 {
        VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
-       struct in_addr addr;
-       int ret;
-
-       if (argc == 3) {
-               ret = inet_aton(argv[2]->arg, &addr);
-               if (!ret) {
-                       vty_out(vty,
-                               "Please specify the valid routerid address.\n");
-                       return CMD_WARNING_CONFIG_FAILED;
-               }
 
-               ospf_gr_helper_support_set_per_routerid(ospf, &addr, OSPF_GR_TRUE);
+       if (address_str) {
+               ospf_gr_helper_support_set_per_routerid(ospf, &address,
+                                                       OSPF_GR_TRUE);
                return CMD_SUCCESS;
        }
 
@@ -9922,33 +9915,68 @@ DEFPY(ospf_gr_helper_enable, ospf_gr_helper_enable_cmd,
 
 DEFPY(no_ospf_gr_helper_enable,
       no_ospf_gr_helper_enable_cmd,
-      "no graceful-restart helper-only [A.B.C.D]",
+      "no graceful-restart helper enable [A.B.C.D$address]",
       NO_STR
       "OSPF Graceful Restart\n"
-      "Disable Helper support\n"
+      "OSPF GR Helper\n"
+      "Enable Helper support\n"
+      "Advertising Router-ID\n")
+{
+       VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
+
+       if (address_str) {
+               ospf_gr_helper_support_set_per_routerid(ospf, &address,
+                                                       OSPF_GR_FALSE);
+               return CMD_SUCCESS;
+       }
+
+       ospf_gr_helper_support_set(ospf, OSPF_GR_FALSE);
+       return CMD_SUCCESS;
+}
+
+#if CONFDATE > 20220921
+CPP_NOTICE(
+       "Time to remove the deprecated \"[no] graceful-restart helper-only\" commands")
+#endif
+
+DEFPY_HIDDEN(ospf_gr_helper_only, ospf_gr_helper_only_cmd,
+      "graceful-restart helper-only [A.B.C.D]",
+      "OSPF Graceful Restart\n"
+      "Enable Helper support\n"
       "Advertising router id\n")
 {
        VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
        struct in_addr addr;
        int ret;
 
-       if (argc == 4) {
-               ret = inet_aton(argv[3]->arg, &addr);
+       vty_out(vty,
+               "%% This command is deprecated. Please, use `graceful-restart helper enable` instead.\n");
+
+       if (argc == 3) {
+               ret = inet_aton(argv[2]->arg, &addr);
                if (!ret) {
                        vty_out(vty,
                                "Please specify the valid routerid address.\n");
                        return CMD_WARNING_CONFIG_FAILED;
                }
 
-               ospf_gr_helper_support_set_per_routerid(ospf, &addr,
-                                                       OSPF_GR_FALSE);
+               ospf_gr_helper_support_set_per_routerid(ospf, &addr, OSPF_GR_TRUE);
                return CMD_SUCCESS;
        }
 
-       ospf_gr_helper_support_set(ospf, OSPF_GR_FALSE);
+       ospf_gr_helper_support_set(ospf, OSPF_GR_TRUE);
+
        return CMD_SUCCESS;
 }
 
+ALIAS_HIDDEN(no_ospf_gr_helper_enable,
+      no_ospf_gr_helper_only_cmd,
+      "no graceful-restart helper-only [A.B.C.D]",
+      NO_STR
+      "OSPF Graceful Restart\n"
+      "Disable Helper support\n"
+      "Advertising router id\n")
+
 DEFPY(ospf_gr_helper_enable_lsacheck,
       ospf_gr_helper_enable_lsacheck_cmd,
       "graceful-restart helper strict-lsa-checking",
@@ -12259,7 +12287,7 @@ static int ospf_cfg_write_helper_dis_rtr_walkcb(struct hash_bucket *bucket,
        struct advRtr *rtr = bucket->data;
        struct vty *vty = (struct vty *)arg;
 
-       vty_out(vty, " graceful-restart helper-only %pI4\n",
+       vty_out(vty, " graceful-restart helper enable %pI4\n",
                &rtr->advRtrAddr);
        return HASHWALK_CONTINUE;
 }
@@ -12279,7 +12307,7 @@ static void config_write_ospf_gr(struct vty *vty, struct ospf *ospf)
 static int config_write_ospf_gr_helper(struct vty *vty, struct ospf *ospf)
 {
        if (ospf->is_helper_supported)
-               vty_out(vty, " graceful-restart helper-only\n");
+               vty_out(vty, " graceful-restart helper enable\n");
 
        if (!ospf->strict_lsa_check)
                vty_out(vty,
@@ -12742,6 +12770,8 @@ static void ospf_vty_zebra_init(void)
        /*Ospf garcefull restart helper configurations */
        install_element(OSPF_NODE, &ospf_gr_helper_enable_cmd);
        install_element(OSPF_NODE, &no_ospf_gr_helper_enable_cmd);
+       install_element(OSPF_NODE, &ospf_gr_helper_only_cmd);
+       install_element(OSPF_NODE, &no_ospf_gr_helper_only_cmd);
        install_element(OSPF_NODE, &ospf_gr_helper_enable_lsacheck_cmd);
        install_element(OSPF_NODE, &no_ospf_gr_helper_enable_lsacheck_cmd);
        install_element(OSPF_NODE, &ospf_gr_helper_supported_grace_time_cmd);
index bd629a2b7048feaa4e3fdca249cdce7bbfd3be0e..46242fd05a6de8353c3566dd9cd579e616532eaf 100644 (file)
@@ -352,7 +352,16 @@ static int segment_list_has_src_dst(
                nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY,
                                      "ipv6_adjacency");
                node_src_id = adj_src_ipv6_str;
+       } else {
+               /*
+                * This is just to make the compiler happy about
+                * node_src_id not being initialized.  This
+                * should never happen unless we change the cli
+                * function.
+                */
+               assert(!"We must have a adj_src_ipv4_str or a adj_src_ipv6_str");
        }
+
        /* addresses */
        snprintf(xpath, XPATH_MAXLEN, "./segment[index='%s']/nai/local-address",
                 index_str);
index 63fda3fe34a1a83b9ee4dc1539c72ce2b6820060..c07cbeb0132dc2b6bef0b0a68d82d415a02a50ab 100644 (file)
 
 #include "if.h"
 
-#include "pim_neighbor.h"
-#include "pim_ifchannel.h"
+struct pim_ifchannel;
+struct pim_neighbor;
+
+enum pim_ifassert_state {
+       PIM_IFASSERT_NOINFO,
+       PIM_IFASSERT_I_AM_WINNER,
+       PIM_IFASSERT_I_AM_LOSER
+};
+
+struct pim_assert_metric {
+       uint32_t rpt_bit_flag;
+       uint32_t metric_preference;
+       uint32_t route_metric;
+       struct in_addr ip_address; /* neighbor router that sourced the Assert
+                                     message */
+};
 
 /*
   RFC 4601: 4.11.  Timer Values
index dfe2d5f2fa1fd0a8781e0edbfebcac2bda579fed..c7fcbba71ef27f03c947b517c9837a788ad93044 100644 (file)
@@ -28,6 +28,7 @@
 #include "zclient.h"
 
 #include "pim_instance.h"
+#include "pim_neighbor.h"
 #include "pim_cmd.h"
 #include "pim_vty.h"
 #include "pim_iface.h"
index f2845ee6e12cd8ff99ba702173fc36c9b179a02a..a3a3426f39098f5beaef0c1fc556e4e9a5420d1e 100644 (file)
@@ -28,6 +28,7 @@
 #include "pimd.h"
 #include "pim_iface.h"
 #include "pim_instance.h"
+#include "pim_neighbor.h"
 #include "pim_rpf.h"
 #include "pim_hello.h"
 #include "pim_pim.h"
index 1238e03a5bbc309e98efd9079e18390f0dd224ca..4cd94e0df9ac8baecc3a7030633094b19d19e02a 100644 (file)
@@ -3430,112 +3430,87 @@ static void igmp_show_groups(struct pim_instance *pim, struct vty *vty, bool uj)
                        pim->igmp_watermark_limit ? "Set" : "Not Set",
                        pim->igmp_watermark_limit);
                vty_out(vty,
-                       "Interface        Address         Group           Mode Timer    Srcs V Uptime  \n");
+                       "Interface        Group           Mode Timer    Srcs V Uptime  \n");
        }
 
        /* scan interfaces */
        FOR_ALL_INTERFACES (pim->vrf, ifp) {
                struct pim_interface *pim_ifp = ifp->info;
-               struct listnode *sock_node;
-               struct igmp_sock *igmp;
+               struct listnode *grpnode;
+               struct igmp_group *grp;
 
                if (!pim_ifp)
                        continue;
 
-               /* scan igmp sockets */
-               for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node,
-                                         igmp)) {
-                       char ifaddr_str[INET_ADDRSTRLEN];
-                       struct listnode *grpnode;
-                       struct igmp_group *grp;
-
-                       pim_inet4_dump("<ifaddr?>", igmp->ifaddr, ifaddr_str,
-                                      sizeof(ifaddr_str));
-
-                       /* scan igmp groups */
-                       for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list,
-                                                 grpnode, grp)) {
-                               char group_str[INET_ADDRSTRLEN];
-                               char hhmmss[10];
-                               char uptime[10];
+               /* scan igmp groups */
+               for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_group_list, grpnode,
+                                         grp)) {
+                       char group_str[INET_ADDRSTRLEN];
+                       char hhmmss[10];
+                       char uptime[10];
 
-                               pim_inet4_dump("<group?>", grp->group_addr,
-                                              group_str, sizeof(group_str));
-                               pim_time_timer_to_hhmmss(hhmmss, sizeof(hhmmss),
-                                                        grp->t_group_timer);
-                               pim_time_uptime(uptime, sizeof(uptime),
-                                               now - grp->group_creation);
+                       pim_inet4_dump("<group?>", grp->group_addr, group_str,
+                                      sizeof(group_str));
+                       pim_time_timer_to_hhmmss(hhmmss, sizeof(hhmmss),
+                                                grp->t_group_timer);
+                       pim_time_uptime(uptime, sizeof(uptime),
+                                       now - grp->group_creation);
 
-                               if (uj) {
-                                       json_object_object_get_ex(
-                                               json, ifp->name, &json_iface);
-
-                                       if (!json_iface) {
-                                               json_iface =
-                                                       json_object_new_object();
-                                               json_object_pim_ifp_add(
-                                                       json_iface, ifp);
-                                               json_object_object_add(
-                                                       json, ifp->name,
-                                                       json_iface);
-                                               json_groups =
-                                                       json_object_new_array();
-                                               json_object_object_add(
-                                                       json_iface,
-                                                       "groups",
-                                                       json_groups);
-                                       }
+                       if (uj) {
+                               json_object_object_get_ex(json, ifp->name,
+                                                         &json_iface);
 
-                                       json_group = json_object_new_object();
-                                       json_object_string_add(json_group,
-                                                              "source",
-                                                              ifaddr_str);
-                                       json_object_string_add(json_group,
-                                                              "group",
-                                                              group_str);
-
-                                       if (grp->igmp_version == 3)
-                                               json_object_string_add(
-                                                       json_group, "mode",
-                                                       grp->group_filtermode_isexcl
+                               if (!json_iface) {
+                                       json_iface = json_object_new_object();
+                                       json_object_pim_ifp_add(json_iface,
+                                                               ifp);
+                                       json_object_object_add(json, ifp->name,
+                                                              json_iface);
+                                       json_groups = json_object_new_array();
+                                       json_object_object_add(json_iface,
+                                                              "groups",
+                                                              json_groups);
+                               }
+
+                               json_group = json_object_new_object();
+                               json_object_string_add(json_group, "group",
+                                                      group_str);
+
+                               if (grp->igmp_version == 3)
+                                       json_object_string_add(
+                                               json_group, "mode",
+                                               grp->group_filtermode_isexcl
                                                        ? "EXCLUDE"
                                                        : "INCLUDE");
 
-                                       json_object_string_add(json_group,
-                                                              "timer", hhmmss);
-                                       json_object_int_add(
-                                               json_group, "sourcesCount",
-                                               grp->group_source_list
-                                               ? listcount(
-                                                       grp->group_source_list)
-                                               : 0);
-                                       json_object_int_add(
-                                               json_group, "version",
-                                               grp->igmp_version);
-                                       json_object_string_add(
-                                               json_group, "uptime", uptime);
-                                       json_object_array_add(json_groups,
-                                                             json_group);
-                               } else {
-                                       vty_out(vty,
-                                               "%-16s %-15s %-15s %4s %8s %4d %d %8s\n",
-                                               ifp->name, ifaddr_str,
-                                               group_str,
-                                               grp->igmp_version == 3
+                               json_object_string_add(json_group, "timer",
+                                                      hhmmss);
+                               json_object_int_add(
+                                       json_group, "sourcesCount",
+                                       grp->group_source_list ? listcount(
+                                               grp->group_source_list)
+                                                              : 0);
+                               json_object_int_add(json_group, "version",
+                                                   grp->igmp_version);
+                               json_object_string_add(json_group, "uptime",
+                                                      uptime);
+                               json_object_array_add(json_groups, json_group);
+                       } else {
+                               vty_out(vty, "%-16s %-15s %4s %8s %4d %d %8s\n",
+                                       ifp->name, group_str,
+                                       grp->igmp_version == 3
                                                ? (grp->group_filtermode_isexcl
-                                                  ? "EXCL"
-                                                  : "INCL")
+                                                          ? "EXCL"
+                                                          : "INCL")
                                                : "----",
-                                               hhmmss,
-                                               grp->group_source_list
-                                               ? listcount(
-                                                       grp->group_source_list)
-                                               : 0,
-                                               grp->igmp_version, uptime);
-                               }
-                       } /* scan igmp groups */
-               }        /* scan igmp sockets */
-       }                 /* scan interfaces */
+                                       hhmmss,
+                                       grp->group_source_list ? listcount(
+                                               grp->group_source_list)
+                                                              : 0,
+                                       grp->igmp_version, uptime);
+                       }
+               } /* scan igmp groups */
+       }         /* scan interfaces */
 
        if (uj) {
                vty_out(vty, "%s\n", json_object_to_json_string_ext(
@@ -3550,63 +3525,49 @@ static void igmp_show_group_retransmission(struct pim_instance *pim,
        struct interface *ifp;
 
        vty_out(vty,
-               "Interface        Address         Group           RetTimer Counter RetSrcs\n");
+               "Interface        Group           RetTimer Counter RetSrcs\n");
 
        /* scan interfaces */
        FOR_ALL_INTERFACES (pim->vrf, ifp) {
                struct pim_interface *pim_ifp = ifp->info;
-               struct listnode *sock_node;
-               struct igmp_sock *igmp;
+               struct listnode *grpnode;
+               struct igmp_group *grp;
 
                if (!pim_ifp)
                        continue;
 
-               /* scan igmp sockets */
-               for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node,
-                                         igmp)) {
-                       char ifaddr_str[INET_ADDRSTRLEN];
-                       struct listnode *grpnode;
-                       struct igmp_group *grp;
-
-                       pim_inet4_dump("<ifaddr?>", igmp->ifaddr, ifaddr_str,
-                                      sizeof(ifaddr_str));
-
-                       /* scan igmp groups */
-                       for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list,
-                                                 grpnode, grp)) {
-                               char group_str[INET_ADDRSTRLEN];
-                               char grp_retr_mmss[10];
-                               struct listnode *src_node;
-                               struct igmp_source *src;
-                               int grp_retr_sources = 0;
-
-                               pim_inet4_dump("<group?>", grp->group_addr,
-                                              group_str, sizeof(group_str));
-                               pim_time_timer_to_mmss(
-                                       grp_retr_mmss, sizeof(grp_retr_mmss),
-                                       grp->t_group_query_retransmit_timer);
-
-
-                               /* count group sources with retransmission state
-                                */
-                               for (ALL_LIST_ELEMENTS_RO(
-                                            grp->group_source_list, src_node,
-                                            src)) {
-                                       if (src->source_query_retransmit_count
-                                           > 0) {
-                                               ++grp_retr_sources;
-                                       }
+               /* scan igmp groups */
+               for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_group_list, grpnode,
+                                         grp)) {
+                       char group_str[INET_ADDRSTRLEN];
+                       char grp_retr_mmss[10];
+                       struct listnode *src_node;
+                       struct igmp_source *src;
+                       int grp_retr_sources = 0;
+
+                       pim_inet4_dump("<group?>", grp->group_addr, group_str,
+                                      sizeof(group_str));
+                       pim_time_timer_to_mmss(
+                               grp_retr_mmss, sizeof(grp_retr_mmss),
+                               grp->t_group_query_retransmit_timer);
+
+
+                       /* count group sources with retransmission state
+                        */
+                       for (ALL_LIST_ELEMENTS_RO(grp->group_source_list,
+                                                 src_node, src)) {
+                               if (src->source_query_retransmit_count > 0) {
+                                       ++grp_retr_sources;
                                }
+                       }
 
-                               vty_out(vty, "%-16s %-15s %-15s %-8s %7d %7d\n",
-                                       ifp->name, ifaddr_str, group_str,
-                                       grp_retr_mmss,
-                                       grp->group_specific_query_retransmit_count,
-                                       grp_retr_sources);
+                       vty_out(vty, "%-16s %-15s %-8s %7d %7d\n", ifp->name,
+                               group_str, grp_retr_mmss,
+                               grp->group_specific_query_retransmit_count,
+                               grp_retr_sources);
 
-                       } /* scan igmp groups */
-               }        /* scan igmp sockets */
-       }                 /* scan interfaces */
+               } /* scan igmp groups */
+       }         /* scan interfaces */
 }
 
 static void igmp_show_sources(struct pim_instance *pim, struct vty *vty)
@@ -3617,71 +3578,54 @@ static void igmp_show_sources(struct pim_instance *pim, struct vty *vty)
        now = pim_time_monotonic_sec();
 
        vty_out(vty,
-               "Interface        Address         Group           Source          Timer Fwd Uptime  \n");
+               "Interface        Group           Source          Timer Fwd Uptime  \n");
 
        /* scan interfaces */
        FOR_ALL_INTERFACES (pim->vrf, ifp) {
                struct pim_interface *pim_ifp = ifp->info;
-               struct listnode *sock_node;
-               struct igmp_sock *igmp;
+               struct listnode *grpnode;
+               struct igmp_group *grp;
 
                if (!pim_ifp)
                        continue;
 
-               /* scan igmp sockets */
-               for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node,
-                                         igmp)) {
-                       char ifaddr_str[INET_ADDRSTRLEN];
-                       struct listnode *grpnode;
-                       struct igmp_group *grp;
+               /* scan igmp groups */
+               for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_group_list, grpnode,
+                                         grp)) {
+                       char group_str[INET_ADDRSTRLEN];
+                       struct listnode *srcnode;
+                       struct igmp_source *src;
+
+                       pim_inet4_dump("<group?>", grp->group_addr, group_str,
+                                      sizeof(group_str));
 
-                       pim_inet4_dump("<ifaddr?>", igmp->ifaddr, ifaddr_str,
-                                      sizeof(ifaddr_str));
+                       /* scan group sources */
+                       for (ALL_LIST_ELEMENTS_RO(grp->group_source_list,
+                                                 srcnode, src)) {
+                               char source_str[INET_ADDRSTRLEN];
+                               char mmss[10];
+                               char uptime[10];
 
-                       /* scan igmp groups */
-                       for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list,
-                                                 grpnode, grp)) {
-                               char group_str[INET_ADDRSTRLEN];
-                               struct listnode *srcnode;
-                               struct igmp_source *src;
+                               pim_inet4_dump("<source?>", src->source_addr,
+                                              source_str, sizeof(source_str));
 
-                               pim_inet4_dump("<group?>", grp->group_addr,
-                                              group_str, sizeof(group_str));
+                               pim_time_timer_to_mmss(mmss, sizeof(mmss),
+                                                      src->t_source_timer);
 
-                               /* scan group sources */
-                               for (ALL_LIST_ELEMENTS_RO(
-                                            grp->group_source_list, srcnode,
-                                            src)) {
-                                       char source_str[INET_ADDRSTRLEN];
-                                       char mmss[10];
-                                       char uptime[10];
-
-                                       pim_inet4_dump(
-                                               "<source?>", src->source_addr,
-                                               source_str, sizeof(source_str));
-
-                                       pim_time_timer_to_mmss(
-                                               mmss, sizeof(mmss),
-                                               src->t_source_timer);
-
-                                       pim_time_uptime(
-                                               uptime, sizeof(uptime),
+                               pim_time_uptime(uptime, sizeof(uptime),
                                                now - src->source_creation);
 
-                                       vty_out(vty,
-                                               "%-16s %-15s %-15s %-15s %5s %3s %8s\n",
-                                               ifp->name, ifaddr_str,
-                                               group_str, source_str, mmss,
-                                               IGMP_SOURCE_TEST_FORWARDING(
-                                                       src->source_flags)
+                               vty_out(vty, "%-16s %-15s %-15s %5s %3s %8s\n",
+                                       ifp->name, group_str, source_str, mmss,
+                                       IGMP_SOURCE_TEST_FORWARDING(
+                                               src->source_flags)
                                                ? "Y"
                                                : "N",
-                                               uptime);
+                                       uptime);
 
-                               } /* scan group sources */
-                       }        /* scan igmp groups */
-               }                 /* scan igmp sockets */
-       }                         /* scan interfaces */
+                       } /* scan group sources */
+               }         /* scan igmp groups */
+       }                 /* scan interfaces */
 }
 
 static void igmp_show_source_retransmission(struct pim_instance *pim,
@@ -3690,57 +3634,42 @@ static void igmp_show_source_retransmission(struct pim_instance *pim,
        struct interface *ifp;
 
        vty_out(vty,
-               "Interface        Address         Group           Source          Counter\n");
+               "Interface        Group           Source          Counter\n");
 
        /* scan interfaces */
        FOR_ALL_INTERFACES (pim->vrf, ifp) {
                struct pim_interface *pim_ifp = ifp->info;
-               struct listnode *sock_node;
-               struct igmp_sock *igmp;
+               struct listnode *grpnode;
+               struct igmp_group *grp;
 
                if (!pim_ifp)
                        continue;
 
-               /* scan igmp sockets */
-               for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node,
-                                         igmp)) {
-                       char ifaddr_str[INET_ADDRSTRLEN];
-                       struct listnode *grpnode;
-                       struct igmp_group *grp;
-
-                       pim_inet4_dump("<ifaddr?>", igmp->ifaddr, ifaddr_str,
-                                      sizeof(ifaddr_str));
-
-                       /* scan igmp groups */
-                       for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list,
-                                                 grpnode, grp)) {
-                               char group_str[INET_ADDRSTRLEN];
-                               struct listnode *srcnode;
-                               struct igmp_source *src;
+               /* scan igmp groups */
+               for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_group_list, grpnode,
+                                         grp)) {
+                       char group_str[INET_ADDRSTRLEN];
+                       struct listnode *srcnode;
+                       struct igmp_source *src;
 
-                               pim_inet4_dump("<group?>", grp->group_addr,
-                                              group_str, sizeof(group_str));
+                       pim_inet4_dump("<group?>", grp->group_addr, group_str,
+                                      sizeof(group_str));
 
-                               /* scan group sources */
-                               for (ALL_LIST_ELEMENTS_RO(
-                                            grp->group_source_list, srcnode,
-                                            src)) {
-                                       char source_str[INET_ADDRSTRLEN];
+                       /* scan group sources */
+                       for (ALL_LIST_ELEMENTS_RO(grp->group_source_list,
+                                                 srcnode, src)) {
+                               char source_str[INET_ADDRSTRLEN];
 
-                                       pim_inet4_dump(
-                                               "<source?>", src->source_addr,
-                                               source_str, sizeof(source_str));
+                               pim_inet4_dump("<source?>", src->source_addr,
+                                              source_str, sizeof(source_str));
 
-                                       vty_out(vty,
-                                               "%-16s %-15s %-15s %-15s %7d\n",
-                                               ifp->name, ifaddr_str,
-                                               group_str, source_str,
-                                               src->source_query_retransmit_count);
+                               vty_out(vty, "%-16s %-15s %-15s %7d\n",
+                                       ifp->name, group_str, source_str,
+                                       src->source_query_retransmit_count);
 
-                               } /* scan group sources */
-                       }        /* scan igmp groups */
-               }                 /* scan igmp sockets */
-       }                         /* scan interfaces */
+                       } /* scan group sources */
+               }         /* scan igmp groups */
+       }                 /* scan interfaces */
 }
 
 static void pim_show_bsr(struct pim_instance *pim,
@@ -3913,7 +3842,7 @@ static void pim_cli_legacy_mesh_group_behavior(struct vty *vty,
                              xpath_member_value)) {
                member_dnode = yang_dnode_get(vty->candidate_config->dnode,
                                              xpath_member_value);
-               if (!yang_is_last_list_dnode(member_dnode))
+               if (!member_dnode || !yang_is_last_list_dnode(member_dnode))
                        return;
        }
 
@@ -3993,8 +3922,7 @@ static void clear_mroute(struct pim_instance *pim)
        /* scan interfaces */
        FOR_ALL_INTERFACES (pim->vrf, ifp) {
                struct pim_interface *pim_ifp = ifp->info;
-               struct listnode *sock_node;
-               struct igmp_sock *igmp;
+               struct igmp_group *grp;
                struct pim_ifchannel *ch;
 
                if (!pim_ifp)
@@ -4008,20 +3936,12 @@ static void clear_mroute(struct pim_instance *pim)
                }
 
                /* clean up all igmp groups */
-               /* scan igmp sockets */
-               for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node,
-                                         igmp)) {
-
-                       struct igmp_group *grp;
 
-                       if (igmp->igmp_group_list) {
-                               while (igmp->igmp_group_list->count) {
-                                       grp = listnode_head(
-                                               igmp->igmp_group_list);
-                                       igmp_group_delete(grp);
-                               }
+               if (pim_ifp->igmp_group_list) {
+                       while (pim_ifp->igmp_group_list->count) {
+                               grp = listnode_head(pim_ifp->igmp_group_list);
+                               igmp_group_delete(grp);
                        }
-
                }
        }
 
@@ -4220,10 +4140,9 @@ static void clear_pim_bsr_db(struct pim_instance *pim)
                        rpnode->info = NULL;
                        route_unlock_node(rpnode);
                        route_unlock_node(rpnode);
+                       XFREE(MTYPE_PIM_RP, rp_info);
                }
 
-               XFREE(MTYPE_PIM_RP, rp_info);
-
                pim_free_bsgrp_node(bsgrp->scope->bsrp_table, &bsgrp->group);
                pim_free_bsgrp_data(bsgrp);
        }
@@ -9842,7 +9761,7 @@ DEFPY(no_ip_msdp_mesh_group_member,
                return CMD_WARNING_CONFIG_FAILED;
        }
 
-       nb_cli_enqueue_change(vty, xpath_value, NB_OP_DESTROY, NULL);
+       nb_cli_enqueue_change(vty, xpath_member_value, NB_OP_DESTROY, NULL);
 
        /*
         * If this is the last member, then we must remove the group altogether
@@ -9876,7 +9795,7 @@ DEFPY(ip_msdp_mesh_group_source,
                 "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname);
        nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL);
 
-       /* Create mesh group member. */
+       /* Create mesh group source. */
        strlcat(xpath_value, "/source", sizeof(xpath_value));
        nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, saddr_str);
 
@@ -9907,7 +9826,7 @@ DEFPY(no_ip_msdp_mesh_group_source,
                 "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname);
        nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL);
 
-       /* Create mesh group member. */
+       /* Create mesh group source. */
        strlcat(xpath_value, "/source", sizeof(xpath_value));
        nb_cli_enqueue_change(vty, xpath_value, NB_OP_DESTROY, NULL);
 
index 0b28a3e84c36e6d2d2a95e0d4fbe6ed1a6867d3b..eb19cf4ddfda0a9a89028cdfc62f47ac20d8f0af 100644 (file)
@@ -156,14 +156,12 @@ struct pim_interface *pim_if_new(struct interface *ifp, bool igmp, bool pim,
        PIM_IF_DO_IGMP_LISTEN_ALLROUTERS(pim_ifp->options);
 
        pim_ifp->igmp_join_list = NULL;
-       pim_ifp->igmp_socket_list = NULL;
        pim_ifp->pim_neighbor_list = NULL;
        pim_ifp->upstream_switch_list = NULL;
        pim_ifp->pim_generation_id = 0;
 
        /* list of struct igmp_sock */
-       pim_ifp->igmp_socket_list = list_new();
-       pim_ifp->igmp_socket_list->del = (void (*)(void *))igmp_sock_free;
+       pim_igmp_if_init(pim_ifp, ifp);
 
        /* list of struct pim_neighbor */
        pim_ifp->pim_neighbor_list = list_new();
@@ -214,7 +212,8 @@ void pim_if_delete(struct interface *ifp)
        pim_if_del_vif(ifp);
        pim_ifp->pim->mcast_if_count--;
 
-       list_delete(&pim_ifp->igmp_socket_list);
+       pim_igmp_if_fini(pim_ifp);
+
        list_delete(&pim_ifp->pim_neighbor_list);
        list_delete(&pim_ifp->upstream_switch_list);
        list_delete(&pim_ifp->sec_addr_list);
index 92784103fe4e5928e4a506cf39cd6f62fbc6aa71..55c278d6e2381f970032707dfadee4e5d54403fb 100644 (file)
@@ -30,6 +30,7 @@
 
 #include "pim_igmp.h"
 #include "pim_upstream.h"
+#include "pim_instance.h"
 #include "bfd.h"
 
 #define PIM_IF_MASK_PIM                             (1 << 0)
@@ -102,6 +103,8 @@ struct pim_interface {
        int igmp_last_member_query_count; /* IGMP last member query count */
        struct list *igmp_socket_list; /* list of struct igmp_sock */
        struct list *igmp_join_list;   /* list of struct igmp_join */
+       struct list *igmp_group_list;  /* list of struct igmp_group */
+       struct hash *igmp_group_hash;
 
        int pim_sock_fd;                /* PIM socket file descriptor */
        struct thread *t_pim_sock_read; /* thread for reading PIM socket */
index 7ec8191e568704d07f42277194405b8a42c60b05..52f02a660b7e4681a63863c76e2a8d601d335524 100644 (file)
@@ -25,6 +25,8 @@
 #include "if.h"
 #include "prefix.h"
 
+#include "pim_assert.h"
+
 struct pim_ifchannel;
 #include "pim_upstream.h"
 
@@ -39,20 +41,6 @@ enum pim_ifjoin_state {
        PIM_IFJOIN_PRUNE_PENDING_TMP,
 };
 
-enum pim_ifassert_state {
-       PIM_IFASSERT_NOINFO,
-       PIM_IFASSERT_I_AM_WINNER,
-       PIM_IFASSERT_I_AM_LOSER
-};
-
-struct pim_assert_metric {
-       uint32_t rpt_bit_flag;
-       uint32_t metric_preference;
-       uint32_t route_metric;
-       struct in_addr ip_address; /* neighbor router that sourced the Assert
-                                     message */
-};
-
 /*
   Flag to detect change in CouldAssert(S,G,I)
 */
index 71b2d9187ae19815d7491a8143e1e31d0a485d0e..795c96c83801bad11b058cf5dadab62c5d73c1a4 100644 (file)
@@ -671,7 +671,6 @@ void pim_igmp_general_query_on(struct igmp_sock *igmp)
                        ifaddr_str, query_interval,
                        startup_mode ? "startup" : "non-startup", igmp->fd);
        }
-       igmp->t_igmp_query_timer = NULL;
        thread_add_timer(router->master, pim_igmp_general_query, igmp,
                         query_interval, &igmp->t_igmp_query_timer);
 }
@@ -810,13 +809,8 @@ static void igmp_group_free(struct igmp_group *group)
        XFREE(MTYPE_PIM_IGMP_GROUP, group);
 }
 
-static void igmp_group_count_incr(struct igmp_sock *igmp)
+static void igmp_group_count_incr(struct pim_interface *pim_ifp)
 {
-       struct pim_interface *pim_ifp = igmp->interface->info;
-
-       if (!pim_ifp)
-               return;
-
        ++pim_ifp->pim->igmp_group_count;
        if (pim_ifp->pim->igmp_group_count
            == pim_ifp->pim->igmp_watermark_limit) {
@@ -827,13 +821,8 @@ static void igmp_group_count_incr(struct igmp_sock *igmp)
        }
 }
 
-static void igmp_group_count_decr(struct igmp_sock *igmp)
+static void igmp_group_count_decr(struct pim_interface *pim_ifp)
 {
-       struct pim_interface *pim_ifp = igmp->interface->info;
-
-       if (!pim_ifp)
-               return;
-
        if (pim_ifp->pim->igmp_group_count == 0) {
                zlog_warn("Cannot decrement igmp group count below 0(vrf: %s)",
                          VRF_LOGNAME(pim_ifp->pim->vrf));
@@ -848,14 +837,14 @@ void igmp_group_delete(struct igmp_group *group)
        struct listnode *src_node;
        struct listnode *src_nextnode;
        struct igmp_source *src;
+       struct pim_interface *pim_ifp = group->interface->info;
 
        if (PIM_DEBUG_IGMP_TRACE) {
                char group_str[INET_ADDRSTRLEN];
                pim_inet4_dump("<group?>", group->group_addr, group_str,
                               sizeof(group_str));
-               zlog_debug("Deleting IGMP group %s from socket %d interface %s",
-                          group_str, group->group_igmp_sock->fd,
-                          group->group_igmp_sock->interface->name);
+               zlog_debug("Deleting IGMP group %s from interface %s",
+                          group_str, group->interface->name);
        }
 
        for (ALL_LIST_ELEMENTS(group->group_source_list, src_node, src_nextnode,
@@ -866,9 +855,9 @@ void igmp_group_delete(struct igmp_group *group)
        THREAD_OFF(group->t_group_query_retransmit_timer);
 
        group_timer_off(group);
-       igmp_group_count_decr(group->group_igmp_sock);
-       listnode_delete(group->group_igmp_sock->igmp_group_list, group);
-       hash_release(group->group_igmp_sock->igmp_group_hash, group);
+       igmp_group_count_decr(pim_ifp);
+       listnode_delete(pim_ifp->igmp_group_list, group);
+       hash_release(pim_ifp->igmp_group_hash, group);
 
        igmp_group_free(group);
 }
@@ -886,11 +875,6 @@ void igmp_sock_free(struct igmp_sock *igmp)
        assert(!igmp->t_igmp_read);
        assert(!igmp->t_igmp_query_timer);
        assert(!igmp->t_other_querier_timer);
-       assert(igmp->igmp_group_list);
-       assert(!listcount(igmp->igmp_group_list));
-
-       list_delete(&igmp->igmp_group_list);
-       hash_free(igmp->igmp_group_hash);
 
        XFREE(MTYPE_PIM_IGMP_SOCKET, igmp);
 }
@@ -898,14 +882,6 @@ void igmp_sock_free(struct igmp_sock *igmp)
 void igmp_sock_delete(struct igmp_sock *igmp)
 {
        struct pim_interface *pim_ifp;
-       struct listnode *grp_node;
-       struct listnode *grp_nextnode;
-       struct igmp_group *grp;
-
-       for (ALL_LIST_ELEMENTS(igmp->igmp_group_list, grp_node, grp_nextnode,
-                              grp)) {
-               igmp_group_delete(grp);
-       }
 
        sock_close(igmp);
 
@@ -914,6 +890,9 @@ void igmp_sock_delete(struct igmp_sock *igmp)
        listnode_delete(pim_ifp->igmp_socket_list, igmp);
 
        igmp_sock_free(igmp);
+
+       if (!listcount(pim_ifp->igmp_socket_list))
+               pim_igmp_if_reset(pim_ifp);
 }
 
 void igmp_sock_delete_all(struct interface *ifp)
@@ -948,12 +927,50 @@ static bool igmp_group_hash_equal(const void *arg1, const void *arg2)
        return false;
 }
 
+void pim_igmp_if_init(struct pim_interface *pim_ifp, struct interface *ifp)
+{
+       char hash_name[64];
+
+       pim_ifp->igmp_socket_list = list_new();
+       pim_ifp->igmp_socket_list->del = (void (*)(void *))igmp_sock_free;
+
+       pim_ifp->igmp_group_list = list_new();
+       pim_ifp->igmp_group_list->del = (void (*)(void *))igmp_group_free;
+
+       snprintf(hash_name, sizeof(hash_name), "IGMP %s hash", ifp->name);
+       pim_ifp->igmp_group_hash = hash_create(
+               igmp_group_hash_key, igmp_group_hash_equal, hash_name);
+}
+
+void pim_igmp_if_reset(struct pim_interface *pim_ifp)
+{
+       struct listnode *grp_node, *grp_nextnode;
+       struct igmp_group *grp;
+
+       for (ALL_LIST_ELEMENTS(pim_ifp->igmp_group_list, grp_node, grp_nextnode,
+                              grp)) {
+               igmp_group_delete(grp);
+       }
+}
+
+void pim_igmp_if_fini(struct pim_interface *pim_ifp)
+{
+       pim_igmp_if_reset(pim_ifp);
+
+       assert(pim_ifp->igmp_group_list);
+       assert(!listcount(pim_ifp->igmp_group_list));
+
+       list_delete(&pim_ifp->igmp_group_list);
+       hash_free(pim_ifp->igmp_group_hash);
+
+       list_delete(&pim_ifp->igmp_socket_list);
+}
+
 static struct igmp_sock *igmp_sock_new(int fd, struct in_addr ifaddr,
                                       struct interface *ifp, int mtrace_only)
 {
        struct pim_interface *pim_ifp;
        struct igmp_sock *igmp;
-       char hash_name[64];
 
        pim_ifp = ifp->info;
 
@@ -965,13 +982,6 @@ static struct igmp_sock *igmp_sock_new(int fd, struct in_addr ifaddr,
 
        igmp = XCALLOC(MTYPE_PIM_IGMP_SOCKET, sizeof(*igmp));
 
-       igmp->igmp_group_list = list_new();
-       igmp->igmp_group_list->del = (void (*)(void *))igmp_group_free;
-
-       snprintf(hash_name, sizeof(hash_name), "IGMP %s hash", ifp->name);
-       igmp->igmp_group_hash = hash_create(igmp_group_hash_key,
-                                           igmp_group_hash_equal, hash_name);
-
        igmp->fd = fd;
        igmp->interface = ifp;
        igmp->ifaddr = ifaddr;
@@ -1041,7 +1051,6 @@ static void igmp_read_on(struct igmp_sock *igmp)
                zlog_debug("Scheduling READ event on IGMP socket fd=%d",
                           igmp->fd);
        }
-       igmp->t_igmp_read = NULL;
        thread_add_read(router->master, pim_igmp_read, igmp, igmp->fd,
                        &igmp->t_igmp_read);
 }
@@ -1114,7 +1123,7 @@ static int igmp_group_timer(struct thread *t)
                pim_inet4_dump("<group?>", group->group_addr, group_str,
                               sizeof(group_str));
                zlog_debug("%s: Timer for group %s on interface %s", __func__,
-                          group_str, group->group_igmp_sock->interface->name);
+                          group_str, group->interface->name);
        }
 
        assert(group->group_filtermode_isexcl);
@@ -1151,7 +1160,7 @@ static void group_timer_off(struct igmp_group *group)
                pim_inet4_dump("<group?>", group->group_addr, group_str,
                               sizeof(group_str));
                zlog_debug("Cancelling TIMER event for group %s on %s",
-                          group_str, group->group_igmp_sock->interface->name);
+                          group_str, group->interface->name);
        }
        THREAD_OFF(group->t_group_timer);
 }
@@ -1188,16 +1197,18 @@ struct igmp_group *find_group_by_addr(struct igmp_sock *igmp,
                                      struct in_addr group_addr)
 {
        struct igmp_group lookup;
+       struct pim_interface *pim_ifp = igmp->interface->info;
 
        lookup.group_addr.s_addr = group_addr.s_addr;
 
-       return hash_lookup(igmp->igmp_group_hash, &lookup);
+       return hash_lookup(pim_ifp->igmp_group_hash, &lookup);
 }
 
 struct igmp_group *igmp_add_group_by_addr(struct igmp_sock *igmp,
                                          struct in_addr group_addr)
 {
        struct igmp_group *group;
+       struct pim_interface *pim_ifp = igmp->interface->info;
 
        group = find_group_by_addr(igmp, group_addr);
        if (group) {
@@ -1239,7 +1250,7 @@ struct igmp_group *igmp_add_group_by_addr(struct igmp_sock *igmp,
        group->t_group_query_retransmit_timer = NULL;
        group->group_specific_query_retransmit_count = 0;
        group->group_addr = group_addr;
-       group->group_igmp_sock = igmp;
+       group->interface = igmp->interface;
        group->last_igmp_v1_report_dsec = -1;
        group->last_igmp_v2_report_dsec = -1;
        group->group_creation = pim_time_monotonic_sec();
@@ -1248,8 +1259,8 @@ struct igmp_group *igmp_add_group_by_addr(struct igmp_sock *igmp,
        /* initialize new group as INCLUDE {empty} */
        group->group_filtermode_isexcl = 0; /* 0=INCLUDE, 1=EXCLUDE */
 
-       listnode_add(igmp->igmp_group_list, group);
-       group = hash_get(igmp->igmp_group_hash, group, hash_alloc_intern);
+       listnode_add(pim_ifp->igmp_group_list, group);
+       group = hash_get(pim_ifp->igmp_group_hash, group, hash_alloc_intern);
 
        if (PIM_DEBUG_IGMP_TRACE) {
                char group_str[INET_ADDRSTRLEN];
@@ -1260,7 +1271,7 @@ struct igmp_group *igmp_add_group_by_addr(struct igmp_sock *igmp,
                        group_str, igmp->fd, igmp->interface->name);
        }
 
-       igmp_group_count_incr(igmp);
+       igmp_group_count_incr(pim_ifp);
 
        /*
          RFC 3376: 6.2.2. Definition of Group Timers
index abb8af836b49802ba1a5f7ab69de321aaa9c16b6..dfe986e8f541fb8fdc0912787e1fd0ab8bfabc3c 100644 (file)
@@ -99,12 +99,15 @@ struct igmp_sock {
 
        bool mtrace_only;
 
-       struct list *igmp_group_list; /* list of struct igmp_group */
-       struct hash *igmp_group_hash;
-
        struct igmp_stats rx_stats;
 };
 
+struct pim_interface;
+
+void pim_igmp_if_init(struct pim_interface *pim_ifp, struct interface *ifp);
+void pim_igmp_if_reset(struct pim_interface *pim_ifp);
+void pim_igmp_if_fini(struct pim_interface *pim_ifp);
+
 struct igmp_sock *pim_igmp_sock_lookup_ifaddr(struct list *igmp_sock_list,
                                              struct in_addr ifaddr);
 struct igmp_sock *igmp_sock_lookup_by_fd(struct list *igmp_sock_list, int fd);
@@ -178,7 +181,7 @@ struct igmp_group {
        int group_filtermode_isexcl;    /* 0=INCLUDE, 1=EXCLUDE */
        struct list *group_source_list; /* list of struct igmp_source */
        time_t group_creation;
-       struct igmp_sock *group_igmp_sock; /* back pointer */
+       struct interface *interface;
        int64_t last_igmp_v1_report_dsec;
        int64_t last_igmp_v2_report_dsec;
 };
@@ -188,6 +191,10 @@ struct igmp_group *find_group_by_addr(struct igmp_sock *igmp,
 struct igmp_group *igmp_add_group_by_addr(struct igmp_sock *igmp,
                                          struct in_addr group_addr);
 
+struct igmp_source *igmp_get_source_by_addr(struct igmp_group *group,
+                                           struct in_addr src_addr,
+                                           bool *created);
+
 void igmp_group_delete_empty_include(struct igmp_group *group);
 
 void igmp_startup_mode_on(struct igmp_sock *igmp);
@@ -195,9 +202,6 @@ void igmp_startup_mode_on(struct igmp_sock *igmp);
 void igmp_group_timer_on(struct igmp_group *group, long interval_msec,
                         const char *ifname);
 
-struct igmp_source *source_new(struct igmp_group *group,
-                              struct in_addr src_addr);
-
 void igmp_send_query(int igmp_version, struct igmp_group *group, int fd,
                     const char *ifname, char *query_buf, int query_buf_size,
                     int num_sources, struct in_addr dst_addr,
index bc67a1dd1d96094e300fdde50f2c5bb480738437..13db11fa80486b3327a1df0b25bb452e1b60d5ee 100644 (file)
@@ -57,16 +57,28 @@ static void on_trace(const char *label, struct interface *ifp,
        }
 }
 
+static inline long igmp_gmi_msec(struct igmp_group *group)
+{
+       struct pim_interface *pim_ifp = group->interface->info;
+       struct igmp_sock *igmp;
+       struct listnode *sock_node;
+
+       long qrv = 0, qqi = 0;
+
+       for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) {
+               qrv = MAX(qrv, igmp->querier_robustness_variable);
+               qqi = MAX(qqi, igmp->querier_query_interval);
+       }
+       return PIM_IGMP_GMI_MSEC(qrv, qqi,
+                                pim_ifp->igmp_query_max_response_time_dsec);
+}
+
 void igmp_group_reset_gmi(struct igmp_group *group)
 {
        long group_membership_interval_msec;
-       struct pim_interface *pim_ifp;
-       struct igmp_sock *igmp;
        struct interface *ifp;
 
-       igmp = group->group_igmp_sock;
-       ifp = igmp->interface;
-       pim_ifp = ifp->info;
+       ifp = group->interface;
 
        /*
          RFC 3376: 8.4. Group Membership Interval
@@ -82,9 +94,7 @@ void igmp_group_reset_gmi(struct igmp_group *group)
                                           (1000 * querier_query_interval) +
                                           100 * query_response_interval_dsec;
        */
-       group_membership_interval_msec = PIM_IGMP_GMI_MSEC(
-               igmp->querier_robustness_variable, igmp->querier_query_interval,
-               pim_ifp->igmp_query_max_response_time_dsec);
+       group_membership_interval_msec = igmp_gmi_msec(group);
 
        if (PIM_DEBUG_IGMP_TRACE) {
                char group_str[INET_ADDRSTRLEN];
@@ -127,7 +137,7 @@ static int igmp_source_timer(struct thread *t)
                zlog_debug(
                        "%s: Source timer expired for group %s source %s on %s",
                        __func__, group_str, source_str,
-                       group->group_igmp_sock->interface->name);
+                       group->interface->name);
        }
 
        /*
@@ -188,8 +198,7 @@ static void source_timer_off(struct igmp_group *group,
                               sizeof(source_str));
                zlog_debug(
                        "Cancelling TIMER event for group %s source %s on %s",
-                       group_str, source_str,
-                       group->group_igmp_sock->interface->name);
+                       group_str, source_str, group->interface->name);
        }
 
        THREAD_OFF(source->t_source_timer);
@@ -199,7 +208,7 @@ static void igmp_source_timer_on(struct igmp_group *group,
                                 struct igmp_source *source, long interval_msec)
 {
        source_timer_off(group, source);
-       struct pim_interface *pim_ifp = group->group_igmp_sock->interface->info;
+       struct pim_interface *pim_ifp = group->interface->info;
 
        if (PIM_DEBUG_IGMP_EVENTS) {
                char group_str[INET_ADDRSTRLEN];
@@ -211,7 +220,7 @@ static void igmp_source_timer_on(struct igmp_group *group,
                zlog_debug(
                        "Scheduling %ld.%03ld sec TIMER event for group %s source %s on %s",
                        interval_msec / 1000, interval_msec % 1000, group_str,
-                       source_str, group->group_igmp_sock->interface->name);
+                       source_str, group->interface->name);
        }
 
        thread_add_timer_msec(router->master, igmp_source_timer, source,
@@ -225,19 +234,14 @@ static void igmp_source_timer_on(struct igmp_group *group,
        igmp_source_forward_start(pim_ifp->pim, source);
 }
 
-void igmp_source_reset_gmi(struct igmp_sock *igmp, struct igmp_group *group,
-                          struct igmp_source *source)
+void igmp_source_reset_gmi(struct igmp_group *group, struct igmp_source *source)
 {
        long group_membership_interval_msec;
-       struct pim_interface *pim_ifp;
        struct interface *ifp;
 
-       ifp = igmp->interface;
-       pim_ifp = ifp->info;
+       ifp = group->interface;
 
-       group_membership_interval_msec = PIM_IGMP_GMI_MSEC(
-               igmp->querier_robustness_variable, igmp->querier_query_interval,
-               pim_ifp->igmp_query_max_response_time_dsec);
+       group_membership_interval_msec = igmp_gmi_msec(group);
 
        if (PIM_DEBUG_IGMP_TRACE) {
                char group_str[INET_ADDRSTRLEN];
@@ -312,7 +316,7 @@ static void source_clear_send_flag(struct list *source_list)
 */
 static void group_exclude_fwd_anysrc_ifempty(struct igmp_group *group)
 {
-       struct pim_interface *pim_ifp = group->group_igmp_sock->interface->info;
+       struct pim_interface *pim_ifp = group->interface->info;
 
        assert(group->group_filtermode_isexcl);
 
@@ -356,9 +360,8 @@ void igmp_source_delete(struct igmp_source *source)
                pim_inet4_dump("<source?>", source->source_addr, source_str,
                               sizeof(source_str));
                zlog_debug(
-                       "Deleting IGMP source %s for group %s from socket %d interface %s c_oil ref_count %d",
-                       source_str, group_str, group->group_igmp_sock->fd,
-                       group->group_igmp_sock->interface->name,
+                       "Deleting IGMP source %s for group %s from interface %s c_oil ref_count %d",
+                       source_str, group_str, group->interface->name,
                        source->source_channel_oil
                                ? source->source_channel_oil->oil_ref_count
                                : 0);
@@ -376,10 +379,9 @@ void igmp_source_delete(struct igmp_source *source)
                pim_inet4_dump("<source?>", source->source_addr, source_str,
                               sizeof(source_str));
                zlog_warn(
-                       "%s: forwarding=ON(!) IGMP source %s for group %s from socket %d interface %s",
+                       "%s: forwarding=ON(!) IGMP source %s for group %s from interface %s",
                        __func__, source_str, group_str,
-                       group->group_igmp_sock->fd,
-                       group->group_igmp_sock->interface->name);
+                       group->interface->name);
                /* warning only */
        }
 
@@ -439,11 +441,18 @@ struct igmp_source *igmp_find_source_by_addr(struct igmp_group *group,
        return 0;
 }
 
-struct igmp_source *source_new(struct igmp_group *group,
-                              struct in_addr src_addr)
+struct igmp_source *igmp_get_source_by_addr(struct igmp_group *group,
+                                           struct in_addr src_addr, bool *new)
 {
        struct igmp_source *src;
 
+       if (new)
+               *new = false;
+
+       src = igmp_find_source_by_addr(group, src_addr);
+       if (src)
+               return src;
+
        if (PIM_DEBUG_IGMP_TRACE) {
                char group_str[INET_ADDRSTRLEN];
                char source_str[INET_ADDRSTRLEN];
@@ -452,9 +461,8 @@ struct igmp_source *source_new(struct igmp_group *group,
                pim_inet4_dump("<source?>", src_addr, source_str,
                               sizeof(source_str));
                zlog_debug(
-                       "Creating new IGMP source %s for group %s on socket %d interface %s",
-                       source_str, group_str, group->group_igmp_sock->fd,
-                       group->group_igmp_sock->interface->name);
+                       "Creating new IGMP source %s for group %s on interface %s",
+                       source_str, group_str, group->interface->name);
        }
 
        src = XCALLOC(MTYPE_PIM_IGMP_GROUP_SOURCE, sizeof(*src));
@@ -471,23 +479,6 @@ struct igmp_source *source_new(struct igmp_group *group,
 
        /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
        igmp_anysource_forward_stop(group);
-
-       return src;
-}
-
-static struct igmp_source *add_source_by_addr(struct igmp_sock *igmp,
-                                             struct igmp_group *group,
-                                             struct in_addr src_addr)
-{
-       struct igmp_source *src;
-
-       src = igmp_find_source_by_addr(group, src_addr);
-       if (src) {
-               return src;
-       }
-
-       src = source_new(group, src_addr);
-
        return src;
 }
 
@@ -518,8 +509,7 @@ static void allow(struct igmp_sock *igmp, struct in_addr from,
 
                                source = igmp_find_source_by_addr(group, star);
                                if (source)
-                                       igmp_source_reset_gmi(igmp, group,
-                                                             source);
+                                       igmp_source_reset_gmi(group, source);
                        }
                } else {
                        igmp_group_delete(group);
@@ -540,10 +530,9 @@ static void allow(struct igmp_sock *igmp, struct in_addr from,
 
                src_addr = sources + i;
 
-               source = add_source_by_addr(igmp, group, *src_addr);
-               if (!source) {
+               source = igmp_get_source_by_addr(group, *src_addr, NULL);
+               if (!source)
                        continue;
-               }
 
                /*
                  RFC 3376: 6.4.1. Reception of Current-State Records
@@ -555,7 +544,7 @@ static void allow(struct igmp_sock *igmp, struct in_addr from,
                  igmp_source_reset_gmi() below, resetting the source timers to
                  GMI, accomplishes this.
                */
-               igmp_source_reset_gmi(igmp, group, source);
+               igmp_source_reset_gmi(group, source);
 
        } /* scan received sources */
 }
@@ -585,21 +574,23 @@ static void isex_excl(struct igmp_group *group, int num_sources,
        /* scan received sources (A) */
        for (i = 0; i < num_sources; ++i) {
                struct in_addr *src_addr;
+               bool new;
 
                src_addr = sources + i;
 
                /* E.2: lookup reported source from (A) in (X,Y) */
-               source = igmp_find_source_by_addr(group, *src_addr);
-               if (source) {
+               source = igmp_get_source_by_addr(group, *src_addr, &new);
+               if (!source)
+                       continue;
+
+               if (!new) {
                        /* E.3: if found, clear deletion flag: (X*A) or (Y*A) */
                        IGMP_SOURCE_DONT_DELETE(source->source_flags);
                } else {
                        /* E.4: if not found, create source with timer=GMI:
                         * (A-X-Y) */
-                       source = source_new(group, *src_addr);
                        assert(!source->t_source_timer); /* timer == 0 */
-                       igmp_source_reset_gmi(group->group_igmp_sock, group,
-                                             source);
+                       igmp_source_reset_gmi(group, source);
                        assert(source->t_source_timer); /* (A-X-Y) timer > 0 */
                }
 
@@ -615,8 +606,7 @@ static void isex_excl(struct igmp_group *group, int num_sources,
                source = igmp_find_source_by_addr(group, star);
                if (source) {
                        IGMP_SOURCE_DONT_DELETE(source->source_flags);
-                       igmp_source_reset_gmi(group->group_igmp_sock, group,
-                                             source);
+                       igmp_source_reset_gmi(group, source);
                }
        }
 
@@ -639,18 +629,21 @@ static void isex_incl(struct igmp_group *group, int num_sources,
        for (i = 0; i < num_sources; ++i) {
                struct igmp_source *source;
                struct in_addr *src_addr;
+               bool new;
 
                src_addr = sources + i;
 
                /* I.2: lookup reported source (B) */
-               source = igmp_find_source_by_addr(group, *src_addr);
-               if (source) {
+               source = igmp_get_source_by_addr(group, *src_addr, &new);
+               if (!source)
+                       continue;
+
+               if (!new) {
                        /* I.3: if found, clear deletion flag (A*B) */
                        IGMP_SOURCE_DONT_DELETE(source->source_flags);
                } else {
                        /* I.4: if not found, create source with timer=0 (B-A)
                         */
-                       source = source_new(group, *src_addr);
                        assert(!source->t_source_timer); /* (B-A) timer=0 */
                }
 
@@ -706,7 +699,6 @@ void igmpv3_report_isex(struct igmp_sock *igmp, struct in_addr from,
 static void toin_incl(struct igmp_group *group, int num_sources,
                      struct in_addr *sources)
 {
-       struct igmp_sock *igmp = group->group_igmp_sock;
        int num_sources_tosend = listcount(group->group_source_list);
        int i;
 
@@ -717,22 +709,23 @@ static void toin_incl(struct igmp_group *group, int num_sources,
        for (i = 0; i < num_sources; ++i) {
                struct igmp_source *source;
                struct in_addr *src_addr;
+               bool new;
 
                src_addr = sources + i;
 
                /* Lookup reported source (B) */
-               source = igmp_find_source_by_addr(group, *src_addr);
-               if (source) {
+               source = igmp_get_source_by_addr(group, *src_addr, &new);
+               if (!source)
+                       continue;
+
+               if (!new) {
                        /* If found, clear SEND flag (A*B) */
                        IGMP_SOURCE_DONT_SEND(source->source_flags);
                        --num_sources_tosend;
-               } else {
-                       /* If not found, create new source */
-                       source = source_new(group, *src_addr);
                }
 
                /* (B)=GMI */
-               igmp_source_reset_gmi(igmp, group, source);
+               igmp_source_reset_gmi(group, source);
        }
 
        /* Send sources marked with SEND flag: Q(G,A-B) */
@@ -744,7 +737,6 @@ static void toin_incl(struct igmp_group *group, int num_sources,
 static void toin_excl(struct igmp_group *group, int num_sources,
                      struct in_addr *sources)
 {
-       struct igmp_sock *igmp = group->group_igmp_sock;
        int num_sources_tosend;
        int i;
 
@@ -755,25 +747,24 @@ static void toin_excl(struct igmp_group *group, int num_sources,
        for (i = 0; i < num_sources; ++i) {
                struct igmp_source *source;
                struct in_addr *src_addr;
+               bool new;
 
                src_addr = sources + i;
 
                /* Lookup reported source (A) */
-               source = igmp_find_source_by_addr(group, *src_addr);
-               if (source) {
-                       if (source->t_source_timer) {
-                               /* If found and timer running, clear SEND flag
-                                * (X*A) */
-                               IGMP_SOURCE_DONT_SEND(source->source_flags);
-                               --num_sources_tosend;
-                       }
-               } else {
-                       /* If not found, create new source */
-                       source = source_new(group, *src_addr);
+               source = igmp_get_source_by_addr(group, *src_addr, &new);
+               if (!source)
+                       continue;
+
+               if (source->t_source_timer) {
+                       /* If found and timer running, clear SEND flag
+                        * (X*A) */
+                       IGMP_SOURCE_DONT_SEND(source->source_flags);
+                       --num_sources_tosend;
                }
 
                /* (A)=GMI */
-               igmp_source_reset_gmi(igmp, group, source);
+               igmp_source_reset_gmi(group, source);
        }
 
        /* Send sources marked with SEND flag: Q(G,X-A) */
@@ -839,22 +830,18 @@ static void toex_incl(struct igmp_group *group, int num_sources,
        for (i = 0; i < num_sources; ++i) {
                struct igmp_source *source;
                struct in_addr *src_addr;
+               bool new;
 
                src_addr = sources + i;
 
                /* Lookup reported source (B) */
-               source = igmp_find_source_by_addr(group, *src_addr);
-               if (source) {
+               source = igmp_get_source_by_addr(group, *src_addr, &new);
+               if (!new) {
                        /* If found, clear deletion flag: (A*B) */
                        IGMP_SOURCE_DONT_DELETE(source->source_flags);
                        /* and set SEND flag (A*B) */
                        IGMP_SOURCE_DO_SEND(source->source_flags);
                        ++num_sources_tosend;
-               } else {
-                       /* If source not found, create source with timer=0:
-                        * (B-A)=0 */
-                       source = source_new(group, *src_addr);
-                       assert(!source->t_source_timer); /* (B-A) timer=0 */
                }
 
        } /* Scan received sources (B) */
@@ -899,12 +886,16 @@ static void toex_excl(struct igmp_group *group, int num_sources,
        for (i = 0; i < num_sources; ++i) {
                struct igmp_source *source;
                struct in_addr *src_addr;
+               bool new;
 
                src_addr = sources + i;
 
                /* lookup reported source (A) in known sources (X,Y) */
-               source = igmp_find_source_by_addr(group, *src_addr);
-               if (source) {
+               source = igmp_get_source_by_addr(group, *src_addr, &new);
+               if (!source)
+                       continue;
+
+               if (!new) {
                        /* if found, clear off DELETE flag from reported source
                         * (A) */
                        IGMP_SOURCE_DONT_DELETE(source->source_flags);
@@ -912,7 +903,6 @@ static void toex_excl(struct igmp_group *group, int num_sources,
                        /* if not found, create source with Group Timer:
                         * (A-X-Y)=Group Timer */
                        long group_timer_msec;
-                       source = source_new(group, *src_addr);
 
                        assert(!source->t_source_timer); /* timer == 0 */
                        group_timer_msec = igmp_group_timer_remain_msec(group);
@@ -986,6 +976,26 @@ void igmpv3_report_allow(struct igmp_sock *igmp, struct in_addr from,
        allow(igmp, from, group_addr, num_sources, sources);
 }
 
+static void igmp_send_query_group(struct igmp_group *group, char *query_buf,
+                                 size_t query_buf_size, int num_sources,
+                                 int s_flag)
+{
+       struct interface *ifp = group->interface;
+       struct pim_interface *pim_ifp = ifp->info;
+       struct igmp_sock *igmp;
+       struct listnode *sock_node;
+
+       for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) {
+               igmp_send_query(
+                       pim_ifp->igmp_version, group, igmp->fd, ifp->name,
+                       query_buf, query_buf_size, num_sources,
+                       group->group_addr, group->group_addr,
+                       pim_ifp->igmp_specific_query_max_response_time_dsec,
+                       s_flag, igmp->querier_robustness_variable,
+                       igmp->querier_query_interval);
+       }
+}
+
 /*
   RFC3376: 6.6.3.1. Building and Sending Group Specific Queries
 
@@ -995,7 +1005,6 @@ void igmpv3_report_allow(struct igmp_sock *igmp, struct in_addr from,
 */
 static void group_retransmit_group(struct igmp_group *group)
 {
-       struct igmp_sock *igmp;
        struct pim_interface *pim_ifp;
        long lmqc;      /* Last Member Query Count */
        long lmqi_msec; /* Last Member Query Interval */
@@ -1003,8 +1012,7 @@ static void group_retransmit_group(struct igmp_group *group)
        int s_flag;
        int query_buf_size;
 
-       igmp = group->group_igmp_sock;
-       pim_ifp = igmp->interface->info;
+       pim_ifp = group->interface->info;
 
        if (pim_ifp->igmp_version == 3) {
                query_buf_size = PIM_IGMP_BUFSIZE_WRITE;
@@ -1033,7 +1041,7 @@ static void group_retransmit_group(struct igmp_group *group)
                               sizeof(group_str));
                zlog_debug(
                        "retransmit_group_specific_query: group %s on %s: s_flag=%d count=%d",
-                       group_str, igmp->interface->name, s_flag,
+                       group_str, group->interface->name, s_flag,
                        group->group_specific_query_retransmit_count);
        }
 
@@ -1045,14 +1053,7 @@ static void group_retransmit_group(struct igmp_group *group)
          interest.
        */
 
-       igmp_send_query(pim_ifp->igmp_version, group, igmp->fd,
-                       igmp->interface->name, query_buf, sizeof(query_buf),
-                       0 /* num_sources_tosend */,
-                       group->group_addr /* dst_addr */,
-                       group->group_addr /* group_addr */,
-                       pim_ifp->igmp_specific_query_max_response_time_dsec,
-                       s_flag, igmp->querier_robustness_variable,
-                       igmp->querier_query_interval);
+       igmp_send_query_group(group, query_buf, sizeof(query_buf), 0, s_flag);
 }
 
 /*
@@ -1070,7 +1071,6 @@ static void group_retransmit_group(struct igmp_group *group)
 static int group_retransmit_sources(struct igmp_group *group,
                                    int send_with_sflag_set)
 {
-       struct igmp_sock *igmp;
        struct pim_interface *pim_ifp;
        long lmqc;      /* Last Member Query Count */
        long lmqi_msec; /* Last Member Query Interval */
@@ -1090,8 +1090,7 @@ static int group_retransmit_sources(struct igmp_group *group,
        source_addr1 = (struct in_addr *)(query_buf1 + IGMP_V3_SOURCES_OFFSET);
        source_addr2 = (struct in_addr *)(query_buf2 + IGMP_V3_SOURCES_OFFSET);
 
-       igmp = group->group_igmp_sock;
-       pim_ifp = igmp->interface->info;
+       pim_ifp = group->interface->info;
 
        lmqc = pim_ifp->igmp_last_member_query_count;
        lmqi_msec = 100 * pim_ifp->igmp_specific_query_max_response_time_dsec;
@@ -1131,7 +1130,7 @@ static int group_retransmit_sources(struct igmp_group *group,
                               sizeof(group_str));
                zlog_debug(
                        "retransmit_grp&src_specific_query: group %s on %s: srcs_with_sflag=%d srcs_wo_sflag=%d will_send_sflag=%d retransmit_src_left=%d",
-                       group_str, igmp->interface->name, num_sources_tosend1,
+                       group_str, group->interface->name, num_sources_tosend1,
                        num_sources_tosend2, send_with_sflag_set,
                        num_retransmit_sources_left);
        }
@@ -1154,7 +1153,7 @@ static int group_retransmit_sources(struct igmp_group *group,
                                zlog_warn(
                                        "%s: group %s on %s: s_flag=1 unable to fit %d sources into buf_size=%zu (max_sources=%d)",
                                        __func__, group_str,
-                                       igmp->interface->name,
+                                       group->interface->name,
                                        num_sources_tosend1, sizeof(query_buf1),
                                        query_buf1_max_sources);
                        } else {
@@ -1169,15 +1168,9 @@ static int group_retransmit_sources(struct igmp_group *group,
                                  interest.
                                */
 
-                               igmp_send_query(
-                                       pim_ifp->igmp_version, group, igmp->fd,
-                                       igmp->interface->name, query_buf1,
-                                       sizeof(query_buf1), num_sources_tosend1,
-                                       group->group_addr, group->group_addr,
-                                       pim_ifp->igmp_specific_query_max_response_time_dsec,
-                                       1 /* s_flag */,
-                                       igmp->querier_robustness_variable,
-                                       igmp->querier_query_interval);
+                               igmp_send_query_group(
+                                       group, query_buf1, sizeof(query_buf1),
+                                       num_sources_tosend1, 1 /* s_flag */);
                        }
 
                } /* send_with_sflag_set */
@@ -1197,7 +1190,7 @@ static int group_retransmit_sources(struct igmp_group *group,
                                       sizeof(group_str));
                        zlog_warn(
                                "%s: group %s on %s: s_flag=0 unable to fit %d sources into buf_size=%zu (max_sources=%d)",
-                               __func__, group_str, igmp->interface->name,
+                               __func__, group_str, group->interface->name,
                                num_sources_tosend2, sizeof(query_buf2),
                                query_buf2_max_sources);
                } else {
@@ -1211,15 +1204,9 @@ static int group_retransmit_sources(struct igmp_group *group,
                          interest.
                        */
 
-                       igmp_send_query(
-                               pim_ifp->igmp_version, group, igmp->fd,
-                               igmp->interface->name, query_buf2,
-                               sizeof(query_buf2), num_sources_tosend2,
-                               group->group_addr, group->group_addr,
-                               pim_ifp->igmp_specific_query_max_response_time_dsec,
-                               0 /* s_flag */,
-                               igmp->querier_robustness_variable,
-                               igmp->querier_query_interval);
+                       igmp_send_query_group(
+                               group, query_buf2, sizeof(query_buf2),
+                               num_sources_tosend2, 0 /* s_flag */);
                }
        }
 
@@ -1239,7 +1226,7 @@ static int igmp_group_retransmit(struct thread *t)
                pim_inet4_dump("<group?>", group->group_addr, group_str,
                               sizeof(group_str));
                zlog_debug("group_retransmit_timer: group %s on %s", group_str,
-                          group->group_igmp_sock->interface->name);
+                          group->interface->name);
        }
 
        /* Retransmit group-specific queries? (RFC3376: 6.6.3.1) */
@@ -1287,7 +1274,6 @@ static int igmp_group_retransmit(struct thread *t)
 */
 static void group_retransmit_timer_on(struct igmp_group *group)
 {
-       struct igmp_sock *igmp;
        struct pim_interface *pim_ifp;
        long lmqi_msec; /* Last Member Query Interval */
 
@@ -1296,8 +1282,7 @@ static void group_retransmit_timer_on(struct igmp_group *group)
                return;
        }
 
-       igmp = group->group_igmp_sock;
-       pim_ifp = igmp->interface->info;
+       pim_ifp = group->interface->info;
 
        lmqi_msec = 100 * pim_ifp->igmp_specific_query_max_response_time_dsec;
 
@@ -1308,7 +1293,7 @@ static void group_retransmit_timer_on(struct igmp_group *group)
                zlog_debug(
                        "Scheduling %ld.%03ld sec retransmit timer for group %s on %s",
                        lmqi_msec / 1000, lmqi_msec % 1000, group_str,
-                       igmp->interface->name);
+                       group->interface->name);
        }
 
        thread_add_timer_msec(router->master, igmp_group_retransmit, group,
@@ -1332,11 +1317,9 @@ static long igmp_source_timer_remain_msec(struct igmp_source *source)
 static void group_query_send(struct igmp_group *group)
 {
        struct pim_interface *pim_ifp;
-       struct igmp_sock *igmp;
        long lmqc; /* Last Member Query Count */
 
-       igmp = group->group_igmp_sock;
-       pim_ifp = igmp->interface->info;
+       pim_ifp = group->interface->info;
        lmqc = pim_ifp->igmp_last_member_query_count;
 
        /* lower group timer to lmqt */
@@ -1359,7 +1342,6 @@ static void group_query_send(struct igmp_group *group)
 static void source_query_send_by_flag(struct igmp_group *group,
                                      int num_sources_tosend)
 {
-       struct igmp_sock *igmp;
        struct pim_interface *pim_ifp;
        struct listnode *src_node;
        struct igmp_source *src;
@@ -1369,8 +1351,7 @@ static void source_query_send_by_flag(struct igmp_group *group,
 
        assert(num_sources_tosend > 0);
 
-       igmp = group->group_igmp_sock;
-       pim_ifp = igmp->interface->info;
+       pim_ifp = group->interface->info;
 
        lmqc = pim_ifp->igmp_last_member_query_count;
        lmqi_msec = 100 * pim_ifp->igmp_specific_query_max_response_time_dsec;
@@ -1417,16 +1398,19 @@ static void block_excl(struct igmp_group *group, int num_sources,
        for (i = 0; i < num_sources; ++i) {
                struct igmp_source *source;
                struct in_addr *src_addr;
+               bool new;
 
                src_addr = sources + i;
 
                /* lookup reported source (A) in known sources (X,Y) */
-               source = igmp_find_source_by_addr(group, *src_addr);
-               if (!source) {
+               source = igmp_get_source_by_addr(group, *src_addr, &new);
+               if (!source)
+                       continue;
+
+               if (new) {
                        /* 3: if not found, create source with Group Timer:
                         * (A-X-Y)=Group Timer */
                        long group_timer_msec;
-                       source = source_new(group, *src_addr);
 
                        assert(!source->t_source_timer); /* timer == 0 */
                        group_timer_msec = igmp_group_timer_remain_msec(group);
@@ -1504,7 +1488,6 @@ void igmpv3_report_block(struct igmp_sock *igmp, struct in_addr from,
 
 void igmp_group_timer_lower_to_lmqt(struct igmp_group *group)
 {
-       struct igmp_sock *igmp;
        struct interface *ifp;
        struct pim_interface *pim_ifp;
        char *ifname;
@@ -1523,8 +1506,7 @@ void igmp_group_timer_lower_to_lmqt(struct igmp_group *group)
                return;
        }
 
-       igmp = group->group_igmp_sock;
-       ifp = igmp->interface;
+       ifp = group->interface;
        pim_ifp = ifp->info;
        ifname = ifp->name;
 
@@ -1551,7 +1533,6 @@ void igmp_group_timer_lower_to_lmqt(struct igmp_group *group)
 void igmp_source_timer_lower_to_lmqt(struct igmp_source *source)
 {
        struct igmp_group *group;
-       struct igmp_sock *igmp;
        struct interface *ifp;
        struct pim_interface *pim_ifp;
        char *ifname;
@@ -1560,8 +1541,7 @@ void igmp_source_timer_lower_to_lmqt(struct igmp_source *source)
        int lmqt_msec; /* Last Member Query Time */
 
        group = source->source_group;
-       igmp = group->group_igmp_sock;
-       ifp = igmp->interface;
+       ifp = group->interface;
        pim_ifp = ifp->info;
        ifname = ifp->name;
 
index 6abaef6e26540c47938a619b1de335dbd0914e66..273f944b3c8964cc7e3b4b580ab6e16cb7c0c14e 100644 (file)
@@ -23,6 +23,8 @@
 #include <zebra.h>
 #include "if.h"
 
+#include "pim_igmp.h"
+
 #define IGMP_V3_CHECKSUM_OFFSET            (2)
 #define IGMP_V3_REPORT_NUMGROUPS_OFFSET    (6)
 #define IGMP_V3_REPORT_GROUPPRECORD_OFFSET (8)
@@ -52,7 +54,7 @@
 #define PIM_IGMP_OHPI_DSEC(qrv,qqi,qri_dsec) ((qrv) * (10 * (qqi)) + (qri_dsec))
 
 void igmp_group_reset_gmi(struct igmp_group *group);
-void igmp_source_reset_gmi(struct igmp_sock *igmp, struct igmp_group *group,
+void igmp_source_reset_gmi(struct igmp_group *group,
                           struct igmp_source *source);
 
 void igmp_source_free(struct igmp_source *source);
index 52ded08ae390e4c02823779456b0d18535605ff1..68c5b9167bb0c7cc2ca6f8576ea8e94cb2bf5f82 100644 (file)
@@ -210,6 +210,8 @@ struct pim_instance {
 void pim_vrf_init(void);
 void pim_vrf_terminate(void);
 
+extern struct pim_router *router;
+
 struct pim_instance *pim_get_pim_instance(vrf_id_t vrf_id);
 
 #endif
index 2d8e1b01fb89117e391aebf0fa21f0d6c63bb0e0..4cd6b9f0ace32a9f4b2c1824b56b7dd4d5844e74 100644 (file)
@@ -167,6 +167,8 @@ struct igmpmsg {
   Above: from <linux/mroute.h>
 */
 
+struct channel_oil;
+
 int pim_mroute_socket_enable(struct pim_instance *pim);
 int pim_mroute_socket_disable(struct pim_instance *pim);
 
index da8916ddbf734100b86cd9a52ec5d204664a7718..ddba33ff9d53768dad316646be4f0b1cd31e50f0 100644 (file)
@@ -720,7 +720,7 @@ static int pim_msdp_sa_comp(const void *p1, const void *p2)
 /* XXX: this can use a bit of refining and extensions */
 bool pim_msdp_peer_rpf_check(struct pim_msdp_peer *mp, struct in_addr rp)
 {
-       struct pim_nexthop nexthop;
+       struct pim_nexthop nexthop = {0};
 
        if (mp->peer.s_addr == rp.s_addr) {
                return true;
index 78a8265a1c88362c68743ad61112150efb57af47..5fff9fca0ed5f7d7fba05e1a57538e40dc7a2da3 100644 (file)
@@ -205,7 +205,6 @@ int pim_msdp_sock_listen(struct pim_instance *pim)
        /* add accept thread */
        listener->fd = sock;
        memcpy(&listener->su, &sin, socklen);
-       listener->thread = NULL;
        thread_add_read(pim->msdp.master, pim_msdp_sock_accept, pim, sock,
                        &listener->thread);
 
index 4b4c1ec7db81df1b751c7ba369fcf5eb366f61cd..b9da8ec0685c32bea16042b3717d70fce542bd4a 100644 (file)
@@ -23,6 +23,7 @@
 #include "pim_nb.h"
 #include "lib/northbound_cli.h"
 #include "pim_igmpv3.h"
+#include "pim_neighbor.h"
 #include "pim_pim.h"
 #include "pim_mlag.h"
 #include "pim_bfd.h"
@@ -60,8 +61,9 @@ static void pim_if_membership_clear(struct interface *ifp)
 static void pim_if_membership_refresh(struct interface *ifp)
 {
        struct pim_interface *pim_ifp;
-       struct listnode *sock_node;
-       struct igmp_sock *igmp;
+       struct listnode *grpnode;
+       struct igmp_group *grp;
+
 
        pim_ifp = ifp->info;
        assert(pim_ifp);
@@ -83,36 +85,27 @@ static void pim_if_membership_refresh(struct interface *ifp)
         * the interface
         */
 
-       /* scan igmp sockets */
-       for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) {
-               struct listnode *grpnode;
-               struct igmp_group *grp;
-
-               /* scan igmp groups */
-               for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list, grpnode,
-                                         grp)) {
-                       struct listnode *srcnode;
-                       struct igmp_source *src;
-
-                       /* scan group sources */
-                       for (ALL_LIST_ELEMENTS_RO(grp->group_source_list,
-                                                 srcnode, src)) {
-
-                               if (IGMP_SOURCE_TEST_FORWARDING(
-                                   src->source_flags)) {
-                                       struct prefix_sg sg;
-
-                                       memset(&sg, 0,
-                                              sizeof(struct prefix_sg));
-                                       sg.src = src->source_addr;
-                                       sg.grp = grp->group_addr;
-                                       pim_ifchannel_local_membership_add(
-                                               ifp, &sg, false /*is_vxlan*/);
-                               }
-
-                       } /* scan group sources */
-               }        /* scan igmp groups */
-       }                 /* scan igmp sockets */
+       /* scan igmp groups */
+       for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_group_list, grpnode, grp)) {
+               struct listnode *srcnode;
+               struct igmp_source *src;
+
+               /* scan group sources */
+               for (ALL_LIST_ELEMENTS_RO(grp->group_source_list, srcnode,
+                                         src)) {
+
+                       if (IGMP_SOURCE_TEST_FORWARDING(src->source_flags)) {
+                               struct prefix_sg sg;
+
+                               memset(&sg, 0, sizeof(struct prefix_sg));
+                               sg.src = src->source_addr;
+                               sg.grp = grp->group_addr;
+                               pim_ifchannel_local_membership_add(
+                                       ifp, &sg, false /*is_vxlan*/);
+                       }
+
+               } /* scan group sources */
+       }         /* scan igmp groups */
 
        /*
         * Finally delete every PIM (S,G) entry lacking all state info
@@ -458,6 +451,8 @@ static void change_query_max_response_time(struct pim_interface *pim_ifp,
 {
        struct listnode *sock_node;
        struct igmp_sock *igmp;
+       struct listnode *grp_node;
+       struct igmp_group *grp;
 
        if (pim_ifp->igmp_query_max_response_time_dsec
            == query_max_response_time_dsec)
@@ -474,32 +469,28 @@ static void change_query_max_response_time(struct pim_interface *pim_ifp,
 
        /* scan all sockets */
        for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) {
-               struct listnode *grp_node;
-               struct igmp_group *grp;
-
                /* reschedule socket general query */
                igmp_sock_query_reschedule(igmp);
+       }
 
-               /* scan socket groups */
-               for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list, grp_node,
-                                       grp)) {
-                       struct listnode *src_node;
-                       struct igmp_source *src;
-
-                       /* reset group timers for groups in EXCLUDE mode */
-                       if (grp->group_filtermode_isexcl)
-                               igmp_group_reset_gmi(grp);
-
-                       /* scan group sources */
-                       for (ALL_LIST_ELEMENTS_RO(grp->group_source_list,
-                                               src_node, src)) {
-
-                               /* reset source timers for sources with running
-                                * timers
-                                */
-                               if (src->t_source_timer)
-                                       igmp_source_reset_gmi(igmp, grp, src);
-                       }
+       /* scan socket groups */
+       for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_group_list, grp_node, grp)) {
+               struct listnode *src_node;
+               struct igmp_source *src;
+
+               /* reset group timers for groups in EXCLUDE mode */
+               if (grp->group_filtermode_isexcl)
+                       igmp_group_reset_gmi(grp);
+
+               /* scan group sources */
+               for (ALL_LIST_ELEMENTS_RO(grp->group_source_list, src_node,
+                                         src)) {
+
+                       /* reset source timers for sources with running
+                        * timers
+                        */
+                       if (src->t_source_timer)
+                               igmp_source_reset_gmi(grp, src);
                }
        }
 }
@@ -1177,6 +1168,7 @@ int pim_msdp_mesh_group_members_destroy(struct nb_cb_destroy_args *args)
 {
        struct pim_msdp_mg_mbr *mbr;
        struct pim_msdp_mg *mg;
+       const struct lyd_node *mg_dnode;
 
        switch (args->event) {
        case NB_EV_VALIDATE:
@@ -1185,9 +1177,11 @@ int pim_msdp_mesh_group_members_destroy(struct nb_cb_destroy_args *args)
                break;
        case NB_EV_APPLY:
                mbr = nb_running_get_entry(args->dnode, NULL, true);
-               mg = nb_running_get_entry(args->dnode, "../", true);
-
+               mg_dnode =
+                       yang_dnode_get_parent(args->dnode, "msdp-mesh-groups");
+               mg = nb_running_get_entry(mg_dnode, NULL, true);
                pim_msdp_mg_mbr_del(mg, mbr);
+               nb_running_unset_entry(args->dnode);
                break;
        }
 
index b461098a602d8274656071fc01a72239f5ac1ea8..d71b2b87c30880a6661724317073ea725e11ec95 100644 (file)
@@ -27,6 +27,7 @@
 #include "prefix.h"
 
 #include "pim_tlv.h"
+#include "pim_iface.h"
 
 struct pim_neighbor {
        int64_t creation; /* timestamp of creation */
index b0aa2b17c584daf28390622180f58a2fa0a779f7..af8ac8459400d8d3ff8ce79513a21e959ebe28d7 100644 (file)
@@ -20,8 +20,9 @@
 #ifndef PIM_OIL_H
 #define PIM_OIL_H
 
+struct pim_interface;
+
 #include "pim_mroute.h"
-#include "pim_iface.h"
 
 /*
  * Where did we get this (S,G) from?
index 8c38cf6c4c382648edf73cab6c9a4ae9b0aaae80..3df7dc41ce318845f89f674d4fb444e3a383e050 100644 (file)
@@ -415,7 +415,6 @@ static void pim_sock_read_on(struct interface *ifp)
                zlog_debug("Scheduling READ event on PIM socket fd=%d",
                           pim_ifp->pim_sock_fd);
        }
-       pim_ifp->t_pim_sock_read = NULL;
        thread_add_read(router->master, pim_sock_read, ifp,
                        pim_ifp->pim_sock_fd, &pim_ifp->t_pim_sock_read);
 }
index 3e3b6dddb5604f01c13a35e2d522cfcfef200b8d..f2a969e04a22fc91dbe99da7dd5627c497c7af2d 100644 (file)
@@ -42,7 +42,7 @@
 #include "pim_rpf.h"
 #include "pim_sock.h"
 #include "pim_memory.h"
-#include "pim_iface.h"
+#include "pim_neighbor.h"
 #include "pim_msdp.h"
 #include "pim_nht.h"
 #include "pim_mroute.h"
index dd7cd5d75e35504a7c57851355042be7f5d07aab..595025e5c97740ca707dedfc22a7e2acfbba7ad6 100644 (file)
 #include "prefix.h"
 #include "vty.h"
 #include "plist.h"
-#include "pim_iface.h"
 #include "pim_rpf.h"
 
+struct pim_interface;
+
 enum rp_source {
        RP_SRC_NONE = 0,
        RP_SRC_STATIC,
index 66c6df65ad43d8dae707439f683f7407a281e700..b93f85e48c342afa8a0caa363e73ad4c843eb263 100644 (file)
@@ -31,6 +31,7 @@
 #include "pim_pim.h"
 #include "pim_str.h"
 #include "pim_iface.h"
+#include "pim_neighbor.h"
 #include "pim_zlookup.h"
 #include "pim_ifchannel.h"
 #include "pim_time.h"
index f006519b7105b1415f8a866e5eece8df27a94e9b..006aa1b636cec85c400c85cbfd76f730ec863a99 100644 (file)
@@ -22,9 +22,6 @@
 
 #include <zebra.h>
 
-#include "pim_upstream.h"
-#include "pim_neighbor.h"
-
 /*
   RFC 4601:
 
index 56039d56057b02310d3bb622852dbfdaace0d6af..ea3b564f8a380dc7679663a82acd781c4a391dde 100644 (file)
@@ -24,7 +24,7 @@
 #include <prefix.h>
 #include "plist.h"
 
-#include <pimd/pim_rpf.h>
+#include "pim_rpf.h"
 #include "pim_str.h"
 #include "pim_ifchannel.h"
 
index 6f933e9e721b2af48740fb553fb96f078016cedc..aa041df85736ed99e19561837e7ac2f67e103876 100644 (file)
@@ -474,7 +474,7 @@ void igmp_anysource_forward_start(struct pim_instance *pim,
        assert(group->group_filtermode_isexcl);
        assert(listcount(group->group_source_list) < 1);
 
-       source = source_new(group, src_addr);
+       source = igmp_get_source_by_addr(group, src_addr, NULL);
        if (!source) {
                zlog_warn("%s: Failure to create * source", __func__);
                return;
@@ -508,7 +508,7 @@ static void igmp_source_forward_reevaluate_one(struct pim_instance *pim,
        sg.src = source->source_addr;
        sg.grp = group->group_addr;
 
-       ch = pim_ifchannel_find(group->group_igmp_sock->interface, &sg);
+       ch = pim_ifchannel_find(group->interface, &sg);
        if (pim_is_grp_ssm(pim, group->group_addr)) {
                /* If SSM group withdraw local membership */
                if (ch
@@ -517,8 +517,8 @@ static void igmp_source_forward_reevaluate_one(struct pim_instance *pim,
                                zlog_debug(
                                        "local membership del for %s as G is now SSM",
                                        pim_str_sg_dump(&sg));
-                       pim_ifchannel_local_membership_del(
-                               group->group_igmp_sock->interface, &sg);
+                       pim_ifchannel_local_membership_del(group->interface,
+                                                          &sg);
                }
        } else {
                /* If ASM group add local membership */
@@ -529,8 +529,7 @@ static void igmp_source_forward_reevaluate_one(struct pim_instance *pim,
                                        "local membership add for %s as G is now ASM",
                                        pim_str_sg_dump(&sg));
                        pim_ifchannel_local_membership_add(
-                               group->group_igmp_sock->interface, &sg,
-                               false /*is_vxlan*/);
+                               group->interface, &sg, false /*is_vxlan*/);
                }
        }
 }
@@ -541,33 +540,24 @@ void igmp_source_forward_reevaluate_all(struct pim_instance *pim)
 
        FOR_ALL_INTERFACES (pim->vrf, ifp) {
                struct pim_interface *pim_ifp = ifp->info;
-               struct listnode *sock_node;
-               struct igmp_sock *igmp;
+               struct listnode *grpnode;
+               struct igmp_group *grp;
 
                if (!pim_ifp)
                        continue;
 
-               /* scan igmp sockets */
-               for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node,
-                                         igmp)) {
-                       struct listnode *grpnode;
-                       struct igmp_group *grp;
-
-                       /* scan igmp groups */
-                       for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list,
-                                                 grpnode, grp)) {
-                               struct listnode *srcnode;
-                               struct igmp_source *src;
-
-                               /* scan group sources */
-                               for (ALL_LIST_ELEMENTS_RO(
-                                            grp->group_source_list, srcnode,
-                                            src)) {
-                                       igmp_source_forward_reevaluate_one(pim,
-                                                                          src);
-                               } /* scan group sources */
-                       }        /* scan igmp groups */
-               }                 /* scan igmp sockets */
+               /* scan igmp groups */
+               for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_group_list, grpnode,
+                                         grp)) {
+                       struct listnode *srcnode;
+                       struct igmp_source *src;
+
+                       /* scan group sources */
+                       for (ALL_LIST_ELEMENTS_RO(grp->group_source_list,
+                                                 srcnode, src)) {
+                               igmp_source_forward_reevaluate_one(pim, src);
+                       }         /* scan group sources */
+               }                 /* scan igmp groups */
        }                         /* scan interfaces */
 }
 
@@ -585,12 +575,10 @@ void igmp_source_forward_start(struct pim_instance *pim,
        sg.grp = source->source_group->group_addr;
 
        if (PIM_DEBUG_IGMP_TRACE) {
-               zlog_debug(
-                       "%s: (S,G)=%s igmp_sock=%d oif=%s fwd=%d", __func__,
-                       pim_str_sg_dump(&sg),
-                       source->source_group->group_igmp_sock->fd,
-                       source->source_group->group_igmp_sock->interface->name,
-                       IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
+               zlog_debug("%s: (S,G)=%s oif=%s fwd=%d", __func__,
+                          pim_str_sg_dump(&sg),
+                          source->source_group->interface->name,
+                          IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
        }
 
        /* Prevent IGMP interface from installing multicast route multiple
@@ -600,13 +588,12 @@ void igmp_source_forward_start(struct pim_instance *pim,
        }
 
        group = source->source_group;
-       pim_oif = group->group_igmp_sock->interface->info;
+       pim_oif = group->interface->info;
        if (!pim_oif) {
                if (PIM_DEBUG_IGMP_TRACE) {
                        zlog_debug("%s: multicast not enabled on oif=%s ?",
                                   __func__,
-                                  source->source_group->group_igmp_sock
-                                          ->interface->name);
+                                  source->source_group->interface->name);
                }
                return;
        }
@@ -688,14 +675,10 @@ void igmp_source_forward_start(struct pim_instance *pim,
                                         */
                                        if (PIM_DEBUG_IGMP_TRACE) {
                                                zlog_debug(
-                                                       "%s: ignoring request for looped MFC entry (S,G)=%s: igmp_sock=%d oif=%s vif_index=%d",
+                                                       "%s: ignoring request for looped MFC entry (S,G)=%s: oif=%s vif_index=%d",
                                                        __func__,
                                                        pim_str_sg_dump(&sg),
                                                        source->source_group
-                                                               ->group_igmp_sock
-                                                               ->fd,
-                                                       source->source_group
-                                                               ->group_igmp_sock
                                                                ->interface->name,
                                                        input_iface_vif_index);
                                        }
@@ -719,7 +702,7 @@ void igmp_source_forward_start(struct pim_instance *pim,
 
        if (PIM_I_am_DR(pim_oif) || PIM_I_am_DualActive(pim_oif)) {
                result = pim_channel_add_oif(source->source_channel_oil,
-                                            group->group_igmp_sock->interface,
+                                            group->interface,
                                             PIM_OIF_FLAG_PROTO_IGMP, __func__);
                if (result) {
                        if (PIM_DEBUG_MROUTE) {
@@ -733,7 +716,7 @@ void igmp_source_forward_start(struct pim_instance *pim,
                        zlog_debug(
                                "%s: %s was received on %s interface but we are not DR for that interface",
                                __func__, pim_str_sg_dump(&sg),
-                               group->group_igmp_sock->interface->name);
+                               group->interface->name);
 
                return;
        }
@@ -741,16 +724,15 @@ void igmp_source_forward_start(struct pim_instance *pim,
          Feed IGMPv3-gathered local membership information into PIM
          per-interface (S,G) state.
         */
-       if (!pim_ifchannel_local_membership_add(
-                                               group->group_igmp_sock->interface, &sg,
+       if (!pim_ifchannel_local_membership_add(group->interface, &sg,
                                                false /*is_vxlan*/)) {
                if (PIM_DEBUG_MROUTE)
                        zlog_warn("%s: Failure to add local membership for %s",
                                  __func__, pim_str_sg_dump(&sg));
 
                pim_channel_del_oif(source->source_channel_oil,
-                                   group->group_igmp_sock->interface,
-                                   PIM_OIF_FLAG_PROTO_IGMP, __func__);
+                                   group->interface, PIM_OIF_FLAG_PROTO_IGMP,
+                                   __func__);
                return;
        }
 
@@ -772,12 +754,10 @@ void igmp_source_forward_stop(struct igmp_source *source)
        sg.grp = source->source_group->group_addr;
 
        if (PIM_DEBUG_IGMP_TRACE) {
-               zlog_debug(
-                       "%s: (S,G)=%s igmp_sock=%d oif=%s fwd=%d", __func__,
-                       pim_str_sg_dump(&sg),
-                       source->source_group->group_igmp_sock->fd,
-                       source->source_group->group_igmp_sock->interface->name,
-                       IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
+               zlog_debug("%s: (S,G)=%s oif=%s fwd=%d", __func__,
+                          pim_str_sg_dump(&sg),
+                          source->source_group->interface->name,
+                          IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
        }
 
        /* Prevent IGMP interface from removing multicast route multiple
@@ -800,9 +780,8 @@ void igmp_source_forward_stop(struct igmp_source *source)
         pim_forward_stop below.
        */
        result = pim_channel_del_oif(source->source_channel_oil,
-                                    group->group_igmp_sock->interface,
-                                        PIM_OIF_FLAG_PROTO_IGMP,
-                                        __func__);
+                                    group->interface, PIM_OIF_FLAG_PROTO_IGMP,
+                                    __func__);
        if (result) {
                if (PIM_DEBUG_IGMP_TRACE)
                        zlog_debug(
@@ -815,8 +794,7 @@ void igmp_source_forward_stop(struct igmp_source *source)
          Feed IGMPv3-gathered local membership information into PIM
          per-interface (S,G) state.
         */
-       pim_ifchannel_local_membership_del(group->group_igmp_sock->interface,
-                                          &sg);
+       pim_ifchannel_local_membership_del(group->interface, &sg);
 
        IGMP_SOURCE_DONT_FORWARDING(source->source_flags);
 }
index dce936b8a99ba9d4cf9ba1b54c5d4ea6f800d4d5..abf9577bd53ac5ec0de6a7fe7d4f7bf69579cc14 100644 (file)
@@ -31,6 +31,7 @@
 
 #include "pimd.h"
 #include "pim_iface.h"
+#include "pim_neighbor.h"
 #include "pim_pim.h"
 #include "pim_str.h"
 #include "pim_oil.h"
index 88e692b50d2c7dc71d36a4f67200862d2970720b..4cb860a6b7a95be4d1463a7bca6f4ab0618b4e60 100644 (file)
@@ -136,7 +136,6 @@ extern const char *const PIM_ALL_ROUTERS;
 extern const char *const PIM_ALL_PIM_ROUTERS;
 extern const char *const PIM_ALL_IGMP_ROUTERS;
 
-extern struct pim_router *router;
 extern struct zebra_privs_t pimd_privs;
 extern struct in_addr qpim_all_pim_routers_addr;
 extern uint8_t qpim_ecmp_enable;
index a47cee2d6b47efe4b5dff5dd9b501f8d7480d2fd..ba7c9072c5880c0da9842ff1a81edf7c030d31ca 100644 (file)
@@ -435,6 +435,8 @@ if __name__ == "__main__":
     macros.load(os.path.join(basepath, "bgpd/bgp_vty.h"))
     # sigh :(
     macros["PROTO_REDIST_STR"] = "FRR_REDIST_STR_ISISD"
+    macros["PROTO_IP_REDIST_STR"] = "FRR_IP_REDIST_STR_ISISD"
+    macros["PROTO_IP6_REDIST_STR"] = "FRR_IP6_REDIST_STR_ISISD"
 
     errors = process_file(args.cfile, ofd, dumpfd, args.all_defun, macros)
     if errors != 0:
index a2c86e3b2280a7222d60de46e31fdb35f13dc3e8..2eb7bb6da1e653a3d4d881333c7b42dfbf74d0fb 100644 (file)
@@ -805,7 +805,6 @@ static int rip_interface_wakeup(struct thread *t)
        ifp = THREAD_ARG(t);
 
        ri = ifp->info;
-       ri->t_wakeup = NULL;
 
        /* Join to multicast group. */
        if (rip_multicast_join(ifp, ri->rip->sock) < 0) {
index 63493e2539c315ed452ff6ee3f12dbad8a898290..12c4edd43611c44299e29739249f27b25642f90e 100644 (file)
@@ -95,7 +95,6 @@ static struct rip_peer *rip_peer_get(struct rip *rip, struct in_addr *addr)
        }
 
        /* Update timeout thread. */
-       peer->t_timeout = NULL;
        thread_add_timer(master, rip_peer_timeout, peer, RIP_PEER_TIMER_DEFAULT,
                         &peer->t_timeout);
 
index 84fb67956e63eee4cf6d27de0dcbe36a6cc6b110..145b4de0a0d119dd7870322d5c9d6b3b7168b787 100644 (file)
@@ -142,7 +142,6 @@ static int rip_garbage_collect(struct thread *t)
        struct route_node *rp;
 
        rinfo = THREAD_ARG(t);
-       rinfo->t_garbage_collect = NULL;
 
        /* Off timeout timer. */
        RIP_TIMER_OFF(rinfo->t_timeout);
@@ -1744,7 +1743,6 @@ static int rip_read(struct thread *t)
 
        /* Fetch socket then register myself. */
        sock = THREAD_FD(t);
-       rip->t_read = NULL;
 
        /* Add myself to tne next event */
        rip_event(rip, RIP_READ, sock);
@@ -2545,9 +2543,6 @@ static int rip_update(struct thread *t)
 {
        struct rip *rip = THREAD_ARG(t);
 
-       /* Clear timer pointer. */
-       rip->t_update = NULL;
-
        if (IS_RIP_DEBUG_EVENT)
                zlog_debug("update timer fire!");
 
@@ -2588,8 +2583,6 @@ static int rip_triggered_interval(struct thread *t)
 {
        struct rip *rip = THREAD_ARG(t);
 
-       rip->t_triggered_interval = NULL;
-
        if (rip->trigger) {
                rip->trigger = 0;
                rip_triggered_update(t);
@@ -2603,9 +2596,6 @@ static int rip_triggered_update(struct thread *t)
        struct rip *rip = THREAD_ARG(t);
        int interval;
 
-       /* Clear thred pointer. */
-       rip->t_triggered_update = NULL;
-
        /* Cancel interval timer. */
        RIP_TIMER_OFF(rip->t_triggered_interval);
        rip->trigger = 0;
@@ -2628,7 +2618,6 @@ static int rip_triggered_update(struct thread *t)
         update is triggered when the timer expires. */
        interval = (frr_weak_random() % 5) + 1;
 
-       rip->t_triggered_interval = NULL;
        thread_add_timer(master, rip_triggered_interval, rip, interval,
                         &rip->t_triggered_interval);
 
@@ -2834,7 +2823,6 @@ void rip_event(struct rip *rip, enum rip_event event, int sock)
 
        switch (event) {
        case RIP_READ:
-               rip->t_read = NULL;
                thread_add_read(master, rip_read, rip, sock, &rip->t_read);
                break;
        case RIP_UPDATE_EVENT:
index f374fcb839017a8e838b558244c50df9ddbf52e9..7b5e7604d273de73e31f624a3d7d5cb70c039af3 100644 (file)
@@ -618,7 +618,6 @@ static int ripng_interface_wakeup(struct thread *t)
        ifp = THREAD_ARG(t);
 
        ri = ifp->info;
-       ri->t_wakeup = NULL;
 
        /* Join to multicast group. */
        if (ripng_multicast_join(ifp, ri->ripng->sock) < 0) {
index 4f5c8e77609d3c606f4d99fd5da6ec00fa091322..86abf1eead7e5daaa0a526b4780ae32d23c66420 100644 (file)
@@ -429,7 +429,6 @@ static int ripng_garbage_collect(struct thread *t)
        struct agg_node *rp;
 
        rinfo = THREAD_ARG(t);
-       rinfo->t_garbage_collect = NULL;
 
        /* Off timeout timer. */
        RIPNG_TIMER_OFF(rinfo->t_timeout);
@@ -1320,7 +1319,6 @@ static int ripng_read(struct thread *thread)
        /* Fetch thread data and set read pointer to empty for event
           managing.  `sock' sould be same as ripng->sock. */
        sock = THREAD_FD(thread);
-       ripng->t_read = NULL;
 
        /* Add myself to the next event. */
        ripng_event(ripng, RIPNG_READ, sock);
@@ -1418,9 +1416,6 @@ static int ripng_update(struct thread *t)
        struct interface *ifp;
        struct ripng_interface *ri;
 
-       /* Clear update timer thread. */
-       ripng->t_update = NULL;
-
        /* Logging update event. */
        if (IS_RIPNG_DEBUG_EVENT)
                zlog_debug("RIPng update timer expired!");
@@ -1469,8 +1464,6 @@ static int ripng_triggered_interval(struct thread *t)
 {
        struct ripng *ripng = THREAD_ARG(t);
 
-       ripng->t_triggered_interval = NULL;
-
        if (ripng->trigger) {
                ripng->trigger = 0;
                ripng_triggered_update(t);
@@ -1486,8 +1479,6 @@ int ripng_triggered_update(struct thread *t)
        struct ripng_interface *ri;
        int interval;
 
-       ripng->t_triggered_update = NULL;
-
        /* Cancel interval timer. */
        thread_cancel(&ripng->t_triggered_interval);
        ripng->trigger = 0;
@@ -1525,7 +1516,6 @@ int ripng_triggered_update(struct thread *t)
           update is triggered when the timer expires. */
        interval = (frr_weak_random() % 5) + 1;
 
-       ripng->t_triggered_interval = NULL;
        thread_add_timer(master, ripng_triggered_interval, ripng, interval,
                         &ripng->t_triggered_interval);
 
@@ -1942,7 +1932,6 @@ void ripng_event(struct ripng *ripng, enum ripng_event event, int sock)
                /* Update timer jitter. */
                jitter = ripng_update_jitter(ripng->update_time);
 
-               ripng->t_update = NULL;
                thread_add_timer(master, ripng_update, ripng,
                                 sock ? 2 : ripng->update_time + jitter,
                                 &ripng->t_update);
index 12e5a6d4ac2ebfb0c4c26d69752eb91e3df1b25b..6bf687b02a6d86b92e0f36565bc72095e2780c12 100644 (file)
@@ -137,10 +137,7 @@ struct ripng {
 
        /* RIPng threads. */
        struct thread *t_read;
-       struct thread *t_write;
        struct thread *t_update;
-       struct thread *t_garbage;
-       struct thread *t_zebra;
 
        /* Triggered update hack. */
        int trigger;
index c1a6253a1dd62bbbe2f63c95b650ee6d2e005cb5..5935364d5a61b35c3adcf9a83a97c6930433bcfe 100644 (file)
 #include "northbound.h"
 #include "libfrr.h"
 #include "static_nb.h"
-
+#include "static_vty.h"
 
 /* clang-format off */
 
 const struct frr_yang_module_info frr_staticd_info = {
        .name = "frr-staticd",
        .nodes = {
+               {
+                       .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd",
+                       .cbs = {
+                               .cli_show = static_cli_show,
+                               .cli_show_end = static_cli_show_end,
+                       }
+               },
                {
                        .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list",
                        .cbs = {
                                .create = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_create,
                                .destroy = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_destroy,
+                               .cli_cmp = static_route_list_cli_cmp,
                        }
                },
                {
@@ -40,6 +48,7 @@ const struct frr_yang_module_info frr_staticd_info = {
                        .cbs = {
                                .create = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_create,
                                .destroy = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_destroy,
+                               .cli_cmp = static_path_list_cli_cmp,
                        }
                },
                {
@@ -55,6 +64,8 @@ const struct frr_yang_module_info frr_staticd_info = {
                                .create = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_create,
                                .destroy = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_destroy,
                                .pre_validate = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_pre_validate,
+                               .cli_show = static_nexthop_cli_show,
+                               .cli_cmp = static_nexthop_cli_cmp,
                        }
                },
                {
@@ -110,6 +121,7 @@ const struct frr_yang_module_info frr_staticd_info = {
                        .cbs = {
                                .create = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_create,
                                .destroy = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_destroy,
+                               .cli_cmp = static_src_list_cli_cmp,
                        }
                },
                {
@@ -117,6 +129,7 @@ const struct frr_yang_module_info frr_staticd_info = {
                        .cbs = {
                                .create = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_create,
                                .destroy = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_destroy,
+                               .cli_cmp = static_path_list_cli_cmp,
                        }
                },
                {
@@ -132,6 +145,8 @@ const struct frr_yang_module_info frr_staticd_info = {
                                .create = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_create,
                                .destroy = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_destroy,
                                .pre_validate = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_pre_validate,
+                               .cli_show = static_src_nexthop_cli_show,
+                               .cli_cmp = static_nexthop_cli_cmp,
                        }
                },
                {
index deeca97b0e48369e9309d2a84477c7034c3cdb04..470c7bdad5eb313090dff1c8a3e723fd5ed17174 100644 (file)
@@ -122,7 +122,7 @@ struct nexthop_iter {
 static int nexthop_iter_cb(const struct lyd_node *dnode, void *arg)
 {
        struct nexthop_iter *iter = arg;
-       int nh_type;
+       enum static_nh_type nh_type;
 
        nh_type = yang_dnode_get_enum(dnode, "./nh-type");
 
@@ -141,7 +141,7 @@ static bool static_nexthop_create(struct nb_cb_create_args *args)
        struct static_path *pn;
        struct ipaddr ipaddr;
        struct static_nexthop *nh;
-       int nh_type;
+       enum static_nh_type nh_type;
        const char *ifname;
        const char *nh_vrf;
 
@@ -304,7 +304,7 @@ static int static_nexthop_mpls_label_modify(struct nb_cb_modify_args *args)
 static int static_nexthop_onlink_modify(struct nb_cb_modify_args *args)
 {
        struct static_nexthop *nh;
-       static_types nh_type;
+       enum static_nh_type nh_type;
 
        switch (args->event) {
        case NB_EV_VALIDATE:
@@ -352,7 +352,7 @@ static int static_nexthop_color_destroy(struct nb_cb_destroy_args *args)
 static int static_nexthop_bh_type_modify(struct nb_cb_modify_args *args)
 {
        struct static_nexthop *nh;
-       static_types nh_type;
+       enum static_nh_type nh_type;
 
        switch (args->event) {
        case NB_EV_VALIDATE:
index 77a10092f8ad78afe3fbdfc1dd4fc7c26f788c7f..60f384e5172789fbd635e25bad88e4549523f984 100644 (file)
@@ -186,7 +186,8 @@ void static_del_route(struct route_node *rn)
        route_unlock_node(rn);
 }
 
-bool static_add_nexthop_validate(const char *nh_vrf_name, static_types type,
+bool static_add_nexthop_validate(const char *nh_vrf_name,
+                                enum static_nh_type type,
                                 struct ipaddr *ipaddr)
 {
        struct vrf *vrf;
@@ -257,7 +258,7 @@ void static_del_path(struct static_path *pn)
 }
 
 struct static_nexthop *static_add_nexthop(struct static_path *pn,
-                                         static_types type,
+                                         enum static_nh_type type,
                                          struct ipaddr *ipaddr,
                                          const char *ifname,
                                          const char *nh_vrf, uint32_t color)
@@ -772,7 +773,7 @@ void static_ifindex_update(struct interface *ifp, bool up)
        static_ifindex_update_af(ifp, up, AFI_IP6, SAFI_MULTICAST);
 }
 
-void static_get_nh_type(static_types stype, char *type, size_t size)
+void static_get_nh_type(enum static_nh_type stype, char *type, size_t size)
 {
        switch (stype) {
        case STATIC_IFNAME:
index 2211384916a35866f2b6ac94e48c954b54814410..c901a8926a437a2352914131c31b67eda497389d 100644 (file)
@@ -47,14 +47,14 @@ enum static_blackhole_type {
  * The order for below macros should be in sync with
  * yang model typedef nexthop-type
  */
-typedef enum {
+enum static_nh_type {
        STATIC_IFNAME = 1,
        STATIC_IPV4_GATEWAY,
        STATIC_IPV4_GATEWAY_IFNAME,
        STATIC_IPV6_GATEWAY,
        STATIC_IPV6_GATEWAY_IFNAME,
        STATIC_BLACKHOLE,
-} static_types;
+};
 
 /*
  * Route Creation gives us:
@@ -123,7 +123,7 @@ struct static_nexthop {
        enum static_install_states state;
 
        /* Flag for this static route's type. */
-       static_types type;
+       enum static_nh_type type;
 
        /*
         * Nexthop value.
@@ -169,7 +169,7 @@ extern struct zebra_privs_t static_privs;
 void static_fixup_vrf_ids(struct static_vrf *svrf);
 
 extern struct static_nexthop *
-static_add_nexthop(struct static_path *pn, static_types type,
+static_add_nexthop(struct static_path *pn, enum static_nh_type type,
                   struct ipaddr *ipaddr, const char *ifname,
                   const char *nh_vrf, uint32_t color);
 extern void static_install_nexthop(struct static_nexthop *nh);
@@ -194,9 +194,10 @@ extern struct static_path *static_add_path(struct route_node *rn,
                                           uint32_t table_id, uint8_t distance);
 extern void static_del_path(struct static_path *pn);
 
-extern void static_get_nh_type(static_types stype, char *type, size_t size);
+extern void static_get_nh_type(enum static_nh_type stype, char *type,
+                              size_t size);
 extern bool static_add_nexthop_validate(const char *nh_vrf_name,
-                                       static_types type,
+                                       enum static_nh_type type,
                                        struct ipaddr *ipaddr);
 extern struct stable_info *static_get_stable_info(struct route_node *rn);
 
index 740d90469089d0801c19b503992394567f637920..4bea3075c9f6aa72b2c4bd7ab172bd9a447d9b1e 100644 (file)
 #include "nexthop.h"
 #include "table.h"
 #include "srcdest_table.h"
+#include "northbound_cli.h"
 
 #include "static_vrf.h"
 #include "static_routes.h"
 #include "static_zebra.h"
-#include "static_vty.h"
 
 DEFINE_MTYPE_STATIC(STATIC, STATIC_RTABLE_INFO, "Static Route Table Info");
 
@@ -150,24 +150,16 @@ struct static_vrf *static_vrf_lookup_by_name(const char *name)
 
 static int static_vrf_config_write(struct vty *vty)
 {
-       struct vrf *vrf;
-
-       RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
-               if (vrf->vrf_id != VRF_DEFAULT)
-                       vty_frame(vty, "vrf %s\n", vrf->name);
+       struct lyd_node *dnode;
+       int written = 0;
 
-               static_config(vty, vrf->info, AFI_IP,
-                             SAFI_UNICAST, "ip route");
-               static_config(vty, vrf->info, AFI_IP,
-                             SAFI_MULTICAST, "ip mroute");
-               static_config(vty, vrf->info, AFI_IP6,
-                             SAFI_UNICAST, "ipv6 route");
-
-               if (vrf->vrf_id != VRF_DEFAULT)
-                       vty_endframe(vty, "exit-vrf\n!\n");
+       dnode = yang_dnode_get(running_config->dnode, "/frr-routing:routing");
+       if (dnode) {
+               nb_cli_show_dnode_cmds(vty, dnode, false);
+               written = 1;
        }
 
-       return 0;
+       return written;
 }
 
 void static_vrf_init(void)
index f16b40a23f0ce07ce05c979d22c1d8575274a29e..751a26277568095a3f713569a585ae3b12c1e72c 100644 (file)
@@ -56,7 +56,7 @@ static int static_route_leak(struct vty *vty, const char *svrf,
        int ret;
        struct prefix p, src;
        struct in_addr mask;
-       uint8_t type;
+       enum static_nh_type type;
        const char *bh_type;
        char xpath_prefix[XPATH_MAXLEN];
        char xpath_nexthop[XPATH_MAXLEN];
@@ -357,129 +357,6 @@ static int static_route(struct vty *vty, afi_t afi, safi_t safi,
                                 table_str, false, NULL);
 }
 
-/* Write static route configuration. */
-int static_config(struct vty *vty, struct static_vrf *svrf, afi_t afi,
-                 safi_t safi, const char *cmd)
-{
-       char spacing[100];
-       struct route_node *rn;
-       struct static_nexthop *nh;
-       struct static_path *pn;
-       struct route_table *stable;
-       struct static_route_info *si;
-       char buf[SRCDEST2STR_BUFFER];
-       int write = 0;
-       struct stable_info *info;
-
-       stable = svrf->stable[afi][safi];
-       if (stable == NULL)
-               return write;
-
-       snprintf(spacing, sizeof(spacing), "%s%s",
-                (svrf->vrf->vrf_id == VRF_DEFAULT) ? "" : " ", cmd);
-
-       for (rn = route_top(stable); rn; rn = srcdest_route_next(rn)) {
-               si = static_route_info_from_rnode(rn);
-               if (!si)
-                       continue;
-               info = static_get_stable_info(rn);
-               frr_each(static_path_list, &si->path_list, pn) {
-                       frr_each(static_nexthop_list, &pn->nexthop_list, nh) {
-                               vty_out(vty, "%s %s", spacing,
-                                       srcdest_rnode2str(rn, buf,
-                                                         sizeof(buf)));
-
-                               switch (nh->type) {
-                               case STATIC_IPV4_GATEWAY:
-                                       vty_out(vty, " %pI4", &nh->addr.ipv4);
-                                       break;
-                               case STATIC_IPV6_GATEWAY:
-                                       vty_out(vty, " %s",
-                                               inet_ntop(AF_INET6,
-                                                         &nh->addr.ipv6, buf,
-                                                         sizeof(buf)));
-                                       break;
-                               case STATIC_IFNAME:
-                                       vty_out(vty, " %s", nh->ifname);
-                                       break;
-                               case STATIC_BLACKHOLE:
-                                       switch (nh->bh_type) {
-                                       case STATIC_BLACKHOLE_DROP:
-                                               vty_out(vty, " blackhole");
-                                               break;
-                                       case STATIC_BLACKHOLE_NULL:
-                                               vty_out(vty, " Null0");
-                                               break;
-                                       case STATIC_BLACKHOLE_REJECT:
-                                               vty_out(vty, " reject");
-                                               break;
-                                       }
-                                       break;
-                               case STATIC_IPV4_GATEWAY_IFNAME:
-                                       vty_out(vty, " %s %s",
-                                               inet_ntop(AF_INET,
-                                                         &nh->addr.ipv4, buf,
-                                                         sizeof(buf)),
-                                               nh->ifname);
-                                       break;
-                               case STATIC_IPV6_GATEWAY_IFNAME:
-                                       vty_out(vty, " %s %s",
-                                               inet_ntop(AF_INET6,
-                                                         &nh->addr.ipv6, buf,
-                                                         sizeof(buf)),
-                                               nh->ifname);
-                                       break;
-                               }
-
-                               if (pn->tag)
-                                       vty_out(vty, " tag %" ROUTE_TAG_PRI,
-                                               pn->tag);
-
-                               if (pn->distance
-                                   != ZEBRA_STATIC_DISTANCE_DEFAULT)
-                                       vty_out(vty, " %u", pn->distance);
-
-                               /* Label information */
-                               if (nh->snh_label.num_labels)
-                                       vty_out(vty, " label %s",
-                                               mpls_label2str(
-                                                       nh->snh_label
-                                                               .num_labels,
-                                                       nh->snh_label.label,
-                                                       buf, sizeof(buf), 0));
-
-                               if (!strmatch(nh->nh_vrfname,
-                                             info->svrf->vrf->name))
-                                       vty_out(vty, " nexthop-vrf %s",
-                                               nh->nh_vrfname);
-
-                               /*
-                                * table ID from VRF overrides
-                                * configured
-                                */
-                               if (pn->table_id
-                                   && svrf->vrf->data.l.table_id
-                                              == RT_TABLE_MAIN)
-                                       vty_out(vty, " table %u", pn->table_id);
-
-                               if (nh->onlink)
-                                       vty_out(vty, " onlink");
-
-                               /*
-                                * SR-TE color
-                                */
-                               if (nh->color != 0)
-                                       vty_out(vty, " color %u", nh->color);
-
-                               vty_out(vty, "\n");
-
-                               write = 1;
-                       }
-               }
-       }
-       return write;
-}
-
 /* Static unicast routes for multicast RPF lookup. */
 DEFPY_YANG (ip_mroute_dist,
        ip_mroute_dist_cmd,
@@ -1124,6 +1001,278 @@ DEFPY_YANG(ipv6_route_vrf,
                                 ifname, flag, tag_str, distance_str, label,
                                 table_str, false, color_str);
 }
+
+void static_cli_show(struct vty *vty, struct lyd_node *dnode,
+                    bool show_defaults)
+{
+       const char *vrf;
+
+       vrf = yang_dnode_get_string(dnode, "../vrf");
+       if (strcmp(vrf, VRF_DEFAULT_NAME))
+               vty_out(vty, "vrf %s\n", vrf);
+}
+
+void static_cli_show_end(struct vty *vty, struct lyd_node *dnode)
+{
+       const char *vrf;
+
+       vrf = yang_dnode_get_string(dnode, "../vrf");
+       if (strcmp(vrf, VRF_DEFAULT_NAME))
+               vty_out(vty, "exit-vrf\n");
+}
+
+struct mpls_label_iter {
+       struct vty *vty;
+       bool first;
+};
+
+static int mpls_label_iter_cb(const struct lyd_node *dnode, void *arg)
+{
+       struct mpls_label_iter *iter = arg;
+
+       if (yang_dnode_exists(dnode, "./label")) {
+               if (iter->first)
+                       vty_out(iter->vty, " label %s",
+                               yang_dnode_get_string(dnode, "./label"));
+               else
+                       vty_out(iter->vty, "/%s",
+                               yang_dnode_get_string(dnode, "./label"));
+               iter->first = false;
+       }
+
+       return YANG_ITER_CONTINUE;
+}
+
+static void nexthop_cli_show(struct vty *vty, const struct lyd_node *route,
+                            const struct lyd_node *src,
+                            const struct lyd_node *path,
+                            const struct lyd_node *nexthop, bool show_defaults)
+{
+       const char *vrf;
+       const char *afi_safi;
+       afi_t afi;
+       safi_t safi;
+       enum static_nh_type nh_type;
+       enum static_blackhole_type bh_type;
+       uint32_t tag;
+       uint8_t distance;
+       struct mpls_label_iter iter;
+       const char *nexthop_vrf;
+       uint32_t table_id;
+       bool onlink;
+
+       vrf = yang_dnode_get_string(route, "../../vrf");
+
+       afi_safi = yang_dnode_get_string(route, "./afi-safi");
+       yang_afi_safi_identity2value(afi_safi, &afi, &safi);
+
+       if (afi == AFI_IP)
+               vty_out(vty, "%sip",
+                       strmatch(vrf, VRF_DEFAULT_NAME) ? "" : " ");
+       else
+               vty_out(vty, "%sipv6",
+                       strmatch(vrf, VRF_DEFAULT_NAME) ? "" : " ");
+
+       if (safi == SAFI_UNICAST)
+               vty_out(vty, " route");
+       else
+               vty_out(vty, " mroute");
+
+       vty_out(vty, " %s", yang_dnode_get_string(route, "./prefix"));
+
+       if (src)
+               vty_out(vty, " from %s",
+                       yang_dnode_get_string(src, "./src-prefix"));
+
+       nh_type = yang_dnode_get_enum(nexthop, "./nh-type");
+       switch (nh_type) {
+       case STATIC_IFNAME:
+               vty_out(vty, " %s",
+                       yang_dnode_get_string(nexthop, "./interface"));
+               break;
+       case STATIC_IPV4_GATEWAY:
+       case STATIC_IPV6_GATEWAY:
+               vty_out(vty, " %s",
+                       yang_dnode_get_string(nexthop, "./gateway"));
+               break;
+       case STATIC_IPV4_GATEWAY_IFNAME:
+       case STATIC_IPV6_GATEWAY_IFNAME:
+               vty_out(vty, " %s",
+                       yang_dnode_get_string(nexthop, "./gateway"));
+               vty_out(vty, " %s",
+                       yang_dnode_get_string(nexthop, "./interface"));
+               break;
+       case STATIC_BLACKHOLE:
+               bh_type = yang_dnode_get_enum(nexthop, "./bh-type");
+               switch (bh_type) {
+               case STATIC_BLACKHOLE_DROP:
+                       vty_out(vty, " blackhole");
+                       break;
+               case STATIC_BLACKHOLE_NULL:
+                       vty_out(vty, " Null0");
+                       break;
+               case STATIC_BLACKHOLE_REJECT:
+                       vty_out(vty, " reject");
+                       break;
+               }
+               break;
+       }
+
+       if (yang_dnode_exists(path, "./tag")) {
+               tag = yang_dnode_get_uint32(path, "./tag");
+               if (tag != 0 || show_defaults)
+                       vty_out(vty, " tag %" PRIu32, tag);
+       }
+
+       distance = yang_dnode_get_uint8(path, "./distance");
+       if (distance != ZEBRA_STATIC_DISTANCE_DEFAULT || show_defaults)
+               vty_out(vty, " %" PRIu8, distance);
+
+       iter.vty = vty;
+       iter.first = true;
+       yang_dnode_iterate(mpls_label_iter_cb, &iter, nexthop,
+                          "./mpls-label-stack/entry");
+
+       nexthop_vrf = yang_dnode_get_string(nexthop, "./vrf");
+       if (strcmp(vrf, nexthop_vrf))
+               vty_out(vty, " nexthop-vrf %s", nexthop_vrf);
+
+       table_id = yang_dnode_get_uint32(path, "./table-id");
+       if (table_id || show_defaults)
+               vty_out(vty, " table %" PRIu32, table_id);
+
+       if (yang_dnode_exists(nexthop, "./onlink")) {
+               onlink = yang_dnode_get_bool(nexthop, "./onlink");
+               if (onlink)
+                       vty_out(vty, " onlink");
+       }
+
+       if (yang_dnode_exists(nexthop, "./srte-color"))
+               vty_out(vty, " color %s",
+                       yang_dnode_get_string(nexthop, "./srte-color"));
+
+       vty_out(vty, "\n");
+}
+
+void static_nexthop_cli_show(struct vty *vty, struct lyd_node *dnode,
+                            bool show_defaults)
+{
+       const struct lyd_node *path = yang_dnode_get_parent(dnode, "path-list");
+       const struct lyd_node *route =
+               yang_dnode_get_parent(path, "route-list");
+
+       nexthop_cli_show(vty, route, NULL, path, dnode, show_defaults);
+}
+
+void static_src_nexthop_cli_show(struct vty *vty, struct lyd_node *dnode,
+                                bool show_defaults)
+{
+       const struct lyd_node *path = yang_dnode_get_parent(dnode, "path-list");
+       const struct lyd_node *src = yang_dnode_get_parent(path, "src-list");
+       const struct lyd_node *route = yang_dnode_get_parent(src, "route-list");
+
+       nexthop_cli_show(vty, route, src, path, dnode, show_defaults);
+}
+
+int static_nexthop_cli_cmp(struct lyd_node *dnode1, struct lyd_node *dnode2)
+{
+       enum static_nh_type nh_type1, nh_type2;
+       struct prefix prefix1, prefix2;
+       int ret = 0;
+
+       nh_type1 = yang_dnode_get_enum(dnode1, "./nh-type");
+       nh_type2 = yang_dnode_get_enum(dnode2, "./nh-type");
+
+       if (nh_type1 != nh_type2)
+               return (int)nh_type1 - (int)nh_type2;
+
+       switch (nh_type1) {
+       case STATIC_IFNAME:
+               ret = if_cmp_name_func(
+                       yang_dnode_get_string(dnode1, "./interface"),
+                       yang_dnode_get_string(dnode2, "./interface"));
+               break;
+       case STATIC_IPV4_GATEWAY:
+       case STATIC_IPV6_GATEWAY:
+               yang_dnode_get_prefix(&prefix1, dnode1, "./gateway");
+               yang_dnode_get_prefix(&prefix2, dnode2, "./gateway");
+               ret = prefix_cmp(&prefix1, &prefix2);
+               break;
+       case STATIC_IPV4_GATEWAY_IFNAME:
+       case STATIC_IPV6_GATEWAY_IFNAME:
+               yang_dnode_get_prefix(&prefix1, dnode1, "./gateway");
+               yang_dnode_get_prefix(&prefix2, dnode2, "./gateway");
+               ret = prefix_cmp(&prefix1, &prefix2);
+               if (!ret)
+                       ret = if_cmp_name_func(
+                               yang_dnode_get_string(dnode1, "./interface"),
+                               yang_dnode_get_string(dnode2, "./interface"));
+               break;
+       case STATIC_BLACKHOLE:
+               /* There's only one blackhole nexthop per route */
+               ret = 0;
+               break;
+       }
+
+       if (ret)
+               return ret;
+
+       return if_cmp_name_func(yang_dnode_get_string(dnode1, "./vrf"),
+                               yang_dnode_get_string(dnode2, "./vrf"));
+}
+
+int static_route_list_cli_cmp(struct lyd_node *dnode1, struct lyd_node *dnode2)
+{
+       const char *afi_safi1, *afi_safi2;
+       afi_t afi1, afi2;
+       safi_t safi1, safi2;
+       struct prefix prefix1, prefix2;
+
+       afi_safi1 = yang_dnode_get_string(dnode1, "./afi-safi");
+       yang_afi_safi_identity2value(afi_safi1, &afi1, &safi1);
+
+       afi_safi2 = yang_dnode_get_string(dnode2, "./afi-safi");
+       yang_afi_safi_identity2value(afi_safi2, &afi2, &safi2);
+
+       if (afi1 != afi2)
+               return (int)afi1 - (int)afi2;
+
+       if (safi1 != safi2)
+               return (int)safi1 - (int)safi2;
+
+       yang_dnode_get_prefix(&prefix1, dnode1, "./prefix");
+       yang_dnode_get_prefix(&prefix2, dnode2, "./prefix");
+
+       return prefix_cmp(&prefix1, &prefix2);
+}
+
+int static_src_list_cli_cmp(struct lyd_node *dnode1, struct lyd_node *dnode2)
+{
+       struct prefix prefix1, prefix2;
+
+       yang_dnode_get_prefix(&prefix1, dnode1, "./src-prefix");
+       yang_dnode_get_prefix(&prefix2, dnode2, "./src-prefix");
+
+       return prefix_cmp(&prefix1, &prefix2);
+}
+
+int static_path_list_cli_cmp(struct lyd_node *dnode1, struct lyd_node *dnode2)
+{
+       uint32_t table_id1, table_id2;
+       uint8_t distance1, distance2;
+
+       table_id1 = yang_dnode_get_uint32(dnode1, "./table-id");
+       table_id2 = yang_dnode_get_uint32(dnode2, "./table-id");
+
+       if (table_id1 != table_id2)
+               return (int)table_id1 - (int)table_id2;
+
+       distance1 = yang_dnode_get_uint8(dnode1, "./distance");
+       distance2 = yang_dnode_get_uint8(dnode2, "./distance");
+
+       return (int)distance1 - (int)distance2;
+}
+
 DEFPY_YANG(debug_staticd, debug_staticd_cmd,
           "[no] debug static [{events$events|route$route}]",
           NO_STR DEBUG_STR STATICD_STR
index 01577685e5e07b74c9c564326660c162e863728f..8861afa46881efb7fda38bb9fda2c2362c71805d 100644 (file)
 extern "C" {
 #endif
 
-int static_config(struct vty *vty, struct static_vrf *svrf,
-                 afi_t afi, safi_t safi, const char *cmd);
+void static_cli_show(struct vty *vty, struct lyd_node *dnode,
+                    bool show_defaults);
+void static_cli_show_end(struct vty *vty, struct lyd_node *dnode);
+void static_nexthop_cli_show(struct vty *vty, struct lyd_node *dnode,
+                            bool show_defaults);
+void static_src_nexthop_cli_show(struct vty *vty, struct lyd_node *dnode,
+                                bool show_defaults);
+int static_nexthop_cli_cmp(struct lyd_node *dnode1, struct lyd_node *dnode2);
+int static_route_list_cli_cmp(struct lyd_node *dnode1, struct lyd_node *dnode2);
+int static_src_list_cli_cmp(struct lyd_node *dnode1, struct lyd_node *dnode2);
+int static_path_list_cli_cmp(struct lyd_node *dnode1, struct lyd_node *dnode2);
 
 void static_vty_init(void);
 
index 92efd4c3d612b3a0e9d61ff7526cf005303eb0be..77fd8765946f6f00fd7496eb12e9ea62ee340ed7 100644 (file)
@@ -310,7 +310,7 @@ static int setup_bgp_path_info_mpath_update(testcase_t *t)
        str2prefix("42.1.1.0/24", &test_rn.p);
        rt_node = bgp_dest_to_rnode(&test_rn);
        memcpy((struct route_table *)&rt_node->table, &rt->route_table,
-              sizeof(struct route_table *));
+              sizeof(struct route_table));
        setup_bgp_mp_list(t);
        for (i = 0; i < test_mp_list_info_count; i++)
                bgp_path_info_add(&test_rn, &test_mp_list_info[i]);
index 8dba1e29f08ba1c922b3b500073f44a6f5fa2618..f8d74018ddfd218532d8e4c19c426284468744f0 100644 (file)
@@ -40,6 +40,8 @@ DUMMY_DEFUN(cmd12, "alt a A.B.C.D");
 DUMMY_DEFUN(cmd13, "alt a X:X::X:X");
 DUMMY_DEFUN(cmd14,
            "pat g {  foo A.B.C.D$foo|foo|bar   X:X::X:X$bar| baz } [final]");
+DUMMY_DEFUN(cmd15, "no pat g ![ WORD ]");
+DUMMY_DEFUN(cmd16, "[no] pat h {foo ![A.B.C.D$foo]|bar X:X::X:X$bar} final");
 
 #include "tests/lib/cli/test_cli_clippy.c"
 
@@ -81,5 +83,7 @@ void test_init(int argc, char **argv)
                install_element(ENABLE_NODE, &cmd13_cmd);
        }
        install_element(ENABLE_NODE, &cmd14_cmd);
+       install_element(ENABLE_NODE, &cmd15_cmd);
+       install_element(ENABLE_NODE, &cmd16_cmd);
        install_element(ENABLE_NODE, &magic_test_cmd);
 }
index 5c146ef984db50fd108c6d10aa2315968b2641e1..bd685a6231fa9ff99bdf54c689d711af907429e2 100644 (file)
@@ -74,6 +74,23 @@ pat f
 pat f foo
 pat f key
 
+no pat g
+no pat g test
+no pat g test more
+
+pat h foo ?1.2.3.4 final
+no pat h foo ?1.2.3.4 final
+pat h foo final
+no pat h foo final
+pat h bar final
+no pat h bar final
+pat h bar 1::2 final
+no pat h bar 1::2 final
+pat h bar 1::2 foo final
+no pat h bar 1::2 foo final
+pat h bar 1::2 foo 1.2.3.4 final
+no pat h bar 1::2 foo 1.2.3.4 final
+
 alt a  a?b
 alt a 1        .2?.3.4
 alt a 1        :2?     ::?3
index 1f38e08b209ee19e2a9c54f2f2c0e4262fa25c83..84365810d51110f3abeb9d2cc638ce18b70167b0 100644 (file)
@@ -147,7 +147,7 @@ test# pa\b\bpat
 % Command incomplete.\r
 test# pat \r
 a          b          c          d          e          f          \r
-g          \r
+g          h          \r
 test# pat \r
 % Command incomplete.\r
 test# \r
@@ -263,6 +263,100 @@ cmd10 with 3 args.
 [01] f@(null): f\r
 [02] key@(null): key\r
 test# \r
+test# no pat g\r
+cmd15 with 3 args.\r
+[00] no@(null): no\r
+[01] pat@(null): pat\r
+[02] g@(null): g\r
+test# no pat g test\r
+cmd15 with 4 args.\r
+[00] no@(null): no\r
+[01] pat@(null): pat\r
+[02] g@(null): g\r
+[03] WORD@g: test\r
+test# no pat g test more\r
+% [NONE] Unknown command: no pat g test more\r
+test# \r
+test# pat h foo \r
+  A.B.C.D  04\r
+test# pat h foo 1.2.3.4 final\r
+cmd16 with 5 args.\r
+[00] pat@(null): pat\r
+[01] h@(null): h\r
+[02] foo@(null): foo\r
+[03] A.B.C.D@foo: 1.2.3.4\r
+[04] final@(null): final\r
+test# no pat h foo \r
+  A.B.C.D  04\r
+  bar      05\r
+  final    07\r
+test# no pat h foo 1.2.3.4 final\r
+cmd16 with 6 args.\r
+[00] no@no: no\r
+[01] pat@(null): pat\r
+[02] h@(null): h\r
+[03] foo@(null): foo\r
+[04] A.B.C.D@foo: 1.2.3.4\r
+[05] final@(null): final\r
+test# pat h foo final\r
+% [NONE] Unknown command: pat h foo final\r
+test# no pat h foo final\r
+cmd16 with 5 args.\r
+[00] no@no: no\r
+[01] pat@(null): pat\r
+[02] h@(null): h\r
+[03] foo@(null): foo\r
+[04] final@(null): final\r
+test# pat h bar final\r
+% [NONE] Unknown command: pat h bar final\r
+test# no pat h bar final\r
+% [NONE] Unknown command: no pat h bar final\r
+test# pat h bar 1::2 final\r
+cmd16 with 5 args.\r
+[00] pat@(null): pat\r
+[01] h@(null): h\r
+[02] bar@(null): bar\r
+[03] X:X::X:X@bar: 1::2\r
+[04] final@(null): final\r
+test# no pat h bar 1::2 final\r
+cmd16 with 6 args.\r
+[00] no@no: no\r
+[01] pat@(null): pat\r
+[02] h@(null): h\r
+[03] bar@(null): bar\r
+[04] X:X::X:X@bar: 1::2\r
+[05] final@(null): final\r
+test# pat h bar 1::2 foo final\r
+% [NONE] Unknown command: pat h bar 1::2 foo final\r
+test# no pat h bar 1::2 foo final\r
+cmd16 with 7 args.\r
+[00] no@no: no\r
+[01] pat@(null): pat\r
+[02] h@(null): h\r
+[03] bar@(null): bar\r
+[04] X:X::X:X@bar: 1::2\r
+[05] foo@(null): foo\r
+[06] final@(null): final\r
+test# pat h bar 1::2 foo 1.2.3.4 final\r
+cmd16 with 7 args.\r
+[00] pat@(null): pat\r
+[01] h@(null): h\r
+[02] bar@(null): bar\r
+[03] X:X::X:X@bar: 1::2\r
+[04] foo@(null): foo\r
+[05] A.B.C.D@foo: 1.2.3.4\r
+[06] final@(null): final\r
+test# no pat h bar 1::2 foo 1.2.3.4 final\r
+cmd16 with 8 args.\r
+[00] no@no: no\r
+[01] pat@(null): pat\r
+[02] h@(null): h\r
+[03] bar@(null): bar\r
+[04] X:X::X:X@bar: 1::2\r
+[05] foo@(null): foo\r
+[06] A.B.C.D@foo: 1.2.3.4\r
+[07] final@(null): final\r
+test# \r
 test# alt a \r
 test# alt a a\r
   WORD      02\r
index 491796802a2375acb262efe968beccd7daf024b2..0aa1bbb7e114bfe6728019eb4d5ca21d5c5a4b23 100644 (file)
@@ -81,11 +81,16 @@ static const struct frr_yang_module_info *const staticd_yang_modules[] = {
 
 static int grpc_thread_stop(struct thread *thread);
 
+static void _err_print(const void *cookie, const char *errstr)
+{
+       std::cout << "Failed to load grpc module:" << errstr << std::endl;
+}
+
 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);
@@ -94,17 +99,14 @@ static void static_startup(void)
 
        /* 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));
+       grpc_module = frrmod_load("grpc:50051", modpath.c_str(), 0, 0);
        if (!grpc_module) {
                modpath = std::string(binpath) +  std::string("../../lib");
-               grpc_module = frrmod_load("grpc:50051", modpath.c_str(), moderr,
-                                         sizeof(moderr));
+               grpc_module = frrmod_load("grpc:50051", modpath.c_str(),
+                                         _err_print, 0);
        }
-       if (!grpc_module) {
-               std::cout << "Failed to load grpc module:" << moderr
-                         << std::endl;
+       if (!grpc_module)
                exit(1);
-       }
 
        static_debug_init();
 
index 659d207b4ee78082b6c60c843a1d0838f80ac8ab..7cf687dffe094811693819abba6532cbad2901a2 100644 (file)
@@ -112,15 +112,15 @@ static void test_run_first(void)
        nexthop_free(nh2);
 
        /* Blackhole */
-       nh1 = nexthop_from_blackhole(BLACKHOLE_REJECT);
-       nh2 = nexthop_from_blackhole(BLACKHOLE_REJECT);
+       nh1 = nexthop_from_blackhole(BLACKHOLE_REJECT, 0);
+       nh2 = nexthop_from_blackhole(BLACKHOLE_REJECT, 0);
 
        ret = nexthop_cmp_basic(nh1, nh2);
        assert(ret == 0);
 
        nexthop_free(nh2);
 
-       nh2 = nexthop_from_blackhole(BLACKHOLE_NULL);
+       nh2 = nexthop_from_blackhole(BLACKHOLE_NULL, 0);
 
        ret = nexthop_cmp_basic(nh1, nh2);
        assert(ret != 0);
index 21b3a916b862464b49b69f527aa22882b53fba92..06996a2f13caad0037626eef1cba47c581c36ce6 100644 (file)
@@ -24,6 +24,7 @@
 #include "lib/printfrr.h"
 #include "lib/memory.h"
 #include "lib/prefix.h"
+#include "lib/nexthop.h"
 
 static int errors;
 
@@ -253,5 +254,25 @@ int main(int argc, char **argv)
        printchk("\"\"", "%pSQqn", (char *)NULL);
        printchk("(null)", "%pSQq", (char *)NULL);
 
+       /*
+        * %pNH<foo> tests
+        *
+        * gateway addresses only for now: interfaces require more setup
+        */
+       printchk("(null)", "%pNHcg", NULL);
+       printchk("(null)", "%pNHci", NULL);
+
+       struct nexthop nh;
+
+       memset(&nh, 0, sizeof(nh));
+
+       nh.type = NEXTHOP_TYPE_IPV4;
+       inet_aton("3.2.1.0", &nh.gate.ipv4);
+       printchk("3.2.1.0", "%pNHcg", &nh);
+
+       nh.type = NEXTHOP_TYPE_IPV6;
+       inet_pton(AF_INET6, "fe2c::34", &nh.gate.ipv6);
+       printchk("fe2c::34", "%pNHcg", &nh);
+
        return !!errors;
 }
diff --git a/tests/lib/test_skiplist.c b/tests/lib/test_skiplist.c
new file mode 100644 (file)
index 0000000..2f9ca5e
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * 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 <zebra.h>
+#include <skiplist.h>
+
+static void sl_debug(struct skiplist *l)
+{
+       int i;
+
+       if (!l)
+               return;
+
+       printf("Skiplist %p has max level %d\n", l, l->level);
+       for (i = l->level; i >= 0; --i)
+               printf("  @%d: %d\n", i, l->level_stats[i]);
+}
+
+static void *scramble(int i)
+{
+       uintptr_t result;
+
+       result = (uintptr_t)(i & 0xff) << 24;
+       result |= (uintptr_t)i >> 8;
+
+       return (void *)result;
+}
+#define sampleSize 65536
+static int sl_test(void)
+{
+       struct skiplist *l;
+       register int i, k;
+       void *keys[sampleSize];
+       void *v = NULL;
+       int errors = 0;
+
+       l = skiplist_new(SKIPLIST_FLAG_ALLOW_DUPLICATES, NULL, NULL);
+
+       printf("%s: skiplist_new returned %p\n", __func__, l);
+
+       for (i = 0; i < 4; i++) {
+
+               for (k = 0; k < sampleSize; k++) {
+                       if (!(k % 10000))
+                               printf("%s: (%d:%d)\n", __func__, i, k);
+                       /* keys[k] = (void *)random(); */
+                       keys[k] = scramble(k);
+                       if (skiplist_insert(l, keys[k], keys[k])) {
+                               ++errors;
+                               printf("error in insert #%d,#%d\n", i, k);
+                       }
+               }
+
+               printf("%s: inserts done\n", __func__);
+               sl_debug(l);
+
+               for (k = 0; k < sampleSize; k++) {
+
+                       if (!(k % 10000))
+                               printf("[%d:%d]\n", i, k);
+                       /* keys[k] = (void *)random(); */
+                       if (skiplist_search(l, keys[k], &v)) {
+                               ++errors;
+                               printf("error in search #%d,#%d\n", i, k);
+                       }
+
+                       if (v != keys[k]) {
+                               ++errors;
+                               printf("search returned wrong value\n");
+                       }
+               }
+               printf("%s: searches done\n", __func__);
+
+
+               for (k = 0; k < sampleSize; k++) {
+
+                       if (!(k % 10000))
+                               printf("<%d:%d>\n", i, k);
+                       /* keys[k] = (void *)random(); */
+                       if (skiplist_delete(l, keys[k], keys[k])) {
+                               ++errors;
+                               printf("error in delete\n");
+                       }
+                       keys[k] = scramble(k ^ 0xf0f0f0f0);
+                       if (skiplist_insert(l, keys[k], keys[k])) {
+                               ++errors;
+                               printf("error in insert #%d,#%d\n", i, k);
+                       }
+               }
+
+               printf("%s: del+inserts done\n", __func__);
+               sl_debug(l);
+
+               for (k = 0; k < sampleSize; k++) {
+
+                       if (!(k % 10000))
+                               printf("{%d:%d}\n", i, k);
+                       /* keys[k] = (void *)random(); */
+                       if (skiplist_delete_first(l)) {
+                               ++errors;
+                               printf("error in delete_first\n");
+                       }
+               }
+       }
+
+       sl_debug(l);
+
+       skiplist_free(l);
+
+       return errors;
+}
+
+int main(int argc, char **argv)
+{
+       int errors = sl_test();
+
+       if (errors)
+               return 1;
+       return 0;
+}
index 416ea39772796de470433d07da968f85467e45f7..0ae9761b117c87f461cb9d3514a087251a690d37 100644 (file)
@@ -134,7 +134,6 @@ int main(int argc, char **argv)
                /* Schedule timers to expire in 0..5 seconds */
                interval_msec = prng_rand(prng) % 5000;
                arg = XMALLOC(MTYPE_TMP, TIMESTR_LEN + 1);
-               timers[i] = NULL;
                thread_add_timer_msec(master, timer_func, arg, interval_msec,
                                      &timers[i]);
                ret = snprintf(arg, TIMESTR_LEN + 1, "%lld.%06lld",
index 45b29b92b1ec30204afc9351ee5c2a1610bde310..23c044c7c1a0de84f1066c5150f1d11dd669a9a4 100644 (file)
@@ -55,7 +55,6 @@ int main(int argc, char **argv)
        /* create thread structures so they won't be allocated during the
         * time measurement */
        for (i = 0; i < SCHEDULE_TIMERS; i++) {
-               timers[i] = NULL;
                thread_add_timer_msec(master, dummy_func, NULL, 0, &timers[i]);
        }
        for (i = 0; i < SCHEDULE_TIMERS; i++)
@@ -67,7 +66,6 @@ int main(int argc, char **argv)
                long interval_msec;
 
                interval_msec = prng_rand(prng) % (100 * SCHEDULE_TIMERS);
-               timers[i] = NULL;
                thread_add_timer_msec(master, dummy_func, NULL, interval_msec,
                                      &timers[i]);
        }
index b0be63c69545f88876a59cf79377e5e7476a9b4c..f21e12ecbb38aff48936b20ba7626839241edb05 100644 (file)
@@ -98,6 +98,7 @@ check_PROGRAMS = \
        tests/lib/test_segv \
        tests/lib/test_seqlock \
        tests/lib/test_sig \
+       tests/lib/test_skiplist \
        tests/lib/test_stream \
        tests/lib/test_table \
        tests/lib/test_timer_correctness \
@@ -183,7 +184,7 @@ TESTS_CXXFLAGS = \
 # note no -Werror
 
 ALL_TESTS_LDADD = lib/libfrr.la $(LIBCAP)
-BGP_TEST_LDADD = bgpd/libbgp.a $(RFPLDADD) $(ALL_TESTS_LDADD) $(LIBYANG_LIBS) -lm
+BGP_TEST_LDADD = bgpd/libbgp.a $(RFPLDADD) $(ALL_TESTS_LDADD) $(LIBYANG_LIBS) $(UST_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
@@ -366,6 +367,10 @@ tests_lib_test_sig_CFLAGS = $(TESTS_CFLAGS)
 tests_lib_test_sig_CPPFLAGS = $(TESTS_CPPFLAGS)
 tests_lib_test_sig_LDADD = $(ALL_TESTS_LDADD)
 tests_lib_test_sig_SOURCES = tests/lib/test_sig.c
+tests_lib_test_skiplist_CFLAGS = $(TESTS_CFLAGS)
+tests_lib_test_skiplist_CPPFLAGS = $(TESTS_CPPFLAGS)
+tests_lib_test_skiplist_LDADD = $(ALL_TESTS_LDADD)
+tests_lib_test_skiplist_SOURCES = tests/lib/test_skiplist.c
 tests_lib_test_srcdest_table_CFLAGS = $(TESTS_CFLAGS)
 tests_lib_test_srcdest_table_CPPFLAGS = $(TESTS_CPPFLAGS)
 tests_lib_test_srcdest_table_LDADD = $(ALL_TESTS_LDADD)
index b1203570a1c391e10d54d624982d8375717fe606..ddb7f4e16e219d1991187e24103362a8f7173cd9 100644 (file)
@@ -932,6 +932,9 @@ def test_bgp_summary():
                 # Remove Unknown Summary (all of it)
                 actual = re.sub(r"Unknown Summary \(VRF default\):", "", actual)
                 actual = re.sub(r"No Unknown neighbor is configured", "", actual)
+                # Make Connect/Active/Idle the same (change them all to Active)
+                actual = re.sub(r" Connect ", "  Active ", actual)
+                actual = re.sub(r"    Idle ", "  Active ", actual)
 
                 actual = re.sub(
                     r"IPv4 labeled-unicast Summary \(VRF default\):", "", actual
@@ -963,7 +966,7 @@ def test_bgp_summary():
                         r"(192.168.7.(1|2)0|fc00:0:0:8::2000).+Active.+", "", expected
                     )
                 elif "10.0.0.1" in arguments:
-                    expected = "No such neighbor in VRF default"
+                    expected = "No such neighbor in this view/vrf"
 
                 if "terse" in arguments:
                     expected = re.sub(r"BGP table version .+", "", expected)
@@ -1089,6 +1092,9 @@ def test_bgp_ipv6_summary():
             # Remove Unknown Summary (all of it)
             actual = re.sub(r"Unknown Summary \(VRF default\):", "", actual)
             actual = re.sub(r"No Unknown neighbor is configured", "", actual)
+            # Make Connect/Active/Idle the same (change them all to Active)
+            actual = re.sub(r" Connect ", "  Active ", actual)
+            actual = re.sub(r"    Idle ", "  Active ", actual)
 
             # Remove Labeled Unicast Summary (all of it)
             actual = re.sub(
index 18def599b4bf58f4c8cf94b386f7e858bffb400b..98da8c261920f3ec9c4a9729e6704174d2579f21 100644 (file)
@@ -6,10 +6,14 @@ hostname rt1
 password 1
 !
 interface eth-rt2
+ ipv6 ospf6 hello-interval 2
+ ipv6 ospf6 dead-interval 8
  ipv6 ospf6 network broadcast
  ipv6 ospf6 bfd
 !
 interface eth-rt3
+ ipv6 ospf6 hello-interval 2
+ ipv6 ospf6 dead-interval 8
  ipv6 ospf6 network broadcast
  ipv6 ospf6 bfd
 !
index 07b42f98859c906b8a3944bd354ba0727bb6d14f..9da876500535bd25d5d7ef03e677f42294805450 100644 (file)
@@ -10,13 +10,19 @@ debug ospf zebra
 !
 interface lo
  ip ospf area 0.0.0.0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 8
 !
 interface eth-rt2
  ip ospf area 0.0.0.0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 8
  ip ospf bfd
 !
 interface eth-rt3
  ip ospf area 0.0.0.0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 8
  ip ospf bfd
 !
 router ospf
index 2f35099564abe6420fda01e78dd09bf0e63d36e2..34b09020949a377e00c37685cc4270d9c4af55ab 100644 (file)
@@ -5,10 +5,14 @@ hostname rt2
 password 1
 !
 interface eth-rt1
+ ipv6 ospf6 hello-interval 2
+ ipv6 ospf6 dead-interval 8
  ipv6 ospf6 network broadcast
  ipv6 ospf6 bfd
 !
 interface eth-rt5
+ ipv6 ospf6 hello-interval 2
+ ipv6 ospf6 dead-interval 8
  ipv6 ospf6 network broadcast
 !
 router ospf6
index a05d8b58c8e7f0d5bf3ccb9084eccd1e24d845bd..11be6a14b23163eddc4fcada384da21313bedd12 100644 (file)
@@ -9,13 +9,19 @@ debug ospf zebra
 !
 interface lo
  ip ospf area 0.0.0.0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 8
 !
 interface eth-rt1
  ip ospf area 0.0.0.0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 8
  ip ospf bfd
 !
 interface eth-rt5
  ip ospf area 0.0.0.0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 8
 !
 router ospf
  ospf router-id 2.2.2.2
index 3e8777019efa4251994e3d6fd482ad890dea4159..8ab4eee1d3c4369a766df6c47bb02d9760fe5538 100644 (file)
@@ -5,10 +5,14 @@ hostname rt3
 password 1
 !
 interface eth-rt1
+ ipv6 ospf6 hello-interval 2
+ ipv6 ospf6 dead-interval 8
  ipv6 ospf6 network broadcast
  ipv6 ospf6 bfd
 !
 interface eth-rt4
+ ipv6 ospf6 hello-interval 2
+ ipv6 ospf6 dead-interval 8
  ipv6 ospf6 network broadcast
 !
 router ospf6
index 1196e6d1896290717a3726ac4f593b9a8ac84914..acc54b38665e136fe66136252e501ebf666bed93 100644 (file)
@@ -9,13 +9,19 @@ debug ospf zebra
 !
 interface lo
  ip ospf area 0.0.0.0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 8
 !
 interface eth-rt1
  ip ospf area 0.0.0.0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 8
  ip ospf bfd
 !
 interface eth-rt4
  ip ospf area 0.0.0.0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 8
 !
 router ospf
  ospf router-id 3.3.3.3
index bccd1e75bde88f2dc274af9b217f146e841a8eca..138b688140d9963345d60a41c7f97bd7e36e63a9 100644 (file)
@@ -5,9 +5,13 @@ hostname rt4
 password 1
 !
 interface eth-rt3
+ ipv6 ospf6 hello-interval 2
+ ipv6 ospf6 dead-interval 8
  ipv6 ospf6 network broadcast
 !
 interface eth-rt5
+ ipv6 ospf6 hello-interval 2
+ ipv6 ospf6 dead-interval 8
  ipv6 ospf6 network broadcast
 !
 router ospf6
index 3a2568b4ab52c47e0d45fb25290e6fe15122611b..670e56ccc8463327a6470a8cbcc9ce8e114306fe 100644 (file)
@@ -9,12 +9,18 @@ debug ospf zebra
 !
 interface lo
  ip ospf area 0.0.0.0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 8
 !
 interface eth-rt3
  ip ospf area 0.0.0.0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 8
 !
 interface eth-rt5
  ip ospf area 0.0.0.0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 8
 !
 router ospf
  ospf router-id 4.4.4.4
index 766862276c953b326c5ed68075f49caa22cb8b6c..6eb4fe59a8875ab200d5f7fb0625f8dabe7b25d4 100644 (file)
@@ -6,9 +6,13 @@ password 1
 !
 interface eth-rt2
  ipv6 ospf6 network broadcast
+ ipv6 ospf6 hello-interval 2
+ ipv6 ospf6 dead-interval 8
 !
 interface eth-rt4
  ipv6 ospf6 network broadcast
+ ipv6 ospf6 hello-interval 2
+ ipv6 ospf6 dead-interval 8
 !
 router ospf6
  ospf6 router-id 5.5.5.5
index a35de5f45fc09fb2f6a8cc3b2da8bf4affad430f..286de512889d135ec2da5222ef563d0708b825bd 100644 (file)
@@ -9,12 +9,18 @@ debug ospf zebra
 !
 interface lo
  ip ospf area 0.0.0.0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 8
 !
 interface eth-rt2
  ip ospf area 0.0.0.0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 8
 !
 interface eth-rt4
  ip ospf area 0.0.0.0
+ ip ospf hello-interval 2
+ ip ospf dead-interval 8
 !
 router ospf
  ospf router-id 5.5.5.5
index 09b86317404a4c38385390b382a464d3dd1c5e5e..bef2c3f162bb35942655d33fb0d991f7925b40ed 100755 (executable)
@@ -132,7 +132,7 @@ def print_cmd_result(rname, command):
     print(get_topogen().gears[rname].vtysh_cmd(command, isjson=False))
 
 
-def router_compare_json_output(rname, command, reference, count=120, wait=0.5):
+def router_compare_json_output(rname, command, reference, count=40, wait=2):
     "Compare router JSON output"
 
     logger.info('Comparing router "%s" "%s" output', rname, command)
@@ -141,7 +141,7 @@ def router_compare_json_output(rname, command, reference, count=120, wait=0.5):
     filename = "{}/{}/{}".format(CWD, rname, reference)
     expected = json.loads(open(filename).read())
 
-    # Run test function until we get an result. Wait at most 60 seconds.
+    # Run test function until we get an result. Wait at most 80 seconds.
     test_func = partial(topotest.router_json_cmp, tgen.gears[rname], command, expected)
     _, diff = topotest.run_and_expect(test_func, None, count=count, wait=wait)
     assertmsg = '"{}" JSON output mismatches the expected result'.format(rname)
@@ -195,8 +195,8 @@ def test_bfd_ospf_interface_failure_rt2_step3():
 
     # By default BFD provides a recovery time of 900ms plus jitter, so let's wait
     # initial 2 seconds to let the CI not suffer.
-    # TODO: add check for array size
-    sleep(2)
+    topotest.sleep(2, 'Wait for BFD down notification')
+
     router_compare_json_output(
         "rt1", "show ip route ospf json", "step3/show_ip_route_rt2_down.ref", 1, 0
     )
@@ -234,8 +234,7 @@ def test_bfd_ospf_interface_failure_rt3_step3():
 
     # By default BFD provides a recovery time of 900ms plus jitter, so let's wait
     # initial 2 seconds to let the CI not suffer.
-    # TODO: add check for array size
-    sleep(2)
+    topotest.sleep(2, 'Wait for BFD down notification')
     router_compare_json_output(
         "rt1", "show ip route ospf json", "step3/show_ip_route_rt3_down.ref", 1, 0
     )
index 27451ec7b37d0e953f62c8017b2d016c48b58a2f..c890b0d7dcf9ca6681d0509a9cabbd45397df01c 100644 (file)
@@ -92,7 +92,13 @@ 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": [{"aspath": {"string": "65000 65000 65000 65000"}, "metric": 123}]
+            "paths": [
+                {
+                    "aspath": {"string": "65000 65000 65000 65000"},
+                    "metric": 123,
+                    "community": None,
+                }
+            ]
         }
         return topotest.json_cmp(output, expected)
 
index 9135545c581ad633c73241b98f71209a4b834f1a..b9f80f112d2bdbcc8349a08585e1917e54bd2693 100644 (file)
@@ -1,4 +1,4 @@
 !
-int host1-eth0
+int host2-eth0
  ip address 50.0.1.21/24
  ipv6 address 50:0:1::21/48
index 8fd344696e46e24aad0652aa52e1dbf3f5e6cc30..fce8e708f2fa828d620076315c8c145b10080369 100644 (file)
@@ -206,7 +206,7 @@ def ltemplatePreRouterStartHook():
         for cmd in cmds:
             cc.doCmd(tgen, rtr, cmd.format(rtr))
         cc.doCmd(tgen, rtr, "ip link set dev {0}-eth0 master {0}-cust2".format(rtr))
-    if cc.getOutput() != 4:
+    if cc.getOutput() != 0:
         InitSuccess = False
         logger.info(
             "Unexpected output seen ({} times, tests will be skipped".format(
@@ -214,6 +214,11 @@ def ltemplatePreRouterStartHook():
             )
         )
     else:
+        rtrs = ["r1", "r3", "r4", "ce4"]
+        for rtr in rtrs:
+            logger.info("{} configured".format(rtr))
+            cc.doCmd(tgen, rtr, "ip -d link show type vrf")
+            cc.doCmd(tgen, rtr, "ip link show")
         InitSuccess = True
         logger.info("VRF config successful!")
     return InitSuccess
index ad1b15a26c2b060bc2ecc38a08857c85cc11d774..381917957035c5b84327f80db920d5727f78e4e4 100644 (file)
@@ -15,14 +15,14 @@ group controller {
                 next-hop 2001::2;
                 extended-community [ target:2:10 ];
                 label 3;
-                attribute [0x28 0xc0 0x0500150020010db800010001000000000000000100ffff00 ];
+                attribute [0x28 0xc0 0x050019000100150020010db800010001000000000000000100ffff00 ];
             }
             route 2001:2::/64 {
                 rd 2:10;
                 next-hop 2001::2;
                 extended-community [ target:2:10 ];
                 label 3;
-                attribute [0x28 0xc0 0x0500150020010db800010001000000000000000100ffff00 ];
+                attribute [0x28 0xc0 0x050019000100150020010db800010001000000000000000100ffff00 ];
             }
         }
     }
index 3e6e417211b5eb8fe4a40fb755182337be36ba89..0d27474cbd1f651fd925565a50ef4ff1a71fda11 100755 (executable)
@@ -151,13 +151,6 @@ def setup_module(mod):
     r1.run("sysctl -w net.mpls.conf.r1-eth0.input=1")
     r1.run("sysctl -w net.mpls.conf.r1-eth1.input=1")
     r1.run("sysctl -w net.mpls.conf.r1-eth2.input=1")
-    r2.run("sysctl -w net.mpls.conf.r1-eth0.input=1")
-    r2.run("sysctl -w net.mpls.conf.r1-eth1.input=1")
-    r3.run("sysctl -w net.mpls.conf.r1-eth0.input=1")
-    r3.run("sysctl -w net.mpls.conf.r1-eth1.input=1")
-    r3.run("sysctl -w net.mpls.conf.r1-eth2.input=1")
-    r4.run("sysctl -w net.mpls.conf.r1-eth0.input=1")
-    r4.run("sysctl -w net.mpls.conf.r1-eth1.input=1")
 
     router_list = tgen.routers()
 
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/vpnv6_rib_locator_deleted.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/vpnv6_rib_locator_deleted.json
new file mode 100644 (file)
index 0000000..f2df9be
--- /dev/null
@@ -0,0 +1,160 @@
+{
+  "vrfId": 0,
+  "vrfName": "default",
+  "routerId": "1.1.1.1",
+  "defaultLocPrf": 100,
+  "localAS": 1,
+  "routes": {
+    "routeDistinguishers": {
+      "1:10": {
+        "2001:1::/64": [
+          {
+            "pathFrom": "external",
+            "prefix": "2001:1::",
+            "prefixLen": 64,
+            "network": "2001:1::/64",
+            "metric": 0,
+            "weight": 32768,
+            "peerId": "(unspec)",
+            "path": "",
+            "origin": "incomplete",
+            "announceNexthopSelf": true,
+            "nhVrfName": "vrf10",
+            "nexthops": [
+              {
+                "ip": "::",
+                "hostname": "r1",
+                "afi": "ipv6",
+                "used": true
+              }
+            ]
+          }
+        ],
+        "2001:3::/64": [
+          {
+            "pathFrom": "external",
+            "prefix": "2001:3::",
+            "prefixLen": 64,
+            "network": "2001:3::/64",
+            "metric": 0,
+            "weight": 32768,
+            "peerId": "(unspec)",
+            "path": "",
+            "origin": "incomplete",
+            "announceNexthopSelf": true,
+            "nhVrfName": "vrf10",
+            "nexthops": [
+              {
+                "ip": "::",
+                "hostname": "r1",
+                "afi": "ipv6",
+                "used": true
+              }
+            ]
+          }
+        ]
+      },
+      "1:20": {
+        "2001:5::/64": [
+          {
+            "pathFrom": "external",
+            "prefix": "2001:5::",
+            "prefixLen": 64,
+            "network": "2001:5::/64",
+            "metric": 0,
+            "weight": 32768,
+            "peerId": "(unspec)",
+            "path": "",
+            "origin": "incomplete",
+            "announceNexthopSelf": true,
+            "nhVrfName": "vrf20",
+            "nexthops": [
+              {
+                "ip": "::",
+                "hostname": "r1",
+                "afi": "ipv6",
+                "used": true
+              }
+            ]
+          }
+        ]
+      },
+      "2:10": {
+        "2001:2::/64": [
+          {
+            "valid": true,
+            "bestpath": true,
+            "selectionReason": "First path received",
+            "pathFrom": "external",
+            "prefix": "2001:2::",
+            "prefixLen": 64,
+            "network": "2001:2::/64",
+            "metric": 0,
+            "weight": 0,
+            "peerId": "2001::2",
+            "path": "2",
+            "origin": "incomplete",
+            "nexthops": [
+              {
+                "ip": "2001::2",
+                "hostname": "r2",
+                "afi": "ipv6",
+                "used": true
+              }
+            ]
+          }
+        ]
+      },
+      "2:20": {
+        "2001:4::/64": [
+          {
+            "valid": true,
+            "bestpath": true,
+            "selectionReason": "First path received",
+            "pathFrom": "external",
+            "prefix": "2001:4::",
+            "prefixLen": 64,
+            "network": "2001:4::/64",
+            "metric": 0,
+            "weight": 0,
+            "peerId": "2001::2",
+            "path": "2",
+            "origin": "incomplete",
+            "nexthops": [
+              {
+                "ip": "2001::2",
+                "hostname": "r2",
+                "afi": "ipv6",
+                "used": true
+              }
+            ]
+          }
+        ],
+        "2001:6::/64": [
+          {
+            "valid": true,
+            "bestpath": true,
+            "selectionReason": "First path received",
+            "pathFrom": "external",
+            "prefix": "2001:6::",
+            "prefixLen": 64,
+            "network": "2001:6::/64",
+            "metric": 0,
+            "weight": 0,
+            "peerId": "2001::2",
+            "path": "2",
+            "origin": "incomplete",
+            "nexthops": [
+              {
+                "ip": "2001::2",
+                "hostname": "r2",
+                "afi": "ipv6",
+                "used": true
+              }
+            ]
+          }
+        ]
+      }
+    }
+  }
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/vpnv6_rib_locator_recreated.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/vpnv6_rib_locator_recreated.json
new file mode 100644 (file)
index 0000000..0fdd3d6
--- /dev/null
@@ -0,0 +1,169 @@
+{
+  "vrfId": 0,
+  "vrfName": "default",
+  "routerId": "1.1.1.1",
+  "defaultLocPrf": 100,
+  "localAS": 1,
+  "routes": {
+    "routeDistinguishers": {
+      "1:10": {
+        "2001:1::/64": [
+          {
+            "valid": true,
+            "bestpath": true,
+            "selectionReason": "First path received",
+            "pathFrom": "external",
+            "prefix": "2001:1::",
+            "prefixLen": 64,
+            "network": "2001:1::/64",
+            "metric": 0,
+            "weight": 32768,
+            "peerId": "(unspec)",
+            "path": "",
+            "origin": "incomplete",
+            "announceNexthopSelf": true,
+            "nhVrfName": "vrf10",
+            "nexthops": [
+              {
+                "ip": "::",
+                "hostname": "r1",
+                "afi": "ipv6",
+                "used": true
+              }
+            ]
+          }
+        ],
+        "2001:3::/64": [
+          {
+            "valid": true,
+            "bestpath": true,
+            "selectionReason": "First path received",
+            "pathFrom": "external",
+            "prefix": "2001:3::",
+            "prefixLen": 64,
+            "network": "2001:3::/64",
+            "metric": 0,
+            "weight": 32768,
+            "peerId": "(unspec)",
+            "path": "",
+            "origin": "incomplete",
+            "announceNexthopSelf": true,
+            "nhVrfName": "vrf10",
+            "nexthops": [
+              {
+                "ip": "::",
+                "hostname": "r1",
+                "afi": "ipv6",
+                "used": true
+              }
+            ]
+          }
+        ]
+      },
+      "1:20": {
+        "2001:5::/64": [
+          {
+            "valid": true,
+            "bestpath": true,
+            "selectionReason": "First path received",
+            "pathFrom": "external",
+            "prefix": "2001:5::",
+            "prefixLen": 64,
+            "network": "2001:5::/64",
+            "metric": 0,
+            "weight": 32768,
+            "peerId": "(unspec)",
+            "path": "",
+            "origin": "incomplete",
+            "announceNexthopSelf": true,
+            "nhVrfName": "vrf20",
+            "nexthops": [
+              {
+                "ip": "::",
+                "hostname": "r1",
+                "afi": "ipv6",
+                "used": true
+              }
+            ]
+          }
+        ]
+      },
+      "2:10": {
+        "2001:2::/64": [
+          {
+            "valid": true,
+            "bestpath": true,
+            "selectionReason": "First path received",
+            "pathFrom": "external",
+            "prefix": "2001:2::",
+            "prefixLen": 64,
+            "network": "2001:2::/64",
+            "metric": 0,
+            "weight": 0,
+            "peerId": "2001::2",
+            "path": "2",
+            "origin": "incomplete",
+            "nexthops": [
+              {
+                "ip": "2001::2",
+                "hostname": "r2",
+                "afi": "ipv6",
+                "used": true
+              }
+            ]
+          }
+        ]
+      },
+      "2:20": {
+        "2001:4::/64": [
+          {
+            "valid": true,
+            "bestpath": true,
+            "selectionReason": "First path received",
+            "pathFrom": "external",
+            "prefix": "2001:4::",
+            "prefixLen": 64,
+            "network": "2001:4::/64",
+            "metric": 0,
+            "weight": 0,
+            "peerId": "2001::2",
+            "path": "2",
+            "origin": "incomplete",
+            "nexthops": [
+              {
+                "ip": "2001::2",
+                "hostname": "r2",
+                "afi": "ipv6",
+                "used": true
+              }
+            ]
+          }
+        ],
+        "2001:6::/64": [
+          {
+            "valid": true,
+            "bestpath": true,
+            "selectionReason": "First path received",
+            "pathFrom": "external",
+            "prefix": "2001:6::",
+            "prefixLen": 64,
+            "network": "2001:6::/64",
+            "metric": 0,
+            "weight": 0,
+            "peerId": "2001::2",
+            "path": "2",
+            "origin": "incomplete",
+            "nexthops": [
+              {
+                "ip": "2001::2",
+                "hostname": "r2",
+                "afi": "ipv6",
+                "used": true
+              }
+            ]
+          }
+        ]
+      }
+    }
+  }
+}
index fa05972a35cb903de35385b6e8ec2142589306a4..141c1cb957a0c6d00727777c9f152f0e4769abb4 100644 (file)
           "interfaceName": "eth0",
           "vrf": "default",
           "active": true,
-          "labels": [
-            3
-          ],
           "weight": 1,
           "seg6": {
-            "segs": "2001:db8:2:2::100"
+            "segs": "2001:db8:2:2:100::"
           }
         }
       ],
index 0155557242c6a8c616c39a9209db45a67c7eaeae..e20998061ff4cf182354e12119355d485c5af7e0 100644 (file)
           "interfaceName": "eth0",
           "vrf": "default",
           "active": true,
-          "labels": [
-            3
-          ],
           "weight": 1,
           "seg6": {
-            "segs": "2001:db8:2:2::200"
+            "segs": "2001:db8:2:2:200::"
           }
         }
       ],
           "interfaceName": "eth0",
           "vrf": "default",
           "active": true,
-          "labels": [
-            3
-          ],
           "weight": 1,
           "seg6": {
-            "segs": "2001:db8:2:2::200"
+            "segs": "2001:db8:2:2:200::"
           }
         }
       ],
index ec36870369ac9b8e41a0a3331db3db5ebaa8de9e..68b5730a63c077b2d588c80734d2f153c7a92d3b 100644 (file)
@@ -34,7 +34,9 @@ segment-routing
 ip forwarding
 ipv6 forwarding
 !
+ipv6 route 2001:db8:2:1::/64 2001::2
 ipv6 route 2001:db8:2:2::/64 2001::2
+ipv6 route 2001:db8:2:3::/64 2001::2
 !
 line vty
 !
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/vpnv6_rib_locator_deleted.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/vpnv6_rib_locator_deleted.json
new file mode 100644 (file)
index 0000000..25cdf03
--- /dev/null
@@ -0,0 +1,93 @@
+{
+  "vrfId": 0,
+  "vrfName": "default",
+  "routerId": "2.2.2.2",
+  "defaultLocPrf": 100,
+  "localAS": 2,
+  "routes": {
+    "routeDistinguishers": {
+      "2:10": {
+        "2001:2::/64": [
+          {
+            "valid": true,
+            "bestpath": true,
+            "selectionReason": "First path received",
+            "pathFrom": "external",
+            "prefix": "2001:2::",
+            "prefixLen": 64,
+            "network": "2001:2::/64",
+            "metric": 0,
+            "weight": 32768,
+            "peerId": "(unspec)",
+            "path": "",
+            "origin": "incomplete",
+            "announceNexthopSelf": true,
+            "nhVrfName": "vrf10",
+            "nexthops": [
+              {
+                "ip": "::",
+                "hostname": "r2",
+                "afi": "ipv6",
+                "used": true
+              }
+            ]
+          }
+        ]
+      },
+      "2:20": {
+        "2001:4::/64": [
+          {
+            "valid": true,
+            "bestpath": true,
+            "selectionReason": "First path received",
+            "pathFrom": "external",
+            "prefix": "2001:4::",
+            "prefixLen": 64,
+            "network": "2001:4::/64",
+            "metric": 0,
+            "weight": 32768,
+            "peerId": "(unspec)",
+            "path": "",
+            "origin": "incomplete",
+            "announceNexthopSelf": true,
+            "nhVrfName": "vrf20",
+            "nexthops": [
+              {
+                "ip": "::",
+                "hostname": "r2",
+                "afi": "ipv6",
+                "used": true
+              }
+            ]
+          }
+        ],
+        "2001:6::/64": [
+          {
+            "valid": true,
+            "bestpath": true,
+            "selectionReason": "First path received",
+            "pathFrom": "external",
+            "prefix": "2001:6::",
+            "prefixLen": 64,
+            "network": "2001:6::/64",
+            "metric": 0,
+            "weight": 32768,
+            "peerId": "(unspec)",
+            "path": "",
+            "origin": "incomplete",
+            "announceNexthopSelf": true,
+            "nhVrfName": "vrf20",
+            "nexthops": [
+              {
+                "ip": "::",
+                "hostname": "r2",
+                "afi": "ipv6",
+                "used": true
+              }
+            ]
+          }
+        ]
+      }
+    }
+  }
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/vpnv6_rib_locator_recreated.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/vpnv6_rib_locator_recreated.json
new file mode 100644 (file)
index 0000000..03bbcc0
--- /dev/null
@@ -0,0 +1,169 @@
+{
+  "vrfId": 0,
+  "vrfName": "default",
+  "routerId": "2.2.2.2",
+  "defaultLocPrf": 100,
+  "localAS": 2,
+  "routes": {
+    "routeDistinguishers": {
+      "1:10": {
+        "2001:1::/64": [
+          {
+            "valid": true,
+            "bestpath": true,
+            "selectionReason": "First path received",
+            "pathFrom": "external",
+            "prefix": "2001:1::",
+            "prefixLen": 64,
+            "network": "2001:1::/64",
+            "metric": 0,
+            "weight": 0,
+            "peerId": "2001::1",
+            "path": "1",
+            "origin": "incomplete",
+            "nexthops": [
+              {
+                "ip": "2001::1",
+                "hostname": "r1",
+                "afi": "ipv6",
+                "used": true
+              }
+            ]
+          }
+        ],
+        "2001:3::/64": [
+          {
+            "valid": true,
+            "bestpath": true,
+            "selectionReason": "First path received",
+            "pathFrom": "external",
+            "prefix": "2001:3::",
+            "prefixLen": 64,
+            "network": "2001:3::/64",
+            "metric": 0,
+            "weight": 0,
+            "peerId": "2001::1",
+            "path": "1",
+            "origin": "incomplete",
+            "nexthops": [
+              {
+                "ip": "2001::1",
+                "hostname": "r1",
+                "afi": "ipv6",
+                "used": true
+              }
+            ]
+          }
+        ]
+      },
+      "1:20": {
+        "2001:5::/64": [
+          {
+            "valid": true,
+            "bestpath": true,
+            "selectionReason": "First path received",
+            "pathFrom": "external",
+            "prefix": "2001:5::",
+            "prefixLen": 64,
+            "network": "2001:5::/64",
+            "metric": 0,
+            "weight": 0,
+            "peerId": "2001::1",
+            "path": "1",
+            "origin": "incomplete",
+            "nexthops": [
+              {
+                "ip": "2001::1",
+                "hostname": "r1",
+                "afi": "ipv6",
+                "used": true
+              }
+            ]
+          }
+        ]
+      },
+      "2:10": {
+        "2001:2::/64": [
+          {
+            "valid": true,
+            "bestpath": true,
+            "selectionReason": "First path received",
+            "pathFrom": "external",
+            "prefix": "2001:2::",
+            "prefixLen": 64,
+            "network": "2001:2::/64",
+            "metric": 0,
+            "weight": 32768,
+            "peerId": "(unspec)",
+            "path": "",
+            "origin": "incomplete",
+            "announceNexthopSelf": true,
+            "nhVrfName": "vrf10",
+            "nexthops": [
+              {
+                "ip": "::",
+                "hostname": "r2",
+                "afi": "ipv6",
+                "used": true
+              }
+            ]
+          }
+        ]
+      },
+      "2:20": {
+        "2001:4::/64": [
+          {
+            "valid": true,
+            "bestpath": true,
+            "selectionReason": "First path received",
+            "pathFrom": "external",
+            "prefix": "2001:4::",
+            "prefixLen": 64,
+            "network": "2001:4::/64",
+            "metric": 0,
+            "weight": 32768,
+            "peerId": "(unspec)",
+            "path": "",
+            "origin": "incomplete",
+            "announceNexthopSelf": true,
+            "nhVrfName": "vrf20",
+            "nexthops": [
+              {
+                "ip": "::",
+                "hostname": "r2",
+                "afi": "ipv6",
+                "used": true
+              }
+            ]
+          }
+        ],
+        "2001:6::/64": [
+          {
+            "valid": true,
+            "bestpath": true,
+            "selectionReason": "First path received",
+            "pathFrom": "external",
+            "prefix": "2001:6::",
+            "prefixLen": 64,
+            "network": "2001:6::/64",
+            "metric": 0,
+            "weight": 32768,
+            "peerId": "(unspec)",
+            "path": "",
+            "origin": "incomplete",
+            "announceNexthopSelf": true,
+            "nhVrfName": "vrf20",
+            "nexthops": [
+              {
+                "ip": "::",
+                "hostname": "r2",
+                "afi": "ipv6",
+                "used": true
+              }
+            ]
+          }
+        ]
+      }
+    }
+  }
+}
index 887eb2438602009eaba48d126f253ef4cb234c3f..7f8a930d002e140f1d2a2f1d8e1583317b36a792 100644 (file)
           "interfaceName": "eth0",
           "vrf": "default",
           "active": true,
-          "labels": [
-            3
-          ],
           "weight": 1,
           "seg6": {
-            "segs": "2001:db8:1:1::100"
+            "segs": "2001:db8:1:1:100::"
           }
         }
       ],
           "interfaceName": "eth0",
           "vrf": "default",
           "active": true,
-          "labels": [
-            3
-          ],
           "weight": 1,
           "seg6": {
-            "segs": "2001:db8:1:1::100"
+            "segs": "2001:db8:1:1:100::"
           }
         }
       ],
index c1185184238f41fea0a441e56555f19bd26885a9..104bdc30d2b710ef13937582c7d006bb780b90f5 100644 (file)
           "interfaceName": "eth0",
           "vrf": "default",
           "active": true,
-          "labels": [
-            3
-          ],
           "weight": 1,
           "seg6": {
-            "segs": "2001:db8:1:1::200"
+            "segs": "2001:db8:1:1:200::"
           }
         }
       ],
index f3e025d23aac5b102b9a287b519d4ca4f1959b67..91fd92d422f04ed8c65ce3f70b5bc2d6a7070c53 100644 (file)
@@ -35,6 +35,8 @@ ip forwarding
 ipv6 forwarding
 !
 ipv6 route 2001:db8:1:1::/64 2001::1
+ipv6 route 2001:db8:1:2::/64 2001::1
+ipv6 route 2001:db8:1:3::/64 2001::1
 !
 line vty
 !
index 2d544c1ccfdbb16efb2a2295aaf2105f64d8c11f..e0cf8c88e6a580a29fc8fd0514a27769fc82d42b 100755 (executable)
@@ -129,6 +129,10 @@ def setup_module(mod):
     tgen.gears["r2"].run("ip link set eth3 master vrf20")
     tgen.start_router()
 
+    # FOR DEVELOPER:
+    # If you want to stop some specific line and start interactive shell,
+    # please use tgen.mininet_cli() to start it.
+
 
 def teardown_module(mod):
     tgen = get_topogen()
@@ -143,7 +147,22 @@ def open_json_file(filename):
         assert False, "Could not read file {}".format(filename)
 
 
-def test_rib():
+def check_ping(name, dest_addr, expect_connected):
+    def _check(name, dest_addr, match):
+        tgen = get_topogen()
+        output = tgen.gears[name].run("ping6 {} -c 1 -w 1".format(dest_addr))
+        logger.info(output)
+        assert match in output, "ping fail"
+
+    match = "{} packet loss".format("0%" if expect_connected else "100%")
+    logger.info("[+] check {} {} {}".format(name, dest_addr, match))
+    tgen = get_topogen()
+    func = functools.partial(_check, name, dest_addr, match)
+    success, result = topotest.run_and_expect(func, None, count=10, wait=0.5)
+    assert result is None, "Failed"
+
+
+def check_rib(name, cmd, expected_file):
     def _check(name, cmd, expected_file):
         logger.info("polling")
         tgen = get_topogen()
@@ -152,51 +171,131 @@ def test_rib():
         expected = open_json_file("{}/{}".format(CWD, expected_file))
         return topotest.json_cmp(output, expected)
 
-    def check(name, cmd, expected_file):
-        logger.info('[+] check {} "{}" {}'.format(name, cmd, expected_file))
-        tgen = get_topogen()
-        func = functools.partial(_check, name, cmd, expected_file)
-        success, result = topotest.run_and_expect(func, None, count=10, wait=0.5)
-        assert result is None, "Failed"
-
-    check("r1", "show bgp ipv6 vpn json", "r1/vpnv6_rib.json")
-    check("r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib.json")
-    check("r1", "show ipv6 route vrf vrf10 json", "r1/vrf10_rib.json")
-    check("r1", "show ipv6 route vrf vrf20 json", "r1/vrf20_rib.json")
-    check("r2", "show ipv6 route vrf vrf10 json", "r2/vrf10_rib.json")
-    check("r2", "show ipv6 route vrf vrf20 json", "r2/vrf20_rib.json")
-    check("ce1", "show ipv6 route json", "ce1/ipv6_rib.json")
-    check("ce2", "show ipv6 route json", "ce2/ipv6_rib.json")
-    check("ce3", "show ipv6 route json", "ce3/ipv6_rib.json")
-    check("ce4", "show ipv6 route json", "ce4/ipv6_rib.json")
-    check("ce5", "show ipv6 route json", "ce5/ipv6_rib.json")
-    check("ce6", "show ipv6 route json", "ce6/ipv6_rib.json")
+    logger.info("[+] check {} \"{}\" {}".format(name, cmd, expected_file))
+    tgen = get_topogen()
+    func = functools.partial(_check, name, cmd, expected_file)
+    success, result = topotest.run_and_expect(func, None, count=10, wait=0.5)
+    assert result is None, "Failed"
+
+
+def test_rib():
+    check_rib("r1", "show bgp ipv6 vpn json", "r1/vpnv6_rib.json")
+    check_rib("r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib.json")
+    check_rib("r1", "show ipv6 route vrf vrf10 json", "r1/vrf10_rib.json")
+    check_rib("r1", "show ipv6 route vrf vrf20 json", "r1/vrf20_rib.json")
+    check_rib("r2", "show ipv6 route vrf vrf10 json", "r2/vrf10_rib.json")
+    check_rib("r2", "show ipv6 route vrf vrf20 json", "r2/vrf20_rib.json")
+    check_rib("ce1", "show ipv6 route json", "ce1/ipv6_rib.json")
+    check_rib("ce2", "show ipv6 route json", "ce2/ipv6_rib.json")
+    check_rib("ce3", "show ipv6 route json", "ce3/ipv6_rib.json")
+    check_rib("ce4", "show ipv6 route json", "ce4/ipv6_rib.json")
+    check_rib("ce5", "show ipv6 route json", "ce5/ipv6_rib.json")
+    check_rib("ce6", "show ipv6 route json", "ce6/ipv6_rib.json")
 
 
 def test_ping():
-    def _check(name, dest_addr, match):
-        tgen = get_topogen()
-        output = tgen.gears[name].run("ping6 {} -c 1 -w 1".format(dest_addr))
-        logger.info(output)
-        assert match in output, "ping fail"
+    check_ping("ce1", "2001:2::2", True)
+    check_ping("ce1", "2001:3::2", True)
+    check_ping("ce1", "2001:4::2", False)
+    check_ping("ce1", "2001:5::2", False)
+    check_ping("ce1", "2001:6::2", False)
+    check_ping("ce4", "2001:1::2", False)
+    check_ping("ce4", "2001:2::2", False)
+    check_ping("ce4", "2001:3::2", False)
+    check_ping("ce4", "2001:5::2", True)
+    check_ping("ce4", "2001:6::2", True)
 
-    def check(name, dest_addr, match):
-        logger.info("[+] check {} {} {}".format(name, dest_addr, match))
-        tgen = get_topogen()
-        func = functools.partial(_check, name, dest_addr, match)
-        success, result = topotest.run_and_expect(func, None, count=10, wait=0.5)
-        assert result is None, "Failed"
-
-    check("ce1", "2001:2::2", " 0% packet loss")
-    check("ce1", "2001:3::2", " 0% packet loss")
-    check("ce1", "2001:4::2", " 100% packet loss")
-    check("ce1", "2001:5::2", " 100% packet loss")
-    check("ce1", "2001:6::2", " 100% packet loss")
-    check("ce4", "2001:1::2", " 100% packet loss")
-    check("ce4", "2001:2::2", " 100% packet loss")
-    check("ce4", "2001:3::2", " 100% packet loss")
-    check("ce4", "2001:5::2", " 0% packet loss")
-    check("ce4", "2001:6::2", " 0% packet loss")
+
+def test_locator_delete():
+    check_ping("ce1", "2001:2::2", True)
+    get_topogen().gears["r1"].vtysh_cmd(
+        """
+        configure terminal
+         segment-routing
+          srv6
+           locators
+            no locator loc1
+        """
+    )
+    check_rib("r1", "show bgp ipv6 vpn json", "r1/vpnv6_rib_locator_deleted.json")
+    check_rib("r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib_locator_deleted.json")
+    check_ping("ce1", "2001:2::2", False)
+
+
+def test_locator_recreate():
+    check_ping("ce1", "2001:2::2", False)
+    get_topogen().gears["r1"].vtysh_cmd(
+        """
+        configure terminal
+         segment-routing
+          srv6
+           locators
+            locator loc1
+             prefix 2001:db8:1:1::/64
+        """
+    )
+    check_rib("r1", "show bgp ipv6 vpn json", "r1/vpnv6_rib_locator_recreated.json")
+    check_rib("r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib_locator_recreated.json")
+    check_ping("ce1", "2001:2::2", True)
+
+
+def test_bgp_locator_unset():
+    check_ping("ce1", "2001:2::2", True)
+    get_topogen().gears["r1"].vtysh_cmd(
+        """
+        configure terminal
+         router bgp 1
+          segment-routing srv6
+           no locator loc1
+        """
+    )
+    check_rib("r1", "show bgp ipv6 vpn json", "r1/vpnv6_rib_locator_deleted.json")
+    check_rib("r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib_locator_deleted.json")
+    check_ping("ce1", "2001:2::2", False)
+
+
+def test_bgp_locator_reset():
+    check_ping("ce1", "2001:2::2", False)
+    get_topogen().gears["r1"].vtysh_cmd(
+        """
+        configure terminal
+         router bgp 1
+          segment-routing srv6
+           locator loc1
+        """
+    )
+    check_rib("r1", "show bgp ipv6 vpn json", "r1/vpnv6_rib_locator_recreated.json")
+    check_rib("r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib_locator_recreated.json")
+    check_ping("ce1", "2001:2::2", True)
+
+
+def test_bgp_srv6_unset():
+    check_ping("ce1", "2001:2::2", True)
+    get_topogen().gears["r1"].vtysh_cmd(
+        """
+        configure terminal
+         router bgp 1
+          no segment-routing srv6
+        """
+    )
+    check_rib("r1", "show bgp ipv6 vpn json", "r1/vpnv6_rib_locator_deleted.json")
+    check_rib("r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib_locator_deleted.json")
+    check_ping("ce1", "2001:2::2", False)
+
+
+def test_bgp_srv6_reset():
+    check_ping("ce1", "2001:2::2", False)
+    get_topogen().gears["r1"].vtysh_cmd(
+        """
+        configure terminal
+         router bgp 1
+          segment-routing srv6
+           locator loc1
+        """
+    )
+    check_rib("r1", "show bgp ipv6 vpn json", "r1/vpnv6_rib_locator_recreated.json")
+    check_rib("r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib_locator_recreated.json")
+    check_ping("ce1", "2001:2::2", True)
 
 
 if __name__ == "__main__":
diff --git a/tests/topotests/example_test/r1/zebra.conf b/tests/topotests/example_test/r1/zebra.conf
new file mode 100644 (file)
index 0000000..b733b7b
--- /dev/null
@@ -0,0 +1,8 @@
+interface r1-eth0
+  ip address 192.168.1.1/24
+
+interface r1-eth1
+  ip address 192.168.2.1/24
+
+interface r1-eth2
+  ip address 192.168.3.1/24
\ No newline at end of file
diff --git a/tests/topotests/example_test/r2/zebra.conf b/tests/topotests/example_test/r2/zebra.conf
new file mode 100644 (file)
index 0000000..c0921f5
--- /dev/null
@@ -0,0 +1,4 @@
+interface r2-eth0
+  ip address 192.168.1.2/24
+interface r2-eth1
+  ip address 192.168.3.2/24
index e94bb905a50dfeac71654bd28d3123ecf794b44d..4c073f259ca17a84e3a0687320f646987fdc6d22 100644 (file)
@@ -1,5 +1,5 @@
 #!/usr/bin/env python
-
+# -*- coding: utf-8 eval: (blacken-mode 1) -*-
 #
 # <template>.py
 # Part of NetDEF Topology Tests
 import sys
 import pytest
 
-# Import topogen and topotest helpers
-from lib.topogen import Topogen, TopoRouter, get_topogen
-
+from lib.topogen import Topogen, TopoRouter
+from lib.topolog import logger
 
 # TODO: select markers based on daemons used during test
 # pytest module level markers
-"""
-pytestmark = pytest.mark.bfdd # single marker
 pytestmark = [
-       pytest.mark.bgpd,
-       pytest.mark.ospfd,
-       pytest.mark.ospf6d
-] # multiple markers
-"""
-
-
+    # pytest.mark.babeld,
+    # pytest.mark.bfdd,
+    # pytest.mark.bgpd,
+    # pytest.mark.eigrpd,
+    # pytest.mark.isisd,
+    # pytest.mark.ldpd,
+    # pytest.mark.nhrpd,
+    # pytest.mark.ospf6d,
+    pytest.mark.ospfd,
+    # pytest.mark.pathd,
+    # pytest.mark.pbrd,
+    # pytest.mark.pimd,
+    # pytest.mark.ripd,
+    # pytest.mark.ripngd,
+    # pytest.mark.sharpd,
+    # pytest.mark.staticd,
+    # pytest.mark.vrrpd,
+]
+
+# Function we pass to Topogen to create the topology
 def build_topo(tgen):
     "Build function"
 
     # Create 2 routers
-    for routern in range(1, 3):
-        tgen.add_router("r{}".format(routern))
+    r1 = tgen.add_router("r1")
+    r2 = tgen.add_router("r2")
 
-    # Create a switch with just one router connected to it to simulate a
-    # empty network.
+    # Create a p2p connection between r1 and r2
+    tgen.add_link(r1, r2)
+
+    # Create a switch with one router connected to it to simulate a empty network.
     switch = tgen.add_switch("s1")
-    switch.add_link(tgen.gears["r1"])
+    switch.add_link(r1)
 
-    # Create a connection between r1 and r2
+    # Create a p2p connection between r1 and r2
     switch = tgen.add_switch("s2")
-    switch.add_link(tgen.gears["r1"])
-    switch.add_link(tgen.gears["r2"])
+    switch.add_link(r1)
+    switch.add_link(r2)
 
 
-def setup_module(mod):
-    "Sets up the pytest environment"
+# New form of setup/teardown using pytest fixture
+@pytest.fixture(scope="module")
+def tgen(request):
+    "Setup/Teardown the environment and provide tgen argument to tests"
 
     # This function initiates the topology build with Topogen...
-    tgen = Topogen(build_topo, mod.__name__)
+    tgen = Topogen(build_topo, request.module.__name__)
 
-    # The basic topology above could also have be more easily specified using a
-    # dictionary, remove the build_topo function and use the following instead:
+    # A basic topology similar to the above could also have be more easily specified
+    # using a # dictionary, remove the build_topo function and use the following
+    # instead:
     #
     # topodef = {
     #     "s1": "r1"
     #     "s2": ("r1", "r2")
     # }
-    # tgen = Topogen(topodef, mod.__name__)
+    # tgen = Topogen(topodef, request.module.__name__)
 
     # ... and here it calls initialization functions.
     tgen.start_topology()
@@ -84,42 +99,69 @@ def setup_module(mod):
     # This is a sample of configuration loading.
     router_list = tgen.routers()
 
-    # For all registred routers, load the zebra configuration file
-    # CWD = os.path.dirname(os.path.realpath(__file__))
+    # For all routers arrange for:
+    # - starting zebra using config file from <rtrname>/zebra.conf
+    # - starting ospfd using an empty config file.
     for rname, router in router_list.items():
-        router.load_config(
-            TopoRouter.RD_ZEBRA,
-            # Uncomment next line to load configuration from ./router/zebra.conf
-            # os.path.join(CWD, '{}/zebra.conf'.format(rname))
-        )
+        router.load_config(TopoRouter.RD_ZEBRA, "zebra.conf")
+        router.load_config(TopoRouter.RD_OSPF)
 
-    # After loading the configurations, this function loads configured daemons.
+    # Start and configure the router daemons
     tgen.start_router()
 
+    # Provide tgen as argument to each test function
+    yield tgen
 
-def teardown_module(mod):
-    "Teardown the pytest environment"
-    tgen = get_topogen()
-
-    # This function tears down the whole topology.
+    # Teardown after last test runs
     tgen.stop_topology()
 
 
-def test_call_cli():
-    "Dummy test that just calls tgen.cli() so we can interact with the build."
-    tgen = get_topogen()
-    # Don't run this test if we have any failure.
+# Fixture that executes before each test
+@pytest.fixture(autouse=True)
+def skip_on_failure(tgen):
     if tgen.routers_have_failure():
-        pytest.skip(tgen.errors)
+        pytest.skip("skipped because of previous test failure")
+
+
+# ===================
+# The tests functions
+# ===================
+
 
-    # logger.info("calling CLI")
-    # tgen.cli()
+def test_get_version(tgen):
+    "Test the logs the FRR version"
+
+    r1 = tgen.gears["r1"]
+    version = r1.vtysh_cmd("show version")
+    logger.info("FRR version is: " + version)
+
+
+def test_connectivity(tgen):
+    "Test the logs the FRR version"
+
+    r1 = tgen.gears["r1"]
+    r2 = tgen.gears["r2"]
+    output = r1.cmd_raises("ping -c1 192.168.1.2")
+    output = r2.cmd_raises("ping -c1 192.168.3.1")
+
+
+@pytest.mark.xfail
+def test_expect_failure(tgen):
+    "A test that is current expected to fail but should be fixed"
+
+    assert False, "Example of temporary expected failure that will eventually be fixed"
+
+
+@pytest.mark.skip
+def test_will_be_skipped(tgen):
+    "A test that will be skipped"
+    assert False
 
 
 # Memory leak test template
-def test_memory_leak():
+def test_memory_leak(tgen):
     "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")
 
index d05332388e47441309b3df09d86f5b12b5e06653..556240bfb5306360959ed0e1c8b17322dbf006c2 100644 (file)
@@ -2672,7 +2672,7 @@ def verify_best_path_as_per_admin_distance(
     return True
 
 
-@retry(retry_timeout=10, initial_wait=2)
+@retry(retry_timeout=30)
 def verify_bgp_rib(
     tgen,
     addr_type,
index 54020d2ff91f08db31de9169c06f5841c1371588..1bce3c6bb2bb44c191ae6a0d2a9d0d9fc6668a17 100644 (file)
@@ -44,6 +44,7 @@ from lib.micronet import comm_error
 from lib.topogen import TopoRouter, get_topogen
 from lib.topolog import get_logger, logger
 from lib.topotest import frr_unicode, interface_set_status, version_cmp
+from lib import topotest
 
 FRRCFG_FILE = "frr_json.conf"
 FRRCFG_BKUP_FILE = "frr_json_initial.conf"
index 910573c14c5674174f7acee1ebf79fae597f0554..c98bfac9ee6dc79e87c404f65662771e7b1e5e2a 100644 (file)
@@ -217,6 +217,7 @@ class ltemplateRtrCmd:
         self.resetCounts()
 
     def doCmd(self, tgen, rtr, cmd, checkstr=None):
+        logger.info("doCmd: {} {}".format(rtr, cmd))
         output = tgen.net[rtr].cmd(cmd).strip()
         if len(output):
             self.output += 1
@@ -227,9 +228,10 @@ class ltemplateRtrCmd:
                 else:
                     self.match += 1
                 return ret
-            logger.info("command: {} {}".format(rtr, cmd))
             logger.info("output: " + output)
-        self.none += 1
+        else:
+            logger.info("No output")
+            self.none += 1
         return None
 
     def resetCounts(self):
index c21cbf0dd87b18b620898b53fd67bdb9f51b21a1..c425e121af18cde2de103316851c70e185a4d8fb 100644 (file)
@@ -329,14 +329,14 @@ def __create_ospf_global(tgen, input_dict, router, build, load_config, ospf):
                 cmd = "no {}".format(cmd)
             config_data.append(cmd)
 
-        if "helper-only" in gr_data and not gr_data["helper-only"]:
-            cmd = "graceful-restart helper-only"
+        if "helper enable" in gr_data and not gr_data["helper enable"]:
+            cmd = "graceful-restart helper enable"
             if gr_data.setdefault("delete", False):
                 cmd = "no {}".format(cmd)
             config_data.append(cmd)
-        elif "helper-only" in gr_data and type(gr_data["helper-only"]) is list:
-            for rtrs in gr_data["helper-only"]:
-                cmd = "graceful-restart helper-only {}".format(rtrs)
+        elif "helper enable" in gr_data and type(gr_data["helper enable"]) is list:
+            for rtrs in gr_data["helper enable"]:
+                cmd = "graceful-restart helper enable {}".format(rtrs)
                 if gr_data.setdefault("delete", False):
                     cmd = "no {}".format(cmd)
                 config_data.append(cmd)
index 9d37088218885625db1d266cbe4a491db959b6df..944981add422fe23fcdf56c528b5e3aa380d1045 100644 (file)
@@ -1020,10 +1020,10 @@ def verify_ip_mroutes(
     if not isinstance(group_addresses, list):
         group_addresses = [group_addresses]
 
-    if not isinstance(iif, list) and iif is not "none":
+    if not isinstance(iif, list) and iif != "none":
         iif = [iif]
 
-    if not isinstance(oil, list) and oil is not "none":
+    if not isinstance(oil, list) and oil != "none":
         oil = [oil]
 
     for grp_addr in group_addresses:
index 1b26ddc1b5b66202813a8abed75fe3b7c5a7712b..b98698185c268ba7b4099bf177aa84c149c4f491 100644 (file)
@@ -439,6 +439,19 @@ def run_and_expect_type(func, etype, count=20, wait=3, avalue=None):
     return (False, result)
 
 
+def router_json_cmp_retry(router, cmd, data, exact=False, retry_timeout=10.0):
+    """
+    Runs `cmd` that returns JSON data (normally the command ends with 'json')
+    and compare with `data` contents. Retry by default for 10 seconds
+    """
+
+    def test_func():
+        return router_json_cmp(router, cmd, data, exact)
+
+    ok, _ = run_and_expect(test_func, None, int(retry_timeout), 1)
+    return ok
+
+
 def int2dpid(dpid):
     "Converting Integer to DPID"
 
index 3e14ab7164b5bfe9669b40df3566450929fc6371..dc14bc646876c85f4ec16cd8e83fcdeae013ddd9 100755 (executable)
@@ -90,7 +90,6 @@ from lib.pim import (
     clear_ip_mroute,
     clear_ip_pim_interface_traffic,
     verify_igmp_config,
-    clear_ip_mroute_verify,
     McastTesterHelper,
 )
 from lib.topolog import logger
@@ -549,21 +548,30 @@ def test_clear_pim_neighbors_and_mroute_p0(request):
     result = app_helper.run_traffic("i2", IGMP_JOIN_RANGE_1, "f1")
     assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
 
-    step("Clear the mroute on l1, wait for 5 sec")
-    result = clear_ip_mroute_verify(tgen, "l1")
-    assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
-
     step(
-        "After clear ip mroute (*,g) entries are re-populated again"
-        " with same OIL and IIF, verify using 'show ip mroute' and "
-        " 'show ip pim upstream' "
+        "Verify clear ip mroute (*,g) entries are populated by using "
+        "'show ip mroute' cli"
     )
 
-    source = topo["routers"]["i2"]["links"]["f1"]["ipv4"].split("/")[0]
     input_dict = [
         {"dut": "l1", "src_address": "*", "iif": "l1-c1-eth0", "oil": "l1-i1-eth1"}
     ]
 
+    for data in input_dict:
+        result = verify_ip_mroutes(
+            tgen, data["dut"], data["src_address"], IGMP_JOIN, data["iif"], data["oil"]
+        )
+        assert result is True, "Testcase{} : Failed Error: {}".format(tc_name, result)
+
+    step("Clear mroutes on l1")
+    clear_ip_mroute(tgen, "l1")
+
+    step(
+        "After clear ip mroute (*,g) entries are re-populated again"
+        " with same OIL and IIF, verify using 'show ip mroute' and "
+        " 'show ip pim upstream' "
+    )
+
     for data in input_dict:
         result = verify_ip_mroutes(
             tgen, data["dut"], data["src_address"], IGMP_JOIN, data["iif"], data["oil"]
diff --git a/tests/topotests/ospf6_gr_topo1/__init__.py b/tests/topotests/ospf6_gr_topo1/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/topotests/ospf6_gr_topo1/rt1/ospf6d.conf b/tests/topotests/ospf6_gr_topo1/rt1/ospf6d.conf
new file mode 100644 (file)
index 0000000..9e2ad29
--- /dev/null
@@ -0,0 +1,30 @@
+:assword 1
+hostname rt1
+log file ospf6d.log
+log commands
+!
+debug ospf6 lsa router originate
+debug ospf6 lsa router flooding
+debug ospf6 zebra
+debug ospf6 interface
+debug ospf6 neighbor
+debug ospf6 flooding
+debug ospf6 graceful-restart
+debug ospf6 spf process
+!
+interface lo
+ ipv6 ospf area 1
+ ipv6 ospf network point-to-point
+!
+interface eth-rt2
+ ipv6 ospf network point-to-point
+ ipv6 ospf area 1
+ ipv6 ospf hello-interval 3
+ ipv6 ospf dead-interval 9
+!
+router ospf6
+ ospf6 router-id 1.1.1.1
+ redistribute connected
+ graceful-restart grace-period 120
+ graceful-restart helper enable
+!
diff --git a/tests/topotests/ospf6_gr_topo1/rt1/show_ipv6_ospf_database.json b/tests/topotests/ospf6_gr_topo1/rt1/show_ipv6_ospf_database.json
new file mode 100644 (file)
index 0000000..58fc114
--- /dev/null
@@ -0,0 +1,95 @@
+{
+  "areaScopedLinkStateDb":[
+    {
+      "areaId":"1",
+      "lsa":[
+        {
+          "type":"Rtr",
+          "advRouter":"1.1.1.1"
+        },
+        {
+          "type":"Rtr",
+          "advRouter":"2.2.2.2"
+        },
+        {
+          "type":"IAP",
+          "advRouter":"2.2.2.2",
+          "payload":"2001:db8:1000::2\/128"
+        },
+        {
+          "type":"IAP",
+          "advRouter":"2.2.2.2",
+          "payload":"2001:db8:1000::3\/128"
+        },
+        {
+          "type":"IAP",
+          "advRouter":"2.2.2.2",
+          "payload":"2001:db8:1000::4\/128"
+        },
+        {
+          "type":"IAP",
+          "advRouter":"2.2.2.2",
+          "payload":"2001:db8:1000::6\/128"
+        },
+        {
+          "type":"IAP",
+          "advRouter":"2.2.2.2",
+          "payload":"2001:db8:1000::5\/128"
+        },
+        {
+          "type":"IAP",
+          "advRouter":"2.2.2.2",
+          "payload":"2001:db8:1000::7\/128"
+        },
+        {
+          "type":"IAR",
+          "advRouter":"2.2.2.2",
+          "payload":"7.7.7.7"
+        },
+        {
+          "type":"INP",
+          "advRouter":"1.1.1.1",
+          "payload":"2001:db8:1000::1\/128"
+        }
+      ]
+    }
+  ],
+  "interfaceScopedLinkStateDb":[
+    {
+      "areaId":"1",
+      "interface":"eth-rt2",
+      "lsa":[
+        {
+          "type":"Lnk",
+          "advRouter":"1.1.1.1"
+        },
+        {
+          "type":"Lnk",
+          "advRouter":"2.2.2.2"
+        }
+      ]
+    },
+    {
+      "areaId":"1",
+      "interface":"lo",
+      "lsa":[
+      ]
+    }
+  ],
+  "asScopedLinkStateDb":[
+    {
+      "lsa":[
+        {
+          "type":"ASE",
+          "advRouter":"1.1.1.1",
+          "payload":"2001:db8:1000::1\/128"
+        },
+        {
+          "type":"ASE",
+          "advRouter":"7.7.7.7",
+          "payload":"2001:db8:1000::7\/128"
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/ospf6_gr_topo1/rt1/show_ipv6_ospf_neighbor.json b/tests/topotests/ospf6_gr_topo1/rt1/show_ipv6_ospf_neighbor.json
new file mode 100644 (file)
index 0000000..cb88358
--- /dev/null
@@ -0,0 +1,12 @@
+{
+  "neighbors":[
+    {
+      "neighborId":"2.2.2.2",
+      "priority":1,
+      "state":"Full",
+      "ifState":"PointToPoint",
+      "interfaceName":"eth-rt2",
+      "interfaceState":"PointToPoint"
+    }
+  ]
+}
diff --git a/tests/topotests/ospf6_gr_topo1/rt1/show_ipv6_ospf_route.json b/tests/topotests/ospf6_gr_topo1/rt1/show_ipv6_ospf_route.json
new file mode 100644 (file)
index 0000000..0c69310
--- /dev/null
@@ -0,0 +1,74 @@
+{
+  "routes":{
+    "2001:db8:1000::1\/128":{
+      "isBestRoute":true,
+      "destinationType":"N",
+      "pathType":"IA",
+      "nextHops":[
+        {
+          "interfaceName":"lo"
+        }
+      ]
+    },
+    "2001:db8:1000::2\/128":{
+      "isBestRoute":true,
+      "destinationType":"N",
+      "pathType":"IE",
+      "nextHops":[
+        {
+          "interfaceName":"eth-rt2"
+        }
+      ]
+    },
+    "2001:db8:1000::3\/128":{
+      "isBestRoute":true,
+      "destinationType":"N",
+      "pathType":"IE",
+      "nextHops":[
+        {
+          "interfaceName":"eth-rt2"
+        }
+      ]
+    },
+    "2001:db8:1000::4\/128":{
+      "isBestRoute":true,
+      "destinationType":"N",
+      "pathType":"IE",
+      "nextHops":[
+        {
+          "interfaceName":"eth-rt2"
+        }
+      ]
+    },
+    "2001:db8:1000::5\/128":{
+      "isBestRoute":true,
+      "destinationType":"N",
+      "pathType":"IE",
+      "nextHops":[
+        {
+          "interfaceName":"eth-rt2"
+        }
+      ]
+    },
+    "2001:db8:1000::6\/128":{
+      "isBestRoute":true,
+      "destinationType":"N",
+      "pathType":"IE",
+      "nextHops":[
+        {
+          "interfaceName":"eth-rt2"
+        }
+      ]
+    },
+    "2001:db8:1000::7\/128":{
+      "isBestRoute":false,
+      "destinationType":"N",
+      "pathType":"E2",
+      "nextHops":[
+        {
+          "interfaceName":"eth-rt2"
+        }
+      ]
+    }
+  }
+}
diff --git a/tests/topotests/ospf6_gr_topo1/rt1/show_ipv6_route.json b/tests/topotests/ospf6_gr_topo1/rt1/show_ipv6_route.json
new file mode 100644 (file)
index 0000000..66ee57c
--- /dev/null
@@ -0,0 +1,139 @@
+{
+  "2001:db8:1000::1\/128":[
+    {
+      "prefix":"2001:db8:1000::1\/128",
+      "protocol":"ospf6",
+      "vrfId":0,
+      "vrfName":"default",
+      "distance":110,
+      "metric":10,
+      "nexthops":[
+        {
+          "directlyConnected":true,
+          "interfaceName":"lo",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::2\/128":[
+    {
+      "prefix":"2001:db8:1000::2\/128",
+      "protocol":"ospf6",
+      "vrfId":0,
+      "vrfName":"default",
+      "selected":true,
+      "destSelected":true,
+      "distance":110,
+      "metric":20,
+      "installed":true,
+      "nexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt2",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::3\/128":[
+    {
+      "prefix":"2001:db8:1000::3\/128",
+      "protocol":"ospf6",
+      "vrfId":0,
+      "vrfName":"default",
+      "selected":true,
+      "destSelected":true,
+      "distance":110,
+      "metric":30,
+      "installed":true,
+      "nexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt2",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::4\/128":[
+    {
+      "prefix":"2001:db8:1000::4\/128",
+      "protocol":"ospf6",
+      "vrfId":0,
+      "vrfName":"default",
+      "selected":true,
+      "destSelected":true,
+      "distance":110,
+      "metric":40,
+      "installed":true,
+      "nexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt2",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::5\/128":[
+    {
+      "prefix":"2001:db8:1000::5\/128",
+      "protocol":"ospf6",
+      "vrfId":0,
+      "vrfName":"default",
+      "selected":true,
+      "destSelected":true,
+      "distance":110,
+      "metric":50,
+      "installed":true,
+      "nexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt2",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::6\/128":[
+    {
+      "prefix":"2001:db8:1000::6\/128",
+      "protocol":"ospf6",
+      "vrfId":0,
+      "vrfName":"default",
+      "selected":true,
+      "destSelected":true,
+      "distance":110,
+      "metric":40,
+      "installed":true,
+      "nexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt2",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::7\/128":[
+    {
+      "prefix":"2001:db8:1000::7\/128",
+      "protocol":"ospf6",
+      "vrfId":0,
+      "vrfName":"default",
+      "selected":true,
+      "destSelected":true,
+      "distance":110,
+      "metric":50,
+      "installed":true,
+      "nexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt2",
+          "active":true
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/ospf6_gr_topo1/rt1/zebra.conf b/tests/topotests/ospf6_gr_topo1/rt1/zebra.conf
new file mode 100644 (file)
index 0000000..f29f5b7
--- /dev/null
@@ -0,0 +1,22 @@
+password 1
+hostname rt1
+log file zebra.log
+log commands
+!
+debug zebra event
+debug zebra packet
+debug zebra rib
+debug zebra kernel
+!
+interface lo
+ ip address 1.1.1.1/32
+ ipv6 address 2001:db8:1000::1/128
+!
+interface stub1
+!
+interface eth-rt2
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/ospf6_gr_topo1/rt2/ospf6d.conf b/tests/topotests/ospf6_gr_topo1/rt2/ospf6d.conf
new file mode 100644 (file)
index 0000000..cfa8758
--- /dev/null
@@ -0,0 +1,35 @@
+password 1
+hostname rt2
+log file ospf6d.log
+log commands
+!
+debug ospf6 lsa router originate
+debug ospf6 lsa router flooding
+debug ospf6 zebra
+debug ospf6 interface
+debug ospf6 neighbor
+debug ospf6 flooding
+debug ospf6 graceful-restart
+debug ospf6 spf process
+!
+interface lo
+ ipv6 ospf area 0
+ ipv6 ospf network point-to-point
+!
+interface eth-rt1
+ ipv6 ospf network point-to-point
+ ipv6 ospf area 1
+ ipv6 ospf hello-interval 3
+ ipv6 ospf dead-interval 9
+!
+interface eth-rt3
+ ipv6 ospf network point-to-point
+ ipv6 ospf area 0
+ ipv6 ospf hello-interval 3
+ ipv6 ospf dead-interval 9
+!
+router ospf6
+ ospf6 router-id 2.2.2.2
+ graceful-restart grace-period 120
+ graceful-restart helper enable
+!
diff --git a/tests/topotests/ospf6_gr_topo1/rt2/show_ipv6_ospf_database.json b/tests/topotests/ospf6_gr_topo1/rt2/show_ipv6_ospf_database.json
new file mode 100644 (file)
index 0000000..fb16326
--- /dev/null
@@ -0,0 +1,183 @@
+{
+  "areaScopedLinkStateDb":[
+    {
+      "areaId":"0",
+      "lsa":[
+        {
+          "type":"Rtr",
+          "advRouter":"2.2.2.2"
+        },
+        {
+          "type":"Rtr",
+          "advRouter":"3.3.3.3"
+        },
+        {
+          "type":"Rtr",
+          "advRouter":"3.3.3.3"
+        },
+        {
+          "type":"Rtr",
+          "advRouter":"3.3.3.3"
+        },
+        {
+          "type":"Rtr",
+          "advRouter":"4.4.4.4"
+        },
+        {
+          "type":"Rtr",
+          "advRouter":"6.6.6.6"
+        },
+        {
+          "type":"IAP",
+          "advRouter":"2.2.2.2",
+          "payload":"2001:db8:1000::1\/128"
+        },
+        {
+          "type":"IAP",
+          "advRouter":"4.4.4.4",
+          "payload":"2001:db8:1000::5\/128"
+        },
+        {
+          "type":"IAP",
+          "advRouter":"6.6.6.6",
+          "payload":"2001:db8:1000::7\/128"
+        },
+        {
+          "type":"IAR",
+          "advRouter":"2.2.2.2",
+          "payload":"1.1.1.1"
+        },
+        {
+          "type":"IAR",
+          "advRouter":"6.6.6.6",
+          "payload":"7.7.7.7"
+        },
+        {
+          "type":"INP",
+          "advRouter":"2.2.2.2",
+          "payload":"2001:db8:1000::2\/128"
+        },
+        {
+          "type":"INP",
+          "advRouter":"3.3.3.3",
+          "payload":"2001:db8:1000::3\/128"
+        },
+        {
+          "type":"INP",
+          "advRouter":"4.4.4.4",
+          "payload":"2001:db8:1000::4\/128"
+        },
+        {
+          "type":"INP",
+          "advRouter":"6.6.6.6",
+          "payload":"2001:db8:1000::6\/128"
+        }
+      ]
+    },
+    {
+      "areaId":"1",
+      "lsa":[
+        {
+          "type":"Rtr",
+          "advRouter":"1.1.1.1"
+        },
+        {
+          "type":"Rtr",
+          "advRouter":"2.2.2.2"
+        },
+        {
+          "type":"IAP",
+          "advRouter":"2.2.2.2",
+          "payload":"2001:db8:1000::2\/128"
+        },
+        {
+          "type":"IAP",
+          "advRouter":"2.2.2.2",
+          "payload":"2001:db8:1000::3\/128"
+        },
+        {
+          "type":"IAP",
+          "advRouter":"2.2.2.2",
+          "payload":"2001:db8:1000::4\/128"
+        },
+        {
+          "type":"IAP",
+          "advRouter":"2.2.2.2",
+          "payload":"2001:db8:1000::6\/128"
+        },
+        {
+          "type":"IAP",
+          "advRouter":"2.2.2.2",
+          "payload":"2001:db8:1000::5\/128"
+        },
+        {
+          "type":"IAP",
+          "advRouter":"2.2.2.2",
+          "payload":"2001:db8:1000::7\/128"
+        },
+        {
+          "type":"IAR",
+          "advRouter":"2.2.2.2",
+          "payload":"7.7.7.7"
+        },
+        {
+          "type":"INP",
+          "advRouter":"1.1.1.1",
+          "payload":"2001:db8:1000::1\/128"
+        }
+      ]
+    }
+  ],
+  "interfaceScopedLinkStateDb":[
+    {
+      "areaId":"0",
+      "interface":"eth-rt3",
+      "lsa":[
+        {
+          "type":"Lnk",
+          "advRouter":"2.2.2.2"
+        },
+        {
+          "type":"Lnk",
+          "advRouter":"3.3.3.3"
+        }
+      ]
+    },
+    {
+      "areaId":"0",
+      "interface":"lo",
+      "lsa":[
+      ]
+    },
+    {
+      "areaId":"1",
+      "interface":"eth-rt1",
+      "lsa":[
+        {
+          "type":"Lnk",
+          "advRouter":"1.1.1.1"
+        },
+        {
+          "type":"Lnk",
+          "advRouter":"2.2.2.2"
+        }
+      ]
+    }
+  ],
+  "asScopedLinkStateDb":[
+    {
+      "lsa":[
+        {
+          "type":"ASE",
+          "advRouter":"1.1.1.1",
+          "payload":"2001:db8:1000::1\/128"
+        },
+        {
+          "type":"ASE",
+          "advRouter":"7.7.7.7",
+          "payload":"2001:db8:1000::7\/128"
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/ospf6_gr_topo1/rt2/show_ipv6_ospf_neighbor.json b/tests/topotests/ospf6_gr_topo1/rt2/show_ipv6_ospf_neighbor.json
new file mode 100644 (file)
index 0000000..e4f27bf
--- /dev/null
@@ -0,0 +1,20 @@
+{
+  "neighbors":[
+    {
+      "neighborId":"3.3.3.3",
+      "priority":1,
+      "state":"Full",
+      "ifState":"PointToPoint",
+      "interfaceName":"eth-rt3",
+      "interfaceState":"PointToPoint"
+    },
+    {
+      "neighborId":"1.1.1.1",
+      "priority":1,
+      "state":"Full",
+      "ifState":"PointToPoint",
+      "interfaceName":"eth-rt1",
+      "interfaceState":"PointToPoint"
+    }
+  ]
+}
diff --git a/tests/topotests/ospf6_gr_topo1/rt2/show_ipv6_ospf_route.json b/tests/topotests/ospf6_gr_topo1/rt2/show_ipv6_ospf_route.json
new file mode 100644 (file)
index 0000000..34013a1
--- /dev/null
@@ -0,0 +1,74 @@
+{
+  "routes":{
+    "2001:db8:1000::1\/128":{
+      "isBestRoute":false,
+      "destinationType":"N",
+      "pathType":"E2",
+      "nextHops":[
+        {
+          "interfaceName":"eth-rt1"
+        }
+      ]
+    },
+    "2001:db8:1000::2\/128":{
+      "isBestRoute":true,
+      "destinationType":"N",
+      "pathType":"IA",
+      "nextHops":[
+        {
+          "interfaceName":"lo"
+        }
+      ]
+    },
+    "2001:db8:1000::3\/128":{
+      "isBestRoute":true,
+      "destinationType":"N",
+      "pathType":"IA",
+      "nextHops":[
+        {
+          "interfaceName":"eth-rt3"
+        }
+      ]
+    },
+    "2001:db8:1000::4\/128":{
+      "isBestRoute":true,
+      "destinationType":"N",
+      "pathType":"IA",
+      "nextHops":[
+        {
+          "interfaceName":"eth-rt3"
+        }
+      ]
+    },
+    "2001:db8:1000::5\/128":{
+      "isBestRoute":true,
+      "destinationType":"N",
+      "pathType":"IE",
+      "nextHops":[
+        {
+          "interfaceName":"eth-rt3"
+        }
+      ]
+    },
+    "2001:db8:1000::6\/128":{
+      "isBestRoute":true,
+      "destinationType":"N",
+      "pathType":"IA",
+      "nextHops":[
+        {
+          "interfaceName":"eth-rt3"
+        }
+      ]
+    },
+    "2001:db8:1000::7\/128":{
+      "isBestRoute":false,
+      "destinationType":"N",
+      "pathType":"E2",
+      "nextHops":[
+        {
+          "interfaceName":"eth-rt3"
+        }
+      ]
+    }
+  }
+}
diff --git a/tests/topotests/ospf6_gr_topo1/rt2/show_ipv6_route.json b/tests/topotests/ospf6_gr_topo1/rt2/show_ipv6_route.json
new file mode 100644 (file)
index 0000000..624ff70
--- /dev/null
@@ -0,0 +1,139 @@
+{
+  "2001:db8:1000::1\/128":[
+    {
+      "prefix":"2001:db8:1000::1\/128",
+      "protocol":"ospf6",
+      "vrfId":0,
+      "vrfName":"default",
+      "selected":true,
+      "destSelected":true,
+      "distance":110,
+      "metric":20,
+      "installed":true,
+      "nexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt1",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::2\/128":[
+    {
+      "prefix":"2001:db8:1000::2\/128",
+      "protocol":"ospf6",
+      "vrfId":0,
+      "vrfName":"default",
+      "distance":110,
+      "metric":10,
+      "nexthops":[
+        {
+          "directlyConnected":true,
+          "interfaceName":"lo",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::3\/128":[
+    {
+      "prefix":"2001:db8:1000::3\/128",
+      "protocol":"ospf6",
+      "vrfId":0,
+      "vrfName":"default",
+      "selected":true,
+      "destSelected":true,
+      "distance":110,
+      "metric":20,
+      "installed":true,
+      "nexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt3",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::4\/128":[
+    {
+      "prefix":"2001:db8:1000::4\/128",
+      "protocol":"ospf6",
+      "vrfId":0,
+      "vrfName":"default",
+      "selected":true,
+      "destSelected":true,
+      "distance":110,
+      "metric":30,
+      "installed":true,
+      "nexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt3",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::5\/128":[
+    {
+      "prefix":"2001:db8:1000::5\/128",
+      "protocol":"ospf6",
+      "vrfId":0,
+      "vrfName":"default",
+      "selected":true,
+      "destSelected":true,
+      "distance":110,
+      "metric":40,
+      "installed":true,
+      "nexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt3",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::6\/128":[
+    {
+      "prefix":"2001:db8:1000::6\/128",
+      "protocol":"ospf6",
+      "vrfId":0,
+      "vrfName":"default",
+      "selected":true,
+      "destSelected":true,
+      "distance":110,
+      "metric":30,
+      "installed":true,
+      "nexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt3",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::7\/128":[
+    {
+      "prefix":"2001:db8:1000::7\/128",
+      "protocol":"ospf6",
+      "vrfId":0,
+      "vrfName":"default",
+      "selected":true,
+      "destSelected":true,
+      "distance":110,
+      "metric":40,
+      "installed":true,
+      "nexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt3",
+          "active":true
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/ospf6_gr_topo1/rt2/zebra.conf b/tests/topotests/ospf6_gr_topo1/rt2/zebra.conf
new file mode 100644 (file)
index 0000000..e4fe762
--- /dev/null
@@ -0,0 +1,22 @@
+password 1
+hostname rt2
+log file zebra.log
+log commands
+!
+debug zebra event
+debug zebra packet
+debug zebra rib
+debug zebra kernel
+!
+interface lo
+ ip address 2.2.2.2/32
+ ipv6 address 2001:db8:1000::2/128
+!
+interface eth-rt1
+!
+interface eth-rt3
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/ospf6_gr_topo1/rt3/ospf6d.conf b/tests/topotests/ospf6_gr_topo1/rt3/ospf6d.conf
new file mode 100644 (file)
index 0000000..f33f14f
--- /dev/null
@@ -0,0 +1,41 @@
+password 1
+hostname rt3
+log file ospf6d.log
+log commands
+!
+debug ospf6 lsa router originate
+debug ospf6 lsa router flooding
+debug ospf6 zebra
+debug ospf6 interface
+debug ospf6 neighbor
+debug ospf6 flooding
+debug ospf6 graceful-restart
+debug ospf6 spf process
+!
+interface lo
+ ipv6 ospf area 0
+ ipv6 ospf network point-to-point
+!
+interface eth-rt2
+ ipv6 ospf network point-to-point
+ ipv6 ospf area 0
+ ipv6 ospf hello-interval 3
+ ipv6 ospf dead-interval 9
+!
+interface eth-rt4
+ ipv6 ospf network point-to-point
+ ipv6 ospf area 0
+ ipv6 ospf hello-interval 3
+ ipv6 ospf dead-interval 9
+!
+interface eth-rt6
+ ipv6 ospf network point-to-point
+ ipv6 ospf area 0
+ ipv6 ospf hello-interval 3
+ ipv6 ospf dead-interval 9
+!
+router ospf6
+ ospf6 router-id 3.3.3.3
+ graceful-restart grace-period 120
+ graceful-restart helper enable
+!
diff --git a/tests/topotests/ospf6_gr_topo1/rt3/show_ipv6_ospf_database.json b/tests/topotests/ospf6_gr_topo1/rt3/show_ipv6_ospf_database.json
new file mode 100644 (file)
index 0000000..f8a8f76
--- /dev/null
@@ -0,0 +1,144 @@
+{
+  "areaScopedLinkStateDb":[
+    {
+      "areaId":"0",
+      "lsa":[
+        {
+          "type":"Rtr",
+          "advRouter":"2.2.2.2"
+        },
+        {
+          "type":"Rtr",
+          "advRouter":"3.3.3.3"
+        },
+        {
+          "type":"Rtr",
+          "advRouter":"3.3.3.3"
+        },
+        {
+          "type":"Rtr",
+          "advRouter":"3.3.3.3"
+        },
+        {
+          "type":"Rtr",
+          "advRouter":"4.4.4.4"
+        },
+        {
+          "type":"Rtr",
+          "advRouter":"6.6.6.6"
+        },
+        {
+          "type":"IAP",
+          "advRouter":"2.2.2.2",
+          "payload":"2001:db8:1000::1\/128"
+        },
+        {
+          "type":"IAP",
+          "advRouter":"4.4.4.4",
+          "payload":"2001:db8:1000::5\/128"
+        },
+        {
+          "type":"IAP",
+          "advRouter":"6.6.6.6",
+          "payload":"2001:db8:1000::7\/128"
+        },
+        {
+          "type":"IAR",
+          "advRouter":"2.2.2.2",
+          "payload":"1.1.1.1"
+        },
+        {
+          "type":"IAR",
+          "advRouter":"6.6.6.6",
+          "payload":"7.7.7.7"
+        },
+        {
+          "type":"INP",
+          "advRouter":"2.2.2.2",
+          "payload":"2001:db8:1000::2\/128"
+        },
+        {
+          "type":"INP",
+          "advRouter":"3.3.3.3",
+          "payload":"2001:db8:1000::3\/128"
+        },
+        {
+          "type":"INP",
+          "advRouter":"4.4.4.4",
+          "payload":"2001:db8:1000::4\/128"
+        },
+        {
+          "type":"INP",
+          "advRouter":"6.6.6.6",
+          "payload":"2001:db8:1000::6\/128"
+        }
+      ]
+    }
+  ],
+  "interfaceScopedLinkStateDb":[
+    {
+      "areaId":"0",
+      "interface":"eth-rt2",
+      "lsa":[
+        {
+          "type":"Lnk",
+          "advRouter":"2.2.2.2"
+        },
+        {
+          "type":"Lnk",
+          "advRouter":"3.3.3.3"
+        }
+      ]
+    },
+    {
+      "areaId":"0",
+      "interface":"eth-rt4",
+      "lsa":[
+        {
+          "type":"Lnk",
+          "advRouter":"3.3.3.3"
+        },
+        {
+          "type":"Lnk",
+          "advRouter":"4.4.4.4"
+        }
+      ]
+    },
+    {
+      "areaId":"0",
+      "interface":"eth-rt6",
+      "lsa":[
+        {
+          "type":"Lnk",
+          "advRouter":"3.3.3.3"
+        },
+        {
+          "type":"Lnk",
+          "advRouter":"6.6.6.6"
+        }
+      ]
+    },
+    {
+      "areaId":"0",
+      "interface":"lo",
+      "lsa":[
+      ]
+    }
+  ],
+  "asScopedLinkStateDb":[
+    {
+      "lsa":[
+        {
+          "type":"ASE",
+          "advRouter":"1.1.1.1",
+          "payload":"2001:db8:1000::1\/128"
+        },
+        {
+          "type":"ASE",
+          "advRouter":"7.7.7.7",
+          "payload":"2001:db8:1000::7\/128"
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/ospf6_gr_topo1/rt3/show_ipv6_ospf_neighbor.json b/tests/topotests/ospf6_gr_topo1/rt3/show_ipv6_ospf_neighbor.json
new file mode 100644 (file)
index 0000000..d0d7f45
--- /dev/null
@@ -0,0 +1,28 @@
+{
+  "neighbors":[
+    {
+      "neighborId":"2.2.2.2",
+      "priority":1,
+      "state":"Full",
+      "ifState":"PointToPoint",
+      "interfaceName":"eth-rt2",
+      "interfaceState":"PointToPoint"
+    },
+    {
+      "neighborId":"4.4.4.4",
+      "priority":1,
+      "state":"Full",
+      "ifState":"PointToPoint",
+      "interfaceName":"eth-rt4",
+      "interfaceState":"PointToPoint"
+    },
+    {
+      "neighborId":"6.6.6.6",
+      "priority":1,
+      "state":"Full",
+      "ifState":"PointToPoint",
+      "interfaceName":"eth-rt6",
+      "interfaceState":"PointToPoint"
+    }
+  ]
+}
diff --git a/tests/topotests/ospf6_gr_topo1/rt3/show_ipv6_ospf_route.json b/tests/topotests/ospf6_gr_topo1/rt3/show_ipv6_ospf_route.json
new file mode 100644 (file)
index 0000000..ee516b9
--- /dev/null
@@ -0,0 +1,74 @@
+{
+  "routes":{
+    "2001:db8:1000::1\/128":{
+      "isBestRoute":false,
+      "destinationType":"N",
+      "pathType":"E2",
+      "nextHops":[
+        {
+          "interfaceName":"eth-rt2"
+        }
+      ]
+    },
+    "2001:db8:1000::2\/128":{
+      "isBestRoute":true,
+      "destinationType":"N",
+      "pathType":"IA",
+      "nextHops":[
+        {
+          "interfaceName":"eth-rt2"
+        }
+      ]
+    },
+    "2001:db8:1000::3\/128":{
+      "isBestRoute":true,
+      "destinationType":"N",
+      "pathType":"IA",
+      "nextHops":[
+        {
+          "interfaceName":"lo"
+        }
+      ]
+    },
+    "2001:db8:1000::4\/128":{
+      "isBestRoute":true,
+      "destinationType":"N",
+      "pathType":"IA",
+      "nextHops":[
+        {
+          "interfaceName":"eth-rt4"
+        }
+      ]
+    },
+    "2001:db8:1000::5\/128":{
+      "isBestRoute":true,
+      "destinationType":"N",
+      "pathType":"IE",
+      "nextHops":[
+        {
+          "interfaceName":"eth-rt4"
+        }
+      ]
+    },
+    "2001:db8:1000::6\/128":{
+      "isBestRoute":true,
+      "destinationType":"N",
+      "pathType":"IA",
+      "nextHops":[
+        {
+          "interfaceName":"eth-rt6"
+        }
+      ]
+    },
+    "2001:db8:1000::7\/128":{
+      "isBestRoute":false,
+      "destinationType":"N",
+      "pathType":"E2",
+      "nextHops":[
+        {
+          "interfaceName":"eth-rt6"
+        }
+      ]
+    }
+  }
+}
diff --git a/tests/topotests/ospf6_gr_topo1/rt3/show_ipv6_route.json b/tests/topotests/ospf6_gr_topo1/rt3/show_ipv6_route.json
new file mode 100644 (file)
index 0000000..f9b43dc
--- /dev/null
@@ -0,0 +1,139 @@
+{
+  "2001:db8:1000::1\/128":[
+    {
+      "prefix":"2001:db8:1000::1\/128",
+      "protocol":"ospf6",
+      "vrfId":0,
+      "vrfName":"default",
+      "selected":true,
+      "destSelected":true,
+      "distance":110,
+      "metric":30,
+      "installed":true,
+      "nexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt2",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::2\/128":[
+    {
+      "prefix":"2001:db8:1000::2\/128",
+      "protocol":"ospf6",
+      "vrfId":0,
+      "vrfName":"default",
+      "selected":true,
+      "destSelected":true,
+      "distance":110,
+      "metric":20,
+      "installed":true,
+      "nexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt2",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::3\/128":[
+    {
+      "prefix":"2001:db8:1000::3\/128",
+      "protocol":"ospf6",
+      "vrfId":0,
+      "vrfName":"default",
+      "distance":110,
+      "metric":10,
+      "nexthops":[
+        {
+          "directlyConnected":true,
+          "interfaceName":"lo",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::4\/128":[
+    {
+      "prefix":"2001:db8:1000::4\/128",
+      "protocol":"ospf6",
+      "vrfId":0,
+      "vrfName":"default",
+      "selected":true,
+      "destSelected":true,
+      "distance":110,
+      "metric":20,
+      "installed":true,
+      "nexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt4",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::5\/128":[
+    {
+      "prefix":"2001:db8:1000::5\/128",
+      "protocol":"ospf6",
+      "vrfId":0,
+      "vrfName":"default",
+      "selected":true,
+      "destSelected":true,
+      "distance":110,
+      "metric":30,
+      "installed":true,
+      "nexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt4",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::6\/128":[
+    {
+      "prefix":"2001:db8:1000::6\/128",
+      "protocol":"ospf6",
+      "vrfId":0,
+      "vrfName":"default",
+      "selected":true,
+      "destSelected":true,
+      "distance":110,
+      "metric":20,
+      "installed":true,
+      "nexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt6",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::7\/128":[
+    {
+      "prefix":"2001:db8:1000::7\/128",
+      "protocol":"ospf6",
+      "vrfId":0,
+      "vrfName":"default",
+      "selected":true,
+      "destSelected":true,
+      "distance":110,
+      "metric":30,
+      "installed":true,
+      "nexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt6",
+          "active":true
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/ospf6_gr_topo1/rt3/zebra.conf b/tests/topotests/ospf6_gr_topo1/rt3/zebra.conf
new file mode 100644 (file)
index 0000000..3a9de21
--- /dev/null
@@ -0,0 +1,24 @@
+password 1
+hostname rt3
+log file zebra.log
+log commands
+!
+debug zebra event
+debug zebra packet
+debug zebra rib
+debug zebra kernel
+!
+interface lo
+ ip address 3.3.3.3/32
+ ipv6 address 2001:db8:1000::3/128
+!
+interface eth-rt2
+!
+interface eth-rt4
+!
+interface eth-rt6
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/ospf6_gr_topo1/rt4/ospf6d.conf b/tests/topotests/ospf6_gr_topo1/rt4/ospf6d.conf
new file mode 100644 (file)
index 0000000..301eb57
--- /dev/null
@@ -0,0 +1,35 @@
+password 1
+hostname rt4
+log file ospf6d.log
+log commands
+!
+debug ospf6 lsa router originate
+debug ospf6 lsa router flooding
+debug ospf6 zebra
+debug ospf6 interface
+debug ospf6 neighbor
+debug ospf6 flooding
+debug ospf6 graceful-restart
+debug ospf6 spf process
+!
+interface lo
+ ipv6 ospf area 0
+ ipv6 ospf network point-to-point
+!
+interface eth-rt3
+ ipv6 ospf network point-to-point
+ ipv6 ospf area 0
+ ipv6 ospf hello-interval 3
+ ipv6 ospf dead-interval 9
+!
+interface eth-rt5
+ ipv6 ospf network point-to-point
+ ipv6 ospf area 2
+ ipv6 ospf hello-interval 3
+ ipv6 ospf dead-interval 9
+!
+router ospf6
+ ospf6 router-id 4.4.4.4
+ graceful-restart grace-period 120
+ graceful-restart helper enable
+!
diff --git a/tests/topotests/ospf6_gr_topo1/rt4/show_ipv6_ospf_database.json b/tests/topotests/ospf6_gr_topo1/rt4/show_ipv6_ospf_database.json
new file mode 100644 (file)
index 0000000..0954d1b
--- /dev/null
@@ -0,0 +1,188 @@
+{
+  "areaScopedLinkStateDb":[
+    {
+      "areaId":"0",
+      "lsa":[
+        {
+          "type":"Rtr",
+          "advRouter":"2.2.2.2"
+        },
+        {
+          "type":"Rtr",
+          "advRouter":"3.3.3.3"
+        },
+        {
+          "type":"Rtr",
+          "advRouter":"3.3.3.3"
+        },
+        {
+          "type":"Rtr",
+          "advRouter":"3.3.3.3"
+        },
+        {
+          "type":"Rtr",
+          "advRouter":"4.4.4.4"
+        },
+        {
+          "type":"Rtr",
+          "advRouter":"6.6.6.6"
+        },
+        {
+          "type":"IAP",
+          "advRouter":"2.2.2.2",
+          "payload":"2001:db8:1000::1\/128"
+        },
+        {
+          "type":"IAP",
+          "advRouter":"4.4.4.4",
+          "payload":"2001:db8:1000::5\/128"
+        },
+        {
+          "type":"IAP",
+          "advRouter":"6.6.6.6",
+          "payload":"2001:db8:1000::7\/128"
+        },
+        {
+          "type":"IAR",
+          "advRouter":"2.2.2.2",
+          "payload":"1.1.1.1"
+        },
+        {
+          "type":"IAR",
+          "advRouter":"6.6.6.6",
+          "payload":"7.7.7.7"
+        },
+        {
+          "type":"INP",
+          "advRouter":"2.2.2.2",
+          "payload":"2001:db8:1000::2\/128"
+        },
+        {
+          "type":"INP",
+          "advRouter":"3.3.3.3",
+          "payload":"2001:db8:1000::3\/128"
+        },
+        {
+          "type":"INP",
+          "advRouter":"4.4.4.4",
+          "payload":"2001:db8:1000::4\/128"
+        },
+        {
+          "type":"INP",
+          "advRouter":"6.6.6.6",
+          "payload":"2001:db8:1000::6\/128"
+        }
+      ]
+    },
+    {
+      "areaId":"2",
+      "lsa":[
+        {
+          "type":"Rtr",
+          "advRouter":"4.4.4.4"
+        },
+        {
+          "type":"Rtr",
+          "advRouter":"5.5.5.5"
+        },
+        {
+          "type":"IAP",
+          "advRouter":"4.4.4.4",
+          "payload":"2001:db8:1000::4\/128"
+        },
+        {
+          "type":"IAP",
+          "advRouter":"4.4.4.4",
+          "payload":"2001:db8:1000::2\/128"
+        },
+        {
+          "type":"IAP",
+          "advRouter":"4.4.4.4",
+          "payload":"2001:db8:1000::3\/128"
+        },
+        {
+          "type":"IAP",
+          "advRouter":"4.4.4.4",
+          "payload":"2001:db8:1000::6\/128"
+        },
+        {
+          "type":"IAP",
+          "advRouter":"4.4.4.4",
+          "payload":"2001:db8:1000::1\/128"
+        },
+        {
+          "type":"IAP",
+          "advRouter":"4.4.4.4",
+          "payload":"2001:db8:1000::7\/128"
+        },
+        {
+          "type":"IAR",
+          "advRouter":"4.4.4.4",
+          "payload":"1.1.1.1"
+        },
+        {
+          "type":"IAR",
+          "advRouter":"4.4.4.4",
+          "payload":"7.7.7.7"
+        },
+        {
+          "type":"INP",
+          "advRouter":"5.5.5.5",
+          "payload":"2001:db8:1000::5\/128"
+        }
+      ]
+    }
+  ],
+  "interfaceScopedLinkStateDb":[
+    {
+      "areaId":"0",
+      "interface":"eth-rt3",
+      "lsa":[
+        {
+          "type":"Lnk",
+          "advRouter":"3.3.3.3"
+        },
+        {
+          "type":"Lnk",
+          "advRouter":"4.4.4.4"
+        }
+      ]
+    },
+    {
+      "areaId":"0",
+      "interface":"lo",
+      "lsa":[
+      ]
+    },
+    {
+      "areaId":"2",
+      "interface":"eth-rt5",
+      "lsa":[
+        {
+          "type":"Lnk",
+          "advRouter":"4.4.4.4"
+        },
+        {
+          "type":"Lnk",
+          "advRouter":"5.5.5.5"
+        }
+      ]
+    }
+  ],
+  "asScopedLinkStateDb":[
+    {
+      "lsa":[
+        {
+          "type":"ASE",
+          "advRouter":"1.1.1.1",
+          "payload":"2001:db8:1000::1\/128"
+        },
+        {
+          "type":"ASE",
+          "advRouter":"7.7.7.7",
+          "payload":"2001:db8:1000::7\/128"
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/ospf6_gr_topo1/rt4/show_ipv6_ospf_neighbor.json b/tests/topotests/ospf6_gr_topo1/rt4/show_ipv6_ospf_neighbor.json
new file mode 100644 (file)
index 0000000..36abba4
--- /dev/null
@@ -0,0 +1,20 @@
+{
+  "neighbors":[
+    {
+      "neighborId":"3.3.3.3",
+      "priority":1,
+      "state":"Full",
+      "ifState":"PointToPoint",
+      "interfaceName":"eth-rt3",
+      "interfaceState":"PointToPoint"
+    },
+    {
+      "neighborId":"5.5.5.5",
+      "priority":1,
+      "state":"Full",
+      "ifState":"PointToPoint",
+      "interfaceName":"eth-rt5",
+      "interfaceState":"PointToPoint"
+    }
+  ]
+}
diff --git a/tests/topotests/ospf6_gr_topo1/rt4/show_ipv6_ospf_route.json b/tests/topotests/ospf6_gr_topo1/rt4/show_ipv6_ospf_route.json
new file mode 100644 (file)
index 0000000..3e5f17f
--- /dev/null
@@ -0,0 +1,74 @@
+{
+  "routes":{
+    "2001:db8:1000::1\/128":{
+      "isBestRoute":false,
+      "destinationType":"N",
+      "pathType":"E2",
+      "nextHops":[
+        {
+          "interfaceName":"eth-rt3"
+        }
+      ]
+    },
+    "2001:db8:1000::2\/128":{
+      "isBestRoute":true,
+      "destinationType":"N",
+      "pathType":"IA",
+      "nextHops":[
+        {
+          "interfaceName":"eth-rt3"
+        }
+      ]
+    },
+    "2001:db8:1000::3\/128":{
+      "isBestRoute":true,
+      "destinationType":"N",
+      "pathType":"IA",
+      "nextHops":[
+        {
+          "interfaceName":"eth-rt3"
+        }
+      ]
+    },
+    "2001:db8:1000::4\/128":{
+      "isBestRoute":true,
+      "destinationType":"N",
+      "pathType":"IA",
+      "nextHops":[
+        {
+          "interfaceName":"lo"
+        }
+      ]
+    },
+    "2001:db8:1000::5\/128":{
+      "isBestRoute":true,
+      "destinationType":"N",
+      "pathType":"IA",
+      "nextHops":[
+        {
+          "interfaceName":"eth-rt5"
+        }
+      ]
+    },
+    "2001:db8:1000::6\/128":{
+      "isBestRoute":true,
+      "destinationType":"N",
+      "pathType":"IA",
+      "nextHops":[
+        {
+          "interfaceName":"eth-rt3"
+        }
+      ]
+    },
+    "2001:db8:1000::7\/128":{
+      "isBestRoute":false,
+      "destinationType":"N",
+      "pathType":"E2",
+      "nextHops":[
+        {
+          "interfaceName":"eth-rt3"
+        }
+      ]
+    }
+  }
+}
diff --git a/tests/topotests/ospf6_gr_topo1/rt4/show_ipv6_route.json b/tests/topotests/ospf6_gr_topo1/rt4/show_ipv6_route.json
new file mode 100644 (file)
index 0000000..f5212da
--- /dev/null
@@ -0,0 +1,139 @@
+{
+  "2001:db8:1000::1\/128":[
+    {
+      "prefix":"2001:db8:1000::1\/128",
+      "protocol":"ospf6",
+      "vrfId":0,
+      "vrfName":"default",
+      "selected":true,
+      "destSelected":true,
+      "distance":110,
+      "metric":40,
+      "installed":true,
+      "nexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt3",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::2\/128":[
+    {
+      "prefix":"2001:db8:1000::2\/128",
+      "protocol":"ospf6",
+      "vrfId":0,
+      "vrfName":"default",
+      "selected":true,
+      "destSelected":true,
+      "distance":110,
+      "metric":30,
+      "installed":true,
+      "nexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt3",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::3\/128":[
+    {
+      "prefix":"2001:db8:1000::3\/128",
+      "protocol":"ospf6",
+      "vrfId":0,
+      "vrfName":"default",
+      "selected":true,
+      "destSelected":true,
+      "distance":110,
+      "metric":20,
+      "installed":true,
+      "nexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt3",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::4\/128":[
+    {
+      "prefix":"2001:db8:1000::4\/128",
+      "protocol":"ospf6",
+      "vrfId":0,
+      "vrfName":"default",
+      "distance":110,
+      "metric":10,
+      "nexthops":[
+        {
+          "directlyConnected":true,
+          "interfaceName":"lo",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::5\/128":[
+    {
+      "prefix":"2001:db8:1000::5\/128",
+      "protocol":"ospf6",
+      "vrfId":0,
+      "vrfName":"default",
+      "selected":true,
+      "destSelected":true,
+      "distance":110,
+      "metric":20,
+      "installed":true,
+      "nexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt5",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::6\/128":[
+    {
+      "prefix":"2001:db8:1000::6\/128",
+      "protocol":"ospf6",
+      "vrfId":0,
+      "vrfName":"default",
+      "selected":true,
+      "destSelected":true,
+      "distance":110,
+      "metric":30,
+      "installed":true,
+      "nexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt3",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::7\/128":[
+    {
+      "prefix":"2001:db8:1000::7\/128",
+      "protocol":"ospf6",
+      "vrfId":0,
+      "vrfName":"default",
+      "selected":true,
+      "destSelected":true,
+      "distance":110,
+      "metric":40,
+      "installed":true,
+      "nexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt3",
+          "active":true
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/ospf6_gr_topo1/rt4/zebra.conf b/tests/topotests/ospf6_gr_topo1/rt4/zebra.conf
new file mode 100644 (file)
index 0000000..eeea417
--- /dev/null
@@ -0,0 +1,22 @@
+password 1
+hostname rt4
+log file zebra.log
+log commands
+!
+debug zebra event
+debug zebra packet
+debug zebra rib
+debug zebra kernel
+!
+interface lo
+ ip address 4.4.4.4/32
+ ipv6 address 2001:db8:1000::4/128
+!
+interface eth-rt3
+!
+interface eth-rt5
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/ospf6_gr_topo1/rt5/ospf6d.conf b/tests/topotests/ospf6_gr_topo1/rt5/ospf6d.conf
new file mode 100644 (file)
index 0000000..254fea7
--- /dev/null
@@ -0,0 +1,29 @@
+password 1
+hostname rt5
+log file ospf6d.log
+log commands
+!
+debug ospf6 lsa router originate
+debug ospf6 lsa router flooding
+debug ospf6 zebra
+debug ospf6 interface
+debug ospf6 neighbor
+debug ospf6 flooding
+debug ospf6 graceful-restart
+debug ospf6 spf process
+!
+interface lo
+ ipv6 ospf area 2
+ ipv6 ospf network point-to-point
+!
+interface eth-rt4
+ ipv6 ospf network point-to-point
+ ipv6 ospf area 2
+ ipv6 ospf hello-interval 3
+ ipv6 ospf dead-interval 9
+!
+router ospf6
+ ospf6 router-id 5.5.5.5
+ graceful-restart grace-period 120
+ graceful-restart helper enable
+!
diff --git a/tests/topotests/ospf6_gr_topo1/rt5/show_ipv6_ospf_database.json b/tests/topotests/ospf6_gr_topo1/rt5/show_ipv6_ospf_database.json
new file mode 100644 (file)
index 0000000..4a163b9
--- /dev/null
@@ -0,0 +1,100 @@
+{
+  "areaScopedLinkStateDb":[
+    {
+      "areaId":"2",
+      "lsa":[
+        {
+          "type":"Rtr",
+          "advRouter":"4.4.4.4"
+        },
+        {
+          "type":"Rtr",
+          "advRouter":"5.5.5.5"
+        },
+        {
+          "type":"IAP",
+          "advRouter":"4.4.4.4",
+          "payload":"2001:db8:1000::4\/128"
+        },
+        {
+          "type":"IAP",
+          "advRouter":"4.4.4.4",
+          "payload":"2001:db8:1000::2\/128"
+        },
+        {
+          "type":"IAP",
+          "advRouter":"4.4.4.4",
+          "payload":"2001:db8:1000::3\/128"
+        },
+        {
+          "type":"IAP",
+          "advRouter":"4.4.4.4",
+          "payload":"2001:db8:1000::6\/128"
+        },
+        {
+          "type":"IAP",
+          "advRouter":"4.4.4.4",
+          "payload":"2001:db8:1000::1\/128"
+        },
+        {
+          "type":"IAP",
+          "advRouter":"4.4.4.4",
+          "payload":"2001:db8:1000::7\/128"
+        },
+        {
+          "type":"IAR",
+          "advRouter":"4.4.4.4",
+          "payload":"1.1.1.1"
+        },
+        {
+          "type":"IAR",
+          "advRouter":"4.4.4.4",
+          "payload":"7.7.7.7"
+        },
+        {
+          "type":"INP",
+          "advRouter":"5.5.5.5",
+          "payload":"2001:db8:1000::5\/128"
+        }
+      ]
+    }
+  ],
+  "interfaceScopedLinkStateDb":[
+    {
+      "areaId":"2",
+      "interface":"eth-rt4",
+      "lsa":[
+        {
+          "type":"Lnk",
+          "advRouter":"4.4.4.4"
+        },
+        {
+          "type":"Lnk",
+          "advRouter":"5.5.5.5"
+        }
+      ]
+    },
+    {
+      "areaId":"2",
+      "interface":"lo",
+      "lsa":[
+      ]
+    }
+  ],
+  "asScopedLinkStateDb":[
+    {
+      "lsa":[
+        {
+          "type":"ASE",
+          "advRouter":"1.1.1.1",
+          "payload":"2001:db8:1000::1\/128"
+        },
+        {
+          "type":"ASE",
+          "advRouter":"7.7.7.7",
+          "payload":"2001:db8:1000::7\/128"
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/ospf6_gr_topo1/rt5/show_ipv6_ospf_neighbor.json b/tests/topotests/ospf6_gr_topo1/rt5/show_ipv6_ospf_neighbor.json
new file mode 100644 (file)
index 0000000..9b6ac91
--- /dev/null
@@ -0,0 +1,12 @@
+{
+  "neighbors":[
+    {
+      "neighborId":"4.4.4.4",
+      "priority":1,
+      "state":"Full",
+      "ifState":"PointToPoint",
+      "interfaceName":"eth-rt4",
+      "interfaceState":"PointToPoint"
+    }
+  ]
+}
diff --git a/tests/topotests/ospf6_gr_topo1/rt5/show_ipv6_ospf_route.json b/tests/topotests/ospf6_gr_topo1/rt5/show_ipv6_ospf_route.json
new file mode 100644 (file)
index 0000000..a56c326
--- /dev/null
@@ -0,0 +1,74 @@
+{
+  "routes":{
+    "2001:db8:1000::1\/128":{
+      "isBestRoute":false,
+      "destinationType":"N",
+      "pathType":"E2",
+      "nextHops":[
+        {
+          "interfaceName":"eth-rt4"
+        }
+      ]
+    },
+    "2001:db8:1000::2\/128":{
+      "isBestRoute":true,
+      "destinationType":"N",
+      "pathType":"IE",
+      "nextHops":[
+        {
+          "interfaceName":"eth-rt4"
+        }
+      ]
+    },
+    "2001:db8:1000::3\/128":{
+      "isBestRoute":true,
+      "destinationType":"N",
+      "pathType":"IE",
+      "nextHops":[
+        {
+          "interfaceName":"eth-rt4"
+        }
+      ]
+    },
+    "2001:db8:1000::4\/128":{
+      "isBestRoute":true,
+      "destinationType":"N",
+      "pathType":"IE",
+      "nextHops":[
+        {
+          "interfaceName":"eth-rt4"
+        }
+      ]
+    },
+    "2001:db8:1000::5\/128":{
+      "isBestRoute":true,
+      "destinationType":"N",
+      "pathType":"IA",
+      "nextHops":[
+        {
+          "interfaceName":"lo"
+        }
+      ]
+    },
+    "2001:db8:1000::6\/128":{
+      "isBestRoute":true,
+      "destinationType":"N",
+      "pathType":"IE",
+      "nextHops":[
+        {
+          "interfaceName":"eth-rt4"
+        }
+      ]
+    },
+    "2001:db8:1000::7\/128":{
+      "isBestRoute":false,
+      "destinationType":"N",
+      "pathType":"E2",
+      "nextHops":[
+        {
+          "interfaceName":"eth-rt4"
+        }
+      ]
+    }
+  }
+}
diff --git a/tests/topotests/ospf6_gr_topo1/rt5/show_ipv6_route.json b/tests/topotests/ospf6_gr_topo1/rt5/show_ipv6_route.json
new file mode 100644 (file)
index 0000000..5ea4f69
--- /dev/null
@@ -0,0 +1,139 @@
+{
+  "2001:db8:1000::1\/128":[
+    {
+      "prefix":"2001:db8:1000::1\/128",
+      "protocol":"ospf6",
+      "vrfId":0,
+      "vrfName":"default",
+      "selected":true,
+      "destSelected":true,
+      "distance":110,
+      "metric":50,
+      "installed":true,
+      "nexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt4",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::2\/128":[
+    {
+      "prefix":"2001:db8:1000::2\/128",
+      "protocol":"ospf6",
+      "vrfId":0,
+      "vrfName":"default",
+      "selected":true,
+      "destSelected":true,
+      "distance":110,
+      "metric":40,
+      "installed":true,
+      "nexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt4",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::3\/128":[
+    {
+      "prefix":"2001:db8:1000::3\/128",
+      "protocol":"ospf6",
+      "vrfId":0,
+      "vrfName":"default",
+      "selected":true,
+      "destSelected":true,
+      "distance":110,
+      "metric":30,
+      "installed":true,
+      "nexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt4",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::4\/128":[
+    {
+      "prefix":"2001:db8:1000::4\/128",
+      "protocol":"ospf6",
+      "vrfId":0,
+      "vrfName":"default",
+      "selected":true,
+      "destSelected":true,
+      "distance":110,
+      "metric":20,
+      "installed":true,
+      "nexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt4",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::5\/128":[
+    {
+      "prefix":"2001:db8:1000::5\/128",
+      "protocol":"ospf6",
+      "vrfId":0,
+      "vrfName":"default",
+      "distance":110,
+      "metric":10,
+      "nexthops":[
+        {
+          "directlyConnected":true,
+          "interfaceName":"lo",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::6\/128":[
+    {
+      "prefix":"2001:db8:1000::6\/128",
+      "protocol":"ospf6",
+      "vrfId":0,
+      "vrfName":"default",
+      "selected":true,
+      "destSelected":true,
+      "distance":110,
+      "metric":40,
+      "installed":true,
+      "nexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt4",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::7\/128":[
+    {
+      "prefix":"2001:db8:1000::7\/128",
+      "protocol":"ospf6",
+      "vrfId":0,
+      "vrfName":"default",
+      "selected":true,
+      "destSelected":true,
+      "distance":110,
+      "metric":50,
+      "installed":true,
+      "nexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt4",
+          "active":true
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/ospf6_gr_topo1/rt5/zebra.conf b/tests/topotests/ospf6_gr_topo1/rt5/zebra.conf
new file mode 100644 (file)
index 0000000..0cdb90b
--- /dev/null
@@ -0,0 +1,20 @@
+password 1
+hostname rt5
+log file zebra.log
+log commands
+!
+debug zebra event
+debug zebra packet
+debug zebra rib
+debug zebra kernel
+!
+interface lo
+ ip address 5.5.5.5/32
+ ipv6 address 2001:db8:1000::5/128
+!
+interface eth-rt4
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/ospf6_gr_topo1/rt6/ospf6d.conf b/tests/topotests/ospf6_gr_topo1/rt6/ospf6d.conf
new file mode 100644 (file)
index 0000000..b1feb1a
--- /dev/null
@@ -0,0 +1,35 @@
+password 1
+hostname rt6
+log file ospf6d.log
+log commands
+!
+debug ospf6 lsa router originate
+debug ospf6 lsa router flooding
+debug ospf6 zebra
+debug ospf6 interface
+debug ospf6 neighbor
+debug ospf6 flooding
+debug ospf6 graceful-restart
+debug ospf6 spf process
+!
+interface lo
+ ipv6 ospf area 0
+ ipv6 ospf network point-to-point
+!
+interface eth-rt3
+ ipv6 ospf network point-to-point
+ ipv6 ospf area 0
+ ipv6 ospf hello-interval 3
+ ipv6 ospf dead-interval 9
+!
+interface eth-rt7
+ ipv6 ospf network point-to-point
+ ipv6 ospf area 3
+ ipv6 ospf hello-interval 3
+ ipv6 ospf dead-interval 9
+!
+router ospf6
+ ospf6 router-id 6.6.6.6
+ graceful-restart grace-period 120
+ graceful-restart helper enable
+!
diff --git a/tests/topotests/ospf6_gr_topo1/rt6/show_ipv6_ospf_database.json b/tests/topotests/ospf6_gr_topo1/rt6/show_ipv6_ospf_database.json
new file mode 100644 (file)
index 0000000..71872d1
--- /dev/null
@@ -0,0 +1,183 @@
+{
+  "areaScopedLinkStateDb":[
+    {
+      "areaId":"0",
+      "lsa":[
+        {
+          "type":"Rtr",
+          "advRouter":"2.2.2.2"
+        },
+        {
+          "type":"Rtr",
+          "advRouter":"3.3.3.3"
+        },
+        {
+          "type":"Rtr",
+          "advRouter":"3.3.3.3"
+        },
+        {
+          "type":"Rtr",
+          "advRouter":"3.3.3.3"
+        },
+        {
+          "type":"Rtr",
+          "advRouter":"4.4.4.4"
+        },
+        {
+          "type":"Rtr",
+          "advRouter":"6.6.6.6"
+        },
+        {
+          "type":"IAP",
+          "advRouter":"2.2.2.2",
+          "payload":"2001:db8:1000::1\/128"
+        },
+        {
+          "type":"IAP",
+          "advRouter":"4.4.4.4",
+          "payload":"2001:db8:1000::5\/128"
+        },
+        {
+          "type":"IAP",
+          "advRouter":"6.6.6.6",
+          "payload":"2001:db8:1000::7\/128"
+        },
+        {
+          "type":"IAR",
+          "advRouter":"2.2.2.2",
+          "payload":"1.1.1.1"
+        },
+        {
+          "type":"IAR",
+          "advRouter":"6.6.6.6",
+          "payload":"7.7.7.7"
+        },
+        {
+          "type":"INP",
+          "advRouter":"2.2.2.2",
+          "payload":"2001:db8:1000::2\/128"
+        },
+        {
+          "type":"INP",
+          "advRouter":"3.3.3.3",
+          "payload":"2001:db8:1000::3\/128"
+        },
+        {
+          "type":"INP",
+          "advRouter":"4.4.4.4",
+          "payload":"2001:db8:1000::4\/128"
+        },
+        {
+          "type":"INP",
+          "advRouter":"6.6.6.6",
+          "payload":"2001:db8:1000::6\/128"
+        }
+      ]
+    },
+    {
+      "areaId":"3",
+      "lsa":[
+        {
+          "type":"Rtr",
+          "advRouter":"6.6.6.6"
+        },
+        {
+          "type":"Rtr",
+          "advRouter":"7.7.7.7"
+        },
+        {
+          "type":"IAP",
+          "advRouter":"6.6.6.6",
+          "payload":"2001:db8:1000::6\/128"
+        },
+        {
+          "type":"IAP",
+          "advRouter":"6.6.6.6",
+          "payload":"2001:db8:1000::2\/128"
+        },
+        {
+          "type":"IAP",
+          "advRouter":"6.6.6.6",
+          "payload":"2001:db8:1000::3\/128"
+        },
+        {
+          "type":"IAP",
+          "advRouter":"6.6.6.6",
+          "payload":"2001:db8:1000::4\/128"
+        },
+        {
+          "type":"IAP",
+          "advRouter":"6.6.6.6",
+          "payload":"2001:db8:1000::1\/128"
+        },
+        {
+          "type":"IAP",
+          "advRouter":"6.6.6.6",
+          "payload":"2001:db8:1000::5\/128"
+        },
+        {
+          "type":"IAR",
+          "advRouter":"6.6.6.6",
+          "payload":"1.1.1.1"
+        },
+        {
+          "type":"INP",
+          "advRouter":"7.7.7.7",
+          "payload":"2001:db8:1000::7\/128"
+        }
+      ]
+    }
+  ],
+  "interfaceScopedLinkStateDb":[
+    {
+      "areaId":"0",
+      "interface":"eth-rt3",
+      "lsa":[
+        {
+          "type":"Lnk",
+          "advRouter":"3.3.3.3"
+        },
+        {
+          "type":"Lnk",
+          "advRouter":"6.6.6.6"
+        }
+      ]
+    },
+    {
+      "areaId":"0",
+      "interface":"lo",
+      "lsa":[
+      ]
+    },
+    {
+      "areaId":"3",
+      "interface":"eth-rt7",
+      "lsa":[
+        {
+          "type":"Lnk",
+          "advRouter":"6.6.6.6"
+        },
+        {
+          "type":"Lnk",
+          "advRouter":"7.7.7.7"
+        }
+      ]
+    }
+  ],
+  "asScopedLinkStateDb":[
+    {
+      "lsa":[
+        {
+          "type":"ASE",
+          "advRouter":"1.1.1.1",
+          "payload":"2001:db8:1000::1\/128"
+        },
+        {
+          "type":"ASE",
+          "advRouter":"7.7.7.7",
+          "payload":"2001:db8:1000::7\/128"
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/ospf6_gr_topo1/rt6/show_ipv6_ospf_neighbor.json b/tests/topotests/ospf6_gr_topo1/rt6/show_ipv6_ospf_neighbor.json
new file mode 100644 (file)
index 0000000..aba181b
--- /dev/null
@@ -0,0 +1,20 @@
+{
+  "neighbors":[
+    {
+      "neighborId":"3.3.3.3",
+      "priority":1,
+      "state":"Full",
+      "ifState":"PointToPoint",
+      "interfaceName":"eth-rt3",
+      "interfaceState":"PointToPoint"
+    },
+    {
+      "neighborId":"7.7.7.7",
+      "priority":1,
+      "state":"Full",
+      "ifState":"PointToPoint",
+      "interfaceName":"eth-rt7",
+      "interfaceState":"PointToPoint"
+    }
+  ]
+}
diff --git a/tests/topotests/ospf6_gr_topo1/rt6/show_ipv6_ospf_route.json b/tests/topotests/ospf6_gr_topo1/rt6/show_ipv6_ospf_route.json
new file mode 100644 (file)
index 0000000..c9494a9
--- /dev/null
@@ -0,0 +1,74 @@
+{
+  "routes":{
+    "2001:db8:1000::1\/128":{
+      "isBestRoute":false,
+      "destinationType":"N",
+      "pathType":"E2",
+      "nextHops":[
+        {
+          "interfaceName":"eth-rt3"
+        }
+      ]
+    },
+    "2001:db8:1000::2\/128":{
+      "isBestRoute":true,
+      "destinationType":"N",
+      "pathType":"IA",
+      "nextHops":[
+        {
+          "interfaceName":"eth-rt3"
+        }
+      ]
+    },
+    "2001:db8:1000::3\/128":{
+      "isBestRoute":true,
+      "destinationType":"N",
+      "pathType":"IA",
+      "nextHops":[
+        {
+          "interfaceName":"eth-rt3"
+        }
+      ]
+    },
+    "2001:db8:1000::4\/128":{
+      "isBestRoute":true,
+      "destinationType":"N",
+      "pathType":"IA",
+      "nextHops":[
+        {
+          "interfaceName":"eth-rt3"
+        }
+      ]
+    },
+    "2001:db8:1000::5\/128":{
+      "isBestRoute":true,
+      "destinationType":"N",
+      "pathType":"IE",
+      "nextHops":[
+        {
+          "interfaceName":"eth-rt3"
+        }
+      ]
+    },
+    "2001:db8:1000::6\/128":{
+      "isBestRoute":true,
+      "destinationType":"N",
+      "pathType":"IA",
+      "nextHops":[
+        {
+          "interfaceName":"lo"
+        }
+      ]
+    },
+    "2001:db8:1000::7\/128":{
+      "isBestRoute":false,
+      "destinationType":"N",
+      "pathType":"E2",
+      "nextHops":[
+        {
+          "interfaceName":"eth-rt7"
+        }
+      ]
+    }
+  }
+}
diff --git a/tests/topotests/ospf6_gr_topo1/rt6/show_ipv6_route.json b/tests/topotests/ospf6_gr_topo1/rt6/show_ipv6_route.json
new file mode 100644 (file)
index 0000000..862f1ba
--- /dev/null
@@ -0,0 +1,139 @@
+{
+  "2001:db8:1000::1\/128":[
+    {
+      "prefix":"2001:db8:1000::1\/128",
+      "protocol":"ospf6",
+      "vrfId":0,
+      "vrfName":"default",
+      "selected":true,
+      "destSelected":true,
+      "distance":110,
+      "metric":40,
+      "installed":true,
+      "nexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt3",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::2\/128":[
+    {
+      "prefix":"2001:db8:1000::2\/128",
+      "protocol":"ospf6",
+      "vrfId":0,
+      "vrfName":"default",
+      "selected":true,
+      "destSelected":true,
+      "distance":110,
+      "metric":30,
+      "installed":true,
+      "nexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt3",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::3\/128":[
+    {
+      "prefix":"2001:db8:1000::3\/128",
+      "protocol":"ospf6",
+      "vrfId":0,
+      "vrfName":"default",
+      "selected":true,
+      "destSelected":true,
+      "distance":110,
+      "metric":20,
+      "installed":true,
+      "nexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt3",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::4\/128":[
+    {
+      "prefix":"2001:db8:1000::4\/128",
+      "protocol":"ospf6",
+      "vrfId":0,
+      "vrfName":"default",
+      "selected":true,
+      "destSelected":true,
+      "distance":110,
+      "metric":30,
+      "installed":true,
+      "nexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt3",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::5\/128":[
+    {
+      "prefix":"2001:db8:1000::5\/128",
+      "protocol":"ospf6",
+      "vrfId":0,
+      "vrfName":"default",
+      "selected":true,
+      "destSelected":true,
+      "distance":110,
+      "metric":40,
+      "installed":true,
+      "nexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt3",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::6\/128":[
+    {
+      "prefix":"2001:db8:1000::6\/128",
+      "protocol":"ospf6",
+      "vrfId":0,
+      "vrfName":"default",
+      "distance":110,
+      "metric":10,
+      "nexthops":[
+        {
+          "directlyConnected":true,
+          "interfaceName":"lo",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::7\/128":[
+    {
+      "prefix":"2001:db8:1000::7\/128",
+      "protocol":"ospf6",
+      "vrfId":0,
+      "vrfName":"default",
+      "selected":true,
+      "destSelected":true,
+      "distance":110,
+      "metric":20,
+      "installed":true,
+      "nexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt7",
+          "active":true
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/ospf6_gr_topo1/rt6/zebra.conf b/tests/topotests/ospf6_gr_topo1/rt6/zebra.conf
new file mode 100644 (file)
index 0000000..3c2312d
--- /dev/null
@@ -0,0 +1,22 @@
+password 1
+hostname rt6
+log file zebra.log
+log commands
+!
+debug zebra event
+debug zebra packet
+debug zebra rib
+debug zebra kernel
+!
+interface lo
+ ip address 6.6.6.6/32
+ ipv6 address 2001:db8:1000::6/128
+!
+interface eth-rt3
+!
+interface eth-rt7
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/ospf6_gr_topo1/rt7/ospf6d.conf b/tests/topotests/ospf6_gr_topo1/rt7/ospf6d.conf
new file mode 100644 (file)
index 0000000..d032741
--- /dev/null
@@ -0,0 +1,30 @@
+password 1
+hostname rt7
+log file ospf6d.log
+log commands
+!
+debug ospf6 lsa router originate
+debug ospf6 lsa router flooding
+debug ospf6 zebra
+debug ospf6 interface
+debug ospf6 neighbor
+debug ospf6 flooding
+debug ospf6 graceful-restart
+debug ospf6 spf process
+!
+interface lo
+ ipv6 ospf area 3
+ ipv6 ospf network point-to-point
+!
+interface eth-rt6
+ ipv6 ospf network point-to-point
+ ipv6 ospf area 3
+ ipv6 ospf hello-interval 3
+ ipv6 ospf dead-interval 9
+!
+router ospf6
+ ospf6 router-id 7.7.7.7
+ redistribute connected
+ graceful-restart grace-period 120
+ graceful-restart helper enable
+!
diff --git a/tests/topotests/ospf6_gr_topo1/rt7/show_ipv6_ospf_database.json b/tests/topotests/ospf6_gr_topo1/rt7/show_ipv6_ospf_database.json
new file mode 100644 (file)
index 0000000..e70eb57
--- /dev/null
@@ -0,0 +1,95 @@
+{
+  "areaScopedLinkStateDb":[
+    {
+      "areaId":"3",
+      "lsa":[
+        {
+          "type":"Rtr",
+          "advRouter":"6.6.6.6"
+        },
+        {
+          "type":"Rtr",
+          "advRouter":"7.7.7.7"
+        },
+        {
+          "type":"IAP",
+          "advRouter":"6.6.6.6",
+          "payload":"2001:db8:1000::6\/128"
+        },
+        {
+          "type":"IAP",
+          "advRouter":"6.6.6.6",
+          "payload":"2001:db8:1000::2\/128"
+        },
+        {
+          "type":"IAP",
+          "advRouter":"6.6.6.6",
+          "payload":"2001:db8:1000::3\/128"
+        },
+        {
+          "type":"IAP",
+          "advRouter":"6.6.6.6",
+          "payload":"2001:db8:1000::4\/128"
+        },
+        {
+          "type":"IAP",
+          "advRouter":"6.6.6.6",
+          "payload":"2001:db8:1000::1\/128"
+        },
+        {
+          "type":"IAP",
+          "advRouter":"6.6.6.6",
+          "payload":"2001:db8:1000::5\/128"
+        },
+        {
+          "type":"IAR",
+          "advRouter":"6.6.6.6",
+          "payload":"1.1.1.1"
+        },
+        {
+          "type":"INP",
+          "advRouter":"7.7.7.7",
+          "payload":"2001:db8:1000::7\/128"
+        }
+      ]
+    }
+  ],
+  "interfaceScopedLinkStateDb":[
+    {
+      "areaId":"3",
+      "interface":"eth-rt6",
+      "lsa":[
+        {
+          "type":"Lnk",
+          "advRouter":"6.6.6.6"
+        },
+        {
+          "type":"Lnk",
+          "advRouter":"7.7.7.7"
+        }
+      ]
+    },
+    {
+      "areaId":"3",
+      "interface":"lo",
+      "lsa":[
+      ]
+    }
+  ],
+  "asScopedLinkStateDb":[
+    {
+      "lsa":[
+        {
+          "type":"ASE",
+          "advRouter":"1.1.1.1",
+          "payload":"2001:db8:1000::1\/128"
+        },
+        {
+          "type":"ASE",
+          "advRouter":"7.7.7.7",
+          "payload":"2001:db8:1000::7\/128"
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/ospf6_gr_topo1/rt7/show_ipv6_ospf_neighbor.json b/tests/topotests/ospf6_gr_topo1/rt7/show_ipv6_ospf_neighbor.json
new file mode 100644 (file)
index 0000000..5548691
--- /dev/null
@@ -0,0 +1,12 @@
+{
+  "neighbors":[
+    {
+      "neighborId":"6.6.6.6",
+      "priority":1,
+      "state":"Full",
+      "ifState":"PointToPoint",
+      "interfaceName":"eth-rt6",
+      "interfaceState":"PointToPoint"
+    }
+  ]
+}
diff --git a/tests/topotests/ospf6_gr_topo1/rt7/show_ipv6_ospf_route.json b/tests/topotests/ospf6_gr_topo1/rt7/show_ipv6_ospf_route.json
new file mode 100644 (file)
index 0000000..42ca54f
--- /dev/null
@@ -0,0 +1,74 @@
+{
+  "routes":{
+    "2001:db8:1000::1\/128":{
+      "isBestRoute":false,
+      "destinationType":"N",
+      "pathType":"E2",
+      "nextHops":[
+        {
+          "interfaceName":"eth-rt6"
+        }
+      ]
+    },
+    "2001:db8:1000::2\/128":{
+      "isBestRoute":true,
+      "destinationType":"N",
+      "pathType":"IE",
+      "nextHops":[
+        {
+          "interfaceName":"eth-rt6"
+        }
+      ]
+    },
+    "2001:db8:1000::3\/128":{
+      "isBestRoute":true,
+      "destinationType":"N",
+      "pathType":"IE",
+      "nextHops":[
+        {
+          "interfaceName":"eth-rt6"
+        }
+      ]
+    },
+    "2001:db8:1000::4\/128":{
+      "isBestRoute":true,
+      "destinationType":"N",
+      "pathType":"IE",
+      "nextHops":[
+        {
+          "interfaceName":"eth-rt6"
+        }
+      ]
+    },
+    "2001:db8:1000::5\/128":{
+      "isBestRoute":true,
+      "destinationType":"N",
+      "pathType":"IE",
+      "nextHops":[
+        {
+          "interfaceName":"eth-rt6"
+        }
+      ]
+    },
+    "2001:db8:1000::6\/128":{
+      "isBestRoute":true,
+      "destinationType":"N",
+      "pathType":"IE",
+      "nextHops":[
+        {
+          "interfaceName":"eth-rt6"
+        }
+      ]
+    },
+    "2001:db8:1000::7\/128":{
+      "isBestRoute":true,
+      "destinationType":"N",
+      "pathType":"IA",
+      "nextHops":[
+        {
+          "interfaceName":"lo"
+        }
+      ]
+    }
+  }
+}
diff --git a/tests/topotests/ospf6_gr_topo1/rt7/show_ipv6_route.json b/tests/topotests/ospf6_gr_topo1/rt7/show_ipv6_route.json
new file mode 100644 (file)
index 0000000..f5f8f71
--- /dev/null
@@ -0,0 +1,139 @@
+{
+  "2001:db8:1000::1\/128":[
+    {
+      "prefix":"2001:db8:1000::1\/128",
+      "protocol":"ospf6",
+      "vrfId":0,
+      "vrfName":"default",
+      "selected":true,
+      "destSelected":true,
+      "distance":110,
+      "metric":50,
+      "installed":true,
+      "nexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt6",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::2\/128":[
+    {
+      "prefix":"2001:db8:1000::2\/128",
+      "protocol":"ospf6",
+      "vrfId":0,
+      "vrfName":"default",
+      "selected":true,
+      "destSelected":true,
+      "distance":110,
+      "metric":40,
+      "installed":true,
+      "nexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt6",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::3\/128":[
+    {
+      "prefix":"2001:db8:1000::3\/128",
+      "protocol":"ospf6",
+      "vrfId":0,
+      "vrfName":"default",
+      "selected":true,
+      "destSelected":true,
+      "distance":110,
+      "metric":30,
+      "installed":true,
+      "nexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt6",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::4\/128":[
+    {
+      "prefix":"2001:db8:1000::4\/128",
+      "protocol":"ospf6",
+      "vrfId":0,
+      "vrfName":"default",
+      "selected":true,
+      "destSelected":true,
+      "distance":110,
+      "metric":40,
+      "installed":true,
+      "nexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt6",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::5\/128":[
+    {
+      "prefix":"2001:db8:1000::5\/128",
+      "protocol":"ospf6",
+      "vrfId":0,
+      "vrfName":"default",
+      "selected":true,
+      "destSelected":true,
+      "distance":110,
+      "metric":50,
+      "installed":true,
+      "nexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt6",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::6\/128":[
+    {
+      "prefix":"2001:db8:1000::6\/128",
+      "protocol":"ospf6",
+      "vrfId":0,
+      "vrfName":"default",
+      "selected":true,
+      "destSelected":true,
+      "distance":110,
+      "metric":20,
+      "installed":true,
+      "nexthops":[
+        {
+          "afi":"ipv6",
+          "interfaceName":"eth-rt6",
+          "active":true
+        }
+      ]
+    }
+  ],
+  "2001:db8:1000::7\/128":[
+    {
+      "prefix":"2001:db8:1000::7\/128",
+      "protocol":"ospf6",
+      "vrfId":0,
+      "vrfName":"default",
+      "distance":110,
+      "metric":10,
+      "nexthops":[
+        {
+          "directlyConnected":true,
+          "interfaceName":"lo",
+          "active":true
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/topotests/ospf6_gr_topo1/rt7/zebra.conf b/tests/topotests/ospf6_gr_topo1/rt7/zebra.conf
new file mode 100644 (file)
index 0000000..9cc8c29
--- /dev/null
@@ -0,0 +1,22 @@
+password 1
+hostname rt7
+log file zebra.log
+log commands
+!
+debug zebra event
+debug zebra packet
+debug zebra rib
+debug zebra kernel
+!
+interface lo
+ ip address 7.7.7.7/32
+ ipv6 address 2001:db8:1000::7/128
+!
+interface stub1
+!
+interface eth-rt6
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/ospf6_gr_topo1/test_ospf6_gr_topo1.py b/tests/topotests/ospf6_gr_topo1/test_ospf6_gr_topo1.py
new file mode 100755 (executable)
index 0000000..ccbcadb
--- /dev/null
@@ -0,0 +1,381 @@
+#!/usr/bin/env python
+
+#
+# test_ospf6_gr_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_ospf6_gr_topo1.py:
+
+             +---------+
+             |   RT1   |
+             | 1.1.1.1 |
+             +---------+
+                  |eth-rt2
+                  |
+                  |eth-rt1
+             +---------+
+             |   RT2   |
+             | 2.2.2.2 |
+             +---------+
+                  |eth-rt3
+                  |
+                  |eth-rt2
+             +---------+
+             |   RT3   |
+             | 3.3.3.3 |
+             +---------+
+          eth-rt4|  |eth-rt6
+                 |  |
+       +---------+  +--------+
+       |                     |
+       |eth-rt3              |eth-rt3
+  +---------+           +---------+
+  |   RT4   |           |   RT6   |
+  | 4.4.4.4 |           | 6.6.6.6 |
+  +---------+           +---------+
+       |eth-rt5              |eth-rt7
+       |                     |
+       |eth-rt4              |eth-rt6
+  +---------+           +---------+
+  |   RT5   |           |   RT7   |
+  | 5.5.5.5 |           | 7.7.7.7 |
+  +---------+           +---------+
+"""
+
+import os
+import sys
+import pytest
+import json
+from time import sleep
+from functools import partial
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+from lib.common_config import (
+    kill_router_daemons,
+    start_router_daemons,
+)
+
+pytestmark = [pytest.mark.ospf6d]
+
+# Global multi-dimensional dictionary containing all expected outputs
+outputs = {}
+
+
+def build_topo(tgen):
+    #
+    # Define FRR Routers
+    #
+    for router in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6", "rt7"]:
+        tgen.add_router(router)
+
+    #
+    # Define connections
+    #
+    switch = tgen.add_switch("s1")
+    switch.add_link(tgen.gears["rt1"], nodeif="eth-rt2")
+    switch.add_link(tgen.gears["rt2"], nodeif="eth-rt1")
+
+    switch = tgen.add_switch("s2")
+    switch.add_link(tgen.gears["rt1"], nodeif="stub1")
+
+    switch = tgen.add_switch("s3")
+    switch.add_link(tgen.gears["rt2"], nodeif="eth-rt3")
+    switch.add_link(tgen.gears["rt3"], nodeif="eth-rt2")
+
+    switch = tgen.add_switch("s4")
+    switch.add_link(tgen.gears["rt3"], nodeif="eth-rt4")
+    switch.add_link(tgen.gears["rt4"], nodeif="eth-rt3")
+
+    switch = tgen.add_switch("s5")
+    switch.add_link(tgen.gears["rt3"], nodeif="eth-rt6")
+    switch.add_link(tgen.gears["rt6"], nodeif="eth-rt3")
+
+    switch = tgen.add_switch("s6")
+    switch.add_link(tgen.gears["rt4"], nodeif="eth-rt5")
+    switch.add_link(tgen.gears["rt5"], nodeif="eth-rt4")
+
+    switch = tgen.add_switch("s7")
+    switch.add_link(tgen.gears["rt6"], nodeif="eth-rt7")
+    switch.add_link(tgen.gears["rt7"], nodeif="eth-rt6")
+
+    switch = tgen.add_switch("s8")
+    switch.add_link(tgen.gears["rt7"], nodeif="stub1")
+
+
+def setup_module(mod):
+    "Sets up the pytest environment"
+    tgen = Topogen(build_topo, mod.__name__)
+    tgen.start_topology()
+
+    router_list = tgen.routers()
+
+    # For all registered routers, load the zebra configuration file
+    for rname, router in router_list.items():
+        router.load_config(
+            TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
+        )
+        router.load_config(
+            TopoRouter.RD_OSPF6, os.path.join(CWD, "{}/ospf6d.conf".format(rname))
+        )
+
+    tgen.start_router()
+
+
+def teardown_module(mod):
+    "Teardown the pytest environment"
+    tgen = get_topogen()
+
+    # This function tears down the whole topology.
+    tgen.stop_topology()
+
+
+def router_compare_json_output(rname, command, reference, tries):
+    "Compare router JSON output"
+
+    logger.info('Comparing router "%s" "%s" output', rname, command)
+
+    tgen = get_topogen()
+    filename = "{}/{}/{}".format(CWD, rname, reference)
+    expected = json.loads(open(filename).read())
+
+    test_func = partial(topotest.router_json_cmp, tgen.gears[rname], command, expected)
+    _, diff = topotest.run_and_expect(test_func, None, count=tries, wait=0.5)
+    assertmsg = '"{}" JSON output mismatches the expected result'.format(rname)
+    assert diff is None, assertmsg
+
+
+def check_routers(initial_convergence=False, exiting=None, restarting=None):
+    for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6", "rt7"]:
+        # Check the RIB first, which should be preserved across restarts in
+        # all routers of the routing domain.
+        if initial_convergence == True:
+            tries = 240
+        else:
+            tries = 1
+        router_compare_json_output(
+            rname, "show ipv6 route ospf json", "show_ipv6_route.json", tries
+        )
+
+        # Check that all adjacencies are up and running (except when there's
+        # an OSPF instance that is shutting down).
+        if exiting == None:
+            tries = 240
+            router_compare_json_output(
+                rname,
+                "show ipv6 ospf neighbor json",
+                "show_ipv6_ospf_neighbor.json",
+                tries,
+            )
+
+        # Check the OSPF RIB and LSDB.
+        # In the restarting router, wait up to one minute for the LSDB to converge.
+        if exiting != rname:
+            if initial_convergence == True or restarting == rname:
+                tries = 240
+            else:
+                tries = 1
+            router_compare_json_output(
+                rname,
+                "show ipv6 ospf database json",
+                "show_ipv6_ospf_database.json",
+                tries,
+            )
+            router_compare_json_output(
+                rname, "show ipv6 ospf route json", "show_ipv6_ospf_route.json", tries
+            )
+
+
+#
+# Test initial network convergence
+#
+def test_initial_convergence():
+    logger.info("Test: verify initial network convergence")
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    check_routers(initial_convergence=True)
+
+
+#
+# Test rt1 performing a graceful restart
+#
+def test_gr_rt1():
+    logger.info("Test: verify rt1 performing a graceful restart")
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    tgen.net["rt1"].cmd('vtysh -c "graceful-restart prepare ipv6 ospf"')
+    sleep(5)
+    kill_router_daemons(tgen, "rt1", ["ospf6d"], save_config=False)
+    check_routers(exiting="rt1")
+
+    start_router_daemons(tgen, "rt1", ["ospf6d"])
+    check_routers(restarting="rt1")
+
+
+#
+# Test rt2 performing a graceful restart
+#
+def test_gr_rt2():
+    logger.info("Test: verify rt2 performing a graceful restart")
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    tgen.net["rt2"].cmd('vtysh -c "graceful-restart prepare ipv6 ospf"')
+    sleep(5)
+    kill_router_daemons(tgen, "rt2", ["ospf6d"], save_config=False)
+    check_routers(exiting="rt2")
+
+    start_router_daemons(tgen, "rt2", ["ospf6d"])
+    check_routers(restarting="rt2")
+
+
+#
+# Test rt3 performing a graceful restart
+#
+def test_gr_rt3():
+    logger.info("Test: verify rt3 performing a graceful restart")
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    tgen.net["rt3"].cmd('vtysh -c "graceful-restart prepare ipv6 ospf"')
+    sleep(5)
+    kill_router_daemons(tgen, "rt3", ["ospf6d"], save_config=False)
+    check_routers(exiting="rt3")
+
+    start_router_daemons(tgen, "rt3", ["ospf6d"])
+    check_routers(restarting="rt3")
+
+
+#
+# Test rt4 performing a graceful restart
+#
+def test_gr_rt4():
+    logger.info("Test: verify rt4 performing a graceful restart")
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    tgen.net["rt4"].cmd('vtysh -c "graceful-restart prepare ipv6 ospf"')
+    sleep(5)
+    kill_router_daemons(tgen, "rt4", ["ospf6d"], save_config=False)
+    check_routers(exiting="rt4")
+
+    start_router_daemons(tgen, "rt4", ["ospf6d"])
+    check_routers(restarting="rt4")
+
+
+#
+# Test rt5 performing a graceful restart
+#
+def test_gr_rt5():
+    logger.info("Test: verify rt5 performing a graceful restart")
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    tgen.net["rt5"].cmd('vtysh -c "graceful-restart prepare ipv6 ospf"')
+    sleep(5)
+    kill_router_daemons(tgen, "rt5", ["ospf6d"], save_config=False)
+    check_routers(exiting="rt5")
+
+    start_router_daemons(tgen, "rt5", ["ospf6d"])
+    check_routers(restarting="rt5")
+
+
+#
+# Test rt6 performing a graceful restart
+#
+def test_gr_rt6():
+    logger.info("Test: verify rt6 performing a graceful restart")
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    tgen.net["rt6"].cmd('vtysh -c "graceful-restart prepare ipv6 ospf"')
+    sleep(5)
+    kill_router_daemons(tgen, "rt6", ["ospf6d"], save_config=False)
+    check_routers(exiting="rt6")
+
+    start_router_daemons(tgen, "rt6", ["ospf6d"])
+    check_routers(restarting="rt6")
+
+
+#
+# Test rt7 performing a graceful restart
+#
+def test_gr_rt7():
+    logger.info("Test: verify rt7 performing a graceful restart")
+    tgen = get_topogen()
+
+    # Skip if previous fatal error condition is raised
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    tgen.net["rt7"].cmd('vtysh -c "graceful-restart prepare ipv6 ospf"')
+    sleep(5)
+    kill_router_daemons(tgen, "rt7", ["ospf6d"], save_config=False)
+    check_routers(exiting="rt7")
+
+    start_router_daemons(tgen, "rt7", ["ospf6d"])
+    check_routers(restarting="rt7")
+
+
+# Memory leak test template
+def test_memory_leak():
+    "Run the memory leak test and report results."
+    tgen = get_topogen()
+    if not tgen.is_memleak_enabled():
+        pytest.skip("Memory leak test/report is disabled")
+
+    tgen.report_memory_leaks()
+
+
+if __name__ == "__main__":
+    args = ["-s"] + sys.argv[1:]
+    sys.exit(pytest.main(args))
index bea3aeaaf6c05452358e53b8e697ef974147a80d..303bcd014d8743bf45be511e4176db7b998e902b 100644 (file)
@@ -217,8 +217,8 @@ def test_ospfv3_expected_route_types():
         {
             "numberOfIntraAreaRoutes": 1,
             "numberOfInterAreaRoutes": 2,
-            "numberOfExternal1Routes": 4,
-            "numberOfExternal2Routes": 0,
+            "numberOfExternal1Routes": 0,
+            "numberOfExternal2Routes": 3,
         },
     )
 
@@ -330,7 +330,7 @@ def test_nssa_lsa_type7():
     ]
     route = {
         "2001:db8:100::/64": {
-            "pathType": "E1",
+            "pathType": "E2",
             "nextHops": [{"nextHop": "::", "interfaceName": "r4-eth0"}],
         }
     }
@@ -431,6 +431,119 @@ def test_nssa_no_summary():
     assert result is None, assertmsg
 
 
+def test_nssa_default_originate():
+    """
+    Test the following:
+    * A type-7 default route should be originated into the NSSA area
+      when the default-information-originate option is configured;
+    * Once the default-information-originate option is unconfigured, the
+      previously originated Type-7 default route should be removed.
+    """
+    tgen = get_topogen()
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    #
+    # Configure r2 to announce a Type-7 default route.
+    #
+    config = """
+    configure terminal
+    router ospf6
+    no default-information originate
+    area 2 nssa default-information-originate
+    """
+    tgen.gears["r2"].vtysh_cmd(config)
+
+    logger.info("Expecting Type-7 default-route to be added")
+    routes = {"::/0": {}}
+    expect_ospfv3_routes("r4", routes, wait=30, type="external-2")
+
+    #
+    # Configure r2 to stop announcing a Type-7 default route.
+    #
+    config = """
+    configure terminal
+    router ospf6
+    area 2 nssa
+    """
+    tgen.gears["r2"].vtysh_cmd(config)
+
+    logger.info("Expecting Type-7 default route to be removed")
+    test_func = partial(dont_expect_route, "r4", "::/0", type="external-2")
+    _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+    assertmsg = "r4's Type-7 default route still exists"
+    assert result is None, assertmsg
+
+
+def test_area_filters():
+    """
+    Test ABR import/export filters.
+    """
+    tgen = get_topogen()
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    #
+    # Configure import/export filters on r2 (ABR for area 1).
+    #
+    config = """
+    configure terminal
+    ipv6 access-list ACL_IMPORT seq 5 permit 2001:db8:2::/64
+    ipv6 access-list ACL_IMPORT seq 10 deny any
+    ipv6 access-list ACL_EXPORT seq 10 deny any
+    router ospf6
+    area 1 import-list ACL_IMPORT
+    area 1 export-list ACL_EXPORT
+    """
+    tgen.gears["r2"].vtysh_cmd(config)
+
+    logger.info("Expecting inter-area routes to be removed on r1")
+    for route in ["::/0", "2001:db8:3::/64"]:
+        test_func = partial(dont_expect_route, "r1", route, type="inter-area")
+        _, result = topotest.run_and_expect(test_func, None, count=130, wait=1)
+        assertmsg = "{}'s {} inter-area route still exists".format("r1", route)
+        assert result is None, assertmsg
+
+    logger.info("Expecting inter-area routes to be removed on r3")
+    for route in ["2001:db8:1::/64"]:
+        test_func = partial(dont_expect_route, "r3", route, type="inter-area")
+        _, result = topotest.run_and_expect(test_func, None, count=130, wait=1)
+        assertmsg = "{}'s {} inter-area route still exists".format("r3", route)
+        assert result is None, assertmsg
+
+    #
+    # Update the ACLs used by the import/export filters.
+    #
+    config = """
+    configure terminal
+    ipv6 access-list ACL_IMPORT seq 6 permit 2001:db8:3::/64
+    ipv6 access-list ACL_EXPORT seq 5 permit 2001:db8:1::/64
+    """
+    tgen.gears["r2"].vtysh_cmd(config)
+
+    logger.info("Expecting 2001:db8:3::/64 to be re-added on r1")
+    routes = {"2001:db8:3::/64": {}}
+    expect_ospfv3_routes("r1", routes, wait=30, type="inter-area")
+    logger.info("Expecting 2001:db8:1::/64 to be re-added on r3")
+    routes = {"2001:db8:1::/64": {}}
+    expect_ospfv3_routes("r3", routes, wait=30, type="inter-area")
+
+    #
+    # Unconfigure r2's ABR import/export filters.
+    #
+    config = """
+    configure terminal
+    router ospf6
+    no area 1 import-list ACL_IMPORT
+    no area 1 export-list ACL_EXPORT
+    """
+    tgen.gears["r2"].vtysh_cmd(config)
+
+    logger.info("Expecting ::/0 to be re-added on r1")
+    routes = {"::/0": {}}
+    expect_ospfv3_routes("r1", routes, wait=30, type="inter-area")
+
+
 def teardown_module(_mod):
     "Teardown the pytest environment"
     tgen = get_topogen()
index 4137712468ebc95a5f1e8354dd13053ebb7ec040..2c7c6df37ef5f46de48e350f7e4f04c7efd2d949 100644 (file)
@@ -226,7 +226,7 @@ def test_ospf_gr_helper_tc1_p0(request):
 
     step("Configure graceful restart in the DUT")
     ospf_gr_r0 = {
-        "r0": {"ospf": {"graceful-restart": {"helper-only": [], "opaque": True}}}
+        "r0": {"ospf": {"graceful-restart": {"helper enable": [], "opaque": True}}}
     }
     result = create_router_ospf(tgen, topo, ospf_gr_r0)
     assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
@@ -243,7 +243,7 @@ def test_ospf_gr_helper_tc1_p0(request):
     assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
 
     ospf_gr_r1 = {
-        "r1": {"ospf": {"graceful-restart": {"helper-only": [], "opaque": True}}}
+        "r1": {"ospf": {"graceful-restart": {"helper enable": [], "opaque": True}}}
     }
     result = create_router_ospf(tgen, topo, ospf_gr_r1)
     assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
@@ -267,7 +267,7 @@ def test_ospf_gr_helper_tc1_p0(request):
     ospf_gr_r0 = {
         "r0": {
             "ospf": {
-                "graceful-restart": {"helper-only": [], "opaque": True, "delete": True}
+                "graceful-restart": {"helper enable": [], "opaque": True, "delete": True}
             }
         }
     }
@@ -282,7 +282,7 @@ def test_ospf_gr_helper_tc1_p0(request):
     step("Configure gr helper using the router id")
     ospf_gr_r0 = {
         "r0": {
-            "ospf": {"graceful-restart": {"helper-only": ["1.1.1.1"], "opaque": True}}
+            "ospf": {"graceful-restart": {"helper enable": ["1.1.1.1"], "opaque": True}}
         }
     }
     result = create_router_ospf(tgen, topo, ospf_gr_r0)
@@ -307,7 +307,7 @@ def test_ospf_gr_helper_tc1_p0(request):
         "r0": {
             "ospf": {
                 "graceful-restart": {
-                    "helper-only": ["1.1.1.1"],
+                    "helper enable": ["1.1.1.1"],
                     "opaque": True,
                     "delete": True,
                 }
@@ -356,13 +356,13 @@ def test_ospf_gr_helper_tc2_p0(request):
         ospf_covergence is True
     ), "OSPF is not after reset config \n Error:" " {}".format(ospf_covergence)
     ospf_gr_r0 = {
-        "r0": {"ospf": {"graceful-restart": {"helper-only": [], "opaque": True}}}
+        "r0": {"ospf": {"graceful-restart": {"helper enable": [], "opaque": True}}}
     }
     result = create_router_ospf(tgen, topo, ospf_gr_r0)
     assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
 
     ospf_gr_r1 = {
-        "r1": {"ospf": {"graceful-restart": {"helper-only": [], "opaque": True}}}
+        "r1": {"ospf": {"graceful-restart": {"helper enable": [], "opaque": True}}}
     }
     result = create_router_ospf(tgen, topo, ospf_gr_r1)
     assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
@@ -450,13 +450,13 @@ def test_ospf_gr_helper_tc3_p1(request):
     assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
 
     ospf_gr_r0 = {
-        "r0": {"ospf": {"graceful-restart": {"helper-only": [], "opaque": True}}}
+        "r0": {"ospf": {"graceful-restart": {"helper enable": [], "opaque": True}}}
     }
     result = create_router_ospf(tgen, topo, ospf_gr_r0)
     assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
 
     ospf_gr_r1 = {
-        "r1": {"ospf": {"graceful-restart": {"helper-only": [], "opaque": True}}}
+        "r1": {"ospf": {"graceful-restart": {"helper enable": [], "opaque": True}}}
     }
     result = create_router_ospf(tgen, topo, ospf_gr_r1)
     assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
@@ -544,13 +544,13 @@ def test_ospf_gr_helper_tc4_p1(request):
     assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
 
     ospf_gr_r0 = {
-        "r0": {"ospf": {"graceful-restart": {"helper-only": [], "opaque": True}}}
+        "r0": {"ospf": {"graceful-restart": {"helper enable": [], "opaque": True}}}
     }
     result = create_router_ospf(tgen, topo, ospf_gr_r0)
     assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
 
     ospf_gr_r1 = {
-        "r1": {"ospf": {"graceful-restart": {"helper-only": [], "opaque": True}}}
+        "r1": {"ospf": {"graceful-restart": {"helper enable": [], "opaque": True}}}
     }
     result = create_router_ospf(tgen, topo, ospf_gr_r1)
     assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
@@ -606,13 +606,13 @@ def test_ospf_gr_helper_tc7_p1(request):
         ospf_covergence is True
     ), "OSPF is not after reset config \n Error:" " {}".format(ospf_covergence)
     ospf_gr_r0 = {
-        "r0": {"ospf": {"graceful-restart": {"helper-only": [], "opaque": True}}}
+        "r0": {"ospf": {"graceful-restart": {"helper enable": [], "opaque": True}}}
     }
     result = create_router_ospf(tgen, topo, ospf_gr_r0)
     assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
 
     ospf_gr_r1 = {
-        "r1": {"ospf": {"graceful-restart": {"helper-only": [], "opaque": True}}}
+        "r1": {"ospf": {"graceful-restart": {"helper enable": [], "opaque": True}}}
     }
     result = create_router_ospf(tgen, topo, ospf_gr_r1)
     assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
@@ -666,13 +666,13 @@ def test_ospf_gr_helper_tc8_p1(request):
         ospf_covergence is True
     ), "OSPF is not after reset config \n Error:" " {}".format(ospf_covergence)
     ospf_gr_r0 = {
-        "r0": {"ospf": {"graceful-restart": {"helper-only": [], "opaque": True}}}
+        "r0": {"ospf": {"graceful-restart": {"helper enable": [], "opaque": True}}}
     }
     result = create_router_ospf(tgen, topo, ospf_gr_r0)
     assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
 
     ospf_gr_r1 = {
-        "r1": {"ospf": {"graceful-restart": {"helper-only": [], "opaque": True}}}
+        "r1": {"ospf": {"graceful-restart": {"helper enable": [], "opaque": True}}}
     }
     result = create_router_ospf(tgen, topo, ospf_gr_r1)
     assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
index 9c04b74d35e3d9b9172dfb159acfe2048ff5534a..9590a7cadf3a2337ff595902c63c53a198d85a90 100644 (file)
@@ -28,5 +28,5 @@ router ospf
  capability opaque
  redistribute connected
  graceful-restart grace-period 120
- graceful-restart helper-only
+ graceful-restart helper enable
 !
index 922db8c8cc3c64880b60d7e44a328ce1306631a3..4f60d37b184b995d7acd5e029608b5399c635f97 100644 (file)
@@ -33,5 +33,5 @@ router ospf
  router-id 2.2.2.2
  capability opaque
  graceful-restart grace-period 120
- graceful-restart helper-only
+ graceful-restart helper enable
 !
index 51e48f13da6a12058dba5209848439859f47ac02..870878287d53a9e1c80b5da70e370246b79fa6b7 100644 (file)
@@ -39,5 +39,5 @@ router ospf
  router-id 3.3.3.3
  capability opaque
  graceful-restart grace-period 120
- graceful-restart helper-only
+ graceful-restart helper enable
 !
index a54f27a1d7f143e5a8eaa7b5e040de769d0cfd84..0aff1faf2cb4063931acf851477e8b499f2a3efa 100644 (file)
@@ -33,5 +33,5 @@ router ospf
  router-id 4.4.4.4
  capability opaque
  graceful-restart grace-period 120
- graceful-restart helper-only
+ graceful-restart helper enable
 !
index 724af0e97cf58cc56751ac015bd7e62549da7e93..4af89389a53dcec01f18fc10653364900b9434f0 100644 (file)
@@ -27,5 +27,5 @@ router ospf
  router-id 5.5.5.5
  capability opaque
  graceful-restart grace-period 120
- graceful-restart helper-only
+ graceful-restart helper enable
 !
index 0b9b83bcd2f7fbc225bb499df897d1fbaed3276b..2295a75fe7abe8202b94bfcd2cb2a56c1d80063b 100644 (file)
@@ -34,5 +34,5 @@ router ospf
  capability opaque
  area 3 nssa
  graceful-restart grace-period 120
- graceful-restart helper-only
+ graceful-restart helper enable
 !
index 49db254410a85decaed7d0285e13ea3ebe73e1c5..8534eda5a7c959ecd43c16e1b78750cc997778e3 100644 (file)
@@ -29,5 +29,5 @@ router ospf
  redistribute connected
  area 3 nssa
  graceful-restart grace-period 120
- graceful-restart helper-only
+ graceful-restart helper enable
 !
diff --git a/tests/topotests/route_scale/scale_test_common.py b/tests/topotests/route_scale/scale_test_common.py
new file mode 100644 (file)
index 0000000..3557cb4
--- /dev/null
@@ -0,0 +1,215 @@
+#!/usr/bin/env python
+
+#
+# scale_test_common.py
+#
+# Copyright (c) 2020 by
+# Cumulus Networks, Inc.
+# Donald Sharp
+#
+# 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.
+#
+
+"""
+scale_test_common.py: Common routines for testing route scale
+
+"""
+
+import os
+import re
+import sys
+import pytest
+import json
+from functools import partial
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+
+
+#####################################################
+##
+##   Network Topology Definition
+##
+#####################################################
+
+
+def scale_build_common(tgen):
+    "Build function"
+
+    # Populate routers
+    for routern in range(1, 2):
+        tgen.add_router("r{}".format(routern))
+
+    # Populate switches
+    for switchn in range(1, 33):
+        switch = tgen.add_switch("sw{}".format(switchn))
+        switch.add_link(tgen.gears["r1"])
+
+
+def scale_setup_module(module):
+    "Setup topology"
+    tgen = Topogen(scale_build_common, module.__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_SHARP, os.path.join(CWD, "{}/sharpd.conf".format(rname))
+        )
+
+    tgen.start_router()
+    # tgen.mininet_cli()
+
+
+def scale_teardown_module(_mod):
+    "Teardown the pytest environment"
+    tgen = get_topogen()
+
+    # This function tears down the whole topology.
+    tgen.stop_topology()
+
+
+def scale_converge_protocols():
+    "Wait for protocol convergence"
+
+    tgen = get_topogen()
+    # Don't run this test if we have any failure.
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+
+def run_one_setup(r1, s):
+    "Run one ecmp config"
+
+    # Extract params
+    expected_installed = s["expect_in"]
+    expected_removed = s["expect_rem"]
+
+    retries = s["retries"]
+    wait = s["wait"]
+
+    for d in expected_installed["routes"]:
+        if d["type"] == "sharp":
+            count = d["rib"]
+            break
+
+    logger.info("Testing {} routes X {} ecmp".format(count, s["ecmp"]))
+
+    r1.vtysh_cmd(
+        "sharp install route 1.0.0.0 \
+                  nexthop-group {} {}".format(
+            s["nhg"], count
+        ),
+        isjson=False,
+    )
+
+    test_func = partial(
+        topotest.router_json_cmp, r1, "show ip route summary json", expected_installed
+    )
+    success, result = topotest.run_and_expect(test_func, None, retries, wait)
+    assert success, "Route scale test install failed:\n{}".format(result)
+
+    output = r1.vtysh_cmd("sharp data route", isjson=False)
+    logger.info("{} routes X {} ecmp installed".format(count, s["ecmp"]))
+    logger.info(output)
+    r1.vtysh_cmd("sharp remove route 1.0.0.0 {}".format(count), isjson=False)
+    test_func = partial(
+        topotest.router_json_cmp, r1, "show ip route summary json", expected_removed
+    )
+    success, result = topotest.run_and_expect(test_func, None, retries, wait)
+    assert success, "Route scale test remove failed:\n{}".format(result)
+
+    output = r1.vtysh_cmd("sharp data route", isjson=False)
+    logger.info("{} routes x {} ecmp removed".format(count, s["ecmp"]))
+    logger.info(output)
+
+
+def route_install_helper(iter):
+    "Test route install for a variety of ecmp"
+
+    tgen = get_topogen()
+    # Don't run this test if we have any failure.
+    if tgen.routers_have_failure():
+        pytest.skip(tgen.errors)
+
+    r1 = tgen.gears["r1"]
+
+    # Avoid top ecmp case for runs with < 4G memory
+    output = tgen.net.cmd_raises("free")
+    m = re.search("Mem:\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)", output)
+    total_mem = int(m.group(2))
+    if total_mem < 4000000 and iter == 5:
+        logger.info(
+            "Limited memory available: {}, skipping x32 testcase".format(total_mem)
+        )
+        return;
+
+    installed_file = "{}/r1/installed.routes.json".format(CWD)
+    expected_installed = json.loads(open(installed_file).read())
+
+    removed_file = "{}/r1/no.routes.json".format(CWD)
+    expected_removed = json.loads(open(removed_file).read())
+
+    # dict keys of params: ecmp number, corresponding nhg name, timeout,
+    # number of times to wait
+    scale_keys = ["ecmp", "nhg", "wait", "retries", "expect_in", "expect_rem"]
+
+    # Table of defaults, used for timeout values and 'expected' objects
+    scale_defaults = dict(
+        zip(scale_keys, [None, None, 7, 30, expected_installed, expected_removed])
+    )
+
+    # List of params for each step in the test; note extra time given
+    # for the highest ecmp steps. Executing 'show' at scale can be costly
+    # so we widen the interval there too.
+    scale_steps = [
+        [1, "one"],
+        [2, "two"],
+        [4, "four"],
+        [8, "eight"],
+        [16, "sixteen", 10, 40],
+        [32, "thirtytwo", 10, 40],
+    ]
+
+    # Build up a list of dicts with params for each step of the test;
+    # use defaults where the step doesn't supply a value
+    scale_setups = []
+    s = scale_steps[iter]
+
+    d = dict(zip(scale_keys, s))
+    for k in scale_keys:
+        if k not in d:
+            d[k] = scale_defaults[k]
+
+    run_one_setup(r1, d)
+
+
+# Mem leak testcase
+def scale_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()
diff --git a/tests/topotests/route_scale/test_route_scale.py b/tests/topotests/route_scale/test_route_scale.py
deleted file mode 100644 (file)
index fefeccd..0000000
+++ /dev/null
@@ -1,233 +0,0 @@
-#!/usr/bin/env python
-
-#
-# test_route_scale.py
-#
-# Copyright (c) 2020 by
-# Cumulus Networks, Inc.
-# Donald Sharp
-#
-# 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_route_scale.py: Testing route scale
-
-"""
-
-import os
-import re
-import sys
-import pytest
-import json
-from functools import partial
-
-# Save the Current Working Directory to find configuration files.
-CWD = os.path.dirname(os.path.realpath(__file__))
-sys.path.append(os.path.join(CWD, "../"))
-
-# pylint: disable=C0413
-# Import topogen and topotest helpers
-from lib import topotest
-from lib.topogen import Topogen, TopoRouter, get_topogen
-from lib.topolog import logger
-
-
-pytestmark = [pytest.mark.sharpd]
-
-
-#####################################################
-##
-##   Network Topology Definition
-##
-#####################################################
-
-
-def build(tgen):
-    "Build function"
-
-    # Populate routers
-    for routern in range(1, 2):
-        tgen.add_router("r{}".format(routern))
-
-    # Populate switches
-    for switchn in range(1, 33):
-        switch = tgen.add_switch("sw{}".format(switchn))
-        switch.add_link(tgen.gears["r1"])
-
-
-#####################################################
-##
-##   Tests starting
-##
-#####################################################
-
-
-def setup_module(module):
-    "Setup topology"
-    tgen = Topogen(build, module.__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_SHARP, os.path.join(CWD, "{}/sharpd.conf".format(rname))
-        )
-
-    tgen.start_router()
-    # tgen.mininet_cli()
-
-
-def teardown_module(_mod):
-    "Teardown the pytest environment"
-    tgen = get_topogen()
-
-    # This function tears down the whole topology.
-    tgen.stop_topology()
-
-
-def test_converge_protocols():
-    "Wait for protocol convergence"
-
-    tgen = get_topogen()
-    # Don't run this test if we have any failure.
-    if tgen.routers_have_failure():
-        pytest.skip(tgen.errors)
-
-
-def run_one_setup(r1, s):
-    "Run one ecmp config"
-
-    # Extract params
-    expected_installed = s["expect_in"]
-    expected_removed = s["expect_rem"]
-
-    retries = s["retries"]
-    wait = s["wait"]
-
-    for d in expected_installed["routes"]:
-        if d["type"] == "sharp":
-            count = d["rib"]
-            break
-
-    logger.info("Testing {} routes X {} ecmp".format(count, s["ecmp"]))
-
-    r1.vtysh_cmd(
-        "sharp install route 1.0.0.0 \
-                  nexthop-group {} {}".format(
-            s["nhg"], count
-        ),
-        isjson=False,
-    )
-
-    test_func = partial(
-        topotest.router_json_cmp, r1, "show ip route summary json", expected_installed
-    )
-    success, result = topotest.run_and_expect(test_func, None, retries, wait)
-    assert success, "Route scale test install failed:\n{}".format(result)
-
-    output = r1.vtysh_cmd("sharp data route", isjson=False)
-    logger.info("{} routes X {} ecmp installed".format(count, s["ecmp"]))
-    logger.info(output)
-    r1.vtysh_cmd("sharp remove route 1.0.0.0 {}".format(count), isjson=False)
-    test_func = partial(
-        topotest.router_json_cmp, r1, "show ip route summary json", expected_removed
-    )
-    success, result = topotest.run_and_expect(test_func, None, retries, wait)
-    assert success, "Route scale test remove failed:\n{}".format(result)
-
-    output = r1.vtysh_cmd("sharp data route", isjson=False)
-    logger.info("{} routes x {} ecmp removed".format(count, s["ecmp"]))
-    logger.info(output)
-
-
-def test_route_install():
-    "Test route install for a variety of ecmp"
-
-    tgen = get_topogen()
-    # Don't run this test if we have any failure.
-    if tgen.routers_have_failure():
-        pytest.skip(tgen.errors)
-
-    r1 = tgen.gears["r1"]
-
-    installed_file = "{}/r1/installed.routes.json".format(CWD)
-    expected_installed = json.loads(open(installed_file).read())
-
-    removed_file = "{}/r1/no.routes.json".format(CWD)
-    expected_removed = json.loads(open(removed_file).read())
-
-    # dict keys of params: ecmp number, corresponding nhg name, timeout,
-    # number of times to wait
-    scale_keys = ["ecmp", "nhg", "wait", "retries", "expect_in", "expect_rem"]
-
-    # Table of defaults, used for timeout values and 'expected' objects
-    scale_defaults = dict(
-        zip(scale_keys, [None, None, 7, 30, expected_installed, expected_removed])
-    )
-
-    # List of params for each step in the test; note extra time given
-    # for the highest ecmp steps. Executing 'show' at scale can be costly
-    # so we widen the interval there too.
-    scale_steps = [
-        [1, "one"],
-        [2, "two"],
-        [4, "four"],
-        [8, "eight"],
-        [16, "sixteen", 10, 40],
-        [32, "thirtytwo", 10, 40],
-    ]
-
-    # Build up a list of dicts with params for each step of the test;
-    # use defaults where the step doesn't supply a value
-    scale_setups = []
-    for s in scale_steps:
-        d = dict(zip(scale_keys, s))
-        for k in scale_keys:
-            if k not in d:
-                d[k] = scale_defaults[k]
-
-        scale_setups.append(d)
-
-    # Avoid top ecmp case for runs with < 4G memory
-    output = tgen.net.cmd_raises("free")
-    m = re.search("Mem:\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)", output)
-    total_mem = int(m.group(2))
-    if total_mem < 4000000:
-        logger.info(
-            "Limited memory available: {}, skipping x32 testcase".format(total_mem)
-        )
-        scale_setups = scale_setups[0:-1]
-
-    # Run each step using the dicts we've built
-    for s in scale_setups:
-        run_one_setup(r1, s)
-
-
-# Mem leak testcase
-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/route_scale/test_route_scale1.py b/tests/topotests/route_scale/test_route_scale1.py
new file mode 100644 (file)
index 0000000..b563883
--- /dev/null
@@ -0,0 +1,77 @@
+#!/usr/bin/env python
+
+#
+# test_route_scale1.py
+#
+# Copyright (c) 2021 by
+# Nvidia, Inc.
+# Donald Sharp
+#
+# 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_route_scale1.py: Testing route scale
+
+"""
+import os
+import re
+import sys
+import pytest
+import json
+from functools import partial
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+
+from scale_test_common import scale_build_common, scale_setup_module, route_install_helper, scale_test_memory_leak, scale_converge_protocols, scale_teardown_module
+
+
+pytestmark = [pytest.mark.sharpd]
+
+def build(tgen):
+    scale_build_common(tgen)
+
+def setup_module(module):
+    scale_setup_module(module)
+
+def teardown_module(_mod):
+    scale_teardown_module(_mod)
+
+def test_converge_protocols():
+    scale_converge_protocols()
+
+def test_route_install_2nh():
+    route_install_helper(1)
+
+def test_route_install_4nh():
+    route_install_helper(2)
+
+def test_route_install_16nh():
+    route_install_helper(4)
+
+def test_memory_leak():
+    scale_test_memory_leak()
+
+if __name__ == "__main__":
+    args = ["-s"] + sys.argv[1:]
+    sys.exit(pytest.main(args))
diff --git a/tests/topotests/route_scale/test_route_scale2.py b/tests/topotests/route_scale/test_route_scale2.py
new file mode 100644 (file)
index 0000000..7045995
--- /dev/null
@@ -0,0 +1,77 @@
+#!/usr/bin/env python
+
+#
+# test_route_scale2.py
+#
+# Copyright (c) 2022 by
+# Nvidia, Inc.
+# Donald Sharp
+#
+# 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 NVIDIA DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NVIDIA 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_route_scale2.py: Testing route scale
+
+"""
+import os
+import re
+import sys
+import pytest
+import json
+from functools import partial
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+
+from scale_test_common import scale_build_common, scale_setup_module, route_install_helper, scale_test_memory_leak, scale_converge_protocols, scale_teardown_module
+
+
+pytestmark = [pytest.mark.sharpd]
+
+def build(tgen):
+    scale_build_common(tgen)
+
+def setup_module(module):
+    scale_setup_module(module)
+
+def teardown_module(_mod):
+    scale_teardown_module(_mod)
+
+def test_converge_protocols():
+    scale_converge_protocols()
+
+def test_route_install_1nh():
+    route_install_helper(0)
+
+def test_route_install_8nh():
+    route_install_helper(3)
+
+def test_route_install_32nh():
+    route_install_helper(5)
+
+def test_memory_leak():
+    scale_test_memory_leak()
+
+if __name__ == "__main__":
+    args = ["-s"] + sys.argv[1:]
+    sys.exit(pytest.main(args))
index 6e49738f37ab235a47960c25a38f8a46be088f16..0d4f101c7a37a4c875e6999bee1a287fdb733380 100644 (file)
@@ -1,6 +1,2 @@
 [
-  {
-    "name": "loc3",
-    "chunks": []
-  }
 ]
index a18221859ec23ac80bea26f54262cd3ccc31ea99..0d4f101c7a37a4c875e6999bee1a287fdb733380 100644 (file)
@@ -1,8 +1,2 @@
 [
-  {
-    "name": "loc3",
-    "chunks": [
-      "2001:db8:3:3::/64"
-    ]
-  }
 ]
diff --git a/tests/topotests/srv6_locator/expected_chunks6.json b/tests/topotests/srv6_locator/expected_chunks6.json
new file mode 100644 (file)
index 0000000..0d4f101
--- /dev/null
@@ -0,0 +1,2 @@
+[
+]
index 7989f9021bdce56d8edec301f9afc9fec60f4874..4b0f95f7be2e1f9f8062711bad9d7617400f3ad4 100644 (file)
       ]
     },
     {
-      "name":"loc3",
-      "statusUp":false,
-      "chunks":[
+      "name": "loc3",
+      "prefix": "2001:db8:3:3::/64",
+      "statusUp": true,
+      "chunks": [
         {
-          "proto":"sharp"
+          "prefix": "2001:db8:3:3::/64",
+          "proto": "system"
         }
       ]
     }
index 8c512ebc460b2a870f7538c890715af18e574cd9..bcffa004bdd45f53e8a8875deef3265b8ce436f8 100644 (file)
@@ -1,16 +1,5 @@
 {
   "locators":[
-    {
-      "name": "loc1",
-      "prefix": "2001:db8:1:1::/64",
-      "statusUp": true,
-      "chunks": [
-        {
-          "prefix": "2001:db8:1:1::/64",
-          "proto": "system"
-        }
-      ]
-    },
     {
       "name": "loc2",
       "prefix": "2001:db8:2:2::/64",
@@ -29,7 +18,7 @@
       "chunks":[
         {
           "prefix": "2001:db8:3:3::/64",
-          "proto": "sharp"
+          "proto": "system"
         }
       ]
     }
diff --git a/tests/topotests/srv6_locator/expected_locators6.json b/tests/topotests/srv6_locator/expected_locators6.json
new file mode 100644 (file)
index 0000000..66d23d5
--- /dev/null
@@ -0,0 +1,5 @@
+{
+  "locators":[
+  ]
+}
+
index b48cd09bf969303985e558fbdddf0e765c79b4cc..bc5fa409d2f3680bcd248060d7a549a3bf858bca 100755 (executable)
@@ -102,6 +102,10 @@ def test_srv6():
         success, result = topotest.run_and_expect(func, None, count=5, wait=0.5)
         assert result is None, "Failed"
 
+    # FOR DEVELOPER:
+    # If you want to stop some specific line and start interactive shell,
+    # please use tgen.mininet_cli() to start it.
+
     logger.info("Test1 for Locator Configuration")
     check_srv6_locator(router, "expected_locators1.json")
     check_sharpd_chunk(router, "expected_chunks1.json")
@@ -116,25 +120,44 @@ def test_srv6():
     check_srv6_locator(router, "expected_locators3.json")
     check_sharpd_chunk(router, "expected_chunks3.json")
 
-    logger.info("Test4 get chunk for non-exist locator by zclient")
-    router.vtysh_cmd("sharp srv6-manager get-locator-chunk loc3")
+    logger.info("Test4 additional locator loc3")
+    router.vtysh_cmd(
+        """
+        configure terminal
+         segment-routing
+          srv6
+           locators
+            locator loc3
+             prefix 2001:db8:3:3::/64
+        """
+    )
     check_srv6_locator(router, "expected_locators4.json")
     check_sharpd_chunk(router, "expected_chunks4.json")
 
-    logger.info("Test5 Test for Zclient. after locator loc3 was configured")
+    logger.info("Test5 delete locator and chunk is released automatically")
     router.vtysh_cmd(
         """
         configure terminal
          segment-routing
           srv6
            locators
-            locator loc3
-             prefix 2001:db8:3:3::/64
+            no locator loc1
         """
     )
     check_srv6_locator(router, "expected_locators5.json")
     check_sharpd_chunk(router, "expected_chunks5.json")
 
+    logger.info("Test6 delete srv6 all configuration")
+    router.vtysh_cmd(
+        """
+        configure terminal
+         segment-routing
+          no srv6
+        """
+    )
+    check_srv6_locator(router, "expected_locators6.json")
+    check_sharpd_chunk(router, "expected_chunks6.json")
+
 
 if __name__ == "__main__":
     args = ["-s"] + sys.argv[1:]
diff --git a/tests/topotests/zebra_netlink/r1/sharpd.conf b/tests/topotests/zebra_netlink/r1/sharpd.conf
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/tests/topotests/zebra_netlink/r1/v4_route.json b/tests/topotests/zebra_netlink/r1/v4_route.json
deleted file mode 100644 (file)
index 39041eb..0000000
+++ /dev/null
@@ -1,2302 +0,0 @@
-{
-  "2.1.3.7\/32":[
-    {
-      "prefix":"2.1.3.7\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.8\/32":[
-    {
-      "prefix":"2.1.3.8\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.9\/32":[
-    {
-      "prefix":"2.1.3.9\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.10\/32":[
-    {
-      "prefix":"2.1.3.10\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.11\/32":[
-    {
-      "prefix":"2.1.3.11\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.12\/32":[
-    {
-      "prefix":"2.1.3.12\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.13\/32":[
-    {
-      "prefix":"2.1.3.13\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.14\/32":[
-    {
-      "prefix":"2.1.3.14\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.15\/32":[
-    {
-      "prefix":"2.1.3.15\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.16\/32":[
-    {
-      "prefix":"2.1.3.16\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.17\/32":[
-    {
-      "prefix":"2.1.3.17\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.18\/32":[
-    {
-      "prefix":"2.1.3.18\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.19\/32":[
-    {
-      "prefix":"2.1.3.19\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.20\/32":[
-    {
-      "prefix":"2.1.3.20\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.21\/32":[
-    {
-      "prefix":"2.1.3.21\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.22\/32":[
-    {
-      "prefix":"2.1.3.22\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.23\/32":[
-    {
-      "prefix":"2.1.3.23\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.24\/32":[
-    {
-      "prefix":"2.1.3.24\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.25\/32":[
-    {
-      "prefix":"2.1.3.25\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.26\/32":[
-    {
-      "prefix":"2.1.3.26\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.27\/32":[
-    {
-      "prefix":"2.1.3.27\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.28\/32":[
-    {
-      "prefix":"2.1.3.28\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.29\/32":[
-    {
-      "prefix":"2.1.3.29\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.30\/32":[
-    {
-      "prefix":"2.1.3.30\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.31\/32":[
-    {
-      "prefix":"2.1.3.31\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.32\/32":[
-    {
-      "prefix":"2.1.3.32\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.33\/32":[
-    {
-      "prefix":"2.1.3.33\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.34\/32":[
-    {
-      "prefix":"2.1.3.34\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.35\/32":[
-    {
-      "prefix":"2.1.3.35\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.36\/32":[
-    {
-      "prefix":"2.1.3.36\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.37\/32":[
-    {
-      "prefix":"2.1.3.37\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.38\/32":[
-    {
-      "prefix":"2.1.3.38\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.39\/32":[
-    {
-      "prefix":"2.1.3.39\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.40\/32":[
-    {
-      "prefix":"2.1.3.40\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.41\/32":[
-    {
-      "prefix":"2.1.3.41\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.42\/32":[
-    {
-      "prefix":"2.1.3.42\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.43\/32":[
-    {
-      "prefix":"2.1.3.43\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.44\/32":[
-    {
-      "prefix":"2.1.3.44\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.45\/32":[
-    {
-      "prefix":"2.1.3.45\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.46\/32":[
-    {
-      "prefix":"2.1.3.46\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.47\/32":[
-    {
-      "prefix":"2.1.3.47\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.48\/32":[
-    {
-      "prefix":"2.1.3.48\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.49\/32":[
-    {
-      "prefix":"2.1.3.49\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.50\/32":[
-    {
-      "prefix":"2.1.3.50\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.51\/32":[
-    {
-      "prefix":"2.1.3.51\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.52\/32":[
-    {
-      "prefix":"2.1.3.52\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.53\/32":[
-    {
-      "prefix":"2.1.3.53\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.54\/32":[
-    {
-      "prefix":"2.1.3.54\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.55\/32":[
-    {
-      "prefix":"2.1.3.55\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.56\/32":[
-    {
-      "prefix":"2.1.3.56\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.57\/32":[
-    {
-      "prefix":"2.1.3.57\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.58\/32":[
-    {
-      "prefix":"2.1.3.58\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.59\/32":[
-    {
-      "prefix":"2.1.3.59\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.60\/32":[
-    {
-      "prefix":"2.1.3.60\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.61\/32":[
-    {
-      "prefix":"2.1.3.61\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.62\/32":[
-    {
-      "prefix":"2.1.3.62\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.63\/32":[
-    {
-      "prefix":"2.1.3.63\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.64\/32":[
-    {
-      "prefix":"2.1.3.64\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.65\/32":[
-    {
-      "prefix":"2.1.3.65\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.66\/32":[
-    {
-      "prefix":"2.1.3.66\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.67\/32":[
-    {
-      "prefix":"2.1.3.67\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.68\/32":[
-    {
-      "prefix":"2.1.3.68\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.69\/32":[
-    {
-      "prefix":"2.1.3.69\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.70\/32":[
-    {
-      "prefix":"2.1.3.70\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.71\/32":[
-    {
-      "prefix":"2.1.3.71\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.72\/32":[
-    {
-      "prefix":"2.1.3.72\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.73\/32":[
-    {
-      "prefix":"2.1.3.73\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.74\/32":[
-    {
-      "prefix":"2.1.3.74\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.75\/32":[
-    {
-      "prefix":"2.1.3.75\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.76\/32":[
-    {
-      "prefix":"2.1.3.76\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.77\/32":[
-    {
-      "prefix":"2.1.3.77\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.78\/32":[
-    {
-      "prefix":"2.1.3.78\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.79\/32":[
-    {
-      "prefix":"2.1.3.79\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.80\/32":[
-    {
-      "prefix":"2.1.3.80\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.81\/32":[
-    {
-      "prefix":"2.1.3.81\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.82\/32":[
-    {
-      "prefix":"2.1.3.82\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.83\/32":[
-    {
-      "prefix":"2.1.3.83\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.84\/32":[
-    {
-      "prefix":"2.1.3.84\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.85\/32":[
-    {
-      "prefix":"2.1.3.85\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.86\/32":[
-    {
-      "prefix":"2.1.3.86\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.87\/32":[
-    {
-      "prefix":"2.1.3.87\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.88\/32":[
-    {
-      "prefix":"2.1.3.88\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.89\/32":[
-    {
-      "prefix":"2.1.3.89\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.90\/32":[
-    {
-      "prefix":"2.1.3.90\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.91\/32":[
-    {
-      "prefix":"2.1.3.91\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.92\/32":[
-    {
-      "prefix":"2.1.3.92\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.93\/32":[
-    {
-      "prefix":"2.1.3.93\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.94\/32":[
-    {
-      "prefix":"2.1.3.94\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.95\/32":[
-    {
-      "prefix":"2.1.3.95\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.96\/32":[
-    {
-      "prefix":"2.1.3.96\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.97\/32":[
-    {
-      "prefix":"2.1.3.97\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.98\/32":[
-    {
-      "prefix":"2.1.3.98\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.99\/32":[
-    {
-      "prefix":"2.1.3.99\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.100\/32":[
-    {
-      "prefix":"2.1.3.100\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.101\/32":[
-    {
-      "prefix":"2.1.3.101\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.102\/32":[
-    {
-      "prefix":"2.1.3.102\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.103\/32":[
-    {
-      "prefix":"2.1.3.103\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.104\/32":[
-    {
-      "prefix":"2.1.3.104\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.105\/32":[
-    {
-      "prefix":"2.1.3.105\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ],
-  "2.1.3.106\/32":[
-    {
-      "prefix":"2.1.3.106\/32",
-      "protocol":"sharp",
-      "selected":true,
-      "destSelected":true,
-      "distance":150,
-      "metric":0,
-      "installed":true,
-      "table":254,
-      "nexthops":[
-        {
-          "flags":3,
-          "fib":true,
-          "ip":"192.168.1.1",
-          "afi":"ipv4",
-          "interfaceName":"r1-eth0",
-          "active":true,
-          "weight":1
-        }
-      ]
-    }
-  ]
-}
index 05cc0ae4a125b6d960bc24fbcde742a4d1b8546f..ca90c5cb15b17b1c1728bc49d084dcd718158a55 100644 (file)
 test_zebra_netlink.py: Test some basic interactions with kernel using Netlink
 
 """
-
-import os
-import sys
-import pytest
+# pylint: disable=C0413
+import ipaddress
 import json
+import sys
 from functools import partial
 
-# Save the Current Working Directory to find configuration files.
-CWD = os.path.dirname(os.path.realpath(__file__))
-sys.path.append(os.path.join(CWD, "../"))
-
-# pylint: disable=C0413
-# Import topogen and topotest helpers
+import pytest
 from lib import topotest
-from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topogen import Topogen, TopoRouter
 from lib.topolog import logger
 
 
@@ -52,62 +46,73 @@ pytestmark = [pytest.mark.sharpd]
 #####################################################
 
 
-def setup_module(mod):
+@pytest.fixture(scope="module")
+def tgen(request):
     "Sets up the pytest environment"
 
     topodef = {"s1": ("r1")}
-    tgen = Topogen(topodef, mod.__name__)
+    tgen = Topogen(topodef, request.module.__name__)
     tgen.start_topology()
 
+    # Initialize all routers.
     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_SHARP, os.path.join(CWD, "{}/sharpd.conf".format(rname))
-        )
+        router.load_config(TopoRouter.RD_ZEBRA, "zebra.conf")
+        router.load_config(TopoRouter.RD_SHARP)
 
-    # Initialize all routers.
     tgen.start_router()
+    yield tgen
+    tgen.stop_topology()
 
 
-def teardown_module(_mod):
-    "Teardown the pytest environment"
-    tgen = get_topogen()
-
-    # This function tears down the whole topology.
-    tgen.stop_topology()
+@pytest.fixture(autouse=True)
+def skip_on_failure(tgen):
+    if tgen.routers_have_failure():
+        pytest.skip("skipped because of previous test failure")
 
 
-def test_zebra_netlink_batching():
+def test_zebra_netlink_batching(tgen):
     "Test the situation where dataplane fills netlink send buffer entirely."
     logger.info(
         "Test the situation where dataplane fills netlink send buffer entirely."
     )
-    tgen = get_topogen()
-    if tgen.routers_have_failure():
-        pytest.skip("skipped because of previous test failure")
     r1 = tgen.gears["r1"]
 
     # Reduce the size of the buffer to hit the limit.
     r1.vtysh_cmd("conf t\nzebra kernel netlink batch-tx-buf 256 256")
 
-    r1.vtysh_cmd("sharp install routes 2.1.3.7 nexthop 192.168.1.1 100")
-    json_file = "{}/r1/v4_route.json".format(CWD)
-    expected = json.loads(open(json_file).read())
-    test_func = partial(
-        topotest.router_json_cmp,
-        r1,
-        "show ip route json",
-        expected,
-    )
-    _, result = topotest.run_and_expect(test_func, None, count=2, wait=0.5)
-    assertmsg = '"r1" JSON output mismatches'
-    assert result is None, assertmsg
-
-    r1.vtysh_cmd("sharp remove routes 2.1.3.7 100")
+    count = 100
+    r1.vtysh_cmd("sharp install routes 2.1.3.7 nexthop 192.168.1.1 " + str(count))
+
+    # Generate expected results
+    entry = {
+        "protocol": "sharp",
+        "distance": 150,
+        "metric": 0,
+        "installed": True,
+        "table": 254,
+        "nexthops": [
+            {
+                "fib": True,
+                "ip": "192.168.1.1",
+                "afi": "ipv4",
+                "interfaceName": "r1-eth0",
+                "active": True,
+                "weight": 1,
+            }
+        ],
+    }
+
+    match = {}
+    base = int(ipaddress.ip_address(u"2.1.3.7"))
+    for i in range(base, base + count):
+        pfx = str(ipaddress.ip_network((i, 32)))
+        match[pfx] = [dict(entry, prefix=pfx)]
+
+    ok = topotest.router_json_cmp_retry(r1, "show ip route json", match)
+    assert ok, '"r1" JSON output mismatches'
+
+    r1.vtysh_cmd("sharp remove routes 2.1.3.7 " + str(count))
 
 
 if __name__ == "__main__":
index 4a9344fee4604bceebcddefa770c63fc79f2055f..ecfb0857934dd3116f56f2016e0e6a87e4bc565e 100644 (file)
@@ -77,7 +77,7 @@ static int lm_release_chunk_pi(struct zserv *client, uint32_t start,
 
 
 /* use external allocations */
-static void lp_plugin_init()
+static void lp_plugin_init(void)
 {
        /* register our own hooks */
        hook_register(lm_client_connect, test_client_connect);
@@ -86,7 +86,7 @@ static void lp_plugin_init()
        hook_register(lm_release_chunk, lm_release_chunk_pi);
 }
 
-static void lp_plugin_cleanup()
+static void lp_plugin_cleanup(void)
 {
        /* register our own hooks */
        hook_unregister(lm_client_connect, test_client_connect);
@@ -98,7 +98,7 @@ static void lp_plugin_cleanup()
 
 /* tests */
 
-static void test_lp_plugin()
+static void test_lp_plugin(void)
 {
        struct label_manager_chunk *lmc;
 
diff --git a/tools/coccinelle/struct_thread_null.cocci b/tools/coccinelle/struct_thread_null.cocci
new file mode 100644 (file)
index 0000000..4867b44
--- /dev/null
@@ -0,0 +1,9 @@
+@@
+identifier I;
+identifier func =~ "thread_add_";
+struct thread *thread;
+@@
+
+*thread = NULL;
+...
+func
diff --git a/tools/coccinelle/zlog_no_newline.cocci b/tools/coccinelle/zlog_no_newline.cocci
new file mode 100644 (file)
index 0000000..20cf9d2
--- /dev/null
@@ -0,0 +1,20 @@
+// zlog_* should not have \n or \r at the end usually.
+// spatch --sp-file tools/coccinelle/zlog_no_newline.cocci --macro-file tools/cocci.h ./ 2>/dev/null
+
+@r@
+expression fmt;
+identifier func =~ "zlog_";
+position p;
+@@
+(
+  func(fmt)@p
+|
+  func(fmt, ...)@p
+)
+
+@script:python@
+fmt << r.fmt;
+p << r.p;
+@@
+if "\\n" in str(fmt) or "\\r" in str(fmt):
+    print("Newline in logging function detected %s:%s:%s:%s" % (p[0].file, p[0].line, p[0].column, fmt))
diff --git a/tools/frr_babeltrace.py b/tools/frr_babeltrace.py
new file mode 100755 (executable)
index 0000000..3058395
--- /dev/null
@@ -0,0 +1,163 @@
+#!/usr/bin/env python3
+'''
+Usage: frr_babeltrace.py trace_path
+
+FRR pushes data into lttng tracepoints in the least overhead way possible
+i.e. as binary-data/crf_arrays. These traces need to be converted into pretty
+strings for easy greping etc. This script is a babeltrace python plugin for
+that pretty printing.
+
+Copyright (C) 2021  NVIDIA Corporation
+Anuradha Karuppiah
+
+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
+'''
+
+import ipaddress
+import socket
+import sys
+
+import babeltrace
+
+########################### common parsers - start ############################
+def print_ip_addr(field_val):
+    '''
+    pretty print "struct ipaddr"
+    '''
+    if field_val[0] == socket.AF_INET:
+        addr = [str(fv) for fv in field_val[4:8]]
+        return str(ipaddress.IPv4Address('.'.join(addr)))
+
+    if field_val[0] == socket.AF_INET6:
+        tmp = ''.join('%02x' % fb for fb in field_val[4:])
+        addr = []
+        while tmp:
+            addr.append(tmp[:4])
+            tmp = tmp[4:]
+        addr = ':'.join(addr)
+        return str(ipaddress.IPv6Address(addr))
+
+    if not field_val[0]:
+        return ''
+
+    return field_val
+
+
+def print_mac(field_val):
+    '''
+    pretty print "u8 mac[6]"
+    '''
+    return ':'.join('%02x' % fb for fb in field_val)
+
+def print_net_ipv4_addr(field_val):
+    '''
+    pretty print ctf_integer_network ipv4
+    '''
+    return str(ipaddress.IPv4Address(field_val))
+
+def print_esi(field_val):
+    '''
+    pretty print ethernet segment id, esi_t
+    '''
+    return ':'.join('%02x' % fb for fb in field_val)
+
+def get_field_list(event):
+    '''
+    only fetch fields added via the TP, skip metadata etc.
+    '''
+    return event.field_list_with_scope(babeltrace.CTFScope.EVENT_FIELDS)
+
+def parse_event(event, field_parsers):
+    '''
+    Wild card event parser; doesn't make things any prettier
+    '''
+    field_list = get_field_list(event)
+    field_info = {}
+    for field in field_list:
+        if field in field_parsers:
+            field_parser = field_parsers.get(field)
+            field_info[field] = field_parser(event.get(field))
+        else:
+            field_info[field] = event.get(field)
+    print(event.name, field_info)
+############################ common parsers - end #############################
+
+############################ evpn parsers - start #############################
+def parse_frr_bgp_evpn_mac_ip_zsend(event):
+    '''
+    bgp evpn mac-ip parser; raw format -
+    ctf_array(unsigned char, mac, &pfx->prefix.macip_addr.mac,
+            sizeof(struct ethaddr))
+    ctf_array(unsigned char, ip, &pfx->prefix.macip_addr.ip,
+            sizeof(struct ipaddr))
+    ctf_integer_network_hex(unsigned int, vtep, vtep.s_addr)
+    ctf_array(unsigned char, esi, esi, sizeof(esi_t))
+    '''
+    field_parsers = {'ip': print_ip_addr,
+                     'mac': print_mac,
+                     'esi': print_esi,
+                     'vtep': print_net_ipv4_addr}
+
+    parse_event(event, field_parsers)
+
+def parse_frr_bgp_evpn_bum_vtep_zsend(event):
+    '''
+    bgp evpn bum-vtep parser; raw format -
+    ctf_integer_network_hex(unsigned int, vtep,
+            pfx->prefix.imet_addr.ip.ipaddr_v4.s_addr)
+
+    '''
+    field_parsers = {'vtep': print_net_ipv4_addr}
+
+    parse_event(event, field_parsers)
+
+def parse_frr_bgp_evpn_mh_nh_rmac_send(event):
+    '''
+    bgp evpn nh-rmac parser; raw format -
+    ctf_array(unsigned char, rmac, &nh->rmac, sizeof(struct ethaddr))
+    '''
+    field_parsers = {'rmac': print_mac}
+
+    parse_event(event, field_parsers)
+
+############################ evpn parsers - end #############################
+
+def main():
+    '''
+    FRR lttng trace output parser; babel trace plugin
+    '''
+    event_parsers = {'frr_bgp:evpn_mac_ip_zsend':
+                     parse_frr_bgp_evpn_mac_ip_zsend,
+                     'frr_bgp:evpn_bum_vtep_zsend':
+                     parse_frr_bgp_evpn_bum_vtep_zsend,
+                     'frr_bgp:evpn_mh_nh_rmac_zsend':
+                     parse_frr_bgp_evpn_mh_nh_rmac_send}
+
+    # get the trace path from the first command line argument
+    trace_path = sys.argv[1]
+
+    # grab events
+    trace_collection = babeltrace.TraceCollection()
+    trace_collection.add_traces_recursive(trace_path, 'ctf')
+
+    for event in trace_collection.events:
+        if event.name in event_parsers:
+            event_parser = event_parsers.get(event.name)
+            event_parser(event)
+        else:
+            parse_event(event, {})
+
+if __name__ == '__main__':
+    main()
index f51d4a4ec9a845a84e9d9117bcbc41ef2b5ae4d0..b280cc15b105748b015571a6fdb6036e100fbe65 100644 (file)
@@ -61,9 +61,22 @@ void permute(struct graph_node *start)
        struct cmd_token *stok = start->data;
        struct graph_node *gnn;
        struct listnode *ln;
+       bool is_neg = false;
 
        // recursive dfs
        listnode_add(position, start);
+
+       for (ALL_LIST_ELEMENTS_RO(position, ln, gnn)) {
+               struct cmd_token *tok = gnn->data;
+
+               if (tok->type == WORD_TKN && !strcmp(tok->text, "no")) {
+                       is_neg = true;
+                       break;
+               }
+               if (tok->type < SPECIAL_TKN)
+                       break;
+       }
+
        for (unsigned int i = 0; i < vector_active(start->to); i++) {
                struct graph_node *gn = vector_slot(start->to, i);
                struct cmd_token *tok = gn->data;
@@ -82,6 +95,9 @@ void permute(struct graph_node *start)
                        fprintf(stdout, "\n");
                } else {
                        bool skip = false;
+
+                       if (tok->type == NEG_ONLY_TKN && !is_neg)
+                               continue;
                        if (stok->type == FORK_TKN && tok->type != FORK_TKN)
                                for (ALL_LIST_ELEMENTS_RO(position, ln, gnn))
                                        if (gnn == gn) {
index fbfb640b2aa60e682bb7512c2a40d888d6baebed..88f46bf5754ba5cfe33d7b97856fad5b1205dcfd 100644 (file)
    ...
    fun:sqlite3_step
 }
+{
+   <libyang2 prefix_data stuff>
+   Memcheck:Leak
+   fun:calloc
+   fun:ly_store_prefix_data
+   ...
+   fun:yang_module_load
+}
+{
+   <libyang2 lys_compile_type_union>
+   Memcheck:Leak
+   fun:realloc
+   fun:lys_compile_type_union
+   ...
+   fun:yang_module_load
+}
+{
+   <libyang2 pcre2_compile>
+   Memcheck:Leak
+   fun:malloc
+   fun:pcre2_compile_8
+   ...
+   fun:yang_module_load
+}
+{
+   <libyang2 lys_compile_type_patterns malloc>
+   Memcheck:Leak
+   fun:malloc
+   fun:lys_compile_type_patterns
+   ...
+   fun:yang_module_load
+}
+{
+   <libyang2 lys_compile_type_patterns calloc>
+   Memcheck:Leak
+   fun:calloc
+   fun:lys_compile_type_patterns
+   ...
+   fun:yang_module_load
+}
+{
+   <libyang2 lys_compile_type>
+   Memcheck:Leak
+   fun:calloc
+   fun:lys_compile_type
+   ...
+   fun:yang_module_load
+}
index 86cf8c9657d13eb5bebe2c876a09fef75dbd419e..334bd7affad83f297ce92f1dec9d29ac19c9e210 100755 (executable)
@@ -42,11 +42,13 @@ sub scan_file {
 
     $cppadd = $fabricd ? "-DFABRICD=1" : "";
 
-    open (FH, "@CPP@ -P -std=gnu11 -DHAVE_CONFIG_H -DVTYSH_EXTRACT_PL -Ivtysh/@top_builddir@ -Ivtysh/@top_srcdir@ -Ivtysh/@top_srcdir@/lib -Ivtysh/@top_builddir@/lib -Ivtysh/@top_srcdir@/bgpd -Ivtysh/@top_srcdir@/bgpd/rfapi @LUA_INCLUDE@ @CPPFLAGS@ @LIBYANG_CFLAGS@ $cppadd $file |");
+    $command_line = "@CPP@ -P -std=gnu11 -DHAVE_CONFIG_H -DVTYSH_EXTRACT_PL -Ivtysh/@top_builddir@ -Ivtysh/@top_srcdir@ -Ivtysh/@top_srcdir@/lib -Ivtysh/@top_builddir@/lib -Ivtysh/@top_srcdir@/bgpd -Ivtysh/@top_srcdir@/bgpd/rfapi @LUA_INCLUDE@ @CPPFLAGS@ @LIBYANG_CFLAGS@ $cppadd $file |";
+    open (FH, $command_line)
+       || die "Open to the pipeline failed: $!\n\nCommand Issued:\n$command_line";
     local $/; undef $/;
     $line = <FH>;
     if (!close (FH)) {
-       printf "File: $file failed to compile, when extracting cli from it please inspect\n"
+       die "File: $file failed to compile:\n$!\nwhen extracting cli from it please inspect\n"
     }
 
     # ?: makes a group non-capturing
index b74360c75fc13d830169f9201d0554d41bbd8394..beb7045a7d43870da2cef8d3b09f62437a4bb9a7 100644 (file)
@@ -602,7 +602,8 @@ static int vtysh_execute_func(const char *line, int pager)
                                                fprintf(stderr,
                                                        "%s is not running\n",
                                                        vtysh_client[i].name);
-                                               continue;
+                                               cmd_stat = CMD_ERR_NO_DAEMON;
+                                               break;
                                        }
                                }
                                cmd_stat = vtysh_client_execute(
@@ -611,7 +612,7 @@ static int vtysh_execute_func(const char *line, int pager)
                                        break;
                        }
                }
-               if (cmd_stat != CMD_SUCCESS)
+               if (cmd_stat != CMD_SUCCESS && cmd_stat != CMD_ERR_NO_DAEMON)
                        break;
 
                if (cmd->func)
index 2e1d7c5bad828fdf34dcb6b3d55f697d03e1a46a..7d663196690f417cc3d70dcf1341dda4a73df5e9 100644 (file)
@@ -286,7 +286,6 @@ void vtysh_config_parse_line(void *arg, const char *line)
                        } else if (config->index == RMAP_NODE
                                   || config->index == INTERFACE_NODE
                                   || config->index == VTY_NODE
-                                  || config->index == VRF_NODE
                                   || config->index == NH_GROUP_NODE)
                                config_add_line_uniq(config->line, line);
                        else
index d0b4be81d4825ca76c18473ff71436140a7f63e9..b09d0924588467e1678bd027675f5c08f90c7305 100644 (file)
@@ -68,6 +68,7 @@ DEFINE_MTYPE_STATIC(WATCHFRR, WATCHFRR_DAEMON, "watchfrr daemon entry");
 struct thread_master *master;
 
 static bool watch_only = false;
+const char *pathspace;
 
 typedef enum {
        PHASE_NONE = 0,
@@ -361,7 +362,6 @@ static int restart_kill(struct thread *t_kill)
                (long)delay.tv_sec, (restart->kills ? SIGKILL : SIGTERM));
        kill(-restart->pid, (restart->kills ? SIGKILL : SIGTERM));
        restart->kills++;
-       restart->t_kill = NULL;
        thread_add_timer(master, restart_kill, restart, gs.restart_timeout,
                         &restart->t_kill);
        return 0;
@@ -495,7 +495,6 @@ static int run_job(struct restart_info *restart, const char *cmdtype,
                char cmd[strlen(command) + strlen(restart->name) + 1];
                snprintf(cmd, sizeof(cmd), command, restart->name);
                if ((restart->pid = run_background(cmd)) > 0) {
-                       restart->t_kill = NULL;
                        thread_add_timer(master, restart_kill, restart,
                                         gs.restart_timeout, &restart->t_kill);
                        restart->what = cmdtype;
@@ -833,10 +832,8 @@ static int try_connect(struct daemon *dmn)
                        zlog_debug("%s: connection in progress", dmn->name);
                dmn->state = DAEMON_CONNECTING;
                dmn->fd = sock;
-               dmn->t_write = NULL;
                thread_add_write(master, check_connect, dmn, dmn->fd,
                                 &dmn->t_write);
-               dmn->t_wakeup = NULL;
                thread_add_timer(master, wakeup_connect_hanging, dmn,
                                 gs.timeout, &dmn->t_wakeup);
                SET_READ_HANDLER(dmn);
@@ -1022,7 +1019,6 @@ static int wakeup_send_echo(struct thread *t_wakeup)
                daemon_down(dmn, why);
        } else {
                gettimeofday(&dmn->echo_sent, NULL);
-               dmn->t_wakeup = NULL;
                thread_add_timer(master, wakeup_no_answer, dmn, gs.timeout,
                                 &dmn->t_wakeup);
        }
@@ -1269,7 +1265,6 @@ static void watchfrr_init(int argc, char **argv)
                gs.numdaemons++;
                gs.numdown++;
                dmn->fd = -1;
-               dmn->t_wakeup = NULL;
                thread_add_timer_msec(master, wakeup_init, dmn, 0,
                                      &dmn->t_wakeup);
                dmn->restart.interval = gs.min_restart_interval;
@@ -1519,8 +1514,15 @@ int main(int argc, char **argv)
        else
                unsetenv("FRR_PATHSPACE");
 
+       /*
+        * when watchfrr_di.pathspace is read, if it is not specified
+        * pathspace is NULL as expected
+        */
+       pathspace = watchfrr_di.pathspace;
+
        if (netns_en && !netns)
                netns = watchfrr_di.pathspace;
+
        if (netns_en && netns && netns[0])
                netns_setup(netns);
 
index 4df1bf74afb78857464704100b9f958c584e6980..4987a932c03c484dee4dd62db085839a32e38510 100644 (file)
 
 DECLARE_MGROUP(WATCHFRR);
 
+/*
+ * This is the name of the pathspace we are in `-N XXX`
+ * If the default then this is NULL
+ */
+extern const char *pathspace;
+
 extern void watchfrr_vty_init(void);
 
 extern pid_t integrated_write_pid;
index eda4f5d516bf3785ea2ca174ddad88bb64e62d0e..1492ee37b600073b443cf3d2aea8eba5e39657a2 100644 (file)
@@ -105,7 +105,10 @@ DEFUN(config_write_integrated,
 
        /* don't allow the user to pass parameters, we're root here!
         * should probably harden vtysh at some point too... */
-       execl(VTYSH_BIN_PATH, "vtysh", "-w", NULL);
+       if (pathspace)
+               execl(VTYSH_BIN_PATH, "vtysh", "-N", pathspace, "-w", NULL);
+       else
+               execl(VTYSH_BIN_PATH, "vtysh", "-w", NULL);
 
        /* unbuffered write; we just messed with stdout... */
        char msg[512];
index 2df2e2958e92499b2be4af5c59ff5e855e53e993..adcbacbfea5e4663fe980b554244b2fdba1324c1 100644 (file)
@@ -61,7 +61,7 @@ module frr-nexthop {
     type union {
       type inet:ip-address;
       type string {
-        pattern "";
+        length "0";
       }
     }
   }
index e1dd0dbdff048ab4470988a42db5038c18a88ec2..80d434bafc7d45d17856dde3852b1de7dd86c531 100644 (file)
@@ -73,8 +73,7 @@ static void connected_announce(struct interface *ifp, struct connected *ifc)
        if (!ifc)
                return;
 
-       if (!if_is_loopback(ifp) && ifc->address->family == AF_INET &&
-           !IS_ZEBRA_IF_VRF(ifp)) {
+       if (!if_is_loopback_or_vrf(ifp) && ifc->address->family == AF_INET) {
                if (ifc->address->prefixlen == IPV4_MAX_BITLEN)
                        SET_FLAG(ifc->flags, ZEBRA_IFA_UNNUMBERED);
                else
@@ -307,9 +306,10 @@ void connected_up(struct interface *ifp, struct connected *ifc)
 }
 
 /* Add connected IPv4 route to the interface. */
-void connected_add_ipv4(struct interface *ifp, int flags, struct in_addr *addr,
-                       uint16_t prefixlen, struct in_addr *dest,
-                       const char *label, uint32_t metric)
+void connected_add_ipv4(struct interface *ifp, int flags,
+                       const struct in_addr *addr, uint16_t prefixlen,
+                       const struct in_addr *dest, const char *label,
+                       uint32_t metric)
 {
        struct prefix_ipv4 *p;
        struct connected *ifc;
@@ -502,8 +502,8 @@ static void connected_delete_helper(struct connected *ifc, struct prefix *p)
 
 /* Delete connected IPv4 route to the interface. */
 void connected_delete_ipv4(struct interface *ifp, int flags,
-                          struct in_addr *addr, uint16_t prefixlen,
-                          struct in_addr *dest)
+                          const struct in_addr *addr, uint16_t prefixlen,
+                          const struct in_addr *dest)
 {
        struct prefix p, d;
        struct connected *ifc;
@@ -527,8 +527,9 @@ void connected_delete_ipv4(struct interface *ifp, int flags,
 }
 
 /* Add connected IPv6 route to the interface. */
-void connected_add_ipv6(struct interface *ifp, int flags, struct in6_addr *addr,
-                       struct in6_addr *dest, uint16_t prefixlen,
+void connected_add_ipv6(struct interface *ifp, int flags,
+                       const struct in6_addr *addr,
+                       const struct in6_addr *dest, uint16_t prefixlen,
                        const char *label, uint32_t metric)
 {
        struct prefix_ipv6 *p;
@@ -589,8 +590,9 @@ void connected_add_ipv6(struct interface *ifp, int flags, struct in6_addr *addr,
        connected_update(ifp, ifc);
 }
 
-void connected_delete_ipv6(struct interface *ifp, struct in6_addr *address,
-                          struct in6_addr *dest, uint16_t prefixlen)
+void connected_delete_ipv6(struct interface *ifp,
+                          const struct in6_addr *address,
+                          const struct in6_addr *dest, uint16_t prefixlen)
 {
        struct prefix p, d;
        struct connected *ifc;
index 14f6cb2db013d5ee3245aca7d7e3e15d0e7ea1c0..3ed9f6d5b9afe1abc76c4ead8dcf32bc2af60915 100644 (file)
@@ -39,13 +39,14 @@ extern struct connected *connected_check_ptp(struct interface *ifp,
                                             union prefixconstptr d);
 
 extern void connected_add_ipv4(struct interface *ifp, int flags,
-                              struct in_addr *addr, uint16_t prefixlen,
-                              struct in_addr *dest, const char *label,
+                              const struct in_addr *addr, uint16_t prefixlen,
+                              const struct in_addr *dest, const char *label,
                               uint32_t metric);
 
 extern void connected_delete_ipv4(struct interface *ifp, int flags,
-                                 struct in_addr *addr, uint16_t prefixlen,
-                                 struct in_addr *dest);
+                                 const struct in_addr *addr,
+                                 uint16_t prefixlen,
+                                 const struct in_addr *dest);
 
 extern void connected_delete_ipv4_unnumbered(struct connected *ifc);
 
@@ -53,12 +54,13 @@ extern void connected_up(struct interface *ifp, struct connected *ifc);
 extern void connected_down(struct interface *ifp, struct connected *ifc);
 
 extern void connected_add_ipv6(struct interface *ifp, int flags,
-                              struct in6_addr *address, struct in6_addr *dest,
-                              uint16_t prefixlen, const char *label,
-                              uint32_t metric);
+                              const struct in6_addr *address,
+                              const struct in6_addr *dest, uint16_t prefixlen,
+                              const char *label, uint32_t metric);
 extern void connected_delete_ipv6(struct interface *ifp,
-                                 struct in6_addr *address,
-                                 struct in6_addr *dest, uint16_t prefixlen);
+                                 const struct in6_addr *address,
+                                 const struct in6_addr *dest,
+                                 uint16_t prefixlen);
 
 extern int connected_is_unnumbered(struct interface *);
 
index 8b3b788b727bb5a6636970441fe01bb3d40cd3d7..15645d024df530ff42d29637bb1c10adc8d1fb1b 100644 (file)
@@ -1021,7 +1021,8 @@ static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup)
        if (IS_ZEBRA_IF_BOND(ifp))
                zebra_l2if_update_bond(ifp, true);
        if (IS_ZEBRA_IF_BRIDGE_SLAVE(ifp))
-               zebra_l2if_update_bridge_slave(ifp, bridge_ifindex, ns_id);
+               zebra_l2if_update_bridge_slave(ifp, bridge_ifindex, ns_id,
+                                              ZEBRA_BRIDGE_NO_ACTION);
        else if (IS_ZEBRA_IF_BOND_SLAVE(ifp))
                zebra_l2if_update_bond_slave(ifp, bond_ifindex, !!bypass);
 
@@ -1088,7 +1089,7 @@ int interface_lookup_netlink(struct zebra_ns *zns)
        if (ret < 0)
                return ret;
        ret = netlink_parse_info(netlink_interface, netlink_cmd, &dp_info, 0,
-                                1);
+                                true);
        if (ret < 0)
                return ret;
 
@@ -1098,17 +1099,7 @@ int interface_lookup_netlink(struct zebra_ns *zns)
        if (ret < 0)
                return ret;
        ret = netlink_parse_info(netlink_interface, netlink_cmd, &dp_info, 0,
-                                0);
-       if (ret < 0)
-               return ret;
-
-       /* Get interface information - for bridge interfaces. */
-       ret = netlink_request_intf_addr(netlink_cmd, AF_BRIDGE, RTM_GETLINK,
-                                       RTEXT_FILTER_BRVLAN);
-       if (ret < 0)
-               return ret;
-       ret = netlink_parse_info(netlink_interface, netlink_cmd, &dp_info, 0,
-                                0);
+                                true);
        if (ret < 0)
                return ret;
 
@@ -1137,7 +1128,7 @@ static int interface_addr_lookup_netlink(struct zebra_ns *zns)
        if (ret < 0)
                return ret;
        ret = netlink_parse_info(netlink_interface_addr, netlink_cmd, &dp_info,
-                                0, 1);
+                                0, true);
        if (ret < 0)
                return ret;
 
@@ -1146,7 +1137,7 @@ static int interface_addr_lookup_netlink(struct zebra_ns *zns)
        if (ret < 0)
                return ret;
        ret = netlink_parse_info(netlink_interface_addr, netlink_cmd, &dp_info,
-                                0, 1);
+                                0, true);
        if (ret < 0)
                return ret;
 
@@ -1177,7 +1168,7 @@ int kernel_interface_set_master(struct interface *master,
        nl_attr_put32(&req.n, sizeof(req), IFLA_LINK, slave->ifindex);
 
        return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns,
-                           0);
+                           false);
 }
 
 /* Interface address modification. */
@@ -1443,7 +1434,6 @@ int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup)
                                              NULL, ifa->ifa_prefixlen);
        }
 
-
        /*
         * Linux kernel does not send route delete on interface down/addr del
         * so we have to re-process routes it owns (i.e. kernel routes)
@@ -1454,6 +1444,215 @@ int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup)
        return 0;
 }
 
+/*
+ * Parse and validate an incoming interface address change message,
+ * generating a dplane context object.
+ * This runs in the dplane pthread; the context is enqueued to the
+ * main pthread for processing.
+ */
+int netlink_interface_addr_dplane(struct nlmsghdr *h, ns_id_t ns_id,
+                                 int startup /*ignored*/)
+{
+       int len;
+       struct ifaddrmsg *ifa;
+       struct rtattr *tb[IFA_MAX + 1];
+       void *addr;
+       void *broad;
+       char *label = NULL;
+       uint32_t metric = METRIC_MAX;
+       uint32_t kernel_flags = 0;
+       struct zebra_dplane_ctx *ctx;
+       struct prefix p;
+
+       ifa = NLMSG_DATA(h);
+
+       /* Validate message types */
+       if (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR)
+               return 0;
+
+       if (ifa->ifa_family != AF_INET && ifa->ifa_family != AF_INET6) {
+               if (IS_ZEBRA_DEBUG_KERNEL)
+                       zlog_debug("%s: %s: Invalid address family: %u",
+                                  __func__, nl_msg_type_to_str(h->nlmsg_type),
+                                  ifa->ifa_family);
+               return 0;
+       }
+
+       len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct ifaddrmsg));
+       if (len < 0) {
+               if (IS_ZEBRA_DEBUG_KERNEL)
+                       zlog_debug("%s: %s: netlink msg bad size: %d %zu",
+                                  __func__, nl_msg_type_to_str(h->nlmsg_type),
+                                  h->nlmsg_len,
+                                  (size_t)NLMSG_LENGTH(
+                                          sizeof(struct ifaddrmsg)));
+               return -1;
+       }
+
+       netlink_parse_rtattr(tb, IFA_MAX, IFA_RTA(ifa), len);
+
+       /* Flags passed through */
+       if (tb[IFA_FLAGS])
+               kernel_flags = *(int *)RTA_DATA(tb[IFA_FLAGS]);
+       else
+               kernel_flags = ifa->ifa_flags;
+
+       if (IS_ZEBRA_DEBUG_KERNEL) { /* remove this line to see initial ifcfg */
+               char buf[PREFIX_STRLEN];
+
+               zlog_debug("%s: %s nsid %u ifindex %u flags 0x%x:", __func__,
+                          nl_msg_type_to_str(h->nlmsg_type), ns_id,
+                          ifa->ifa_index, kernel_flags);
+               if (tb[IFA_LOCAL])
+                       zlog_debug("  IFA_LOCAL     %s/%d",
+                                  inet_ntop(ifa->ifa_family,
+                                            RTA_DATA(tb[IFA_LOCAL]), buf,
+                                            sizeof(buf)),
+                                  ifa->ifa_prefixlen);
+               if (tb[IFA_ADDRESS])
+                       zlog_debug("  IFA_ADDRESS   %s/%d",
+                                  inet_ntop(ifa->ifa_family,
+                                            RTA_DATA(tb[IFA_ADDRESS]), buf,
+                                            sizeof(buf)),
+                                  ifa->ifa_prefixlen);
+               if (tb[IFA_BROADCAST])
+                       zlog_debug("  IFA_BROADCAST %s/%d",
+                                  inet_ntop(ifa->ifa_family,
+                                            RTA_DATA(tb[IFA_BROADCAST]), buf,
+                                            sizeof(buf)),
+                                  ifa->ifa_prefixlen);
+               if (tb[IFA_LABEL])
+                       zlog_debug("  IFA_LABEL     %s",
+                                  (const char *)RTA_DATA(tb[IFA_LABEL]));
+
+               if (tb[IFA_CACHEINFO]) {
+                       struct ifa_cacheinfo *ci = RTA_DATA(tb[IFA_CACHEINFO]);
+
+                       zlog_debug("  IFA_CACHEINFO pref %d, valid %d",
+                                  ci->ifa_prefered, ci->ifa_valid);
+               }
+       }
+
+       /* Validate prefix length */
+
+       if (ifa->ifa_family == AF_INET
+           && ifa->ifa_prefixlen > IPV4_MAX_BITLEN) {
+               if (IS_ZEBRA_DEBUG_KERNEL)
+                       zlog_debug("%s: %s: Invalid prefix length: %u",
+                                  __func__, nl_msg_type_to_str(h->nlmsg_type),
+                                  ifa->ifa_prefixlen);
+               return -1;
+       }
+
+       if (ifa->ifa_family == AF_INET6) {
+               if (ifa->ifa_prefixlen > IPV6_MAX_BITLEN) {
+                       if (IS_ZEBRA_DEBUG_KERNEL)
+                               zlog_debug("%s: %s: Invalid prefix length: %u",
+                                          __func__,
+                                          nl_msg_type_to_str(h->nlmsg_type),
+                                          ifa->ifa_prefixlen);
+                       return -1;
+               }
+
+               /* Only consider valid addresses; we'll not get a kernel
+                * notification till IPv6 DAD has completed, but at init
+                * time, FRR does query for and will receive all addresses.
+                */
+               if (h->nlmsg_type == RTM_NEWADDR
+                   && (kernel_flags & (IFA_F_DADFAILED | IFA_F_TENTATIVE))) {
+                       if (IS_ZEBRA_DEBUG_KERNEL)
+                               zlog_debug("%s: %s: Invalid/tentative addr",
+                                          __func__,
+                                          nl_msg_type_to_str(h->nlmsg_type));
+                       return 0;
+               }
+       }
+
+       /* logic copied from iproute2/ip/ipaddress.c:print_addrinfo() */
+       if (tb[IFA_LOCAL] == NULL)
+               tb[IFA_LOCAL] = tb[IFA_ADDRESS];
+       if (tb[IFA_ADDRESS] == NULL)
+               tb[IFA_ADDRESS] = tb[IFA_LOCAL];
+
+       /* local interface address */
+       addr = (tb[IFA_LOCAL] ? RTA_DATA(tb[IFA_LOCAL]) : NULL);
+
+       /* addr is primary key, SOL if we don't have one */
+       if (addr == NULL) {
+               if (IS_ZEBRA_DEBUG_KERNEL)
+                       zlog_debug("%s: %s: No local interface address",
+                                  __func__, nl_msg_type_to_str(h->nlmsg_type));
+               return -1;
+       }
+
+       /* Allocate a context object, now that validation is done. */
+       ctx = dplane_ctx_alloc();
+       if (h->nlmsg_type == RTM_NEWADDR)
+               dplane_ctx_set_op(ctx, DPLANE_OP_INTF_ADDR_ADD);
+       else
+               dplane_ctx_set_op(ctx, DPLANE_OP_INTF_ADDR_DEL);
+
+       dplane_ctx_set_ifindex(ctx, ifa->ifa_index);
+       dplane_ctx_set_ns_id(ctx, ns_id);
+
+       /* Convert addr to prefix */
+       memset(&p, 0, sizeof(p));
+       p.family = ifa->ifa_family;
+       p.prefixlen = ifa->ifa_prefixlen;
+       if (p.family == AF_INET)
+               p.u.prefix4 = *(struct in_addr *)addr;
+       else
+               p.u.prefix6 = *(struct in6_addr *)addr;
+
+       dplane_ctx_set_intf_addr(ctx, &p);
+
+       /* is there a peer address? */
+       if (tb[IFA_ADDRESS]
+           && memcmp(RTA_DATA(tb[IFA_ADDRESS]), RTA_DATA(tb[IFA_LOCAL]),
+                     RTA_PAYLOAD(tb[IFA_ADDRESS]))) {
+               broad = RTA_DATA(tb[IFA_ADDRESS]);
+               dplane_ctx_intf_set_connected(ctx);
+       } else if (tb[IFA_BROADCAST]) {
+               /* seeking a broadcast address */
+               broad = RTA_DATA(tb[IFA_BROADCAST]);
+               dplane_ctx_intf_set_broadcast(ctx);
+       } else
+               broad = NULL;
+
+       if (broad) {
+               /* Convert addr to prefix */
+               memset(&p, 0, sizeof(p));
+               p.family = ifa->ifa_family;
+               p.prefixlen = ifa->ifa_prefixlen;
+               if (p.family == AF_INET)
+                       p.u.prefix4 = *(struct in_addr *)broad;
+               else
+                       p.u.prefix6 = *(struct in6_addr *)broad;
+
+               dplane_ctx_set_intf_dest(ctx, &p);
+       }
+
+       /* Flags. */
+       if (kernel_flags & IFA_F_SECONDARY)
+               dplane_ctx_intf_set_secondary(ctx);
+
+       /* Label */
+       if (tb[IFA_LABEL]) {
+               label = (char *)RTA_DATA(tb[IFA_LABEL]);
+               dplane_ctx_set_intf_label(ctx, label);
+       }
+
+       if (tb[IFA_RT_PRIORITY])
+               metric = *(uint32_t *)RTA_DATA(tb[IFA_RT_PRIORITY]);
+
+       dplane_ctx_set_intf_metric(ctx, metric);
+
+       /* Enqueue ctx for main pthread to process */
+       dplane_provider_enqueue_to_zebra(ctx);
+
+       return 0;
+}
+
 int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
 {
        int len;
@@ -1644,9 +1843,9 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
                                ifp, linkinfo[IFLA_INFO_DATA],
                                1, link_nsid);
                        if (IS_ZEBRA_IF_BRIDGE_SLAVE(ifp))
-                               zebra_l2if_update_bridge_slave(ifp,
-                                                              bridge_ifindex,
-                                                              ns_id);
+                               zebra_l2if_update_bridge_slave(
+                                       ifp, bridge_ifindex, ns_id,
+                                       ZEBRA_BRIDGE_NO_ACTION);
                        else if (IS_ZEBRA_IF_BOND_SLAVE(ifp))
                                zebra_l2if_update_bond_slave(ifp, bond_ifindex,
                                                             !!bypass);
@@ -1670,6 +1869,7 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
                        if_handle_vrf_change(ifp, vrf_id);
                } else {
                        bool was_bridge_slave, was_bond_slave;
+                       uint8_t chgflags = ZEBRA_BRIDGE_NO_ACTION;
 
                        /* Interface update. */
                        if (IS_ZEBRA_DEBUG_KERNEL)
@@ -1711,6 +1911,8 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
                                        if_down(ifp);
                                        rib_update(RIB_UPDATE_KERNEL);
                                } else if (if_is_operative(ifp)) {
+                                       bool mac_updated = false;
+
                                        /* Must notify client daemons of new
                                         * interface status. */
                                        if (IS_ZEBRA_DEBUG_KERNEL)
@@ -1721,9 +1923,11 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
 
                                        /* Update EVPN VNI when SVI MAC change
                                         */
-                                       if (IS_ZEBRA_IF_VLAN(ifp) &&
-                                           memcmp(old_hw_addr, ifp->hw_addr,
-                                                  INTERFACE_HWADDR_MAX)) {
+                                       if (memcmp(old_hw_addr, ifp->hw_addr,
+                                                  INTERFACE_HWADDR_MAX))
+                                               mac_updated = true;
+                                       if (IS_ZEBRA_IF_VLAN(ifp)
+                                           && mac_updated) {
                                                struct interface *link_if;
 
                                                link_if =
@@ -1733,6 +1937,13 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
                                                if (link_if)
                                                        zebra_vxlan_svi_up(ifp,
                                                                link_if);
+                                       } else if (mac_updated
+                                                  && IS_ZEBRA_IF_BRIDGE(ifp)) {
+                                               zlog_debug(
+                                                       "Intf %s(%u) bridge changed MAC address",
+                                                       name, ifp->ifindex);
+                                               chgflags =
+                                                       ZEBRA_BRIDGE_MASTER_MAC_CHANGE;
                                        }
                                }
                        } else {
@@ -1743,6 +1954,9 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
                                                        "Intf %s(%u) has come UP",
                                                        name, ifp->ifindex);
                                        if_up(ifp);
+                                       if (IS_ZEBRA_IF_BRIDGE(ifp))
+                                               chgflags =
+                                                       ZEBRA_BRIDGE_MASTER_UP;
                                } else {
                                        if (IS_ZEBRA_DEBUG_KERNEL)
                                                zlog_debug(
@@ -1758,12 +1972,13 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
                        netlink_interface_update_l2info(
                                ifp, linkinfo[IFLA_INFO_DATA],
                                0, link_nsid);
+                       if (IS_ZEBRA_IF_BRIDGE(ifp))
+                               zebra_l2if_update_bridge(ifp, chgflags);
                        if (IS_ZEBRA_IF_BOND(ifp))
                                zebra_l2if_update_bond(ifp, true);
                        if (IS_ZEBRA_IF_BRIDGE_SLAVE(ifp) || was_bridge_slave)
-                               zebra_l2if_update_bridge_slave(ifp,
-                                                              bridge_ifindex,
-                                                              ns_id);
+                               zebra_l2if_update_bridge_slave(
+                                       ifp, bridge_ifindex, ns_id, chgflags);
                        else if (IS_ZEBRA_IF_BOND_SLAVE(ifp) || was_bond_slave)
                                zebra_l2if_update_bond_slave(ifp, bond_ifindex,
                                                             !!bypass);
@@ -1839,7 +2054,7 @@ int netlink_protodown(struct interface *ifp, bool down)
        nl_attr_put32(&req.n, sizeof(req), IFLA_LINK, ifp->ifindex);
 
        return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns,
-                           0);
+                           false);
 }
 
 /* Interface information read by netlink. */
index 4f09b10b755f285f51269c16084ded384ef95fd5..a1ce7af8c7807ddb52ea2a732b8a8a819744209e 100644 (file)
@@ -29,6 +29,14 @@ extern "C" {
 
 extern int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id,
                                  int startup);
+
+/*
+ * Parse an incoming interface address change message, generate a dplane
+ * context object for processing.
+ */
+int netlink_interface_addr_dplane(struct nlmsghdr *h, ns_id_t ns_id,
+                                 int startup);
+
 extern int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup);
 extern int interface_lookup_netlink(struct zebra_ns *zns);
 
index 328ef3fa41cb6ecf00d579c65e61c482e513bf1f..a68d00d55ce035c04d5812110d9c0a0a99e0179e 100644 (file)
@@ -1205,6 +1205,109 @@ void zebra_if_set_protodown(struct interface *ifp, bool down)
 #endif
 }
 
+/*
+ * Handle an interface addr event based on info in a dplane context object.
+ * This runs in the main pthread, using the info in the context object to
+ * modify an interface.
+ */
+void zebra_if_addr_update_ctx(struct zebra_dplane_ctx *ctx)
+{
+       struct interface *ifp;
+       uint8_t flags = 0;
+       const char *label = NULL;
+       ns_id_t ns_id;
+       struct zebra_ns *zns;
+       uint32_t metric = METRIC_MAX;
+       ifindex_t ifindex;
+       const struct prefix *addr, *dest = NULL;
+       enum dplane_op_e op;
+
+       op = dplane_ctx_get_op(ctx);
+       ns_id = dplane_ctx_get_ns_id(ctx);
+
+       zns = zebra_ns_lookup(ns_id);
+       if (zns == NULL) {
+               /* No ns - deleted maybe? */
+               if (IS_ZEBRA_DEBUG_KERNEL)
+                       zlog_debug("%s: can't find zns id %u", __func__, ns_id);
+               goto done;
+       }
+
+       ifindex = dplane_ctx_get_ifindex(ctx);
+
+       ifp = if_lookup_by_index_per_ns(zns, ifindex);
+       if (ifp == NULL) {
+               if (IS_ZEBRA_DEBUG_KERNEL)
+                       zlog_debug("%s: can't find ifp at nsid %u index %d",
+                                  __func__, ns_id, ifindex);
+               goto done;
+       }
+
+       addr = dplane_ctx_get_intf_addr(ctx);
+
+       if (IS_ZEBRA_DEBUG_KERNEL)
+               zlog_debug("%s: %s: ifindex %u, addr %pFX", __func__,
+                          dplane_op2str(op), ifindex, addr);
+
+       /* Is there a peer or broadcast address? */
+       dest = dplane_ctx_get_intf_dest(ctx);
+       if (dest->prefixlen == 0)
+               dest = NULL;
+
+       if (dplane_ctx_intf_is_connected(ctx))
+               SET_FLAG(flags, ZEBRA_IFA_PEER);
+
+       /* Flags. */
+       if (dplane_ctx_intf_is_secondary(ctx))
+               SET_FLAG(flags, ZEBRA_IFA_SECONDARY);
+
+       /* Label? */
+       if (dplane_ctx_intf_has_label(ctx))
+               label = dplane_ctx_get_intf_label(ctx);
+
+       if (label && strcmp(ifp->name, label) == 0)
+               label = NULL;
+
+       metric = dplane_ctx_get_intf_metric(ctx);
+
+       /* Register interface address to the interface. */
+       if (addr->family == AF_INET) {
+               if (op == DPLANE_OP_INTF_ADDR_ADD)
+                       connected_add_ipv4(
+                               ifp, flags, &addr->u.prefix4, addr->prefixlen,
+                               dest ? &dest->u.prefix4 : NULL, label, metric);
+               else if (CHECK_FLAG(flags, ZEBRA_IFA_PEER)) {
+                       /* Delete with a peer address */
+                       connected_delete_ipv4(ifp, flags, &addr->u.prefix4,
+                                             addr->prefixlen,
+                                             &dest->u.prefix4);
+               } else
+                       connected_delete_ipv4(ifp, flags, &addr->u.prefix4,
+                                             addr->prefixlen, NULL);
+       }
+
+       if (addr->family == AF_INET6) {
+               if (op == DPLANE_OP_INTF_ADDR_ADD) {
+                       connected_add_ipv6(ifp, flags, &addr->u.prefix6,
+                                          dest ? &dest->u.prefix6 : NULL,
+                                          addr->prefixlen, label, metric);
+               } else
+                       connected_delete_ipv6(ifp, &addr->u.prefix6, NULL,
+                                             addr->prefixlen);
+       }
+
+       /*
+        * Linux kernel does not send route delete on interface down/addr del
+        * so we have to re-process routes it owns (i.e. kernel routes)
+        */
+       if (op != DPLANE_OP_INTF_ADDR_ADD)
+               rib_update(RIB_UPDATE_KERNEL);
+
+done:
+       /* We're responsible for the ctx object */
+       dplane_ctx_fini(&ctx);
+}
+
 /* Dump if address information to vty. */
 static void connected_dump_vty(struct vty *vty, json_object *json,
                               struct connected *connected)
index d86bc68ef03823e436f10499b4e563d1bc74d61d..23e22bdda8976fad88a9912f5c12fd4229bcd5d7 100644 (file)
@@ -513,6 +513,7 @@ extern void zebra_l2_map_slave_to_bond(struct zebra_if *zif, vrf_id_t vrf);
 extern void zebra_l2_unmap_slave_from_bond(struct zebra_if *zif);
 extern const char *zebra_protodown_rc_str(enum protodown_reasons protodown_rc,
                                          char *pd_buf, uint32_t pd_buf_len);
+void zebra_if_addr_update_ctx(struct zebra_dplane_ctx *ctx);
 
 #ifdef HAVE_PROC_NET_DEV
 extern void ifstat_update_proc(void);
index 66a6bd0545273ec043cc7753a1133611b7833e07..f141b727194ca96fe1513090857985d196509cf7 100644 (file)
@@ -112,7 +112,6 @@ int irdp_sock_init(void)
                return ret;
        };
 
-       t_irdp_raw = NULL;
        thread_add_read(zrouter.master, irdp_read_raw, NULL, sock, &t_irdp_raw);
 
        return sock;
index 7d67c42a79e9b06f843b7ca9f4f7bf6af164ebf8..5601b13a92ad6d4991a5897e3d7087378e1e1cb2 100644 (file)
@@ -233,7 +233,6 @@ int irdp_read_raw(struct thread *r)
        int ret, ifindex = 0;
 
        int irdp_sock = THREAD_FD(r);
-       t_irdp_raw = NULL;
        thread_add_read(zrouter.master, irdp_read_raw, NULL, irdp_sock,
                        &t_irdp_raw);
 
index effec24c1f3e0813fc67a6e6e0881e91c91cb9f7..86e8f65b5f8133200ba2ab1b2d877d75ace97210 100644 (file)
@@ -324,6 +324,10 @@ static int netlink_socket(struct nlsock *nl, unsigned long groups,
        return ret;
 }
 
+/*
+ * Dispatch an incoming netlink message; used by the zebra main pthread's
+ * netlink event reader.
+ */
 static int netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id,
                                     int startup)
 {
@@ -345,10 +349,6 @@ static int netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id,
                return netlink_link_change(h, ns_id, startup);
        case RTM_DELLINK:
                return netlink_link_change(h, ns_id, startup);
-       case RTM_NEWADDR:
-               return netlink_interface_addr(h, ns_id, startup);
-       case RTM_DELADDR:
-               return netlink_interface_addr(h, ns_id, startup);
        case RTM_NEWNEIGH:
        case RTM_DELNEIGH:
        case RTM_GETNEIGH:
@@ -361,6 +361,12 @@ static int netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id,
                return netlink_nexthop_change(h, ns_id, startup);
        case RTM_DELNEXTHOP:
                return netlink_nexthop_change(h, ns_id, startup);
+
+       /* Messages handled in the dplane thread */
+       case RTM_NEWADDR:
+       case RTM_DELADDR:
+               return 0;
+
        default:
                /*
                 * If we have received this message then
@@ -378,6 +384,32 @@ static int netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id,
        return 0;
 }
 
+/*
+ * Dispatch an incoming netlink message; used by the dataplane pthread's
+ * netlink event reader code.
+ */
+static int dplane_netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id,
+                                           int startup)
+{
+       /*
+        * Dispatch the incoming messages that the dplane pthread handles
+        */
+       switch (h->nlmsg_type) {
+       case RTM_NEWADDR:
+       case RTM_DELADDR:
+               return netlink_interface_addr_dplane(h, ns_id, startup);
+
+       /* TODO */
+       case RTM_NEWLINK:
+       case RTM_DELLINK:
+
+       default:
+               break;
+       }
+
+       return 0;
+}
+
 static int kernel_read(struct thread *thread)
 {
        struct zebra_ns *zns = (struct zebra_ns *)THREAD_ARG(thread);
@@ -387,14 +419,25 @@ static int kernel_read(struct thread *thread)
        zebra_dplane_info_from_zns(&dp_info, zns, false);
 
        netlink_parse_info(netlink_information_fetch, &zns->netlink, &dp_info,
-                          5, 0);
-       zns->t_netlink = NULL;
+                          5, false);
+
        thread_add_read(zrouter.master, kernel_read, zns, zns->netlink.sock,
                        &zns->t_netlink);
 
        return 0;
 }
 
+/*
+ * Called by the dplane pthread to read incoming OS messages and dispatch them.
+ */
+int kernel_dplane_read(struct zebra_dplane_info *info)
+{
+       netlink_parse_info(dplane_netlink_information_fetch, &info->nls, info,
+                          5, false);
+
+       return 0;
+}
+
 /*
  * Filter out messages from self that occur on listener socket,
  * caused by our actions on the command socket(s)
@@ -408,7 +451,7 @@ static int kernel_read(struct thread *thread)
  * so that we only had to write one way to handle incoming
  * address add/delete changes.
  */
-static void netlink_install_filter(int sock, __u32 pid, __u32 dplane_pid)
+static void netlink_install_filter(int sock, uint32_t pid, uint32_t dplane_pid)
 {
        /*
         * BPF_JUMP instructions and where you jump to are based upon
@@ -476,8 +519,8 @@ static void netlink_install_filter(int sock, __u32 pid, __u32 dplane_pid)
                             safe_strerror(errno));
 }
 
-void netlink_parse_rtattr_flags(struct rtattr **tb, int max,
-               struct rtattr *rta, int len, unsigned short flags)
+void netlink_parse_rtattr_flags(struct rtattr **tb, int max, struct rtattr *rta,
+                               int len, unsigned short flags)
 {
        unsigned short type;
 
@@ -799,8 +842,7 @@ static int netlink_recv_msg(const struct nlsock *nl, struct msghdr msg,
  * ignored, -1 otherwise.
  */
 static int netlink_parse_error(const struct nlsock *nl, struct nlmsghdr *h,
-                              const struct zebra_dplane_info *zns,
-                              bool startup)
+                              bool is_cmd, bool startup)
 {
        struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(h);
        int errnum = err->error;
@@ -833,7 +875,7 @@ static int netlink_parse_error(const struct nlsock *nl, struct nlmsghdr *h,
        }
 
        /* Deal with errors that occur because of races in link handling. */
-       if (zns->is_cmd
+       if (is_cmd
            && ((msg_type == RTM_DELROUTE
                 && (-errnum == ENODEV || -errnum == ESRCH))
                || (msg_type == RTM_NEWROUTE
@@ -852,7 +894,7 @@ static int netlink_parse_error(const struct nlsock *nl, struct nlmsghdr *h,
         * do not log these as an error.
         */
        if (msg_type == RTM_DELNEIGH
-           || (zns->is_cmd && msg_type == RTM_NEWROUTE
+           || (is_cmd && msg_type == RTM_NEWROUTE
                && (-errnum == ESRCH || -errnum == ENETUNREACH))) {
                /*
                 * This is known to happen in some situations, don't log as
@@ -891,7 +933,7 @@ static int netlink_parse_error(const struct nlsock *nl, struct nlmsghdr *h,
 int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int),
                       const struct nlsock *nl,
                       const struct zebra_dplane_info *zns,
-                      int count, int startup)
+                      int count, bool startup)
 {
        int status;
        int ret = 0;
@@ -924,8 +966,9 @@ int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int),
 
                        /* Error handling. */
                        if (h->nlmsg_type == NLMSG_ERROR) {
-                               int err = netlink_parse_error(nl, h, zns,
-                                                             startup);
+                               int err = netlink_parse_error(
+                                       nl, h, zns->is_cmd, startup);
+
                                if (err == 1) {
                                        if (!(h->nlmsg_flags & NLM_F_MULTI))
                                                return 0;
@@ -937,8 +980,8 @@ int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int),
                        /* OK we got netlink message. */
                        if (IS_ZEBRA_DEBUG_KERNEL)
                                zlog_debug(
-                                       "netlink_parse_info: %s type %s(%u), len=%d, seq=%u, pid=%u",
-                                       nl->name,
+                                       "%s: %s type %s(%u), len=%d, seq=%u, pid=%u",
+                                       __func__, nl->name,
                                        nl_msg_type_to_str(h->nlmsg_type),
                                        h->nlmsg_type, h->nlmsg_len,
                                        h->nlmsg_seq, h->nlmsg_pid);
@@ -993,7 +1036,7 @@ int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int),
 static int
 netlink_talk_info(int (*filter)(struct nlmsghdr *, ns_id_t, int startup),
                  struct nlmsghdr *n, const struct zebra_dplane_info *dp_info,
-                 int startup)
+                 bool startup)
 {
        const struct nlsock *nl;
 
@@ -1024,7 +1067,7 @@ netlink_talk_info(int (*filter)(struct nlmsghdr *, ns_id_t, int startup),
  */
 int netlink_talk(int (*filter)(struct nlmsghdr *, ns_id_t, int startup),
                 struct nlmsghdr *n, struct nlsock *nl, struct zebra_ns *zns,
-                int startup)
+                bool startup)
 {
        struct zebra_dplane_info dp_info;
 
@@ -1140,7 +1183,8 @@ static int nl_batch_read_resp(struct nl_batch *bth)
                }
 
                if (h->nlmsg_type == NLMSG_ERROR) {
-                       int err = netlink_parse_error(nl, h, bth->zns, 0);
+                       int err = netlink_parse_error(nl, h, bth->zns->is_cmd,
+                                                     false);
 
                        if (err == -1)
                                dplane_ctx_set_status(
@@ -1359,6 +1403,8 @@ static enum netlink_msg_status nl_put_msg(struct nl_batch *bth,
        case DPLANE_OP_GRE_SET:
                return netlink_put_gre_set_msg(bth, ctx);
 
+       case DPLANE_OP_INTF_ADDR_ADD:
+       case DPLANE_OP_INTF_ADDR_DEL:
        case DPLANE_OP_NONE:
                return FRR_NETLINK_ERROR;
        }
@@ -1455,12 +1501,25 @@ void kernel_init(struct zebra_ns *zns)
                exit(-1);
        }
 
-       snprintf(zns->netlink_dplane.name, sizeof(zns->netlink_dplane.name),
-                "netlink-dp (NS %u)", zns->ns_id);
-       zns->netlink_dplane.sock = -1;
-       if (netlink_socket(&zns->netlink_dplane, 0, zns->ns_id) < 0) {
+       /* Outbound socket for dplane programming of the host OS. */
+       snprintf(zns->netlink_dplane_out.name,
+                sizeof(zns->netlink_dplane_out.name), "netlink-dp (NS %u)",
+                zns->ns_id);
+       zns->netlink_dplane_out.sock = -1;
+       if (netlink_socket(&zns->netlink_dplane_out, 0, zns->ns_id) < 0) {
                zlog_err("Failure to create %s socket",
-                        zns->netlink_dplane.name);
+                        zns->netlink_dplane_out.name);
+               exit(-1);
+       }
+
+       /* Inbound socket for OS events coming to the dplane. */
+       snprintf(zns->netlink_dplane_in.name,
+                sizeof(zns->netlink_dplane_in.name), "netlink-dp-in (NS %u)",
+                zns->ns_id);
+       zns->netlink_dplane_in.sock = -1;
+       if (netlink_socket(&zns->netlink_dplane_in, groups, zns->ns_id) < 0) {
+               zlog_err("Failure to create %s socket",
+                        zns->netlink_dplane_in.name);
                exit(-1);
        }
 
@@ -1483,8 +1542,8 @@ void kernel_init(struct zebra_ns *zns)
                            errno, safe_strerror(errno));
 
        one = 1;
-       ret = setsockopt(zns->netlink_dplane.sock, SOL_NETLINK, NETLINK_EXT_ACK,
-                        &one, sizeof(one));
+       ret = setsockopt(zns->netlink_dplane_out.sock, SOL_NETLINK,
+                        NETLINK_EXT_ACK, &one, sizeof(one));
 
        if (ret < 0)
                zlog_notice("Registration for extended dp ACK failed : %d %s",
@@ -1496,8 +1555,8 @@ void kernel_init(struct zebra_ns *zns)
         * setsockopt fails, ignore the error.
         */
        one = 1;
-       ret = setsockopt(zns->netlink_dplane.sock, SOL_NETLINK, NETLINK_CAP_ACK,
-                        &one, sizeof(one));
+       ret = setsockopt(zns->netlink_dplane_out.sock, SOL_NETLINK,
+                        NETLINK_CAP_ACK, &one, sizeof(one));
        if (ret < 0)
                zlog_notice(
                        "Registration for reduced ACK packet size failed, probably running an early kernel");
@@ -1512,20 +1571,33 @@ void kernel_init(struct zebra_ns *zns)
                zlog_err("Can't set %s socket error: %s(%d)",
                         zns->netlink_cmd.name, safe_strerror(errno), errno);
 
-       if (fcntl(zns->netlink_dplane.sock, F_SETFL, O_NONBLOCK) < 0)
+       if (fcntl(zns->netlink_dplane_out.sock, F_SETFL, O_NONBLOCK) < 0)
                zlog_err("Can't set %s socket error: %s(%d)",
-                        zns->netlink_dplane.name, safe_strerror(errno), errno);
+                        zns->netlink_dplane_out.name, safe_strerror(errno),
+                        errno);
+
+       if (fcntl(zns->netlink_dplane_in.sock, F_SETFL, O_NONBLOCK) < 0)
+               zlog_err("Can't set %s socket error: %s(%d)",
+                        zns->netlink_dplane_in.name, safe_strerror(errno),
+                        errno);
 
        /* Set receive buffer size if it's set from command line */
        if (nl_rcvbufsize) {
                netlink_recvbuf(&zns->netlink, nl_rcvbufsize);
                netlink_recvbuf(&zns->netlink_cmd, nl_rcvbufsize);
-               netlink_recvbuf(&zns->netlink_dplane, nl_rcvbufsize);
+               netlink_recvbuf(&zns->netlink_dplane_out, nl_rcvbufsize);
+               netlink_recvbuf(&zns->netlink_dplane_in, nl_rcvbufsize);
        }
 
-       netlink_install_filter(zns->netlink.sock,
+       /* Set filter for inbound sockets, to exclude events we've generated
+        * ourselves.
+        */
+       netlink_install_filter(zns->netlink.sock, zns->netlink_cmd.snl.nl_pid,
+                              zns->netlink_dplane_out.snl.nl_pid);
+
+       netlink_install_filter(zns->netlink_dplane_in.sock,
                               zns->netlink_cmd.snl.nl_pid,
-                              zns->netlink_dplane.snl.nl_pid);
+                              zns->netlink_dplane_out.snl.nl_pid);
 
        zns->t_netlink = NULL;
 
@@ -1549,13 +1621,18 @@ void kernel_terminate(struct zebra_ns *zns, bool complete)
                zns->netlink_cmd.sock = -1;
        }
 
+       if (zns->netlink_dplane_in.sock >= 0) {
+               close(zns->netlink_dplane_in.sock);
+               zns->netlink_dplane_in.sock = -1;
+       }
+
        /* During zebra shutdown, we need to leave the dataplane socket
         * around until all work is done.
         */
        if (complete) {
-               if (zns->netlink_dplane.sock >= 0) {
-                       close(zns->netlink_dplane.sock);
-                       zns->netlink_dplane.sock = -1;
+               if (zns->netlink_dplane_out.sock >= 0) {
+                       close(zns->netlink_dplane_out.sock);
+                       zns->netlink_dplane_out.sock = -1;
                }
        }
 }
index d8e5671b72ddc69f60864ac3b21b6c7cf4c5486d..37c76b9e598d4e4f101cb94fbfe5fd50ed9124d5 100644 (file)
@@ -94,11 +94,11 @@ extern const char *nl_rttype_to_str(uint8_t rttype);
 extern int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int),
                              const struct nlsock *nl,
                              const struct zebra_dplane_info *dp_info,
-                             int count, int startup);
+                             int count, bool startup);
 extern int netlink_talk_filter(struct nlmsghdr *h, ns_id_t ns, int startup);
 extern int netlink_talk(int (*filter)(struct nlmsghdr *, ns_id_t, int startup),
                        struct nlmsghdr *n, struct nlsock *nl,
-                       struct zebra_ns *zns, int startup);
+                       struct zebra_ns *zns, bool startup);
 extern int netlink_request(struct nlsock *nl, void *req);
 
 enum netlink_msg_status {
index 5c060ac6f86015a4445a7049bd03925abdb9069b..d9c69ceb6d7ed043053981906d8ce1b4dca874bd 100644 (file)
@@ -529,7 +529,7 @@ int ifm_read(struct if_msghdr *ifm)
        /* paranoia: sanity check structure */
        if (ifm->ifm_msglen < sizeof(struct if_msghdr)) {
                flog_err(EC_ZEBRA_NETLINK_LENGTH_ERROR,
-                        "ifm_read: ifm->ifm_msglen %d too short\n",
+                        "ifm_read: ifm->ifm_msglen %d too short",
                         ifm->ifm_msglen);
                return -1;
        }
@@ -807,23 +807,17 @@ static void ifam_read_mesg(struct ifa_msghdr *ifm, union sockunion *addr,
                switch (sockunion_family(addr)) {
                case AF_INET:
                case AF_INET6: {
-                       char buf[4][INET6_ADDRSTRLEN];
                        int masklen =
                                (sockunion_family(addr) == AF_INET)
                                        ? ip_masklen(mask->sin.sin_addr)
                                        : ip6_masklen(mask->sin6.sin6_addr);
                        zlog_debug(
-                               "%s: ifindex %d, ifname %s, ifam_addrs {%s}, ifam_flags 0x%x, addr %s/%d broad %s dst %s gateway %s",
+                               "%s: ifindex %d, ifname %s, ifam_addrs {%s}, ifam_flags 0x%x, addr %pSU/%d broad %pSU dst %pSU gateway %pSU",
                                __func__, ifm->ifam_index,
                                (ifnlen ? ifname : "(nil)"),
                                rtatostr(ifm->ifam_addrs, fbuf, sizeof(fbuf)),
-                               ifm->ifam_flags,
-                               sockunion2str(addr, buf[0], sizeof(buf[0])),
-                               masklen,
-                               sockunion2str(brd, buf[1], sizeof(buf[1])),
-                               sockunion2str(&dst, buf[2], sizeof(buf[2])),
-                               sockunion2str(&gateway, buf[2],
-                                             sizeof(buf[2])));
+                               ifm->ifam_flags, addr, masklen, brd, &dst,
+                               &gateway);
                } break;
                default:
                        zlog_debug("%s: ifindex %d, ifname %s, ifam_addrs {%s}",
@@ -951,7 +945,7 @@ static int rtm_read_mesg(struct rt_msghdr *rtm, union sockunion *dest,
        /* rt_msghdr version check. */
        if (rtm->rtm_version != RTM_VERSION)
                flog_warn(EC_ZEBRA_RTM_VERSION_MISMATCH,
-                         "Routing message version different %d should be %d.This may cause problem\n",
+                         "Routing message version different %d should be %d.This may cause problem",
                          rtm->rtm_version, RTM_VERSION);
 
        /* Be sure structure is cleared */
@@ -1463,6 +1457,14 @@ void kernel_terminate(struct zebra_ns *zns, bool complete)
        return;
 }
 
+/*
+ * Called by the dplane pthread to read incoming OS messages and dispatch them.
+ */
+int kernel_dplane_read(struct zebra_dplane_info *info)
+{
+       return 0;
+}
+
 void kernel_update_multi(struct dplane_ctx_q *ctx_list)
 {
        struct zebra_dplane_ctx *ctx;
index 929a44ade721d0ed26036d3ce9da7e17f721c57c..90148d2c0d8489ea79ef2703509c0731dfdaa3e9 100644 (file)
@@ -110,6 +110,11 @@ extern int kernel_del_mac_nhg(uint32_t nhg_id);
  */
 extern void kernel_update_multi(struct dplane_ctx_q *ctx_list);
 
+/*
+ * Called by the dplane pthread to read incoming OS messages and dispatch them.
+ */
+int kernel_dplane_read(struct zebra_dplane_info *info);
+
 #ifdef __cplusplus
 }
 #endif
index e36f320ad91744604e7efd770a6741c161a7f3ce..488bca06da9aece04fe17161fb2bde17b80fd910 100644 (file)
@@ -1171,7 +1171,7 @@ int netlink_route_read(struct zebra_ns *zns)
        if (ret < 0)
                return ret;
        ret = netlink_parse_info(netlink_route_change_read_unicast,
-                                &zns->netlink_cmd, &dp_info, 0, 1);
+                                &zns->netlink_cmd, &dp_info, 0, true);
        if (ret < 0)
                return ret;
 
@@ -1180,7 +1180,7 @@ int netlink_route_read(struct zebra_ns *zns)
        if (ret < 0)
                return ret;
        ret = netlink_parse_info(netlink_route_change_read_unicast,
-                                &zns->netlink_cmd, &dp_info, 0, 1);
+                                &zns->netlink_cmd, &dp_info, 0, true);
        if (ret < 0)
                return ret;
 
@@ -1810,7 +1810,7 @@ static int netlink_neigh_update(int cmd, int ifindex, void *addr, char *lla,
                nl_attr_put(&req.n, sizeof(req), NDA_LLADDR, lla, llalen);
 
        return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns,
-                           0);
+                           false);
 }
 
 static bool nexthop_set_src(const struct nexthop *nexthop, int family,
@@ -2268,7 +2268,7 @@ int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *in)
        nl_attr_put32(&req.n, sizeof(req), RTA_TABLE, actual_table);
 
        suc = netlink_talk(netlink_route_change_read_multicast, &req.n,
-                          &zns->netlink_cmd, zns, 0);
+                          &zns->netlink_cmd, zns, false);
 
        mroute = NULL;
        return suc;
@@ -3019,7 +3019,7 @@ int netlink_nexthop_read(struct zebra_ns *zns)
        if (ret < 0)
                return ret;
        ret = netlink_parse_info(netlink_nexthop_change, &zns->netlink_cmd,
-                                &dp_info, 0, 1);
+                                &dp_info, 0, true);
 
        if (!ret)
                /* If we succesfully read in nexthop objects,
@@ -3427,7 +3427,7 @@ int netlink_macfdb_read(struct zebra_ns *zns)
        /* We are reading entire table. */
        filter_vlan = 0;
        ret = netlink_parse_info(netlink_macfdb_table, &zns->netlink_cmd,
-                                &dp_info, 0, 1);
+                                &dp_info, 0, true);
 
        return ret;
 }
@@ -3461,7 +3461,7 @@ int netlink_macfdb_read_for_bridge(struct zebra_ns *zns, struct interface *ifp,
        if (ret < 0)
                return ret;
        ret = netlink_parse_info(netlink_macfdb_table, &zns->netlink_cmd,
-                                &dp_info, 0, 0);
+                                &dp_info, 0, false);
 
        /* Reset VLAN filter. */
        filter_vlan = 0;
@@ -3526,7 +3526,7 @@ int netlink_macfdb_read_specific_mac(struct zebra_ns *zns,
                return ret;
 
        ret = netlink_parse_info(netlink_macfdb_table, &zns->netlink_cmd,
-                                &dp_info, 1, 0);
+                                &dp_info, 1, false);
 
        return ret;
 }
@@ -3930,7 +3930,7 @@ int netlink_neigh_read(struct zebra_ns *zns)
        if (ret < 0)
                return ret;
        ret = netlink_parse_info(netlink_neigh_table, &zns->netlink_cmd,
-                                &dp_info, 0, 1);
+                                &dp_info, 0, true);
 
        return ret;
 }
@@ -3951,7 +3951,7 @@ int netlink_neigh_read_for_vlan(struct zebra_ns *zns, struct interface *vlan_if)
        if (ret < 0)
                return ret;
        ret = netlink_parse_info(netlink_neigh_table, &zns->netlink_cmd,
-                                &dp_info, 0, 0);
+                                &dp_info, 0, false);
 
        return ret;
 }
@@ -4022,7 +4022,7 @@ int netlink_neigh_read_specific_ip(const struct ipaddr *ip,
                return ret;
 
        ret = netlink_parse_info(netlink_neigh_table, &zns->netlink_cmd,
-                                &dp_info, 1, 0);
+                                &dp_info, 1, false);
 
        return ret;
 }
@@ -4442,7 +4442,7 @@ static int netlink_fdb_nh_update(uint32_t nh_id, struct in_addr vtep_ip)
        }
 
        return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns,
-                           0);
+                           false);
 }
 
 static int netlink_fdb_nh_del(uint32_t nh_id)
@@ -4477,7 +4477,7 @@ static int netlink_fdb_nh_del(uint32_t nh_id)
        }
 
        return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns,
-                           0);
+                           false);
 }
 
 static int netlink_fdb_nhg_update(uint32_t nhg_id, uint32_t nh_cnt,
@@ -4537,7 +4537,7 @@ static int netlink_fdb_nhg_update(uint32_t nhg_id, uint32_t nh_cnt,
        }
 
        return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns,
-                           0);
+                           false);
 }
 
 static int netlink_fdb_nhg_del(uint32_t nhg_id)
index 976beefab05fa0dc894c0f04cd78ba1a30a2affb..9610f71d09c7c57f29d8fea6765a705c4c787998 100644 (file)
@@ -493,9 +493,7 @@ static int rtadv_timer(struct thread *thread)
 
        RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id)
                FOR_ALL_INTERFACES (vrf, ifp) {
-                       if (if_is_loopback(ifp)
-                           || CHECK_FLAG(ifp->status,
-                                         ZEBRA_INTERFACE_VRF_LOOPBACK)
+                       if (if_is_loopback_or_vrf(ifp)
                            || !if_is_operative(ifp))
                                continue;
 
@@ -728,8 +726,7 @@ static void rtadv_process_packet(uint8_t *buf, unsigned int len,
                           VRF_LOGNAME(vrf), ifp->ifindex, len, addr_str);
        }
 
-       if (if_is_loopback(ifp)
-           || CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK))
+       if (if_is_loopback_or_vrf(ifp))
                return;
 
        /* Check interface configuration. */
@@ -1465,8 +1462,7 @@ DEFUN (ipv6_nd_ra_fast_retrans,
        VTY_DECLVAR_CONTEXT(interface, ifp);
        struct zebra_if *zif = ifp->info;
 
-       if (if_is_loopback(ifp)
-           || CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK)) {
+       if (if_is_loopback_or_vrf(ifp)) {
                vty_out(vty,
                        "Cannot configure IPv6 Router Advertisements on this  interface\n");
                return CMD_WARNING_CONFIG_FAILED;
@@ -1488,8 +1484,7 @@ DEFUN (no_ipv6_nd_ra_fast_retrans,
        VTY_DECLVAR_CONTEXT(interface, ifp);
        struct zebra_if *zif = ifp->info;
 
-       if (if_is_loopback(ifp)
-           || CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK)) {
+       if (if_is_loopback_or_vrf(ifp)) {
                vty_out(vty,
                        "Cannot configure IPv6 Router Advertisements on this  interface\n");
                return CMD_WARNING_CONFIG_FAILED;
@@ -1511,8 +1506,7 @@ DEFPY (ipv6_nd_ra_hop_limit,
        VTY_DECLVAR_CONTEXT(interface, ifp);
        struct zebra_if *zif = ifp->info;
 
-       if (if_is_loopback(ifp)
-           || CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK)) {
+       if (if_is_loopback_or_vrf(ifp)) {
                vty_out(vty,
                        "Cannot configure IPv6 Router Advertisements on this interface\n");
                return CMD_WARNING_CONFIG_FAILED;
@@ -1535,8 +1529,7 @@ DEFPY (no_ipv6_nd_ra_hop_limit,
        VTY_DECLVAR_CONTEXT(interface, ifp);
        struct zebra_if *zif = ifp->info;
 
-       if (if_is_loopback(ifp)
-           || CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK)) {
+       if (if_is_loopback_or_vrf(ifp)) {
                vty_out(vty,
                        "Cannot configure IPv6 Router Advertisements on this interface\n");
                return CMD_WARNING_CONFIG_FAILED;
@@ -1558,8 +1551,7 @@ DEFPY (ipv6_nd_ra_retrans_interval,
        VTY_DECLVAR_CONTEXT(interface, ifp);
        struct zebra_if *zif = ifp->info;
 
-       if (if_is_loopback(ifp)
-           || CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK)) {
+       if (if_is_loopback_or_vrf(ifp)) {
                vty_out(vty,
                        "Cannot configure IPv6 Router Advertisements on loopback interface\n");
                return CMD_WARNING_CONFIG_FAILED;
@@ -1582,8 +1574,7 @@ DEFPY (no_ipv6_nd_ra_retrans_interval,
        VTY_DECLVAR_CONTEXT(interface, ifp);
        struct zebra_if *zif = ifp->info;
 
-       if (if_is_loopback(ifp)
-           || CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK)) {
+       if (if_is_loopback_or_vrf(ifp)) {
                vty_out(vty,
                        "Cannot remove IPv6 Router Advertisements on loopback interface\n");
                return CMD_WARNING_CONFIG_FAILED;
@@ -1604,8 +1595,7 @@ DEFUN (ipv6_nd_suppress_ra,
        VTY_DECLVAR_CONTEXT(interface, ifp);
        struct zebra_if *zif = ifp->info;
 
-       if (if_is_loopback(ifp)
-           || CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK)) {
+       if (if_is_loopback_or_vrf(ifp)) {
                vty_out(vty,
                        "Cannot configure IPv6 Router Advertisements on this  interface\n");
                return CMD_WARNING_CONFIG_FAILED;
@@ -1629,8 +1619,7 @@ DEFUN (no_ipv6_nd_suppress_ra,
        VTY_DECLVAR_CONTEXT(interface, ifp);
        struct zebra_if *zif = ifp->info;
 
-       if (if_is_loopback(ifp)
-           || CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK)) {
+       if (if_is_loopback_or_vrf(ifp)) {
                vty_out(vty,
                        "Cannot configure IPv6 Router Advertisements on this interface\n");
                return CMD_WARNING_CONFIG_FAILED;
@@ -2619,8 +2608,7 @@ static int rtadv_config_write(struct vty *vty, struct interface *ifp)
 
        zif = ifp->info;
 
-       if (!(if_is_loopback(ifp)
-             || CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK))) {
+       if (!if_is_loopback_or_vrf(ifp)) {
                if (zif->rtadv.AdvSendAdvertisements
                    && CHECK_FLAG(zif->rtadv.ra_configured, VTY_RA_CONFIGURED))
                        vty_out(vty, " no ipv6 nd suppress-ra\n");
index b651edd8f99f3e5a6fd09c6e5dbfc554195ccf82..fbf2620375f3b2b4d18fb3dffa1f6b6a86a32682 100644 (file)
@@ -403,7 +403,7 @@ int netlink_rules_read(struct zebra_ns *zns)
                return ret;
 
        ret = netlink_parse_info(netlink_rule_change, &zns->netlink_cmd,
-                                &dp_info, 0, 1);
+                                &dp_info, 0, true);
        if (ret < 0)
                return ret;
 
@@ -412,7 +412,7 @@ int netlink_rules_read(struct zebra_ns *zns)
                return ret;
 
        ret = netlink_parse_info(netlink_rule_change, &zns->netlink_cmd,
-                                &dp_info, 0, 1);
+                                &dp_info, 0, true);
        return ret;
 }
 
index 0aef1965d214bdaafea9acba3b7d7980aa73bc93..ecfc7da8837cda6ef2ce31375b3ccaffb1c7b3e5 100644 (file)
@@ -1137,6 +1137,31 @@ static int zsend_table_manager_connect_response(struct zserv *client,
        return zserv_send_message(client, s);
 }
 
+/* SRv6 locator add notification from zebra daemon. */
+int zsend_zebra_srv6_locator_add(struct zserv *client, struct srv6_locator *loc)
+{
+       struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ);
+
+       zclient_create_header(s, ZEBRA_SRV6_LOCATOR_ADD, VRF_DEFAULT);
+       zapi_srv6_locator_encode(s, loc);
+       stream_putw_at(s, 0, stream_get_endp(s));
+
+       return zserv_send_message(client, s);
+}
+
+/* SRv6 locator delete notification from zebra daemon. */
+int zsend_zebra_srv6_locator_delete(struct zserv *client,
+                                   struct srv6_locator *loc)
+{
+       struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ);
+
+       zclient_create_header(s, ZEBRA_SRV6_LOCATOR_DELETE, VRF_DEFAULT);
+       zapi_srv6_locator_encode(s, loc);
+       stream_putw_at(s, 0, stream_get_endp(s));
+
+       return zserv_send_message(client, s);
+}
+
 /* Inbound message handling ------------------------------------------------ */
 
 const int cmd2type[] = {
@@ -1611,7 +1636,8 @@ static struct nexthop *nexthop_from_zapi(const struct zapi_nexthop *api_nh,
                        zlog_debug("%s: nh blackhole %d",
                                   __func__, api_nh->bh_type);
 
-               nexthop = nexthop_from_blackhole(api_nh->bh_type);
+               nexthop =
+                       nexthop_from_blackhole(api_nh->bh_type, api_nh->vrf_id);
                break;
        }
 
index 39f865fbfcd430abc8a4039cf824306603a705f3..ab06ea643807acd9664e7bf5a6947a8f808972f8 100644 (file)
 #include "zebra/zebra_pbr.h"
 #include "printfrr.h"
 
-/* Memory type for context blocks */
+/* Memory types */
 DEFINE_MTYPE_STATIC(ZEBRA, DP_CTX, "Zebra DPlane Ctx");
 DEFINE_MTYPE_STATIC(ZEBRA, DP_INTF, "Zebra DPlane Intf");
 DEFINE_MTYPE_STATIC(ZEBRA, DP_PROV, "Zebra DPlane Provider");
 DEFINE_MTYPE_STATIC(ZEBRA, DP_NETFILTER, "Zebra Netfilter Internal Object");
+DEFINE_MTYPE_STATIC(ZEBRA, DP_NS, "DPlane NSes");
 
 #ifndef AOK
 #  define AOK 0
@@ -402,6 +403,19 @@ struct zebra_dplane_provider {
        TAILQ_ENTRY(zebra_dplane_provider) dp_prov_link;
 };
 
+/* Declare types for list of zns info objects */
+PREDECL_DLIST(zns_info_list);
+
+struct dplane_zns_info {
+       struct zebra_dplane_info info;
+
+       /* Read event */
+       struct thread *t_read;
+
+       /* List linkage */
+       struct zns_info_list_item link;
+};
+
 /*
  * Globals
  */
@@ -424,6 +438,9 @@ static struct zebra_dplane_globals {
        /* Ordered list of providers */
        TAILQ_HEAD(zdg_prov_q, zebra_dplane_provider) dg_providers_q;
 
+       /* List of info about each zns */
+       struct zns_info_list_head dg_zns_list;
+
        /* Counter used to assign internal ids to providers */
        uint32_t dg_provider_id;
 
@@ -498,6 +515,9 @@ static struct zebra_dplane_globals {
 
 } zdplane_info;
 
+/* Instantiate zns list type */
+DECLARE_DLIST(zns_info_list, struct dplane_zns_info, link);
+
 /*
  * Lock and unlock for interactions with the zebra 'core' pthread
  */
@@ -690,6 +710,8 @@ static void dplane_ctx_free_internal(struct zebra_dplane_ctx *ctx)
 
        case DPLANE_OP_ADDR_INSTALL:
        case DPLANE_OP_ADDR_UNINSTALL:
+       case DPLANE_OP_INTF_ADDR_ADD:
+       case DPLANE_OP_INTF_ADDR_DEL:
                /* Maybe free label string, if allocated */
                if (ctx->u.intf.label != NULL &&
                    ctx->u.intf.label != ctx->u.intf.label_buf) {
@@ -1011,6 +1033,12 @@ const char *dplane_op2str(enum dplane_op_e op)
        case DPLANE_OP_GRE_SET:
                ret = "GRE_SET";
                break;
+
+       case DPLANE_OP_INTF_ADDR_ADD:
+               return "INTF_ADDR_ADD";
+
+       case DPLANE_OP_INTF_ADDR_DEL:
+               return "INTF_ADDR_DEL";
        }
 
        return ret;
@@ -1108,6 +1136,21 @@ vrf_id_t dplane_ctx_get_vrf(const struct zebra_dplane_ctx *ctx)
        return ctx->zd_vrf_id;
 }
 
+/* In some paths we have only a namespace id */
+void dplane_ctx_set_ns_id(struct zebra_dplane_ctx *ctx, ns_id_t nsid)
+{
+       DPLANE_CTX_VALID(ctx);
+
+       ctx->zd_ns_info.ns_id = nsid;
+}
+
+ns_id_t dplane_ctx_get_ns_id(const struct zebra_dplane_ctx *ctx)
+{
+       DPLANE_CTX_VALID(ctx);
+
+       return ctx->zd_ns_info.ns_id;
+}
+
 bool dplane_ctx_is_from_notif(const struct zebra_dplane_ctx *ctx)
 {
        DPLANE_CTX_VALID(ctx);
@@ -1154,6 +1197,13 @@ ifindex_t dplane_ctx_get_ifindex(const struct zebra_dplane_ctx *ctx)
        return ctx->zd_ifindex;
 }
 
+void dplane_ctx_set_ifindex(struct zebra_dplane_ctx *ctx, ifindex_t ifindex)
+{
+       DPLANE_CTX_VALID(ctx);
+
+       ctx->zd_ifindex = ifindex;
+}
+
 void dplane_ctx_set_type(struct zebra_dplane_ctx *ctx, int type)
 {
        DPLANE_CTX_VALID(ctx);
@@ -1669,6 +1719,13 @@ uint32_t dplane_ctx_get_intf_metric(const struct zebra_dplane_ctx *ctx)
        return ctx->u.intf.metric;
 }
 
+void dplane_ctx_set_intf_metric(struct zebra_dplane_ctx *ctx, uint32_t metric)
+{
+       DPLANE_CTX_VALID(ctx);
+
+       ctx->u.intf.metric = metric;
+}
+
 /* Is interface addr p2p? */
 bool dplane_ctx_intf_is_connected(const struct zebra_dplane_ctx *ctx)
 {
@@ -1691,6 +1748,27 @@ bool dplane_ctx_intf_is_broadcast(const struct zebra_dplane_ctx *ctx)
        return (ctx->u.intf.flags & DPLANE_INTF_BROADCAST);
 }
 
+void dplane_ctx_intf_set_connected(struct zebra_dplane_ctx *ctx)
+{
+       DPLANE_CTX_VALID(ctx);
+
+       ctx->u.intf.flags |= DPLANE_INTF_CONNECTED;
+}
+
+void dplane_ctx_intf_set_secondary(struct zebra_dplane_ctx *ctx)
+{
+       DPLANE_CTX_VALID(ctx);
+
+       ctx->u.intf.flags |= DPLANE_INTF_SECONDARY;
+}
+
+void dplane_ctx_intf_set_broadcast(struct zebra_dplane_ctx *ctx)
+{
+       DPLANE_CTX_VALID(ctx);
+
+       ctx->u.intf.flags |= DPLANE_INTF_BROADCAST;
+}
+
 const struct prefix *dplane_ctx_get_intf_addr(
        const struct zebra_dplane_ctx *ctx)
 {
@@ -1699,6 +1777,14 @@ const struct prefix *dplane_ctx_get_intf_addr(
        return &(ctx->u.intf.prefix);
 }
 
+void dplane_ctx_set_intf_addr(struct zebra_dplane_ctx *ctx,
+                             const struct prefix *p)
+{
+       DPLANE_CTX_VALID(ctx);
+
+       prefix_copy(&(ctx->u.intf.prefix), p);
+}
+
 bool dplane_ctx_intf_has_dest(const struct zebra_dplane_ctx *ctx)
 {
        DPLANE_CTX_VALID(ctx);
@@ -1711,10 +1797,15 @@ const struct prefix *dplane_ctx_get_intf_dest(
 {
        DPLANE_CTX_VALID(ctx);
 
-       if (ctx->u.intf.flags & DPLANE_INTF_HAS_DEST)
-               return &(ctx->u.intf.dest_prefix);
-       else
-               return NULL;
+       return &(ctx->u.intf.dest_prefix);
+}
+
+void dplane_ctx_set_intf_dest(struct zebra_dplane_ctx *ctx,
+                             const struct prefix *p)
+{
+       DPLANE_CTX_VALID(ctx);
+
+       prefix_copy(&(ctx->u.intf.dest_prefix), p);
 }
 
 bool dplane_ctx_intf_has_label(const struct zebra_dplane_ctx *ctx)
@@ -1731,6 +1822,35 @@ const char *dplane_ctx_get_intf_label(const struct zebra_dplane_ctx *ctx)
        return ctx->u.intf.label;
 }
 
+void dplane_ctx_set_intf_label(struct zebra_dplane_ctx *ctx, const char *label)
+{
+       size_t len;
+
+       DPLANE_CTX_VALID(ctx);
+
+       if (ctx->u.intf.label && ctx->u.intf.label != ctx->u.intf.label_buf)
+               free(ctx->u.intf.label);
+
+       ctx->u.intf.label = NULL;
+
+       if (label) {
+               ctx->u.intf.flags |= DPLANE_INTF_HAS_LABEL;
+
+               /* Use embedded buffer if it's adequate; else allocate. */
+               len = strlen(label);
+
+               if (len < sizeof(ctx->u.intf.label_buf)) {
+                       strlcpy(ctx->u.intf.label_buf, label,
+                               sizeof(ctx->u.intf.label_buf));
+                       ctx->u.intf.label = ctx->u.intf.label_buf;
+               } else {
+                       ctx->u.intf.label = strdup(label);
+               }
+       } else {
+               ctx->u.intf.flags &= ~DPLANE_INTF_HAS_LABEL;
+       }
+}
+
 /* Accessors for MAC information */
 vlanid_t dplane_ctx_mac_get_vlan(const struct zebra_dplane_ctx *ctx)
 {
@@ -2177,9 +2297,9 @@ static int dplane_ctx_ns_init(struct zebra_dplane_ctx *ctx,
         * two messages in some 'update' cases.
         */
        if (is_update)
-               zns->netlink_dplane.seq += 2;
+               zns->netlink_dplane_out.seq += 2;
        else
-               zns->netlink_dplane.seq++;
+               zns->netlink_dplane_out.seq++;
 #endif /* HAVE_NETLINK */
 
        return AOK;
@@ -4709,10 +4829,92 @@ static void dplane_info_from_zns(struct zebra_dplane_info *ns_info,
 
 #if defined(HAVE_NETLINK)
        ns_info->is_cmd = true;
-       ns_info->nls = zns->netlink_dplane;
+       ns_info->nls = zns->netlink_dplane_out;
 #endif /* NETLINK */
 }
 
+#ifdef HAVE_NETLINK
+/*
+ * Callback when an OS (netlink) incoming event read is ready. This runs
+ * in the dplane pthread.
+ */
+static int dplane_incoming_read(struct thread *event)
+{
+       struct dplane_zns_info *zi = THREAD_ARG(event);
+
+       kernel_dplane_read(&zi->info);
+
+       /* Re-start read task */
+       thread_add_read(zdplane_info.dg_master, dplane_incoming_read, zi,
+                       zi->info.nls.sock, &zi->t_read);
+
+       return 0;
+}
+#endif /* HAVE_NETLINK */
+
+/*
+ * Notify dplane when namespaces are enabled and disabled. The dplane
+ * needs to start and stop reading incoming events from the zns. In the
+ * common case where vrfs are _not_ namespaces, there will only be one
+ * of these.
+ *
+ * This is called in the main pthread.
+ */
+void zebra_dplane_ns_enable(struct zebra_ns *zns, bool enabled)
+{
+       struct dplane_zns_info *zi;
+
+       if (IS_ZEBRA_DEBUG_DPLANE)
+               zlog_debug("%s: %s for nsid %u", __func__,
+                          (enabled ? "ENABLED" : "DISABLED"), zns->ns_id);
+
+       /* Search for an existing zns info entry */
+       frr_each (zns_info_list, &zdplane_info.dg_zns_list, zi) {
+               if (zi->info.ns_id == zns->ns_id)
+                       break;
+       }
+
+       if (enabled) {
+               /* Create a new entry if necessary; start reading. */
+               if (zi == NULL) {
+                       zi = XCALLOC(MTYPE_DP_NS, sizeof(*zi));
+
+                       zi->info.ns_id = zns->ns_id;
+
+                       zns_info_list_add_tail(&zdplane_info.dg_zns_list, zi);
+
+                       if (IS_ZEBRA_DEBUG_DPLANE)
+                               zlog_debug("%s: nsid %u, new zi %p", __func__,
+                                          zns->ns_id, zi);
+               }
+
+               /* Make sure we're up-to-date with the zns object */
+#if defined(HAVE_NETLINK)
+               zi->info.is_cmd = false;
+               zi->info.nls = zns->netlink_dplane_in;
+
+               /* Start read task for the dplane pthread. */
+               if (zdplane_info.dg_master)
+                       thread_add_read(zdplane_info.dg_master,
+                                       dplane_incoming_read, zi,
+                                       zi->info.nls.sock, &zi->t_read);
+#endif
+       } else if (zi) {
+               if (IS_ZEBRA_DEBUG_DPLANE)
+                       zlog_debug("%s: nsid %u, deleting zi %p", __func__,
+                                  zns->ns_id, zi);
+
+               /* Stop reading, free memory */
+               zns_info_list_del(&zdplane_info.dg_zns_list, zi);
+
+               if (zdplane_info.dg_master)
+                       thread_cancel_async(zdplane_info.dg_master, &zi->t_read,
+                                           NULL);
+
+               XFREE(MTYPE_DP_NS, zi);
+       }
+}
+
 /*
  * Provider api to signal that work/events are available
  * for the dataplane pthread.
@@ -4878,6 +5080,14 @@ static void kernel_dplane_log_detail(struct zebra_dplane_ctx *ctx)
                           dplane_ctx_get_ifname(ctx),
                           ctx->u.gre.link_ifindex);
                break;
+
+       case DPLANE_OP_INTF_ADDR_ADD:
+       case DPLANE_OP_INTF_ADDR_DEL:
+               zlog_debug("Dplane incoming op %s, intf %s, addr %pFX",
+                          dplane_op2str(dplane_ctx_get_op(ctx)),
+                          dplane_ctx_get_ifname(ctx),
+                          dplane_ctx_get_intf_addr(ctx));
+               break;
        }
 }
 
@@ -5020,6 +5230,11 @@ static void kernel_dplane_handle_result(struct zebra_dplane_ctx *ctx)
        case DPLANE_OP_BR_PORT_UPDATE:
                break;
 
+       /* TODO -- error counters for incoming events? */
+       case DPLANE_OP_INTF_ADDR_ADD:
+       case DPLANE_OP_INTF_ADDR_DEL:
+               break;
+
        case DPLANE_OP_NONE:
                if (res != ZEBRA_DPLANE_REQUEST_SUCCESS)
                        atomic_fetch_add_explicit(&zdplane_info.dg_other_errors,
@@ -5355,9 +5570,21 @@ done:
  */
 static int dplane_check_shutdown_status(struct thread *event)
 {
+       struct dplane_zns_info *zi;
+
        if (IS_ZEBRA_DEBUG_DPLANE)
                zlog_debug("Zebra dataplane shutdown status check called");
 
+       /* Remove any zns info entries as we stop the dplane pthread. */
+       frr_each_safe (zns_info_list, &zdplane_info.dg_zns_list, zi) {
+               zns_info_list_del(&zdplane_info.dg_zns_list, zi);
+
+               if (zdplane_info.dg_master)
+                       thread_cancel(&zi->t_read);
+
+               XFREE(MTYPE_DP_NS, zi);
+       }
+
        if (dplane_work_pending()) {
                /* Reschedule dplane check on a short timer */
                thread_add_timer_msec(zdplane_info.dg_master,
@@ -5652,6 +5879,7 @@ static void zebra_dplane_init_internal(void)
 
        TAILQ_INIT(&zdplane_info.dg_update_ctx_q);
        TAILQ_INIT(&zdplane_info.dg_providers_q);
+       zns_info_list_init(&zdplane_info.dg_zns_list);
 
        zdplane_info.dg_updates_per_cycle = DPLANE_DEFAULT_NEW_WORK;
 
@@ -5667,6 +5895,7 @@ static void zebra_dplane_init_internal(void)
  */
 void zebra_dplane_start(void)
 {
+       struct dplane_zns_info *zi;
        struct zebra_dplane_provider *prov;
        struct frr_pthread_attr pattr = {
                .start = frr_pthread_attr_default.start,
@@ -5686,6 +5915,14 @@ void zebra_dplane_start(void)
        thread_add_event(zdplane_info.dg_master, dplane_thread_loop, NULL, 0,
                         &zdplane_info.dg_t_update);
 
+       /* Enqueue reads if necessary */
+       frr_each (zns_info_list, &zdplane_info.dg_zns_list, zi) {
+#if defined(HAVE_NETLINK)
+               thread_add_read(zdplane_info.dg_master, dplane_incoming_read,
+                               zi, zi->info.nls.sock, &zi->t_read);
+#endif
+       }
+
        /* Call start callbacks for registered providers */
 
        DPLANE_LOCK();
index 3f3ff4de0f87af00c086113f7965be46ee7b68ce..a23de61c80acec7a10ce3aa49a47113999ec0479 100644 (file)
@@ -63,6 +63,12 @@ zebra_dplane_info_from_zns(struct zebra_dplane_info *zns_info,
 #endif /* NETLINK */
 }
 
+/*
+ * Notify dplane when namespaces are enabled and disabled. The dplane
+ * needs to start and stop reading incoming events from the ns.
+ */
+void zebra_dplane_ns_enable(struct zebra_ns *zns, bool enabled);
+
 /*
  * Result codes used when returning status back to the main zebra context.
  */
@@ -98,7 +104,7 @@ enum zebra_dplane_result {
  */
 
 /*
- * Enqueue a route install or update for the dataplane.
+ * Operations that the dataplane can process.
  */
 enum dplane_op_e {
        DPLANE_OP_NONE = 0,
@@ -172,6 +178,10 @@ enum dplane_op_e {
 
        DPLANE_OP_NEIGH_TABLE_UPDATE,
        DPLANE_OP_GRE_SET,
+
+       /* Incoming interface address events */
+       DPLANE_OP_INTF_ADDR_ADD,
+       DPLANE_OP_INTF_ADDR_DEL,
 };
 
 /*
@@ -284,6 +294,7 @@ void dplane_ctx_set_dest(struct zebra_dplane_ctx *ctx,
 const char *dplane_ctx_get_ifname(const struct zebra_dplane_ctx *ctx);
 void dplane_ctx_set_ifname(struct zebra_dplane_ctx *ctx, const char *ifname);
 ifindex_t dplane_ctx_get_ifindex(const struct zebra_dplane_ctx *ctx);
+void dplane_ctx_set_ifindex(struct zebra_dplane_ctx *ctx, ifindex_t ifindex);
 
 /* Retrieve last/current provider id */
 uint32_t dplane_ctx_get_provider(const struct zebra_dplane_ctx *ctx);
@@ -306,6 +317,10 @@ uint32_t dplane_ctx_get_old_seq(const struct zebra_dplane_ctx *ctx);
 void dplane_ctx_set_vrf(struct zebra_dplane_ctx *ctx, vrf_id_t vrf);
 vrf_id_t dplane_ctx_get_vrf(const struct zebra_dplane_ctx *ctx);
 
+/* In some paths we have only a namespace id */
+void dplane_ctx_set_ns_id(struct zebra_dplane_ctx *ctx, ns_id_t nsid);
+ns_id_t dplane_ctx_get_ns_id(const struct zebra_dplane_ctx *ctx);
+
 bool dplane_ctx_is_from_notif(const struct zebra_dplane_ctx *ctx);
 void dplane_ctx_set_notif_provider(struct zebra_dplane_ctx *ctx,
                                   uint32_t id);
@@ -441,17 +456,26 @@ dplane_ctx_get_pw_backup_nhg(const struct zebra_dplane_ctx *ctx);
 
 /* Accessors for interface information */
 uint32_t dplane_ctx_get_intf_metric(const struct zebra_dplane_ctx *ctx);
+void dplane_ctx_set_intf_metric(struct zebra_dplane_ctx *ctx, uint32_t metric);
 /* Is interface addr p2p? */
 bool dplane_ctx_intf_is_connected(const struct zebra_dplane_ctx *ctx);
+void dplane_ctx_intf_set_connected(struct zebra_dplane_ctx *ctx);
 bool dplane_ctx_intf_is_secondary(const struct zebra_dplane_ctx *ctx);
+void dplane_ctx_intf_set_secondary(struct zebra_dplane_ctx *ctx);
 bool dplane_ctx_intf_is_broadcast(const struct zebra_dplane_ctx *ctx);
+void dplane_ctx_intf_set_broadcast(struct zebra_dplane_ctx *ctx);
 const struct prefix *dplane_ctx_get_intf_addr(
        const struct zebra_dplane_ctx *ctx);
+void dplane_ctx_set_intf_addr(struct zebra_dplane_ctx *ctx,
+                             const struct prefix *p);
 bool dplane_ctx_intf_has_dest(const struct zebra_dplane_ctx *ctx);
 const struct prefix *dplane_ctx_get_intf_dest(
        const struct zebra_dplane_ctx *ctx);
+void dplane_ctx_set_intf_dest(struct zebra_dplane_ctx *ctx,
+                             const struct prefix *p);
 bool dplane_ctx_intf_has_label(const struct zebra_dplane_ctx *ctx);
 const char *dplane_ctx_get_intf_label(const struct zebra_dplane_ctx *ctx);
+void dplane_ctx_set_intf_label(struct zebra_dplane_ctx *ctx, const char *label);
 
 /* Accessors for MAC information */
 vlanid_t dplane_ctx_mac_get_vlan(const struct zebra_dplane_ctx *ctx);
index 08ff7011e2e6801c8dfe172a023228575560c658..af46ea6d7af9dc5bf93f976045d9b292f0eb75ee 100644 (file)
@@ -2113,12 +2113,12 @@ void zebra_evpn_neigh_remote_macip_add(struct zebra_evpn *zevpn,
                                                "sync->remote neigh vni %u ip %pIA mac %pEA seq %d f0x%x",
                                                n->zevpn->vni, &n->ip, &n->emac,
                                                seq, n->flags);
-                               zebra_evpn_neigh_clear_sync_info(n);
                                if (IS_ZEBRA_NEIGH_ACTIVE(n))
                                        zebra_evpn_neigh_send_del_to_client(
                                                zevpn->vni, &n->ip, &n->emac,
                                                n->flags, n->state,
                                                false /*force*/);
+                               zebra_evpn_neigh_clear_sync_info(n);
                        }
                        if (memcmp(&n->emac, &mac->macaddr,
                                   sizeof(struct ethaddr))
index 64366d6f4fa20e45b0aa06997e3124985c43117a..43958fdfdec54170c337be4a3b6f5a6a4b49713a 100644 (file)
@@ -292,6 +292,9 @@ static void zfpm_start_connect_timer(const char *reason);
 static void zfpm_start_stats_timer(void);
 static void zfpm_mac_info_del(struct fpm_mac_info_t *fpm_mac);
 
+static const char ipv4_ll_buf[16] = "169.254.0.1";
+union g_addr ipv4ll_gateway;
+
 /*
  * zfpm_thread_should_yield
  */
@@ -1993,6 +1996,10 @@ static int zfpm_init(struct thread_master *master)
        zfpm_stats_init(&zfpm_g->last_ivl_stats);
        zfpm_stats_init(&zfpm_g->cumulative_stats);
 
+       memset(&ipv4ll_gateway, 0, sizeof(ipv4ll_gateway));
+       if (inet_pton(AF_INET, ipv4_ll_buf, &ipv4ll_gateway.ipv4) != 1)
+               zlog_warn("inet_pton failed for %s", ipv4_ll_buf);
+
        install_node(&zebra_node);
        install_element(ENABLE_NODE, &show_zebra_fpm_stats_cmd);
        install_element(ENABLE_NODE, &clear_zebra_fpm_stats_cmd);
index efbd078a526352bc2cb7c228b7d1e80be2f34fc5..168e36ac9bcb5f9e95c481eb9b991e434d50a14a 100644 (file)
@@ -189,7 +189,12 @@ static int netlink_route_info_add_nh(struct netlink_route_info *ri,
 
        if (nexthop->type == NEXTHOP_TYPE_IPV6
            || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) {
-               nhi.gateway = &nexthop->gate;
+               /* Special handling for IPv4 route with IPv6 Link Local next hop
+                */
+               if (ri->af == AF_INET)
+                       nhi.gateway = &ipv4ll_gateway;
+               else
+                       nhi.gateway = &nexthop->gate;
        }
 
        if (nexthop->type == NEXTHOP_TYPE_IFINDEX) {
@@ -276,7 +281,7 @@ static int netlink_route_info_fill(struct netlink_route_info *ri, int cmd,
        ri->af = rib_dest_af(dest);
 
        if (zvrf && zvrf->zns)
-               ri->nlmsg_pid = zvrf->zns->netlink_dplane.snl.nl_pid;
+               ri->nlmsg_pid = zvrf->zns->netlink_dplane_out.snl.nl_pid;
 
        ri->nlmsg_type = cmd;
        ri->rtm_table = table_info->table_id;
index c169ee8c2219481a160e246919b2331fa7f919cd..13415c7e1d9bd3e56df3a3fe4eda40dfac8f7cd6 100644 (file)
@@ -97,6 +97,8 @@ extern int zfpm_netlink_encode_mac(struct fpm_mac_info_t *mac, char *in_buf,
 
 extern struct route_entry *zfpm_route_for_update(rib_dest_t *dest);
 
+extern union g_addr ipv4ll_gateway;
+
 #ifdef __cplusplus
 }
 #endif
index 71fac556e19006c8638efde60d3dd83834fe5f4d..5a02149611fbaf8e8d27694ae8f28b439ac0140e 100644 (file)
@@ -50,7 +50,8 @@
 /* static function declarations */
 
 /* Private functions */
-static void map_slaves_to_bridge(struct interface *br_if, int link)
+static void map_slaves_to_bridge(struct interface *br_if, int link,
+                                bool update_slave, uint8_t chgflags)
 {
        struct vrf *vrf;
        struct interface *ifp;
@@ -79,9 +80,17 @@ static void map_slaves_to_bridge(struct interface *br_if, int link)
                        br_slave = &zif->brslave_info;
 
                        if (link) {
-                               if (br_slave->bridge_ifindex == br_if->ifindex &&
-                                   br_slave->ns_id == zns->ns_id)
+                               if (br_slave->bridge_ifindex == br_if->ifindex
+                                   && br_slave->ns_id == zns->ns_id) {
                                        br_slave->br_if = br_if;
+                                       if (update_slave) {
+                                               zebra_l2if_update_bridge_slave(
+                                                       ifp,
+                                                       br_slave->bridge_ifindex,
+                                                       br_slave->ns_id,
+                                                       chgflags);
+                                       }
+                               }
                        } else {
                                if (br_slave->br_if == br_if)
                                        br_slave->br_if = NULL;
@@ -261,7 +270,7 @@ void zebra_l2_bridge_add_update(struct interface *ifp,
        memcpy(&zif->l2info.br, bridge_info, sizeof(*bridge_info));
 
        /* Link all slaves to this bridge */
-       map_slaves_to_bridge(ifp, 1);
+       map_slaves_to_bridge(ifp, 1, false, ZEBRA_BRIDGE_NO_ACTION);
 }
 
 /*
@@ -270,7 +279,14 @@ void zebra_l2_bridge_add_update(struct interface *ifp,
 void zebra_l2_bridge_del(struct interface *ifp)
 {
        /* Unlink all slaves to this bridge */
-       map_slaves_to_bridge(ifp, 0);
+       map_slaves_to_bridge(ifp, 0, false, ZEBRA_BRIDGE_NO_ACTION);
+}
+
+void zebra_l2if_update_bridge(struct interface *ifp, uint8_t chgflags)
+{
+       if (!chgflags)
+               return;
+       map_slaves_to_bridge(ifp, 1, true, chgflags);
 }
 
 /*
@@ -398,8 +414,8 @@ void zebra_l2_vxlanif_del(struct interface *ifp)
  * from a bridge before it can be mapped to another bridge.
  */
 void zebra_l2if_update_bridge_slave(struct interface *ifp,
-                                   ifindex_t bridge_ifindex,
-                                   ns_id_t ns_id)
+                                   ifindex_t bridge_ifindex, ns_id_t ns_id,
+                                   uint8_t chgflags)
 {
        struct zebra_if *zif;
        ifindex_t old_bridge_ifindex;
@@ -413,6 +429,14 @@ void zebra_l2if_update_bridge_slave(struct interface *ifp,
        if (!zvrf)
                return;
 
+       if (zif->zif_type == ZEBRA_IF_VXLAN
+           && chgflags != ZEBRA_BRIDGE_NO_ACTION) {
+               if (ZEBRA_BRIDGE_MASTER_MAC_CHANGE)
+                       zebra_vxlan_if_update(ifp,
+                                             ZEBRA_VXLIF_MASTER_MAC_CHANGE);
+               if (ZEBRA_BRIDGE_MASTER_UP)
+                       zebra_vxlan_if_update(ifp, ZEBRA_VXLIF_MASTER_CHANGE);
+       }
        old_bridge_ifindex = zif->brslave_info.bridge_ifindex;
        old_ns_id = zif->brslave_info.ns_id;
        if (old_bridge_ifindex == bridge_ifindex &&
index 6572f344c4d0de2cd6fa1fa79f7ed276fb3765bd..98744f3c1fbf390598d5c14eb7f977bed1abb7ad 100644 (file)
 extern "C" {
 #endif
 
+#define ZEBRA_BRIDGE_NO_ACTION (0)
+#define ZEBRA_BRIDGE_MASTER_MAC_CHANGE (1 << 1)
+#define ZEBRA_BRIDGE_MASTER_UP (1 << 2)
+
 /* zebra L2 interface information - bridge slave (linkage to bridge) */
 struct zebra_l2info_brslave {
        ifindex_t bridge_ifindex; /* Bridge Master */
@@ -121,7 +125,7 @@ extern void zebra_l2_greif_del(struct interface *ifp);
 extern void zebra_l2_vxlanif_del(struct interface *ifp);
 extern void zebra_l2if_update_bridge_slave(struct interface *ifp,
                                           ifindex_t bridge_ifindex,
-                                          ns_id_t ns_id);
+                                          ns_id_t ns_id, uint8_t chgflags);
 
 extern void zebra_l2if_update_bond_slave(struct interface *ifp,
                                         ifindex_t bond_ifindex, bool bypass);
@@ -130,6 +134,7 @@ extern void zebra_vlan_bitmap_compute(struct interface *ifp,
 extern void zebra_vlan_mbr_re_eval(struct interface *ifp,
                bitfield_t vlan_bitmap);
 extern void zebra_l2if_update_bond(struct interface *ifp, bool add);
+extern void zebra_l2if_update_bridge(struct interface *ifp, uint8_t chgflags);
 
 #ifdef __cplusplus
 }
index 054015846f478dadb460262cc4e3f65470cea34c..61f97ce6a948e061f51356190d9f5f982fb36bc0 100644 (file)
@@ -346,7 +346,6 @@ void zebra_ns_notify_init(void)
 {
        int fd_monitor;
 
-       zebra_netns_notify_current = NULL;
        fd_monitor = inotify_init();
        if (fd_monitor < 0) {
                flog_err_sys(
index ce1126438390238f1cee6d3949f5435e82ef0e2f..aa015992d5680354afe44b40570374204feb58ae 100644 (file)
@@ -1773,6 +1773,14 @@ static struct nexthop *nexthop_set_resolved(afi_t afi,
                nexthop_add_labels(resolved_hop, label_type, num_labels,
                                   labels);
 
+       if (nexthop->nh_srv6) {
+               nexthop_add_srv6_seg6local(resolved_hop,
+                                          nexthop->nh_srv6->seg6local_action,
+                                          &nexthop->nh_srv6->seg6local_ctx);
+               nexthop_add_srv6_seg6(resolved_hop,
+                                     &nexthop->nh_srv6->seg6_segs);
+       }
+
        resolved_hop->rparent = nexthop;
        _nexthop_add(&nexthop->resolved, resolved_hop);
 
@@ -2979,6 +2987,8 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx)
        case DPLANE_OP_IPSET_ENTRY_DELETE:
        case DPLANE_OP_NEIGH_TABLE_UPDATE:
        case DPLANE_OP_GRE_SET:
+       case DPLANE_OP_INTF_ADDR_ADD:
+       case DPLANE_OP_INTF_ADDR_DEL:
                break;
        }
 
index 0f53de8c31c9cdd6b009b32b67ffbd4322e1ec55..50e1d0f3892e97a94a945432e81187ddadd88699 100644 (file)
@@ -123,6 +123,7 @@ int zebra_ns_enable(ns_id_t ns_id, void **info)
        zns->ns_id = ns_id;
 
        kernel_init(zns);
+       zebra_dplane_ns_enable(zns, true);
        interface_list(zns);
        route_read(zns);
        kernel_read_pbr_rules(zns);
@@ -137,6 +138,8 @@ static int zebra_ns_disable_internal(struct zebra_ns *zns, bool complete)
 {
        route_table_finish(zns->if_table);
 
+       zebra_dplane_ns_enable(zns, false /*Disable*/);
+
        kernel_terminate(zns, complete);
 
        zns->ns_id = NS_DEFAULT;
index f7d1f40782a7e42b97f0932b7cc2a59be7be21b8..8237de7ddea447bdc188b3131d2b16bf80da44c3 100644 (file)
@@ -52,7 +52,12 @@ struct zebra_ns {
 #ifdef HAVE_NETLINK
        struct nlsock netlink;        /* kernel messages */
        struct nlsock netlink_cmd;    /* command channel */
-       struct nlsock netlink_dplane; /* dataplane channel */
+
+       /* dplane system's channels: one for outgoing programming,
+        * for the FIB e.g., and one for incoming events from the OS.
+        */
+       struct nlsock netlink_dplane_out;
+       struct nlsock netlink_dplane_in;
        struct thread *t_netlink;
 #endif
 
index 7e9382518f4b9d96246917c1eef9294b97d4a63e..e17465b112a4787a7213616db3cc0f5d419b13ff 100644 (file)
@@ -520,7 +520,13 @@ static int zebra_ptm_handle_bfd_msg(void *arg, void *in_ctxt,
        if (!strcmp(ZEBRA_PTM_INVALID_VRF, vrf_str) && ifp) {
                vrf_id = ifp->vrf_id;
        } else {
-               vrf_id = vrf_name_to_id(vrf_str);
+               struct vrf *pVrf;
+
+               pVrf = vrf_lookup_by_name(vrf_str);
+               if (pVrf)
+                       vrf_id = pVrf->vrf_id;
+               else
+                       vrf_id = VRF_DEFAULT;
        }
 
        if (!strcmp(bfdst_str, ZEBRA_PTM_BFDSTATUS_DOWN_STR)) {
index 1fb4e5e6fc155637114fac442103f18459e27990..24c51e485ff5c8ef8e64922298f04722cfd9c1e0 100644 (file)
@@ -4209,6 +4209,11 @@ static int rib_process_dplane_results(struct thread *thread)
                                zebra_pbr_dplane_result(ctx);
                                break;
 
+                       case DPLANE_OP_INTF_ADDR_ADD:
+                       case DPLANE_OP_INTF_ADDR_DEL:
+                               zebra_if_addr_update_ctx(ctx);
+                               break;
+
                        /* Some op codes not handled here */
                        case DPLANE_OP_ADDR_INSTALL:
                        case DPLANE_OP_ADDR_UNINSTALL:
index b11331a180a225b88063b728d4f9ccc83739cee0..219d04769441baacf11c429d7197de5952ac80ab 100644 (file)
@@ -106,15 +106,60 @@ void zebra_srv6_locator_add(struct srv6_locator *locator)
 {
        struct zebra_srv6 *srv6 = zebra_srv6_get_default();
        struct srv6_locator *tmp;
+       struct listnode *node;
+       struct zserv *client;
 
        tmp = zebra_srv6_locator_lookup(locator->name);
        if (!tmp)
                listnode_add(srv6->locators, locator);
+
+       /*
+        * Notify new locator info to zclients.
+        *
+        * The srv6 locators and their prefixes are managed by zserv(zebra).
+        * And an actual configuration the srv6 sid in the srv6 locator is done
+        * by zclient(bgpd, isisd, etc). The configuration of each locator
+        * allocation and specify it by zserv and zclient should be
+        * asynchronous. For that, zclient should be received the event via
+        * ZAPI when a srv6 locator is added on zebra.
+        * Basically, in SRv6, adding/removing SRv6 locators is performed less
+        * frequently than adding rib entries, so a broad to all zclients will
+        * not degrade the overall performance of FRRouting.
+        */
+       for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client))
+               zsend_zebra_srv6_locator_add(client, locator);
 }
 
 void zebra_srv6_locator_delete(struct srv6_locator *locator)
 {
+       struct listnode *n;
+       struct srv6_locator_chunk *c;
        struct zebra_srv6 *srv6 = zebra_srv6_get_default();
+       struct zserv *client;
+
+       /*
+        * Notify deleted locator info to zclients if needed.
+        *
+        * zclient(bgpd,isisd,etc) allocates a sid from srv6 locator chunk and
+        * uses it for its own purpose. For example, in the case of BGP L3VPN,
+        * the SID assigned to vpn unicast rib will be given.
+        * And when the locator is deleted by zserv(zebra), those SIDs need to
+        * be withdrawn. The zclient must initiate the withdrawal of the SIDs
+        * by ZEBRA_SRV6_LOCATOR_DELETE, and this notification is sent to the
+        * owner of each chunk.
+        */
+       for (ALL_LIST_ELEMENTS_RO((struct list *)locator->chunks, n, c)) {
+               if (c->proto == ZEBRA_ROUTE_SYSTEM)
+                       continue;
+               client = zserv_find_client(c->proto, c->instance);
+               if (!client) {
+                       zlog_warn(
+                               "%s: Not found zclient(proto=%u, instance=%u).",
+                               __func__, c->proto, c->instance);
+                       continue;
+               }
+               zsend_zebra_srv6_locator_delete(client, locator);
+       }
 
        listnode_delete(srv6->locators, locator);
 }
@@ -171,19 +216,7 @@ assign_srv6_locator_chunk(uint8_t proto,
        if (!loc) {
                zlog_info("%s: locator %s was not found",
                          __func__, locator_name);
-
-               loc = srv6_locator_alloc(locator_name);
-               if (!loc) {
-                       zlog_info("%s: locator %s can't allocated",
-                                 __func__, locator_name);
-                       return NULL;
-               }
-
-               loc->status_up = false;
-               chunk = srv6_locator_chunk_alloc();
-               chunk->proto = NO_PROTO;
-               listnode_add(loc->chunks, chunk);
-               zebra_srv6_locator_add(loc);
+               return NULL;
        }
 
        for (ALL_LIST_ELEMENTS_RO((struct list *)loc->chunks, node, chunk)) {
index d2b91b6c07e1e71d373f004c217db77ee445b78b..cb1e6c42283ad41330f986ba97e1c4cea8af1931 100644 (file)
@@ -197,6 +197,21 @@ DEFUN_NOSH (srv6,
        return CMD_SUCCESS;
 }
 
+DEFUN (no_srv6,
+       no_srv6_cmd,
+       "no srv6",
+       NO_STR
+       "Segment Routing SRv6\n")
+{
+       struct zebra_srv6 *srv6 = zebra_srv6_get_default();
+       struct srv6_locator *locator;
+       struct listnode *node, *nnode;
+
+       for (ALL_LIST_ELEMENTS(srv6->locators, node, nnode, locator))
+               zebra_srv6_locator_delete(locator);
+       return CMD_SUCCESS;
+}
+
 DEFUN_NOSH (srv6_locators,
             srv6_locators_cmd,
             "locators",
@@ -233,6 +248,23 @@ DEFUN_NOSH (srv6_locator,
        return CMD_SUCCESS;
 }
 
+DEFUN (no_srv6_locator,
+       no_srv6_locator_cmd,
+       "no locator WORD",
+       NO_STR
+       "Segment Routing SRv6 locator\n"
+       "Specify locator-name\n")
+{
+       struct srv6_locator *locator = zebra_srv6_locator_lookup(argv[2]->arg);
+       if (!locator) {
+               vty_out(vty, "%% Can't find SRv6 locator\n");
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       zebra_srv6_locator_delete(locator);
+       return CMD_SUCCESS;
+}
+
 DEFPY (locator_prefix,
        locator_prefix_cmd,
        "prefix X:X::X:X/M$prefix [func-bits (16-64)$func_bit_len]",
@@ -348,8 +380,10 @@ void zebra_srv6_vty_init(void)
        /* Command for change node */
        install_element(CONFIG_NODE, &segment_routing_cmd);
        install_element(SEGMENT_ROUTING_NODE, &srv6_cmd);
+       install_element(SEGMENT_ROUTING_NODE, &no_srv6_cmd);
        install_element(SRV6_NODE, &srv6_locators_cmd);
        install_element(SRV6_LOCS_NODE, &srv6_locator_cmd);
+       install_element(SRV6_LOCS_NODE, &no_srv6_locator_cmd);
 
        /* Command for configuration */
        install_element(SRV6_LOC_NODE, &locator_prefix_cmd);
index b787c7c3428561dc9087eae511bda18e457237c6..c6b3eb48a0d87ea44acb9e928d245023e40c7d31 100644 (file)
@@ -354,13 +354,13 @@ static void show_nexthop_detail_helper(struct vty *vty,
                        break;
                }
                break;
-       default:
-               break;
        }
 
-       if ((re->vrf_id != nexthop->vrf_id)
-           && (nexthop->type != NEXTHOP_TYPE_BLACKHOLE))
-               vty_out(vty, "(vrf %s)", vrf_id_to_name(nexthop->vrf_id));
+       if (re->vrf_id != nexthop->vrf_id) {
+               struct vrf *vrf = vrf_lookup_by_id(nexthop->vrf_id);
+
+               vty_out(vty, "(vrf %s)", VRF_LOGNAME(vrf));
+       }
 
        if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE))
                vty_out(vty, " (duplicate nexthop removed)");
@@ -604,12 +604,9 @@ static void show_route_nexthop_helper(struct vty *vty,
                        break;
                }
                break;
-       default:
-               break;
        }
 
-       if ((re == NULL || (nexthop->vrf_id != re->vrf_id))
-           && (nexthop->type != NEXTHOP_TYPE_BLACKHOLE))
+       if ((re == NULL || (nexthop->vrf_id != re->vrf_id)))
                vty_out(vty, " (vrf %s)", vrf_id_to_name(nexthop->vrf_id));
 
        if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
@@ -777,12 +774,9 @@ static void show_nexthop_json_helper(json_object *json_nexthop,
                        break;
                }
                break;
-       default:
-               break;
        }
 
-       if ((nexthop->vrf_id != re->vrf_id)
-           && (nexthop->type != NEXTHOP_TYPE_BLACKHOLE))
+       if (nexthop->vrf_id != re->vrf_id)
                json_object_string_add(json_nexthop, "vrf",
                                       vrf_id_to_name(nexthop->vrf_id));
 
@@ -972,6 +966,7 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
                json_object_int_add(json_route, "internalNextHopActiveNum",
                                    nexthop_group_active_nexthop_num(
                                            &(re->nhe->nhg)));
+               json_object_int_add(json_route, "nexthopGroupId", re->nhe_id);
 
                json_object_string_add(json_route, "uptime", up_str);
 
@@ -2248,8 +2243,6 @@ static void show_ip_route_nht_dump(struct vty *vty, struct nexthop *nexthop,
                        break;
                }
                break;
-       default:
-               break;
        }
 }
 
index aede4098b4ec15cd19c9ddf20ae647b6e8099418..c13c867d2a4a18879ef47341fe360e96c5edbf89 100644 (file)
@@ -1798,6 +1798,51 @@ struct zebra_l3vni *zl3vni_from_vrf(vrf_id_t vrf_id)
        return zl3vni_lookup(zvrf->l3vni);
 }
 
+static int zl3vni_from_svi_ns(struct ns *ns, void *_in_param, void **_p_zl3vni)
+{
+       int found = 0;
+       struct zebra_ns *zns = ns->info;
+       struct zebra_l3vni **p_zl3vni = (struct zebra_l3vni **)_p_zl3vni;
+       struct zebra_from_svi_param *in_param =
+               (struct zebra_from_svi_param *)_in_param;
+       struct route_node *rn = NULL;
+       struct interface *tmp_if = NULL;
+       struct zebra_if *zif = NULL;
+       struct zebra_l2info_vxlan *vxl = NULL;
+
+       if (!in_param)
+               return NS_WALK_STOP;
+
+       /* loop through all vxlan-interface */
+       for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
+               tmp_if = (struct interface *)rn->info;
+               if (!tmp_if)
+                       continue;
+               zif = tmp_if->info;
+               if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
+                       continue;
+               if (!if_is_operative(tmp_if))
+                       continue;
+               vxl = &zif->l2info.vxl;
+
+               if (zif->brslave_info.br_if != in_param->br_if)
+                       continue;
+
+               if (!in_param->bridge_vlan_aware
+                   || vxl->access_vlan == in_param->vid) {
+                       found = 1;
+                       break;
+               }
+       }
+
+       if (!found)
+               return NS_WALK_CONTINUE;
+
+       if (p_zl3vni)
+               *p_zl3vni = zl3vni_lookup(vxl->vni);
+       return NS_WALK_STOP;
+}
+
 /*
  * Map SVI and associated bridge to a VNI. This is invoked upon getting
  * neighbor notifications, to see if they are of interest.
@@ -1805,16 +1850,11 @@ struct zebra_l3vni *zl3vni_from_vrf(vrf_id_t vrf_id)
 static struct zebra_l3vni *zl3vni_from_svi(struct interface *ifp,
                                           struct interface *br_if)
 {
-       int found = 0;
-       vlanid_t vid = 0;
-       uint8_t bridge_vlan_aware = 0;
        struct zebra_l3vni *zl3vni = NULL;
-       struct zebra_ns *zns = NULL;
-       struct route_node *rn = NULL;
        struct zebra_if *zif = NULL;
-       struct interface *tmp_if = NULL;
        struct zebra_l2info_bridge *br = NULL;
-       struct zebra_l2info_vxlan *vxl = NULL;
+       struct zebra_from_svi_param in_param = {};
+       struct zebra_l3vni **p_zl3vni;
 
        if (!br_if)
                return NULL;
@@ -1822,13 +1862,14 @@ static struct zebra_l3vni *zl3vni_from_svi(struct interface *ifp,
        /* Make sure the linked interface is a bridge. */
        if (!IS_ZEBRA_IF_BRIDGE(br_if))
                return NULL;
+       in_param.br_if = br_if;
 
        /* Determine if bridge is VLAN-aware or not */
        zif = br_if->info;
        assert(zif);
        br = &zif->l2info.br;
-       bridge_vlan_aware = br->vlan_aware;
-       if (bridge_vlan_aware) {
+       in_param.bridge_vlan_aware = br->vlan_aware;
+       if (in_param.bridge_vlan_aware) {
                struct zebra_l2info_vlan *vl;
 
                if (!IS_ZEBRA_IF_VLAN(ifp))
@@ -1837,36 +1878,15 @@ static struct zebra_l3vni *zl3vni_from_svi(struct interface *ifp,
                zif = ifp->info;
                assert(zif);
                vl = &zif->l2info.vl;
-               vid = vl->vid;
+               in_param.vid = vl->vid;
        }
 
        /* See if this interface (or interface plus VLAN Id) maps to a VxLAN */
        /* TODO: Optimize with a hash. */
-       zns = zebra_ns_lookup(NS_DEFAULT);
-       for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
-               tmp_if = (struct interface *)rn->info;
-               if (!tmp_if)
-                       continue;
-               zif = tmp_if->info;
-               if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
-                       continue;
-               if (!if_is_operative(tmp_if))
-                       continue;
-               vxl = &zif->l2info.vxl;
-
-               if (zif->brslave_info.br_if != br_if)
-                       continue;
 
-               if (!bridge_vlan_aware || vxl->access_vlan == vid) {
-                       found = 1;
-                       break;
-               }
-       }
+       p_zl3vni = &zl3vni;
 
-       if (!found)
-               return NULL;
-
-       zl3vni = zl3vni_lookup(vxl->vni);
+       ns_walk_func(zl3vni_from_svi_ns, (void *)&in_param, (void **)p_zl3vni);
        return zl3vni;
 }
 
@@ -5023,6 +5043,13 @@ int zebra_vxlan_if_update(struct interface *ifp, uint16_t chgflags)
                        return 0;
                }
 
+               if ((chgflags & ZEBRA_VXLIF_MASTER_MAC_CHANGE)
+                   && if_is_operative(ifp) && is_l3vni_oper_up(zl3vni)) {
+                       zebra_vxlan_process_l3vni_oper_down(zl3vni);
+                       zebra_vxlan_process_l3vni_oper_up(zl3vni);
+                       return 0;
+               }
+
                /* access-vlan change - process oper down, associate with new
                 * svi_if and then process oper up again
                 */
index 915e987b6bbd8b57d1c899b2e2d33e89575030a5..464a8e5fc46ca76d806e8b6dadc76dd1f18cddee 100644 (file)
@@ -65,6 +65,7 @@ is_vxlan_flooding_head_end(void)
 #define ZEBRA_VXLIF_MASTER_CHANGE       (1 << 1)
 #define ZEBRA_VXLIF_VLAN_CHANGE         (1 << 2)
 #define ZEBRA_VXLIF_MCAST_GRP_CHANGE    (1 << 3)
+#define ZEBRA_VXLIF_MASTER_MAC_CHANGE (1 << 4)
 
 
 #define VNI_STR_LEN 32