]> git.proxmox.com Git - mirror_frr.git/commitdiff
Merge branch 'master' into type5-default-originate
authorMitesh Kanjariya <mitesh@cumulusnetworks.com>
Tue, 6 Mar 2018 21:48:33 +0000 (13:48 -0800)
committerGitHub <noreply@github.com>
Tue, 6 Mar 2018 21:48:33 +0000 (13:48 -0800)
28 files changed:
COMMUNITY.md
bgpd/bgp_evpn.c
bgpd/bgp_main.c
bgpd/bgp_route.c
bgpd/bgp_vty.c
bgpd/bgp_zebra.c
doc/OSPF-SR.rst
doc/ospfd.texi
lib/command.c
lib/zclient.c
lib/zebra.h
nhrpd/nhrp_route.c
ospf6d/ospf6_asbr.c
ospf6d/ospf6_asbr.h
ospf6d/ospf6_route.c
ospf6d/ospf6_top.c
ospfd/ospf_main.c
ospfd/ospf_sr.c
pimd/TODO
sharpd/sharp_zebra.c
tests/.gitignore
tests/lib/test_ringbuf.py
vtysh/vtysh.c
vtysh/vtysh_config.c
zebra/zebra_rib.c
zebra/zebra_rnh.c
zebra/zebra_vxlan.c
zebra/zserv.c

index 0eee524d585b74ec35c277357fd951e72d156ec6..081f7ab3b832461f9c9a49d2642c15d657d86f53 100644 (file)
@@ -492,6 +492,36 @@ In all cases, compatibility pieces should be marked with compiler/preprocessor
 annotations to print warnings at compile time, pointing to the appropriate
 update path.  A `-Werror` build should fail if compatibility bits are used.
 
+### Release Process/Schedule
+
+FRR employs a <MAJOR>.<MINOR>.<BUGFIX> versioning scheme.
+
+* MAJOR - Significant new features or multiple minor features
+  A example of a MAJOR feature is a New Routing Protocol
+* MINOR - Smaller Features
+  A example of a MINOR feature is the addition of the BGP Shutdown feature.
+* BUGFIX - Fixes for actual bugs and/or security issues.
+
+We will pull a new development branch for the next release every 4 months.
+The current schedule is Feb/June/October 1.  The decision for a MAJOR/MINOR
+release is made at the time of branch pull based on what has been received
+the previous 4 months.  The branch name will be dev/MAJOR.MINOR.  At
+this point in time the master branch configure.ac and packaging systems
+will be updated to reflect the next possible release name to allow
+for easy distinguishing.  Additionally the new dev branch will have
+these files updated too.
+
+After one month the development branch will be renamed to
+stable/MAJOR.MINOR.  This process is not held up unless a crash or
+security issue has been found and needs to be addressed.  Issues
+being fixed will not cause a delay.
+
+Bug fix releases are at 1 month intervals until next MAJOR.MINOR is
+pulled.  Then at that time as needed for issues filed.
+
+Security issues are fixed for 1 year minimum on old releases and
+normal bug fixes for the current and previous release
+
 ### Miscellaneous
 
 When in doubt, follow the guidelines in the Linux kernel style guide, or ask on
index c079dd05fbb0c55742f72af1c9d614c146931338..9b98e1a8bce8bcb2e358350c39554082c05da3ed 100644 (file)
@@ -1760,8 +1760,10 @@ static int delete_routes_for_vni(struct bgp *bgp, struct bgpevpn *vpn)
 }
 
 /*
- * There is a tunnel endpoint IP address change for this VNI,
- * need to re-advertise routes with the new nexthop.
+ * There is a tunnel endpoint IP address change for this VNI, delete
+ * prior type-3 route (if needed) and update.
+ * Note: Route re-advertisement happens elsewhere after other processing
+ * other changes.
  */
 static int handle_tunnel_ip_change(struct bgp *bgp, struct bgpevpn *vpn,
                                   struct in_addr originator_ip)
@@ -1789,7 +1791,7 @@ static int handle_tunnel_ip_change(struct bgp *bgp, struct bgpevpn *vpn,
 
        /* Update the tunnel IP and re-advertise all routes for this VNI. */
        vpn->originator_ip = originator_ip;
-       return update_routes_for_vni(bgp, vpn);
+       return 0;
 }
 
 /*
@@ -3245,11 +3247,21 @@ void bgp_evpn_withdraw_type5_routes(struct bgp *bgp_vrf,
 {
        struct bgp_table *table = NULL;
        struct bgp_node *rn = NULL;
+       struct bgp_info *ri;
 
        table = bgp_vrf->rib[afi][safi];
-       for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn))
-               bgp_evpn_withdraw_type5_route(bgp_vrf, &rn->p, afi, safi);
-
+       for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
+               /* Only care about "selected" routes - non-imported. */
+               /* TODO: Support for AddPath for EVPN. */
+               for (ri = rn->info; ri; ri = ri->next) {
+                       if (CHECK_FLAG(ri->flags, BGP_INFO_SELECTED) &&
+                           (!ri->extra || !ri->extra->parent)) {
+                               bgp_evpn_withdraw_type5_route(bgp_vrf, &rn->p,
+                                                             afi, safi);
+                               break;
+                       }
+               }
+       }
 }
 
 /*
@@ -3265,11 +3277,7 @@ void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf, struct prefix *p,
        int ret = 0;
        struct prefix_evpn evp;
        char buf[PREFIX_STRLEN];
-
-       /* only advertise subnet routes as type-5 */
-       if (is_host_route(p))
-               return;
-
+  
        build_type5_prefix_from_ip_prefix(&evp, p);
        ret = update_evpn_type5_route(bgp_vrf, &evp, src_attr);
        if (ret)
@@ -3293,11 +3301,12 @@ void bgp_evpn_advertise_type5_routes(struct bgp *bgp_vrf,
        table = bgp_vrf->rib[afi][safi];
        for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
                /* Need to identify the "selected" route entry to use its
-                * attribute.
+                * attribute. Also, we only consider "non-imported" routes.
                 * TODO: Support for AddPath for EVPN.
                 */
                for (ri = rn->info; ri; ri = ri->next) {
-                       if (CHECK_FLAG(ri->flags, BGP_INFO_SELECTED)) {
+                       if (CHECK_FLAG(ri->flags, BGP_INFO_SELECTED) &&
+                           (!ri->extra || !ri->extra->parent)) {
 
                                /* apply the route-map */
                                if (bgp_vrf->adv_cmd_rmap[afi][safi].map) {
@@ -3310,7 +3319,6 @@ void bgp_evpn_advertise_type5_routes(struct bgp *bgp_vrf,
                                        if (ret == RMAP_DENYMATCH)
                                                continue;
                                }
-
                                bgp_evpn_advertise_type5_route(bgp_vrf, &rn->p,
                                                               ri->attr,
                                                               afi, safi);
@@ -4437,8 +4445,8 @@ int bgp_evpn_local_vni_del(struct bgp *bgp, vni_t vni)
 }
 
 /*
- * Handle add (or update) of a local VNI. The only VNI change we care
- * about is change to local-tunnel-ip.
+ * Handle add (or update) of a local VNI. The VNI changes we care
+ * about are for the local-tunnel-ip and the (tenant) VRF.
  */
 int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni,
                           struct in_addr originator_ip,
@@ -4456,24 +4464,31 @@ int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni,
        vpn = bgp_evpn_lookup_vni(bgp, vni);
        if (vpn) {
 
-               /* update tenant_vrf_id if required */
+               if (is_vni_live(vpn)
+                   && IPV4_ADDR_SAME(&vpn->originator_ip, &originator_ip)
+                   && vpn->tenant_vrf_id == tenant_vrf_id)
+                       /* Probably some other param has changed that we don't
+                        * care about. */
+                       return 0;
+
+               /* Update tenant_vrf_id if it has changed. */
                if (vpn->tenant_vrf_id != tenant_vrf_id) {
                        bgpevpn_unlink_from_l3vni(vpn);
                        vpn->tenant_vrf_id = tenant_vrf_id;
                        bgpevpn_link_to_l3vni(vpn);
-
-                       /* update all routes with new export RT for VRFs */
-                       update_routes_for_vni(bgp, vpn);
                }
 
-               if (is_vni_live(vpn)
-                   && IPV4_ADDR_SAME(&vpn->originator_ip, &originator_ip))
-                       /* Probably some other param has changed that we don't
-                        * care about. */
-                       return 0;
+               /* If tunnel endpoint IP has changed, update (and delete prior
+                * type-3 route, if needed.)
+                */
+               if (!IPV4_ADDR_SAME(&vpn->originator_ip, &originator_ip))
+                       handle_tunnel_ip_change(bgp, vpn, originator_ip);
 
-               /* Local tunnel endpoint IP address has changed */
-               handle_tunnel_ip_change(bgp, vpn, originator_ip);
+               /* Update all routes with new endpoint IP and/or export RT
+                * for VRFs
+                */
+               if (is_vni_live(vpn))
+                       update_routes_for_vni(bgp, vpn);
        }
 
        /* Create or update as appropriate. */
index 82c74e4afa5b971e0531405790096cba255f19d2..30b7afff9280f974d7804e537fa60493d94febfa 100644 (file)
@@ -106,7 +106,7 @@ static int retain_mode = 0;
 
 /* privileges */
 static zebra_capabilities_t _caps_p[] = {
-       ZCAP_BIND, ZCAP_NET_RAW, ZCAP_NET_ADMIN,
+       ZCAP_BIND, ZCAP_NET_RAW, ZCAP_NET_ADMIN, ZCAP_SYS_ADMIN
 };
 
 struct zebra_privs_t bgpd_privs = {
index 0d226f9e72e1c39e6bab4284eec2d05047f246da..6e3751fb9d1d143643c860de306d58ce38107841 100644 (file)
@@ -2228,10 +2228,13 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
 
        /* advertise/withdraw type-5 routes */
        if ((afi == AFI_IP || afi == AFI_IP6) && (safi == SAFI_UNICAST)) {
-               if (advertise_type5_routes(bgp, afi) && new_select)
-                       bgp_evpn_advertise_type5_route(
-                               bgp, &rn->p, new_select->attr, afi, safi);
-               else if (advertise_type5_routes(bgp, afi) && old_select)
+               if (advertise_type5_routes(bgp, afi) && new_select &&
+                   (!new_select->extra || !new_select->extra->parent))
+                       bgp_evpn_advertise_type5_route(bgp, &rn->p,
+                                                      new_select->attr,
+                                                      afi, safi);
+               else if (advertise_type5_routes(bgp, afi) && old_select &&
+                        (!old_select->extra || !old_select->extra->parent))
                        bgp_evpn_withdraw_type5_route(bgp, &rn->p, afi, safi);
        }
 
index 15cc5673accf4bff2fab1c94460c6fd1d3432d46..8fa5dc9c6f64e198ac736be06ee1df4fc2706445 100644 (file)
@@ -833,7 +833,7 @@ DEFUN_NOSH (router_bgp,
 
                if (listcount(bm->bgp) > 1) {
                        vty_out(vty,
-                               "%% Multiple BGP processes are configured\n");
+                               "%% Please specify ASN and VRF\n");
                        return CMD_WARNING_CONFIG_FAILED;
                }
        }
@@ -909,7 +909,7 @@ DEFUN (no_router_bgp,
 
                if (listcount(bm->bgp) > 1) {
                        vty_out(vty,
-                               "%% Multiple BGP processes are configured\n");
+                               "%% Please specify ASN and VRF\n");
                        return CMD_WARNING_CONFIG_FAILED;
                }
 
index 1da6136428a3beca98c23b71447d3fa307b638de..029b3d4d36b801baaef65879734636e57476756b 100644 (file)
@@ -1026,14 +1026,14 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
        if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED
            || info->sub_type == BGP_ROUTE_AGGREGATE) {
                SET_FLAG(api.flags, ZEBRA_FLAG_IBGP);
-               SET_FLAG(api.flags, ZEBRA_FLAG_INTERNAL);
+               SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION);
        }
 
        if ((peer->sort == BGP_PEER_EBGP && peer->ttl != 1)
            || CHECK_FLAG(peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)
            || bgp_flag_check(bgp, BGP_FLAG_DISABLE_NH_CONNECTED_CHK))
 
-               SET_FLAG(api.flags, ZEBRA_FLAG_INTERNAL);
+               SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION);
 
        /* Metric is currently based on the best-path only */
        metric = info->attr->med;
@@ -1054,6 +1054,9 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
                else
                        continue;
 
+               api_nh = &api.nexthops[valid_nh_count];
+               api_nh->vrf_id = bgp->vrf_id;
+
                if (nh_family == AF_INET) {
                        struct in_addr *nexthop;
 
@@ -1078,9 +1081,7 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
 
                        nexthop = &mpinfo_cp->attr->nexthop;
 
-                       api_nh = &api.nexthops[valid_nh_count];
                        api_nh->gate.ipv4 = *nexthop;
-                       api_nh->vrf_id = bgp->vrf_id;
                        /* EVPN type-2 routes are
                           programmed as onlink on l3-vni SVI
                         */
@@ -1135,7 +1136,6 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
                        if (ifindex == 0)
                                continue;
 
-                       api_nh = &api.nexthops[valid_nh_count];
                        api_nh->gate.ipv6 = *nexthop;
                        api_nh->ifindex = ifindex;
                        api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX;
@@ -1265,14 +1265,14 @@ void bgp_zebra_withdraw(struct prefix *p, struct bgp_info *info, safi_t safi)
                SET_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE);
 
        if (peer->sort == BGP_PEER_IBGP) {
-               SET_FLAG(api.flags, ZEBRA_FLAG_INTERNAL);
+               SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION);
                SET_FLAG(api.flags, ZEBRA_FLAG_IBGP);
        }
 
        if ((peer->sort == BGP_PEER_EBGP && peer->ttl != 1)
            || CHECK_FLAG(peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)
            || bgp_flag_check(peer->bgp, BGP_FLAG_DISABLE_NH_CONNECTED_CHK))
-               SET_FLAG(api.flags, ZEBRA_FLAG_INTERNAL);
+               SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION);
 
        if (bgp_debug_zebra(p)) {
                char buf[PREFIX_STRLEN];
index 0ee1a12f2858923540c5f26359e44143f1dced8c..299a7e1c87ec45f7fbb3bcbf9e09ec3a08cea862 100644 (file)
@@ -5,6 +5,26 @@ This is an EXPERIMENTAL support of draft
 `draft-ietf-ospf-segment-routing-extensions-24`.
 DON'T use it for production network.
 
+Supported Features
+------------------
+
+* Automatic computation of Primary and Backup Adjacency SID with
+  Cisco experimental remote IP address
+* SRGB configuration
+* Prefix configuration for Node SID with optional NO-PHP flag (Linux
+  kernel support both mode)
+* Node MSD configuration (with Linux Kernel >= 4.10 a maximum of 32 labels
+  could be stack)
+* Automatic provisioning of MPLS table
+* Static route configuration with label stack up to 32 labels
+
+Interoperability
+----------------
+
+* tested on various topology including point-to-point and LAN interfaces
+  in a mix of Free Range Routing instance and Cisco IOS-XR 6.0.x
+* check OSPF LSA conformity with latest wireshark release 2.5.0-rc
+
 Implementation details
 ----------------------
 
@@ -248,9 +268,6 @@ Known limitations
 * MPLS table are not flush at startup. Thus, restarting zebra process is
   mandatory to remove old MPLS entries in the data plane after a crash of
   ospfd daemon
-* Due to a bug in OSPF Opaque, LSA are not flood when enable Segment Routing
-  through CLI once OSPFd started. You must configure Segment Routing within
-  configuration file before launching OSPFd
 * With NO Penultimate Hop Popping, it is not possible to express a Segment
   Path with an Adjacency SID due to the impossibility for the Linux Kernel to
   perform double POP instruction.
index 33341d2be6de6a8e3a010d578bc7657548ec7297..9694be1efe0f3e18523ff9c82afe3e753dc42a9c 100644 (file)
@@ -759,10 +759,11 @@ currently supported. The 'no-php-flag' means NO Penultimate Hop Popping that
 allows SR node to request to its neighbor to not pop the label.
 @end deffn
 
-@deffn {Command} {show ip ospf database segment-routing} {}
-@deffnx {Command} {show ip ospf database segment-routing adv-router @var{adv-router}} {}
-@deffnx {Command} {show ip ospf database segment-routing self-originate} {}
+@deffn {Command} {show ip ospf database segment-routing [json]} {}
+@deffnx {Command} {show ip ospf database segment-routing adv-router @var{adv-router} [json]} {}
+@deffnx {Command} {show ip ospf database segment-routing self-originate [json]} {}
 Show Segment Routing Data Base, all SR nodes, specific advertized router or self router.
+Optional Json output could be obtain by adding 'json' at the end of the command.
 @end deffn
 
 @node Debugging OSPF
index 10996d5dd4b80dfbd800662e5defc80ae255bf1c..3fa086bf62d4d1feeaf4f1728967082e746fcec2 100644 (file)
@@ -500,6 +500,9 @@ static int config_write_host(struct vty *vty)
        if (cmd_hostname_get())
                vty_out(vty, "hostname %s\n", cmd_hostname_get());
 
+       if (cmd_domainname_get())
+               vty_out(vty, "domainname %s\n", cmd_domainname_get());
+
        if (host.encrypt) {
                if (host.password_encrypt)
                        vty_out(vty, "password 8 %s\n", host.password_encrypt);
index ad91eb504bafe483fef1d3e52781ddff637ff813..8535c3b5f521cdc828cb34c909c69e6b00a55748 100644 (file)
@@ -1085,7 +1085,7 @@ int zapi_route_decode(struct stream *s, struct zapi_route *api)
        STREAM_GETC(s, api->message);
        STREAM_GETC(s, api->safi);
        if (CHECK_FLAG(api->flags, ZEBRA_FLAG_EVPN_ROUTE))
-               stream_get(&(api->rmac), s, sizeof(struct ethaddr));
+               STREAM_GET(&(api->rmac), s, sizeof(struct ethaddr));
 
        /* Prefix. */
        STREAM_GETC(s, api->prefix.family);
@@ -1266,6 +1266,8 @@ bool zapi_nexthop_update_decode(struct stream *s, struct zapi_route *nhr)
                break;
        }
 
+       STREAM_GETC(s, nhr->type);
+       STREAM_GETW(s, nhr->instance);
        STREAM_GETC(s, nhr->distance);
        STREAM_GETL(s, nhr->metric);
        STREAM_GETC(s, nhr->nexthop_num);
index b9a795d16099894beac1f9adb4c63cb60d0c87b5..11bf764b630c549ffd6df48517fd50b5d0119028 100644 (file)
@@ -402,7 +402,7 @@ extern const char *zserv_command_string(unsigned int command);
 #define strmatch(a,b) (!strcmp((a), (b)))
 
 /* Zebra message flags */
-#define ZEBRA_FLAG_INTERNAL           0x01
+#define ZEBRA_FLAG_ALLOW_RECURSION    0x01
 #define ZEBRA_FLAG_SELFROUTE          0x02
 #define ZEBRA_FLAG_IBGP               0x08
 #define ZEBRA_FLAG_SELECTED           0x10
index d43aa4929e10c492347789f85d58dd8eaa479453..8178a8b4b5993a3ef8b88fec6d98fbe876de80bc 100644 (file)
@@ -114,7 +114,7 @@ void nhrp_route_announce(int add, enum nhrp_cache_type type, const struct prefix
                SET_FLAG(api.flags, ZEBRA_FLAG_FIB_OVERRIDE);
                break;
        }
-       SET_FLAG(api.flags, ZEBRA_FLAG_INTERNAL);
+       SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION);
 
        SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
        api.nexthop_num = 1;
index 11f9e7c7b6e4dfc2dfcdde6268a4a96e1d596525..b52f1cef6c8992b5ff86074b7f046277c2b33055 100644 (file)
@@ -204,26 +204,142 @@ void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old,
 {
        struct ospf6_route *old_route;
        struct ospf6_path *ecmp_path, *o_path = NULL;
-       struct listnode *anode;
+       struct listnode *anode, *anext;
        struct listnode *nnode, *rnode, *rnext;
        struct ospf6_nexthop *nh, *rnh;
        char buf[PREFIX2STR_BUFFER];
        bool route_found = false;
 
+       /* check for old entry match with new route origin,
+        * delete old entry.
+        */
        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) &&
-                       (old_route->path.cost == route->path.cost) &&
-                       (old_route->path.u.cost_e2 == route->path.u.cost_e2)) {
+               bool route_updated = false;
+
+               if (!ospf6_route_is_same(old_route, route) ||
+                       (old_route->path.type != route->path.type))
+                       continue;
+
+               /* Current and New route has same origin,
+                * delete old entry.
+                */
+               for (ALL_LIST_ELEMENTS(old_route->paths, anode, anext,
+                                                 o_path)) {
+                       /* 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))
+                               continue;
+
+                       /* Cost is not same then delete current path */
+                       if ((o_path->cost == route->path.cost) &&
+                           (o_path->u.cost_e2 == route->path.u.cost_e2))
+                               continue;
 
                        if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
                                prefix2str(&old_route->prefix, buf,
                                           sizeof(buf));
-                               zlog_debug("%s: old route %s path  cost %u [%u]",
+                               zlog_debug("%s: route %s cost old %u new %u is not same, replace route",
+                                          __PRETTY_FUNCTION__, buf,
+                                          o_path->cost, route->path.cost);
+                       }
+
+                       /* Remove selected current rout path's nh from
+                        * effective nh list.
+                        */
+                       for (ALL_LIST_ELEMENTS_RO(o_path->nh_list, nnode, nh)) {
+                               for (ALL_LIST_ELEMENTS(old_route->nh_list,
+                                                       rnode, rnext, rnh)) {
+                                       if (!ospf6_nexthop_is_same(rnh, nh))
+                                               continue;
+                                       listnode_delete(old_route->nh_list,
+                                                               rnh);
+                                       ospf6_nexthop_delete(rnh);
+                                       route_updated = true;
+                               }
+                       }
+
+                       listnode_delete(old_route->paths, o_path);
+                       ospf6_path_free(o_path);
+
+                       /* Current route's path (adv_router info) is similar
+                        * to route being added.
+                        * Replace current route's path with paths list head.
+                        * Update FIB with effective NHs.
+                        */
+                       if (listcount(old_route->paths)) {
+                               if (old_route->path.origin.id ==
+                                       route->path.origin.id &&
+                                       old_route->path.origin.adv_router ==
+                                               route->path.origin.adv_router) {
+                                       struct ospf6_path *h_path;
+
+                                       h_path = (struct ospf6_path *)
+                                       listgetdata(listhead(old_route->paths));
+                                       old_route->path.origin.type =
+                                               h_path->origin.type;
+                                       old_route->path.origin.id =
+                                               h_path->origin.id;
+                                       old_route->path.origin.adv_router =
+                                               h_path->origin.adv_router;
+                               }
+
+                               if (route_updated) {
+                                       for (ALL_LIST_ELEMENTS(old_route->paths,
+                                                       anode, anext, o_path)) {
+                                               ospf6_merge_nexthops(
+                                                       old_route->nh_list,
+                                                       o_path->nh_list);
+                                       }
+                                       /* Update RIB/FIB with effective
+                                        * nh_list
+                                        */
+                                       if (ospf6->route_table->hook_add)
+                                               (*ospf6->route_table->hook_add)
+                                                       (old_route);
+                                       break;
+                               }
+                       } else {
+                               if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
+                                       prefix2str(&old_route->prefix, buf,
+                                                  sizeof(buf));
+                                       zlog_debug("%s: route %s old cost %u new cost %u, delete old entry.",
+                                                  __PRETTY_FUNCTION__, buf,
+                                                  old_route->path.cost,
+                                                  route->path.cost);
+                               }
+                               ospf6_route_remove(old_route,
+                                                  ospf6->route_table);
+                               break;
+                       }
+               }
+               if (route_updated)
+                       break;
+       }
+
+       /* 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.
+                */
+               if (!ospf6_route_is_same(old_route, route) ||
+                       (old_route->path.type != route->path.type))
+                       continue;
+
+               /* Old Route and New Route have Equal Cost, Merge NHs */
+               if ((old_route->path.cost == route->path.cost) &&
+                   (old_route->path.u.cost_e2 == route->path.u.cost_e2)) {
+
+                       if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
+                               prefix2str(&old_route->prefix, buf,
+                                          sizeof(buf));
+                               zlog_debug("%s: old route %s path  cost %u e2 %u",
                                           __PRETTY_FUNCTION__, buf,
                                           old_route->path.cost,
-                                          ospf6_route_is_same(old_route,
-                                                              route));
+                                          old_route->path.u.cost_e2);
                        }
                        route_found = true;
                        /* check if this path exists already in
@@ -232,9 +348,10 @@ 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->origin.id == route->path.origin.id)
-                                       && (o_path->origin.adv_router ==
-                                               route->path.origin.adv_router))
+                               if (o_path->area_id == route->path.area_id &&
+                                   (memcmp(&(o_path)->origin,
+                                       &(route)->path.origin,
+                                       sizeof(struct ospf6_ls_origin)) == 0))
                                        break;
                        }
                        /* If path is not found in old_route paths's list,
@@ -262,12 +379,13 @@ void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old,
                                if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
                                        prefix2str(&route->prefix, buf,
                                                   sizeof(buf));
-                                       zlog_debug("%s: route %s another path added with nh %u, Paths %u",
+                                       zlog_debug("%s: route %s another path added with nh %u, effective paths %u nh %u",
                                                __PRETTY_FUNCTION__, buf,
                                                listcount(ecmp_path->nh_list),
                                                old_route->paths ?
                                                listcount(old_route->paths)
-                                               : 0);
+                                               : 0,
+                                               listcount(old_route->nh_list));
                                }
                        } else {
                                for (ALL_LIST_ELEMENTS_RO(o_path->nh_list,
@@ -313,6 +431,7 @@ void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old,
                         * route.
                         */
                        ospf6_route_delete(route);
+
                        break;
                }
        }
@@ -426,11 +545,12 @@ void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa)
 
 }
 
-void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa)
+void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa,
+                          struct ospf6_route *asbr_entry)
 {
        struct ospf6_as_external_lsa *external;
        struct prefix prefix;
-       struct ospf6_route *route, *nroute;
+       struct ospf6_route *route, *nroute, *route_to_del;
        char buf[PREFIX2STR_BUFFER];
 
        external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END(
@@ -445,6 +565,35 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa)
                return;
        }
 
+       route_to_del = ospf6_route_create();
+       route_to_del->type = OSPF6_DEST_TYPE_NETWORK;
+       route_to_del->prefix.family = AF_INET6;
+       route_to_del->prefix.prefixlen = external->prefix.prefix_length;
+       ospf6_prefix_in6_addr(&route_to_del->prefix.u.prefix6,
+                             &external->prefix);
+
+       route_to_del->path.origin.type = lsa->header->type;
+       route_to_del->path.origin.id = lsa->header->id;
+       route_to_del->path.origin.adv_router = lsa->header->adv_router;
+
+       if (asbr_entry) {
+               route_to_del->path.area_id = asbr_entry->path.area_id;
+               if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_E)) {
+                       route_to_del->path.type = OSPF6_PATH_TYPE_EXTERNAL2;
+                       route_to_del->path.metric_type = 2;
+                       route_to_del->path.cost = asbr_entry->path.cost;
+                       route_to_del->path.u.cost_e2 =
+                               OSPF6_ASBR_METRIC(external);
+               } else {
+                       route_to_del->path.type = OSPF6_PATH_TYPE_EXTERNAL1;
+                       route_to_del->path.metric_type = 1;
+                       route_to_del->path.cost =
+                               asbr_entry->path.cost +
+                               OSPF6_ASBR_METRIC(external);
+                       route_to_del->path.u.cost_e2 = 0;
+               }
+       }
+
        memset(&prefix, 0, sizeof(struct prefix));
        prefix.family = AF_INET6;
        prefix.prefixlen = external->prefix.prefix_length;
@@ -459,14 +608,25 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa)
                return;
        }
 
-       for (ospf6_route_lock(route);
-            route && ospf6_route_is_prefix(&prefix, route); route = nroute) {
+       if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
+               prefix2str(&prefix, buf, sizeof(buf));
+               zlog_debug("%s: Current route %s cost %u e2 %u, route to del cost %u e2 %u",
+                          __PRETTY_FUNCTION__, buf, route->path.cost,
+                          route->path.u.cost_e2,
+                          route_to_del->path.cost,
+                          route_to_del->path.u.cost_e2);
+       }
+
+       for (ospf6_route_lock(route); route &&
+            ospf6_route_is_prefix(&prefix, route); route = nroute) {
                nroute = ospf6_route_next(route);
+
                if (route->type != OSPF6_DEST_TYPE_NETWORK)
                        continue;
 
-               /* Route has multiple ECMP paths remove,
-                * matching path and update effective route's  nh list.
+               /* Route has multiple ECMP paths, remove matching
+                * path. Update current route's effective nh list
+                * after removal of one of the path.
                 */
                if (listcount(route->paths) > 1) {
                        struct listnode *anode, *anext;
@@ -481,18 +641,36 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa)
                         */
                        for (ALL_LIST_ELEMENTS(route->paths, anode, anext,
                                                  o_path)) {
-                               if (o_path->origin.type != lsa->header->type)
-                                       continue;
-                               if (o_path->origin.id != lsa->header->id)
+                               if ((o_path->origin.type != lsa->header->type)
+                                   || (o_path->origin.adv_router !=
+                                       lsa->header->adv_router) ||
+                                   (o_path->origin.id != lsa->header->id))
                                        continue;
-                               if (o_path->origin.adv_router !=
-                                       lsa->header->adv_router)
+
+                               /* Compare LSA cost with current
+                                * route info.
+                                */
+                               if (!asbr_entry && (o_path->cost !=
+                                               route_to_del->path.cost ||
+                                               o_path->u.cost_e2 !=
+                                               route_to_del->path.u.cost_e2)) {
+                                       if (IS_OSPF6_DEBUG_EXAMIN(
+                                                       AS_EXTERNAL)) {
+                                               prefix2str(&prefix, buf,
+                                                          sizeof(buf));
+                                               zlog_debug(
+                                               "%s: route %s to delete is not same, cost %u del cost %u. skip",
+                                               __PRETTY_FUNCTION__, buf,
+                                               route->path.cost,
+                                               route_to_del->path.cost);
+                                       }
                                        continue;
+                               }
 
                                if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL))  {
                                        prefix2str(&prefix, buf, sizeof(buf));
                                        zlog_debug(
-                                               "%s: route %s path found with nh %u",
+                                               "%s: route %s path found with nh %u to remove.",
                                                __PRETTY_FUNCTION__, buf,
                                                listcount(o_path->nh_list));
                                }
@@ -542,13 +720,13 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa)
                                                   listcount(route->nh_list));
                                }
 
-                               /* Update RIB/FIB w/ effective nh_list */
+                               /* Update RIB/FIB with effective nh_list */
                                if (ospf6->route_table->hook_add)
                                        (*ospf6->route_table->hook_add)(route);
 
-                               /* route's path is similar to lsa header,
-                                * replace route's path with route's
-                                * paths list head.
+                               /* route's primary path is similar to LSA,
+                                * replace route's primary path with
+                                * route's paths list head.
                                 */
                                if (route->path.origin.id == lsa->header->id &&
                                    route->path.origin.adv_router ==
@@ -568,12 +746,29 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa)
                        continue;
 
                } else {
-                       if (route->path.origin.type != lsa->header->type)
-                               continue;
-                       if (route->path.origin.id != lsa->header->id)
+                       /* Compare LSA origin and cost with current route info.
+                        * if any check fails skip del this route node.
+                        */
+                       if (asbr_entry && (!ospf6_route_is_same_origin(route,
+                                                       route_to_del) ||
+                           (route->path.type != route_to_del->path.type) ||
+                           (route->path.cost != route_to_del->path.cost) ||
+                           (route->path.u.cost_e2 !=
+                            route_to_del->path.u.cost_e2))) {
+                               if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
+                                       prefix2str(&prefix, buf, sizeof(buf));
+                                       zlog_debug("%s: route %s to delete is not same, cost %u del cost %u. skip",
+                                       __PRETTY_FUNCTION__, buf,
+                                       route->path.cost,
+                                       route_to_del->path.cost);
+                               }
                                continue;
-                       if (route->path.origin.adv_router !=
-                                       lsa->header->adv_router)
+                       }
+
+                       if ((route->path.origin.type != lsa->header->type) ||
+                           (route->path.origin.adv_router !=
+                                       lsa->header->adv_router) ||
+                           (route->path.origin.id != lsa->header->id))
                                continue;
                }
                if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
@@ -589,6 +784,8 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa)
        }
        if (route != NULL)
                ospf6_route_unlock(route);
+
+       ospf6_route_delete(route_to_del);
 }
 
 void ospf6_asbr_lsentry_add(struct ospf6_route *asbr_entry)
@@ -622,7 +819,7 @@ void ospf6_asbr_lsentry_remove(struct ospf6_route *asbr_entry)
        type = htons(OSPF6_LSTYPE_AS_EXTERNAL);
        router = ospf6_linkstate_prefix_adv_router(&asbr_entry->prefix);
        for (ALL_LSDB_TYPED_ADVRTR(ospf6->lsdb, type, router, lsa))
-               ospf6_asbr_lsa_remove(lsa);
+               ospf6_asbr_lsa_remove(lsa, asbr_entry);
 }
 
 
index cc4f0272aabbfc4d33c6710cb1253df341760af3..bd160a6456cc5a3e30f5c19376962d469f4a008e 100644 (file)
@@ -71,7 +71,8 @@ struct ospf6_as_external_lsa {
        }
 
 extern void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa);
-extern void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa);
+extern void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa,
+                                 struct ospf6_route *asbr_entry);
 extern void ospf6_asbr_lsentry_add(struct ospf6_route *asbr_entry);
 extern void ospf6_asbr_lsentry_remove(struct ospf6_route *asbr_entry);
 
index 19eb9a3fe660fa3d32629bb5c1358cf31be8038c..ef0a093d13804f6c53d357ffe7432b8289347ded 100644 (file)
@@ -469,6 +469,8 @@ int ospf6_route_cmp(struct ospf6_route *ra, struct ospf6_route *rb)
        if (ra->path.type == OSPF6_PATH_TYPE_EXTERNAL2) {
                if (ra->path.u.cost_e2 != rb->path.u.cost_e2)
                        return (ra->path.u.cost_e2 - rb->path.u.cost_e2);
+               else
+                       return (ra->path.cost - rb->path.cost);
        } else {
                if (ra->path.cost != rb->path.cost)
                        return (ra->path.cost - rb->path.cost);
@@ -627,10 +629,10 @@ struct ospf6_route *ospf6_route_add(struct ospf6_route *route,
                if (ospf6_route_is_identical(old, route)) {
                        if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
                                zlog_debug(
-                                       "%s %p: route add %p: needless update of %p",
+                                       "%s %p: route add %p: needless update of %p old cost %u",
                                        ospf6_route_table_name(table),
                                        (void *)table, (void *)route,
-                                       (void *)old);
+                                       (void *)old, old->path.cost);
                        else if (IS_OSPF6_DEBUG_ROUTE(TABLE))
                                zlog_debug("%s: route add: needless update",
                                           ospf6_route_table_name(table));
@@ -645,9 +647,10 @@ struct ospf6_route *ospf6_route_add(struct ospf6_route *route,
                }
 
                if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
-                       zlog_debug("%s %p: route add %p: update of %p",
+                       zlog_debug("%s %p: route add %p cost %u: update of %p old cost %u",
                                   ospf6_route_table_name(table), (void *)table,
-                                  (void *)route, (void *)old);
+                                  (void *)route, route->path.cost, (void *)old,
+                                  old->path.cost);
                else if (IS_OSPF6_DEBUG_ROUTE(TABLE))
                        zlog_debug("%s: route add: update",
                                   ospf6_route_table_name(table));
@@ -686,13 +689,14 @@ struct ospf6_route *ospf6_route_add(struct ospf6_route *route,
        if (prev || next) {
                if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
                        zlog_debug(
-                               "%s %p: route add %p: another path: prev %p, next %p node refcount %u",
+                               "%s %p: route add %p cost %u: another path: prev %p, next %p node ref %u",
                                ospf6_route_table_name(table), (void *)table,
-                               (void *)route, (void *)prev, (void *)next,
-                               node->lock);
+                               (void *)route, route->path.cost, (void *)prev,
+                               (void *)next, node->lock);
                else if (IS_OSPF6_DEBUG_ROUTE(TABLE))
-                       zlog_debug("%s: route add: another path found",
-                                  ospf6_route_table_name(table));
+                       zlog_debug("%s: route add cost %u: another path found",
+                                  ospf6_route_table_name(table),
+                                  route->path.cost);
 
                if (prev == NULL)
                        prev = next->prev;
@@ -814,9 +818,9 @@ void ospf6_route_remove(struct ospf6_route *route,
                prefix2str(&route->prefix, buf, sizeof(buf));
 
        if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
-               zlog_debug("%s %p: route remove %p: %s refcount %u",
+               zlog_debug("%s %p: route remove %p: %s cost %u refcount %u",
                           ospf6_route_table_name(table), (void *)table,
-                          (void *)route, buf, route->lock);
+                          (void *)route, buf, route->path.cost, route->lock);
        else if (IS_OSPF6_DEBUG_ROUTE(TABLE))
                zlog_debug("%s: route remove: %s",
                           ospf6_route_table_name(table), buf);
index 25d968fb689e575dc3c5ada7240769ea6f2a2710..afe2d7397b2efa05aed679c3421155ab3bd46fc9 100644 (file)
@@ -72,7 +72,7 @@ static void ospf6_top_lsdb_hook_remove(struct ospf6_lsa *lsa)
 {
        switch (ntohs(lsa->header->type)) {
        case OSPF6_LSTYPE_AS_EXTERNAL:
-               ospf6_asbr_lsa_remove(lsa);
+               ospf6_asbr_lsa_remove(lsa, NULL);
                break;
 
        default:
@@ -96,11 +96,16 @@ static void ospf6_top_route_hook_remove(struct ospf6_route *route)
 static void ospf6_top_brouter_hook_add(struct ospf6_route *route)
 {
        if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
-               char buf[PREFIX2STR_BUFFER];
-
-               prefix2str(&route->prefix, buf, sizeof(buf));
-               zlog_debug("%s: brouter %s add with nh count %u",
-                          __PRETTY_FUNCTION__, buf, listcount(route->nh_list));
+               uint32_t brouter_id;
+               char brouter_name[16];
+
+               brouter_id = ADV_ROUTER_IN_PREFIX(&route->prefix);
+               inet_ntop(AF_INET, &brouter_id, brouter_name,
+                         sizeof(brouter_name));
+               zlog_debug("%s: brouter %s add with adv router %x nh count %u",
+                          __PRETTY_FUNCTION__, brouter_name,
+                          route->path.origin.adv_router,
+                          listcount(route->nh_list));
        }
        ospf6_abr_examin_brouter(ADV_ROUTER_IN_PREFIX(&route->prefix));
        ospf6_asbr_lsentry_add(route);
@@ -110,11 +115,15 @@ static void ospf6_top_brouter_hook_add(struct ospf6_route *route)
 static void ospf6_top_brouter_hook_remove(struct ospf6_route *route)
 {
        if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
-               char buf[PREFIX2STR_BUFFER];
+               uint32_t brouter_id;
+               char brouter_name[16];
 
-               prefix2str(&route->prefix, buf, sizeof(buf));
+               brouter_id = ADV_ROUTER_IN_PREFIX(&route->prefix);
+               inet_ntop(AF_INET, &brouter_id, brouter_name,
+                         sizeof(brouter_name));
                zlog_debug("%s: brouter %s del with nh count %u",
-                          __PRETTY_FUNCTION__, buf, listcount(route->nh_list));
+                          __PRETTY_FUNCTION__, brouter_name,
+                          listcount(route->nh_list));
        }
        route->flag |= OSPF6_ROUTE_REMOVE;
        ospf6_abr_examin_brouter(ADV_ROUTER_IN_PREFIX(&route->prefix));
index 7bd644f43d676d73c95049e61ad89571348f9ada..8dbf39ef5df9e70bfe8c87e4e1db5188edaadf8b 100644 (file)
@@ -55,7 +55,7 @@
 
 /* ospfd privileges */
 zebra_capabilities_t _caps_p[] = {
-       ZCAP_NET_RAW, ZCAP_BIND, ZCAP_NET_ADMIN,
+       ZCAP_NET_RAW, ZCAP_BIND, ZCAP_NET_ADMIN, ZCAP_SYS_ADMIN
 };
 
 struct zebra_privs_t ospfd_privs = {
index 1560977ae86bfece3fb1f21651e88302ea1ada3e..fef77f574e1c31907568c3193de50922dbc48856 100644 (file)
@@ -47,6 +47,7 @@
 #include "thread.h"
 #include "vty.h"
 #include "zclient.h"
+#include <lib/json.h>
 
 #include "ospfd/ospfd.h"
 #include "ospfd/ospf_interface.h"
@@ -306,7 +307,8 @@ int ospf_sr_init(void)
 {
        int rc = -1;
 
-       zlog_info("SR (%s): Initialize SR Data Base", __func__);
+       if (IS_DEBUG_OSPF_SR)
+               zlog_info("SR (%s): Initialize SR Data Base", __func__);
 
        memset(&OspfSR, 0, sizeof(struct ospf_sr_db));
        OspfSR.enabled = false;
@@ -675,6 +677,7 @@ static int ospf_zebra_send_mpls_ftn(int cmd, struct sr_nhlfe nhlfe)
                SET_FLAG(api.message, ZAPI_MESSAGE_LABEL);
                api_nh->labels[0] = nhlfe.label_out;
                api_nh->label_num = 1;
+               api_nh->vrf_id = VRF_DEFAULT;
                api.nexthop_num = 1;
        }
 
@@ -1616,11 +1619,11 @@ static int ospf_sr_update_schedule(struct thread *t)
 
        monotime(&stop_time);
 
-       zlog_info(
-               "SR (%s): SPF Processing Time(usecs): %lld\n",
-               __func__,
-               (stop_time.tv_sec - start_time.tv_sec) * 1000000LL
-                       + (stop_time.tv_usec - start_time.tv_usec));
+       if (IS_DEBUG_OSPF_SR)
+               zlog_debug("SR (%s): SPF Processing Time(usecs): %lld\n",
+                          __func__,
+                          (stop_time.tv_sec - start_time.tv_sec) * 1000000LL
+                          + (stop_time.tv_usec - start_time.tv_usec));
 
        OspfSR.update = false;
        return 1;
@@ -2128,91 +2131,197 @@ DEFUN (no_sr_prefix_sid,
 
 
 
-static void show_vty_sr_node(struct vty *vty, struct sr_node *srn)
+static void show_sr_node(struct vty *vty, struct json_object *json,
+                            struct sr_node *srn)
 {
 
        struct listnode *node;
        struct sr_link *srl;
        struct sr_prefix *srp;
        struct interface *itf;
-       char pref[16];
+       char pref[19];
        char sid[22];
        char label[8];
+       json_object *json_node = NULL, *json_algo, *json_obj;
+       json_object *json_prefix = NULL, *json_link = NULL;
 
        /* Sanity Check */
        if (srn == NULL)
                return;
 
-       vty_out(vty, "SR-Node: %s", inet_ntoa(srn->adv_router));
-       vty_out(vty, "\tSRGB (Size/Label): %u/%u", srn->srgb.range_size,
-               srn->srgb.lower_bound);
-       vty_out(vty, "\tAlgorithm(s): %s",
-               srn->algo[0] == SR_ALGORITHM_SPF ? "SPF" : "S-SPF");
-       for (int i = 1; i < ALGORITHM_COUNT; i++) {
-               if (srn->algo[i] == SR_ALGORITHM_UNSET)
-                       continue;
-               vty_out(vty, "/%s",
-                       srn->algo[i] == SR_ALGORITHM_SPF ? "SPF" : "S-SPF");
-       }
-       if (srn->msd != 0)
-               vty_out(vty, "\tMSD: %u", srn->msd);
-
-       vty_out(vty,
-               "\n\n    Prefix or Link  Label In  Label Out       "
-               "Node or Adj. SID  Interface          Nexthop\n");
-       vty_out(vty,
-               "------------------  --------  ---------  "
-               "---------------------  ---------  ---------------\n");
+       if (json) {
+               json_node = json_object_new_object();
+               json_object_string_add(json_node, "routerID",
+                       inet_ntoa(srn->adv_router));
+               json_object_int_add(json_node, "srgbSize",
+                       srn->srgb.range_size);
+               json_object_int_add(json_node, "srgbLabel",
+                       srn->srgb.lower_bound);
+               json_algo = json_object_new_array();
+               json_object_object_add(json_node, "algorithms", json_algo);
+               for (int i = 0; i < ALGORITHM_COUNT; i++) {
+                       if (srn->algo[i] == SR_ALGORITHM_UNSET)
+                               continue;
+                       json_obj = json_object_new_object();
+                       char tmp[2];
+
+                       snprintf(tmp, 2, "%u", i);
+                       json_object_string_add(json_obj, tmp,
+                               srn->algo[i] == SR_ALGORITHM_SPF ?
+                                               "SPF" : "S-SPF");
+                       json_object_array_add(json_algo, json_obj);
+               }
+               if (srn->msd != 0)
+                       json_object_int_add(json_node, "nodeMsd", srn->msd);
+       } else {
+               vty_out(vty, "SR-Node: %s", inet_ntoa(srn->adv_router));
+               vty_out(vty, "\tSRGB (Size/Label): %u/%u",
+                       srn->srgb.range_size, srn->srgb.lower_bound);
+               vty_out(vty, "\tAlgorithm(s): %s",
+                       srn->algo[0] == SR_ALGORITHM_SPF ? "SPF" : "S-SPF");
+               for (int i = 1; i < ALGORITHM_COUNT; i++) {
+                       if (srn->algo[i] == SR_ALGORITHM_UNSET)
+                               continue;
+                       vty_out(vty, "/%s",
+                               srn->algo[i] == SR_ALGORITHM_SPF ?
+                                               "SPF" : "S-SPF");
+               }
+               if (srn->msd != 0)
+                       vty_out(vty, "\tMSD: %u", srn->msd);
+       }
+
+       if (!json) {
+               vty_out(vty,
+                       "\n\n    Prefix or Link  Label In  Label Out       "
+                       "Node or Adj. SID  Interface          Nexthop\n");
+               vty_out(vty,
+                       "------------------  --------  ---------  "
+                       "---------------------  ---------  ---------------\n");
+       }
        for (ALL_LIST_ELEMENTS_RO(srn->ext_prefix, node, srp)) {
-               strncpy(pref, inet_ntoa(srp->nhlfe.prefv4.prefix), 16);
+               snprintf(pref, 19, "%s/%u",
+                       inet_ntoa(srp->nhlfe.prefv4.prefix),
+                       srp->nhlfe.prefv4.prefixlen);
                snprintf(sid, 22, "SR Pfx (idx %u)", srp->sid);
                if (srp->nhlfe.label_out == MPLS_LABEL_IMPLICIT_NULL)
                        sprintf(label, "pop");
                else
                        sprintf(label, "%u", srp->nhlfe.label_out);
                itf = if_lookup_by_index(srp->nhlfe.ifindex, VRF_DEFAULT);
-               vty_out(vty, "%15s/%u  %8u  %9s  %21s  %9s  %15s\n", pref,
-                       srp->nhlfe.prefv4.prefixlen, srp->nhlfe.label_in, label,
-                       sid, itf ? itf->name : "-",
-                       inet_ntoa(srp->nhlfe.nexthop));
+               if (json) {
+                       if (!json_prefix) {
+                               json_prefix = json_object_new_array();
+                               json_object_object_add(json_node,
+                                       "extendedPrefix", json_prefix);
+                       }
+                       json_obj = json_object_new_object();
+                       json_object_string_add(json_obj, "prefix", pref);
+                       json_object_int_add(json_obj, "sid", srp->sid);
+                       json_object_int_add(json_obj, "inputLabel",
+                               srp->nhlfe.label_in);
+                       json_object_string_add(json_obj, "outputLabel",
+                               label);
+                       json_object_string_add(json_obj, "interface",
+                               itf ? itf->name : "-");
+                       json_object_string_add(json_obj, "nexthop",
+                               inet_ntoa(srp->nhlfe.nexthop));
+                       json_object_array_add(json_prefix, json_obj);
+               } else {
+                       vty_out(vty, "%18s  %8u  %9s  %21s  %9s  %15s\n",
+                               pref, srp->nhlfe.label_in, label,
+                               sid, itf ? itf->name : "-",
+                               inet_ntoa(srp->nhlfe.nexthop));
+               }
        }
 
        for (ALL_LIST_ELEMENTS_RO(srn->ext_link, node, srl)) {
-               strncpy(pref, inet_ntoa(srl->nhlfe[0].prefv4.prefix), 16);
+               snprintf(pref, 19, "%s/%u",
+                       inet_ntoa(srl->nhlfe[0].prefv4.prefix),
+                       srl->nhlfe[0].prefv4.prefixlen);
                snprintf(sid, 22, "SR Adj. (lbl %u)", srl->sid[0]);
                if (srl->nhlfe[0].label_out == MPLS_LABEL_IMPLICIT_NULL)
                        sprintf(label, "pop");
                else
                        sprintf(label, "%u", srl->nhlfe[0].label_out);
                itf = if_lookup_by_index(srl->nhlfe[0].ifindex, VRF_DEFAULT);
-               vty_out(vty, "%15s/%u  %8u  %9s  %21s  %9s  %15s\n", pref,
-                       srl->nhlfe[0].prefv4.prefixlen, srl->nhlfe[0].label_in,
-                       label, sid, itf ? itf->name : "-",
-                       inet_ntoa(srl->nhlfe[0].nexthop));
-               snprintf(sid, 22, "SR Adj. (lbl %u)", srl->sid[1]);
-               if (srl->nhlfe[1].label_out == MPLS_LABEL_IMPLICIT_NULL)
-                       sprintf(label, "pop");
-               else
-                       sprintf(label, "%u", srl->nhlfe[0].label_out);
-               vty_out(vty, "%15s/%u  %8u  %9s  %21s  %9s  %15s\n", pref,
-                       srl->nhlfe[1].prefv4.prefixlen, srl->nhlfe[1].label_in,
-                       label, sid, itf ? itf->name : "-",
-                       inet_ntoa(srl->nhlfe[1].nexthop));
+               if (json) {
+                       if (!json_link) {
+                               json_link = json_object_new_array();
+                               json_object_object_add(json_node,
+                                       "extendedLink", json_link);
+                       }
+                       /* Primary Link */
+                       json_obj = json_object_new_object();
+                       json_object_string_add(json_obj, "prefix", pref);
+                       json_object_int_add(json_obj, "sid", srl->sid[0]);
+                       json_object_int_add(json_obj, "inputLabel",
+                               srl->nhlfe[0].label_in);
+                       json_object_string_add(json_obj, "outputLabel",
+                               label);
+                       json_object_string_add(json_obj, "interface",
+                               itf ? itf->name : "-");
+                       json_object_string_add(json_obj, "nexthop",
+                               inet_ntoa(srl->nhlfe[0].nexthop));
+                       json_object_array_add(json_link, json_obj);
+                       /* Backup Link */
+                       json_obj = json_object_new_object();
+                       snprintf(sid, 22, "SR Adj. (lbl %u)", srl->sid[1]);
+                       if (srl->nhlfe[1].label_out == MPLS_LABEL_IMPLICIT_NULL)
+                               sprintf(label, "pop");
+                       else
+                               sprintf(label, "%u", srl->nhlfe[0].label_out);
+                       json_object_string_add(json_obj, "prefix", pref);
+                       json_object_int_add(json_obj, "sid", srl->sid[1]);
+                       json_object_int_add(json_obj, "inputLabel",
+                               srl->nhlfe[1].label_in);
+                       json_object_string_add(json_obj, "outputLabel",
+                               label);
+                       json_object_string_add(json_obj, "interface",
+                               itf ? itf->name : "-");
+                       json_object_string_add(json_obj, "nexthop",
+                               inet_ntoa(srl->nhlfe[1].nexthop));
+                       json_object_array_add(json_link, json_obj);
+               } else {
+                       vty_out(vty, "%18s  %8u  %9s  %21s  %9s  %15s\n",
+                               pref, srl->nhlfe[0].label_in,
+                               label, sid, itf ? itf->name : "-",
+                               inet_ntoa(srl->nhlfe[0].nexthop));
+                       snprintf(sid, 22, "SR Adj. (lbl %u)", srl->sid[1]);
+                       if (srl->nhlfe[1].label_out == MPLS_LABEL_IMPLICIT_NULL)
+                               sprintf(label, "pop");
+                       else
+                               sprintf(label, "%u", srl->nhlfe[1].label_out);
+                       vty_out(vty, "%18s  %8u  %9s  %21s  %9s  %15s\n",
+                               pref, srl->nhlfe[1].label_in,
+                               label, sid, itf ? itf->name : "-",
+                               inet_ntoa(srl->nhlfe[1].nexthop));
+               }
        }
-       vty_out(vty, "\n");
+       if (json)
+               json_object_array_add(json, json_node);
+       else
+               vty_out(vty, "\n");
 }
 
-static void show_srdb_entry(struct hash_backet *backet, void *args)
+static void show_vty_srdb(struct hash_backet *backet, void *args)
 {
        struct vty *vty = (struct vty *)args;
        struct sr_node *srn = (struct sr_node *)backet->data;
 
-       show_vty_sr_node(vty, srn);
+       show_sr_node(vty, NULL, srn);
+}
+
+static void show_json_srdb(struct hash_backet *backet, void *args)
+{
+       struct json_object *json = (struct json_object *)args;
+       struct sr_node *srn = (struct sr_node *)backet->data;
+
+       show_sr_node(NULL, json, srn);
 }
 
 DEFUN (show_ip_opsf_srdb,
        show_ip_ospf_srdb_cmd,
-       "show ip ospf database segment-routing [adv-router A.B.C.D|self-originate]",
+       "show ip ospf database segment-routing [adv-router A.B.C.D|self-originate] [json]",
        SHOW_STR
        IP_STR
        OSPF_STR
@@ -2220,23 +2329,41 @@ DEFUN (show_ip_opsf_srdb,
        "Show Segment Routing Data Base\n"
        "Advertising SR node\n"
        "Advertising SR node ID (as an IP address)\n"
-       "Self-originated SR node\n")
+       "Self-originated SR node\n"
+       JSON_STR)
 {
        int idx = 0;
        struct in_addr rid;
        struct sr_node *srn;
+       u_char uj = use_json(argc, argv);
+       json_object *json = NULL, *json_node_array = NULL;
 
        if (!OspfSR.enabled) {
                vty_out(vty, "Segment Routing is disabled on this router\n");
                return CMD_WARNING;
        }
 
-       vty_out(vty, "\n          OSPF Segment Routing database for ID %s\n\n",
-               inet_ntoa(OspfSR.self->adv_router));
+       if (uj) {
+               json = json_object_new_object();
+               json_node_array = json_object_new_array();
+               json_object_string_add(json, "srdbID",
+                       inet_ntoa(OspfSR.self->adv_router));
+               json_object_object_add(json, "srNodes", json_node_array);
+       } else {
+               vty_out(vty,
+                       "\n\t\tOSPF Segment Routing database for ID %s\n\n",
+                       inet_ntoa(OspfSR.self->adv_router));
+       }
 
        if (argv_find(argv, argc, "self-originate", &idx)) {
                srn = OspfSR.self;
-               show_vty_sr_node(vty, srn);
+               show_sr_node(vty, json_node_array, srn);
+               if (uj) {
+                       vty_out(vty, "%s\n",
+                               json_object_to_json_string_ext(json,
+                                         JSON_C_TO_STRING_PRETTY));
+                       json_object_free(json);
+               }
                return CMD_SUCCESS;
        }
 
@@ -2250,15 +2377,32 @@ DEFUN (show_ip_opsf_srdb,
                /* Get the SR Node from the SRDB */
                srn = (struct sr_node *)hash_lookup(OspfSR.neighbors,
                                                    (void *)&rid);
-               show_vty_sr_node(vty, srn);
+               show_sr_node(vty, json_node_array, srn);
+               if (uj) {
+                       vty_out(vty, "%s\n",
+                               json_object_to_json_string_ext(json,
+                                         JSON_C_TO_STRING_PRETTY));
+                       json_object_free(json);
+               }
                return CMD_SUCCESS;
        }
 
        /* No parameters have been provided, Iterate through all the SRDB */
-       hash_iterate(
-               OspfSR.neighbors,
-               (void (*)(struct hash_backet *, void *))show_srdb_entry,
-               (void *)vty);
+       if (uj) {
+               hash_iterate(
+                       OspfSR.neighbors,
+                       (void (*)(struct hash_backet *, void *))show_json_srdb,
+                       (void *)json_node_array);
+               vty_out(vty, "%s\n",
+                       json_object_to_json_string_ext(json,
+                                 JSON_C_TO_STRING_PRETTY));
+               json_object_free(json);
+       } else {
+               hash_iterate(
+                       OspfSR.neighbors,
+                       (void (*)(struct hash_backet *, void *))show_vty_srdb,
+                       (void *)vty);
+       }
        return CMD_SUCCESS;
 }
 
index 57d2a17b5f6b58183f679012fdfb798df93dd773..4a147751ddfb4384cb4ed8fd24329b7d40cd0121 100644 (file)
--- a/pimd/TODO
+++ b/pimd/TODO
-T1 DONE Implement debug command
-   test pim receive join
-
-T2 DONE Implement debug command
-   test pim receive prune
-
-T3 DONE Per-interface Downstream (S,G) state machine
-   (RFC 4601 4.5.3. Receiving (S,G) Join/Prune Messages)
-
-T4 DONE Upstream (S,G) state machine
-   (RFC 4601 4.5.7. Sending (S,G) Join/Prune Messages)
-
-T5 DONE Verify Data Packet Forwarding Rules
-   RFC 4601 4.2.  Data Packet Forwarding Rules
-   RFC 4601 4.8.2.  PIM-SSM-Only Routers
-
-   Additionally, the Packet forwarding rules of Section 4.2 can be
-   simplified in a PIM-SSM-only router:
-
-     iif is the incoming interface of the packet.
-     oiflist = NULL
-     if (iif == RPF_interface(S) AND UpstreamJPState(S,G) == Joined) {
-       oiflist = inherited_olist(S,G)
-     } else if (iif is in inherited_olist(S,G)) {
-       send Assert(S,G) on iif
-     }
-     oiflist = oiflist (-) iif
-     forward packet on all interfaces in oiflist
-
-   Macro:
-     inherited_olist(S,G) =
-       joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
-
-T6 DONE Implement (S,G) Assert state machine (RFC 4601, section 4.6.1).
-   Changes in pim_ifchannel.ifassert_winner should trigger
-   pim_upstream_update_join_desired().
-   Depends on TODO T27.
-   Depends on TODO T33.
-   See also CAVEAT C7.
-   See also: RFC 4601 4.5.7. Sending (S,G) Join/Prune Messages
-    Transitions from Joined State
-     RPF'(S,G) changes due to an Assert
-
-   http://www.hep.ucl.ac.uk/~ytl/multi-cast/pim-dm_01.html:
-
-     The PIM Assert mechanism is used to shutoff duplicate flows onto
-     the same multiaccess network. Routers detect this condiction when
-     they receive an (S,G) packet via a multi-access interface that is
-     in the (S,G) OIL. This causes the routers to send Assert
-     Messages.
-
-   Note that neighbors will not accept Join/Prune or Assert messages
-   from a router unless they have first heard a Hello message from that
-   router.  Thus, if a router needs to send a Join/Prune or Assert
-   message on an interface on which it has not yet sent a Hello message
-   with the currently configured IP address, then it MUST immediately
-   send the relevant Hello message without waiting for the Hello Timer
-   to expire, followed by the Join/Prune or Assert message.
-
-T7 DONE Implement hello option: LAN Prune Delay
-
-T8 DONE Implement J/P_Override_Interval(I)
-   Depends on TODO T7.
-   See pim_ifchannel.c, pim_ifchannel_prune(), jp_override_interval.
-
-T9 DONE Detect change in IGMPv3 RPF interface/next-hop for S and update.
-   channel_oil vif index accordingly ?
-   Beware accidentaly adding looped MFC entries (IIF=OIF).
-
-T10 DONE React to (S,G) join directed to another upstream address. See
-    also:
-    
-    RFC 4601: 4.5.7.  Sending (S,G) Join/Prune Messages
-
-    If a router wishes to propagate a Join(S,G) upstream, it must also
-    watch for messages on its upstream interface from other routers on
-    that subnet, and these may modify its behavior.  If it sees a
-    Join(S,G) to the correct upstream neighbor, it should suppress its
-    own Join(S,G).  If it sees a Prune(S,G), Prune(S,G,rpt), or
-    Prune(*,G) to the correct upstream neighbor towards S, it should
-    be prepared to override that prune by scheduling a Join(S,G) to be
-    sent almost immediately.
-
-T11 DONE Review protocol modifications for SSM
-    (RFC 4601 4.8.1.  Protocol Modifications for SSM Destination
-    Addresses)
-
-T12 DONE Review updates of RPF entries.
-    FIXME pim_upstream.c send_join():
-    Currently only one upstream state is affected by detection of RPF change.
-    RPF change should affect all upstream states sharing the RPF cache.
-
-T13 DONE Check that RFC macros using S,G,RPF_interface(S) are actually
-    implemented with this strategy:
-    rpf_ifch=find_ifch(up->rpf->interface).
-    See pim_rpf.c pim_rpf_find_rpf_addr() for a correct example.
-
-    $ grep -i macro pimd/*.c
-    pimd/pim_iface.c:  RFC 4601: 4.1.6.  State Summarization Macros
-    pimd/pim_ifchannel.c:    RFC 4601: 4.6.5.  Assert State Macros
-    pimd/pim_ifchannel.c:  RFC 4601: 4.1.6.  State Summarization Macros
-    pimd/pim_ifchannel.c:  RFC 4601: 4.1.6.  State Summarization Macros
-    pimd/pim_ifchannel.c:  RFC 4601: 4.6.5.  Assert State Macros
-    pimd/pim_ifchannel.c:  Macro:
-    pimd/pim_rpf.c:  RFC 4601: 4.1.6.  State Summarization Macros
-
-T14 DONE Send Assert(S,G) on iif as response to WRONGVIF kernel upcall.
-    See pim_mroute.c mroute_msg().
-
-T15 DONE Interface command to statically join (S,G).
-    interface eth0
-     ip igmp join-group 239.1.1.1 source 1.1.1.1
-
-T16 DONE RPF'(S,G) lookup is not working for S reachable with default route.
-    See "RPF'(S,G) not found" in pim_rpf_update() from pim_rpf.c.
-    Zebra daemon RIB is not reflecting changes in kernel routes
-    accurately?
-
-T17 DONE Prevent CLI from creating bogus interfaces.
-    Example:
-    conf t
-     interface xxx
-
-T18 Consider reliable pim solution (refresh reduction)
+T1  Consider reliable pim solution (refresh reduction)
     A Reliable Transport Mechanism for PIM
     http://tools.ietf.org/wg/pim/draft-ietf-pim-port/
     PORT=PIM-Over-Reliable-Transport
 
-T19 DONE Fix self as neighbor 
-    See mailing list post:
-    http://lists.gnu.org/archive/html/qpimd-users/2009-04/msg00000.html
-
-T20 DONE Fix debug message: "pim_neighbor_update: internal error:
-    trying to replace same prefix list"
-    See mailing list post:
-    http://lists.gnu.org/archive/html/qpimd-users/2009-04/msg00000.html
-
-T21 DONE Clean-up PIM/IGMP interface mismatch debugging
-    See option PIM_CHECK_RECV_IFINDEX_SANITY in pimd/Makefile.am
-    See mailing list post:
-    http://lists.nongnu.org/archive/html/qpimd-users/2009-04/msg00003.html
-
-T22 DONE IGMP must be protected against adding looped MFC entries
-    created by both source and receiver attached to the same
-    interface.
-
-T23 DONE libfrr crash after zclient_lookup_nexthop.
-    See mailing list post:
-    http://lists.nongnu.org/archive/html/qpimd-users/2009-04/msg00008.html
-
-T24 DONE zserv may return recursive routes:
-     - nexthop type is set to ZEBRA_NEXTHOP_IPV4
-     - ifindex is not reported
-     - calls expecting ifindex (fib_lookup_if_vif_index) are disrupted
-    See also this mailing list post:
-    [PATCH 21/21] Link detect and recursive routes
-    http://www.gossamer-threads.com/lists/quagga/dev/17564
-
-T25 DONE Zclient nexthop lookup missing OSPF route to 1.1.1.1/32
-    See also:
-    pim_zlookup.c zclient_lookup_nexthop misses OSPF 1.1.1.1/32
-    zebra/zebra_vty.c show_ip_route_addr_cmd hits OSPF 1.1.1.1/32
-
-T26 DONE Zebra daemon is marking recursive static route as inactive.
-
-    FIXED: zebra daemon was incorrectly marking recursive routes
-    pointing to kernel routes as inactive:
-      zebra/zebra_rib.c nexthop_active_ipv4:
-        -- Original:
-         else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL))
-        -- Fixed:
-         else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL) ||
-                  match->type == ZEBRA_ROUTE_KERNEL)
-
-    Old problem description:
-
-    This prevents rib_match_ipv4 from returning its nexthop:
-    client: pim_zlookup.c zclient_read_nexthop
-    server: zebra/zserv.c zsend_ipv4_nexthop_lookup_v2 -> rib_match_ipv4
-
-    Kernel route is injected into zebra in zebra_rib.c rib_add_ipv4
-    Examples:
-    rt_netlink.c:726: rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, src, index, table, metric, 0);
-    rt_netlink.c:864: rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, table, 0, 0);
-
-    This patch didn't fix the issue:
-    [PATCH 21/21] Link detect and recursive routes
-    http://www.gossamer-threads.com/lists/quagga/dev/17564
-
-    See the example below for the route 2.2.2.2.
-
-bash# route add -host 1.1.1.1 gw 127.0.0.1
-bash# route add -host 2.2.2.2 gw 1.1.1.1
-bash# netstat -nvr
-Kernel IP routing table
-Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
-2.2.2.2         1.1.1.1         255.255.255.255 UGH       0 0          0 lo
-1.1.1.1         127.0.0.1       255.255.255.255 UGH       0 0          0 lo
-192.168.0.0     0.0.0.0         255.255.255.0   U         0 0          0 eth0
-0.0.0.0         192.168.0.2     0.0.0.0         UG        0 0          0 eth0
-bash# 
-
-zebra# sh ip route         
-Codes: K - kernel route, C - connected, S - static, R - RIP, O - OSPF,
-       I - ISIS, B - BGP, > - selected route, * - FIB route
-
-K>* 0.0.0.0/0 via 192.168.0.2, eth0
-K>* 1.1.1.1/32 via 127.0.0.1, lo
-K * 2.2.2.2/32 via 1.1.1.1, lo inactive
-C>* 127.0.0.0/8 is directly connected, lo
-C>* 192.168.0.0/24 is directly connected, eth0
-
-quagga-pimd-router# sh ip route 1.1.1.1
-Address         NextHop         Interface Metric Preference
-1.1.1.1         127.0.0.1       lo             0          0
-quagga-pimd-router# 
-quagga-pimd-router# sh ip route 2.2.2.2
-Address         NextHop         Interface Metric Preference
-2.2.2.2         192.168.0.2     eth0           0          0
-quagga-pimd-router# 
-
-T27 DONE Implement debug command
-    test pim receive assert
-    See also TODO T6: (S,G) Assert state machine.
-
-T28 DONE Bad IPv4 address family=02 in Join/Prune dump
-    Reported by Andrew Lunn <andrew.lunn@ascom.ch>
-    
-    # 58-byte pim v2 Join/Prune dump
-    # ------------------------------
-    # IPv4 address family=02 is wrong, correct IPv4 address family is 01
-    # See http://www.iana.org/assignments/address-family-numbers
-    #
-    c8XX YY03 : ip src 200.xx.yy.3
-    e000 000d : ip dst 224.0.0.13
-    9404 0000 : ip router alert option 148.4.0.0
-    2300 ab13 : pimv2,type=3 res=00 checksum=ab13
-    0200      : upstream family=02, encoding=00
-    c8XX YY08 : upstream 200.xx.yy.8
-    0001 00d2 : res=00 groups=01 holdtime=00d2
-    0200 0020 : group family=02, encoding=00, res=00, mask_len=20
-    ef01 0101 : group address 239.1.1.1
-    0001 0000 : joined=0001 pruned=0000
-    0200 0020 : source family=02, encoding=00, res=00, mask_len=20
-    0101 0101 : source address 1.1.1.1
-
-T29 DONE Reset interface PIM-hello-sent counter when primary address changes
-    See pim_ifp->pim_ifstat_hello_sent
-
-    RFC 4601: 4.3.1.  Sending Hello Messages
-
-    Thus, if a router needs to send a Join/Prune or Assert message on
-    an interface on which it has not yet sent a Hello message with the
-    currently configured IP address, then it MUST immediately send the
-    relevant Hello message without waiting for the Hello Timer to
-    expire, followed by the Join/Prune or Assert message.
-
-T30 DONE Run interface DR election when primary address changes
-    Reported by Andrew Lunn <andrew.lunn@ascom.ch>
-    See pim_if_dr_election().
-
-T31 If an interface changes one of its secondary IP addresses, a Hello
+T2  If an interface changes one of its secondary IP addresses, a Hello
     message with an updated Address_List option and a non-zero
     HoldTime should be sent immediately.
     See also detect_secondary_address_change
     See also CAVEAT C15.
     See also RFC 4601: 4.3.1.  Sending Hello Messages
 
-T32 FIXED Detection of interface primary address changes may fail when
-    there are multiple addresses.
-    See also CAVEAT C14.
-
-    pim_find_primary_addr() should return interface primary address
-    from connected list. Currently it returns the first address.
-
-    Zebra daemon "show int" is able to keep the primary address as
-    first address.
-
-T33 DONE Implement debug command: test pim receive upcall
-    See also TODO T6: (S,G) Assert state machine.
-
-T34 DONE assert_action_a1
-
-T35 DONE Review macros depending on interface I.
-
-    See also: grep ,I\) pimd/*.c
-
-    For the case (S,G,I) check if I is either
-    1) interface attached to this per-interface S,G state (don't think so)
-    or
-    2) an arbitrary interface (most probably)
-
-    For the arbitrary interface case (2), consider representing
-    interface ifp as its primary address (struct in_addr ifaddr).  The
-    benefit is in_addr does not need to be dereferenced, so it does
-    not demand protection against crashes.
-
-T36 DONE React to zebra daemon link-detect up/down notification.
-    pim_ifp->primary_address is managed by detect_primary_address_change()
-    depending on to ifp->connected (managed by zebra_interface_address_read()).
-
-T37 DONE Review list of variables which may affect pim_upstream.c
-    pim_upstream_evaluate_join_desired().
-    Call pim_upstream_update_join_desired() accordingly.
-
-    See the order of invokation:
-      pim_if_dr_election(ifp);
-      pim_if_update_join_desired(pim_ifp); /* depends on DR */
-      pim_if_update_could_assert(ifp); /* depends on DR */
-      pim_if_update_my_assert_metric(ifp); /* depends on could_assert */
-
-    join_desired depends on:
-      pim_ifp->primary_address
-      pim_ifp->pim_dr_addr
-      ch->ifassert_winner_metric
-      ch->ifassert_winner
-      ch->local_ifmembership 
-      ch->ifjoin_state
-      ch->upstream->rpf.source_nexthop.mrib_metric_preference
-      ch->upstream->rpf.source_nexthop.mrib_route_metric
-      ch->upstream->rpf.source_nexthop.interface
-
-T38 DONE Detect change in AssertTrackingDesired(S,G,I)
-
-    See the order of invokation:
-      dr_election: none
-      update_join_desired: depends on DR
-      update_tracking_desired: depends on DR, join_desired
-
-    AssertTrackingDesired(S,G,I) depends on:
-      pim_ifp->primary_address
-      pim_ifp->pim_dr_addr
-      ch->local_ifmembership
-      ch->ifassert_winner
-      ch->ifjoin_state
-      ch->upstream->rpf.source_nexthop.interface
-      PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(ch->upstream->flags)
-
-T39 DONE AssertTrackingDesired: flags is not matching evaluation
-    
-    # show ip pim assert-internal 
-    CA:   CouldAssert
-    ECA:  Evaluate CouldAssert
-    ATD:  AssertTrackingDesired
-    eATD: Evaluate AssertTrackingDesired
-
-    Interface Address         Source          Group           CA  eCA ATD eATD
-    eth0      192.168.1.100   1.1.1.1         239.1.1.1       no  no  no  yes 
-    # 
-
-T40 Lightweight MLDv2
+T3  Lightweight MLDv2
     http://tools.ietf.org/html/draft-ietf-mboned-lightweight-igmpv3-mldv2-05
     http://www.ietf.org/internet-drafts/draft-ietf-mboned-lightweight-igmpv3-mldv2-05.txt
     http://www.ietf.org/html.charters/mboned-charter.html
 
-T41 DONE ssmping support
-
-    See also:
-      http://www.venaas.no/multicast/ssmping/
-      draft-ietf-mboned-ssmping-07
-      http://tools.ietf.org/html/draft-ietf-mboned-ssmping-07
-
-    Example:
-
-    debug ssmpingd
-    
-    conf t
-     ip ssmpingd 1.1.1.1
-    
-    show ip ssmpingd
-
-T42 Static igmp join fails when loading config at boot time
+T4  Static igmp join fails when loading config at boot time
 
     ! Wrong behavior seen at boot time:
     !
@@ -396,7 +42,7 @@ T42 Static igmp join fails when loading config at boot time
     eth0      200.202.112.3     2   2       0       0          0          0
     lo        127.0.0.1         1   1       0       0          0          0
 
-T43 PIM Neighbor Reduction
+T PIM Neighbor Reduction
     https://datatracker.ietf.org/doc/draft-wijnands-pim-neighbor-reduction/
     
     "In a transit LAN (no directly connected source or receiver), many
@@ -404,19 +50,19 @@ T43 PIM Neighbor Reduction
     a procedure to reduce the amount of neighbors established over a
     transit LAN."
 
-T44 Single Stream Multicast Fast Reroute (SMFR) Method
+T Single Stream Multicast Fast Reroute (SMFR) Method
     https://datatracker.ietf.org/doc/draft-liu-pim-single-stream-multicast-frr/
 
     "This document proposes an IP multicast fast convergence method
     based on differentiating primary and backup PIM join."
 
-T45 RFC5384 - The Join Attribute Format
+T RFC5384 - The Join Attribute Format
     "This document describes a modification of the Join message that
     allows a node to associate attributes with a particular tree."
 
-T46 PIM Multi-Topology ID (MT-ID) Join-Attribute
+T PIM Multi-Topology ID (MT-ID) Join-Attribute
     http://tools.ietf.org/html/draft-cai-pim-mtid-00
-    Depends on T45.
+    Depends on T7.
 
     "This draft introduces a new type of PIM Join Attribute used to
     encode the identity of the topology PIM uses for RPF."
index 3b22db20aa155e7e33f6a45e4d7b783f55a7ad73..f02ce4979cdc2f2b95a979e816b9252cfc570f94 100644 (file)
@@ -169,6 +169,7 @@ void route_add(struct prefix *p, struct nexthop *nh)
        api.safi = SAFI_UNICAST;
        memcpy(&api.prefix, p, sizeof(*p));
 
+       SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION);
        SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
 
        api_nh = &api.nexthops[0];
index ab1d55b548a3021f1bd8f9951c6b49601a165d61..c2fe9c8890298bb93016585834b7b20098421095 100644 (file)
@@ -24,10 +24,12 @@ __pycache__
 /bgpd/test_ecommunity
 /bgpd/test_mp_attr
 /bgpd/test_mpath
+/bgpd/test_packet
 /isisd/test_fuzz_isis_tlv
 /isisd/test_fuzz_isis_tlv_tests.h
 /isisd/test_isis_vertex_queue
 /lib/cli/test_cli
+/lib/cli/test_cli_clippy.c
 /lib/cli/test_commands
 /lib/cli/test_commands_defun.c
 /lib/test_buffer
@@ -38,6 +40,7 @@ __pycache__
 /lib/test_memory
 /lib/test_nexthop_iter
 /lib/test_privs
+/lib/test_ringbuf
 /lib/test_srcdest_table
 /lib/test_segv
 /lib/test_sig
@@ -48,3 +51,4 @@ __pycache__
 /lib/test_ttable
 /lib/test_zmq
 /ospf6d/test_lsdb
+/ospf6d/test_lsdb_clippy.c
index 860d872f860ceae7209a366dfa5d1eaa7c4430ca..5d994ddd7bdb6469e77beba1c5de7bac467211cc 100644 (file)
@@ -1,4 +1,6 @@
 import frrtest
 
-class TestRingbuf(frrtest.TestExitNonzero):
+class TestRingbuf(frrtest.TestMultiOut):
     program = './test_ringbuf'
+
+TestRingbuf.exit_cleanly()
index 8719226281f162afa2a9562afb71692229a828f3..bf9d70bae96db456550d405f4d7b2edc5b5ff37f 100644 (file)
@@ -539,7 +539,7 @@ int vtysh_mark_file(const char *filename)
        }
 
        vty = vty_new();
-       vty->fd = 0; /* stdout */
+       vty->wfd = STDERR_FILENO;
        vty->type = VTY_TERM;
        vty->node = CONFIG_NODE;
 
index aa1dd407eb5c3557253231eeb83459d7743544ce..c055d29d4ba05a58558f5e18cd855af3aa446c23 100644 (file)
@@ -398,7 +398,7 @@ static int vtysh_read_file(FILE *confp)
        int ret;
 
        vty = vty_new();
-       vty->fd = 0; /* stdout */
+       vty->wfd = STDERR_FILENO;
        vty->type = VTY_TERM;
        vty->node = CONFIG_NODE;
 
@@ -448,6 +448,11 @@ void vtysh_config_write()
                sprintf(line, "hostname %s", cmd_hostname_get());
                vtysh_config_parse_line(NULL, line);
        }
+
+       if (cmd_domainname_get()) {
+               sprintf(line, "domainname %s", cmd_domainname_get());
+               vtysh_config_parse_line(NULL, line);
+       }
        if (vtysh_write_integrated == WRITE_INTEGRATED_NO)
                vtysh_config_parse_line(NULL,
                                        "no service integrated-vtysh-config");
index 5c316e077fbd4f924bf03e2b7c5129b256f2f48b..7f6c8aefa8086626d4e40b31fe3b0b49b6801348 100644 (file)
@@ -514,7 +514,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
                                        nexthop->ifindex = newhop->ifindex;
                        }
                        return 1;
-               } else if (CHECK_FLAG(re->flags, ZEBRA_FLAG_INTERNAL)) {
+               } else if (CHECK_FLAG(re->flags, ZEBRA_FLAG_ALLOW_RECURSION)) {
                        resolved = 0;
                        for (ALL_NEXTHOPS(match->nexthop, newhop)) {
                                if (!CHECK_FLAG(newhop->flags,
index 9fc5afff0f392e01bf16638ad16247f4f7f56048..d960dbd93773a5946b64466d591bdd2ef88d834c 100644 (file)
@@ -1019,6 +1019,8 @@ static int send_client(struct rnh *rnh, struct zserv *client, rnh_type_t type,
                break;
        }
        if (re) {
+               stream_putc(s, re->type);
+               stream_putw(s, re->instance);
                stream_putc(s, re->distance);
                stream_putl(s, re->metric);
                num = 0;
@@ -1054,6 +1056,8 @@ static int send_client(struct rnh *rnh, struct zserv *client, rnh_type_t type,
                        }
                stream_putc_at(s, nump, num);
        } else {
+               stream_putc(s, 0); // type
+               stream_putw(s, 0); // instance
                stream_putc(s, 0); // distance
                stream_putl(s, 0); // metric
                stream_putc(s, 0); // nexthops
index 20b9e94288792c5d433fce497af9bc7f2157f2b1..e07dc6059f13889986a73f0388c729d1be47d3a4 100644 (file)
@@ -1135,7 +1135,8 @@ static void zvni_print_hash(struct hash_backet *backet, void *ctxt[])
                        "%-10u %-4s %-21s %-8u %-8u %-15u %-37s\n",
                        zvni->vni, "L2",
                        zvni->vxlan_if ? zvni->vxlan_if->name : "unknown",
-                       num_macs, num_neigh, num_vteps,
+                       num_macs, num_neigh,
+                       num_vteps,
                        vrf_id_to_name(zvni->vrf_id));
        else {
                char vni_str[VNI_STR_LEN];
@@ -1858,20 +1859,18 @@ static int zvni_gw_macip_del(struct interface *ifp, zebra_vni_t *zvni,
                return -1;
 
        /* only need to delete the entry from bgp if we sent it before */
-       if (advertise_gw_macip_enabled(zvni)) {
-               if (IS_ZEBRA_DEBUG_VXLAN)
-                       zlog_debug("%u:SVI %s(%u) VNI %u, sending GW MAC %s IP %s del to BGP",
-                                  ifp->vrf_id, ifp->name,
-                                  ifp->ifindex, zvni->vni,
-                                  prefix_mac2str(&(n->emac),
-                                                 NULL,
-                                                 ETHER_ADDR_STRLEN),
-                                  ipaddr2str(ip, buf2, sizeof(buf2)));
-
-               /* Remove neighbor from BGP. */
-               zvni_neigh_send_del_to_client(zvni->vni, &n->ip, &n->emac,
-                                             ZEBRA_MACIP_TYPE_GW);
-       }
+       if (IS_ZEBRA_DEBUG_VXLAN)
+               zlog_debug("%u:SVI %s(%u) VNI %u, sending GW MAC %s IP %s del to BGP",
+                          ifp->vrf_id, ifp->name,
+                          ifp->ifindex, zvni->vni,
+                          prefix_mac2str(&(n->emac),
+                                         NULL,
+                                         ETHER_ADDR_STRLEN),
+                          ipaddr2str(ip, buf2, sizeof(buf2)));
+
+       /* Remove neighbor from BGP. */
+       zvni_neigh_send_del_to_client(zvni->vni, &n->ip, &n->emac,
+                                     ZEBRA_MACIP_TYPE_GW);
 
        /* Delete this neighbor entry. */
        zvni_neigh_del(zvni, n);
@@ -6256,15 +6255,33 @@ int zebra_vxlan_if_update(struct interface *ifp, u_int16_t chgflags)
                                zebra_vxlan_process_l3vni_oper_down(zl3vni);
                                zl3vni->svi_if = NULL;
                                zl3vni->svi_if = zl3vni_map_to_svi_if(zl3vni);
+                               zl3vni->local_vtep_ip = vxl->vtep_ip;
                                if (is_l3vni_oper_up(zl3vni))
                                        zebra_vxlan_process_l3vni_oper_up(
                                                                        zl3vni);
                        }
                }
 
+               /*
+                * local-ip change - process oper down, associate with new
+                * local-ip and then process oper up again
+                */
+               if (chgflags & ZEBRA_VXLIF_LOCAL_IP_CHANGE) {
+                       if (if_is_operative(ifp)) {
+                               zebra_vxlan_process_l3vni_oper_down(zl3vni);
+                               zl3vni->local_vtep_ip = vxl->vtep_ip;
+                               if (is_l3vni_oper_up(zl3vni))
+                                       zebra_vxlan_process_l3vni_oper_up(
+                                                                       zl3vni);
+                       }
+               }
+
+               /* Update local tunnel IP. */
+               zl3vni->local_vtep_ip = vxl->vtep_ip;
+
                /* if we have a valid new master, process l3-vni oper up */
                if (chgflags & ZEBRA_VXLIF_MASTER_CHANGE) {
-                       if (is_l3vni_oper_up(zl3vni))
+                       if (if_is_operative(ifp) && is_l3vni_oper_up(zl3vni))
                                zebra_vxlan_process_l3vni_oper_up(zl3vni);
                }
        } else {
@@ -6704,6 +6721,10 @@ int zebra_vxlan_advertise_gw_macip(struct zserv *client, u_short length,
                struct interface *vlan_if = NULL;
                struct interface *vrr_if = NULL;
 
+               zvni = zvni_lookup(vni);
+               if (!zvni)
+                       return 0;
+
                if (IS_ZEBRA_DEBUG_VXLAN)
                        zlog_debug(
                                "EVPN gateway macip Adv %s on VNI %d , currently %s",
@@ -6712,10 +6733,6 @@ int zebra_vxlan_advertise_gw_macip(struct zserv *client, u_short length,
                                        ? "enabled"
                                        : "disabled");
 
-               zvni = zvni_lookup(vni);
-               if (!zvni)
-                       return 0;
-
                if (zvni->advertise_gw_macip == advertise)
                        return 0;
 
index 98cb54f7b8f9a827fd52f38d35300be094faa43e..bca8a509d82ededda2b0db02be3adb82d6ed9174 100644 (file)
@@ -1166,12 +1166,12 @@ static int zread_route_add(struct zserv *client, u_short length,
                        switch (api_nh->type) {
                        case NEXTHOP_TYPE_IFINDEX:
                                nexthop = route_entry_nexthop_ifindex_add(
-                                       re, api_nh->ifindex, re->vrf_id);
+                                       re, api_nh->ifindex, api_nh->vrf_id);
                                break;
                        case NEXTHOP_TYPE_IPV4:
                                nexthop = route_entry_nexthop_ipv4_add(
                                        re, &api_nh->gate.ipv4, NULL,
-                                       re->vrf_id);
+                                       api_nh->vrf_id);
                                break;
                        case NEXTHOP_TYPE_IPV4_IFINDEX: {
 
@@ -1188,7 +1188,7 @@ static int zread_route_add(struct zserv *client, u_short length,
 
                                nexthop = route_entry_nexthop_ipv4_ifindex_add(
                                        re, &api_nh->gate.ipv4, NULL, ifindex,
-                                       re->vrf_id);
+                                       api_nh->vrf_id);
 
                                /* if this an EVPN route entry,
                                   program the nh as neigh
@@ -1211,12 +1211,12 @@ static int zread_route_add(struct zserv *client, u_short length,
                        }
                        case NEXTHOP_TYPE_IPV6:
                                nexthop = route_entry_nexthop_ipv6_add(
-                                       re, &api_nh->gate.ipv6, re->vrf_id);
+                                       re, &api_nh->gate.ipv6, api_nh->vrf_id);
                                break;
                        case NEXTHOP_TYPE_IPV6_IFINDEX:
                                nexthop = route_entry_nexthop_ipv6_ifindex_add(
                                        re, &api_nh->gate.ipv6, api_nh->ifindex,
-                                       re->vrf_id);
+                                       api_nh->vrf_id);
                                break;
                        case NEXTHOP_TYPE_BLACKHOLE:
                                nexthop = route_entry_nexthop_blackhole_add(