]> git.proxmox.com Git - mirror_frr.git/commitdiff
Merge pull request #4274 from rgirada/fix_clear_mroute
authorDonald Sharp <sharpd@cumulusnetworks.com>
Mon, 3 Jun 2019 11:39:04 +0000 (07:39 -0400)
committerGitHub <noreply@github.com>
Mon, 3 Jun 2019 11:39:04 +0000 (07:39 -0400)
pimd: Re-deisgn the "clear ip mroute" command.

77 files changed:
bgpd/bgp_community.c
bgpd/bgp_evpn.c
bgpd/bgp_fsm.c
bgpd/bgp_packet.c
bgpd/bgp_route.c
bgpd/bgp_routemap.c
bgpd/bgp_rpki.c
bgpd/bgp_updgrp_adv.c
bgpd/bgp_zebra.c
bgpd/rfapi/rfapi_import.c
doc/developer/building-frr-for-centos7.rst
doc/developer/topotests.rst
doc/developer/workflow.rst
doc/user/pim.rst
doc/user/rpki.rst
eigrpd/eigrp_routemap.c
isisd/isis_route.c
isisd/isis_routemap.c
isisd/isis_vty_fabricd.c
isisd/isisd.c
lib/command.c
lib/command.h
lib/command_match.c
lib/debug.c
lib/debug.h
lib/libfrr.c
lib/linklist.c
lib/linklist.h
lib/log.c
lib/northbound.c
lib/northbound_cli.c
lib/prefix.c
lib/routemap.c
lib/routemap.h
lib/table.h
lib/vty.c
lib/zclient.c
lib/zclient.h
ospf6d/ospf6_asbr.c
ospfd/ospf_routemap.c
ospfd/ospf_te.c
ospfd/ospf_zebra.c
pbrd/pbr_nht.c
pimd/pim_cmd.c
pimd/pim_cmd.h
pimd/pim_iface.c
pimd/pim_iface.h
pimd/pim_igmpv3.c
pimd/pim_msdp.c
pimd/pim_upstream.c
pimd/pim_upstream.h
pimd/pim_vty.c
ripd/rip_routemap.c
ripngd/ripng_routemap.c
ripngd/ripngd.c
staticd/static_routes.c
vtysh/vtysh.c
vtysh/vtysh_config.c
zebra/ioctl.c
zebra/ioctl_solaris.c
zebra/kernel_socket.c
zebra/redistribute.c
zebra/rib.h
zebra/rt_netlink.c
zebra/subdir.am
zebra/zapi_msg.c
zebra/zebra_dplane.c
zebra/zebra_dplane.h
zebra/zebra_mpls.c
zebra/zebra_mpls.h
zebra/zebra_nhg.c [new file with mode: 0644]
zebra/zebra_nhg.h [new file with mode: 0644]
zebra/zebra_rib.c
zebra/zebra_rnh.c
zebra/zebra_routemap.c
zebra/zebra_vty.c
zebra/zserv.c

index 82762072df0966e37d2776ecef0beeea18fd7506..6fc52ff9e03195cec06a202fa7989fb8a2115ec3 100644 (file)
@@ -205,7 +205,6 @@ static void set_community_string(struct community *com, bool make_json)
 {
        int i;
        char *str;
-       char *pnt;
        int len;
        int first;
        uint32_t comval;
@@ -297,7 +296,7 @@ static void set_community_string(struct community *com, bool make_json)
        }
 
        /* Allocate memory.  */
-       str = pnt = XMALLOC(MTYPE_COMMUNITY_STR, len);
+       str = XCALLOC(MTYPE_COMMUNITY_STR, len);
        first = 1;
 
        /* Fill in string.  */
@@ -308,12 +307,11 @@ static void set_community_string(struct community *com, bool make_json)
                if (first)
                        first = 0;
                else
-                       *pnt++ = ' ';
+                       strlcat(str, " ", len);
 
                switch (comval) {
                case COMMUNITY_INTERNET:
-                       strcpy(pnt, "internet");
-                       pnt += strlen("internet");
+                       strlcat(str, "internet", len);
                        if (make_json) {
                                json_string =
                                        json_object_new_string("internet");
@@ -322,8 +320,7 @@ static void set_community_string(struct community *com, bool make_json)
                        }
                        break;
                case COMMUNITY_GSHUT:
-                       strcpy(pnt, "graceful-shutdown");
-                       pnt += strlen("graceful-shutdown");
+                       strlcat(str, "graceful-shutdown", len);
                        if (make_json) {
                                json_string = json_object_new_string(
                                        "gracefulShutdown");
@@ -332,8 +329,7 @@ static void set_community_string(struct community *com, bool make_json)
                        }
                        break;
                case COMMUNITY_ACCEPT_OWN:
-                       strcpy(pnt, "accept-own");
-                       pnt += strlen("accept-own");
+                       strlcat(str, "accept-own", len);
                        if (make_json) {
                                json_string = json_object_new_string(
                                        "acceptown");
@@ -342,8 +338,7 @@ static void set_community_string(struct community *com, bool make_json)
                        }
                        break;
                case COMMUNITY_ROUTE_FILTER_TRANSLATED_v4:
-                       strcpy(pnt, "route-filter-translated-v4");
-                       pnt += strlen("route-filter-translated-v4");
+                       strlcat(str, "route-filter-translated-v4", len);
                        if (make_json) {
                                json_string = json_object_new_string(
                                        "routeFilterTranslatedV4");
@@ -352,8 +347,7 @@ static void set_community_string(struct community *com, bool make_json)
                        }
                        break;
                case COMMUNITY_ROUTE_FILTER_v4:
-                       strcpy(pnt, "route-filter-v4");
-                       pnt += strlen("route-filter-v4");
+                       strlcat(str, "route-filter-v4", len);
                        if (make_json) {
                                json_string = json_object_new_string(
                                        "routeFilterV4");
@@ -362,8 +356,7 @@ static void set_community_string(struct community *com, bool make_json)
                        }
                        break;
                case COMMUNITY_ROUTE_FILTER_TRANSLATED_v6:
-                       strcpy(pnt, "route-filter-translated-v6");
-                       pnt += strlen("route-filter-translated-v6");
+                       strlcat(str, "route-filter-translated-v6", len);
                        if (make_json) {
                                json_string = json_object_new_string(
                                        "routeFilterTranslatedV6");
@@ -372,8 +365,7 @@ static void set_community_string(struct community *com, bool make_json)
                        }
                        break;
                case COMMUNITY_ROUTE_FILTER_v6:
-                       strcpy(pnt, "route-filter-v6");
-                       pnt += strlen("route-filter-v6");
+                       strlcat(str, "route-filter-v6", len);
                        if (make_json) {
                                json_string = json_object_new_string(
                                        "routeFilterV6");
@@ -382,8 +374,7 @@ static void set_community_string(struct community *com, bool make_json)
                        }
                        break;
                case COMMUNITY_LLGR_STALE:
-                       strcpy(pnt, "llgr-stale");
-                       pnt += strlen("llgr-stale");
+                       strlcat(str, "llgr-stale", len);
                        if (make_json) {
                                json_string = json_object_new_string(
                                        "llgrStale");
@@ -392,8 +383,7 @@ static void set_community_string(struct community *com, bool make_json)
                        }
                        break;
                case COMMUNITY_NO_LLGR:
-                       strcpy(pnt, "no-llgr");
-                       pnt += strlen("no-llgr");
+                       strlcat(str, "no-llgr", len);
                        if (make_json) {
                                json_string = json_object_new_string(
                                        "noLlgr");
@@ -402,8 +392,7 @@ static void set_community_string(struct community *com, bool make_json)
                        }
                        break;
                case COMMUNITY_ACCEPT_OWN_NEXTHOP:
-                       strcpy(pnt, "accept-own-nexthop");
-                       pnt += strlen("accept-own-nexthop");
+                       strlcat(str, "accept-own-nexthop", len);
                        if (make_json) {
                                json_string = json_object_new_string(
                                        "acceptownnexthop");
@@ -412,8 +401,7 @@ static void set_community_string(struct community *com, bool make_json)
                        }
                        break;
                case COMMUNITY_BLACKHOLE:
-                       strcpy(pnt, "blackhole");
-                       pnt += strlen("blackhole");
+                       strlcat(str, "blackhole", len);
                        if (make_json) {
                                json_string = json_object_new_string(
                                        "blackhole");
@@ -422,8 +410,7 @@ static void set_community_string(struct community *com, bool make_json)
                        }
                        break;
                case COMMUNITY_NO_EXPORT:
-                       strcpy(pnt, "no-export");
-                       pnt += strlen("no-export");
+                       strlcat(str, "no-export", len);
                        if (make_json) {
                                json_string =
                                        json_object_new_string("noExport");
@@ -432,8 +419,7 @@ static void set_community_string(struct community *com, bool make_json)
                        }
                        break;
                case COMMUNITY_NO_ADVERTISE:
-                       strcpy(pnt, "no-advertise");
-                       pnt += strlen("no-advertise");
+                       strlcat(str, "no-advertise", len);
                        if (make_json) {
                                json_string =
                                        json_object_new_string("noAdvertise");
@@ -442,8 +428,7 @@ static void set_community_string(struct community *com, bool make_json)
                        }
                        break;
                case COMMUNITY_LOCAL_AS:
-                       strcpy(pnt, "local-AS");
-                       pnt += strlen("local-AS");
+                       strlcat(str, "local-AS", len);
                        if (make_json) {
                                json_string = json_object_new_string("localAs");
                                json_object_array_add(json_community_list,
@@ -451,8 +436,7 @@ static void set_community_string(struct community *com, bool make_json)
                        }
                        break;
                case COMMUNITY_NO_PEER:
-                       strcpy(pnt, "no-peer");
-                       pnt += strlen("no-peer");
+                       strlcat(str, "no-peer", len);
                        if (make_json) {
                                json_string = json_object_new_string("noPeer");
                                json_object_array_add(json_community_list,
@@ -462,17 +446,17 @@ static void set_community_string(struct community *com, bool make_json)
                default:
                        as = (comval >> 16) & 0xFFFF;
                        val = comval & 0xFFFF;
-                       sprintf(pnt, "%u:%d", as, val);
+                       char buf[32];
+                       snprintf(buf, sizeof(buf), "%u:%d", as, val);
+                       strlcat(str, buf, len);
                        if (make_json) {
-                               json_string = json_object_new_string(pnt);
+                               json_string = json_object_new_string(buf);
                                json_object_array_add(json_community_list,
                                                      json_string);
                        }
-                       pnt += strlen(pnt);
                        break;
                }
        }
-       *pnt = '\0';
 
        if (make_json) {
                json_object_string_add(com->json, "string", str);
index 112e4b836c2e90857663501204f17ccc88e960e4..a58fca0cc2d85a6ab1564a298b0e671b08b11008 100644 (file)
@@ -2472,7 +2472,7 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
 
        if (bgp_debug_zebra(NULL)) {
                zlog_debug(
-                       "installing evpn prefix %s as ip prefix %s in vrf %s",
+                       "import evpn prefix %s as ip prefix %s in vrf %s",
                        prefix2str(evp, buf, sizeof(buf)),
                        prefix2str(pp, buf1, sizeof(buf)),
                        vrf_id_to_name(bgp_vrf->vrf_id));
@@ -4411,7 +4411,7 @@ void bgp_evpn_advertise_type5_routes(struct bgp *bgp_vrf, afi_t afi,
 
                                /* apply the route-map */
                                if (bgp_vrf->adv_cmd_rmap[afi][safi].map) {
-                                       int ret = 0;
+                                       route_map_result_t ret;
 
                                        ret = route_map_apply(
                                                bgp_vrf->adv_cmd_rmap[afi][safi]
index 12ae1f841a511d20bb28434388f728662d51cdea..dd765731dcabc02f158327c1836ae6b2ac466031 100644 (file)
@@ -949,9 +949,15 @@ void bgp_fsm_change_status(struct peer *peer, int status)
        else if ((peer->status == Established) && (status != Established))
                bgp->established_peers--;
 
-       if (BGP_DEBUG(neighbor_events, NEIGHBOR_EVENTS))
-               zlog_debug("%s : vrf %u, established_peers %u", __func__,
-                               bgp->vrf_id, bgp->established_peers);
+       if (bgp_debug_neighbor_events(peer)) {
+               struct vrf *vrf = vrf_lookup_by_id(bgp->vrf_id);
+
+               zlog_debug("%s : vrf %s(%u), Status: %s established_peers %u", __func__,
+                          vrf ? vrf->name : "Unknown", bgp->vrf_id,
+                          lookup_msg(bgp_status_msg, status, NULL),
+                          bgp->established_peers);
+       }
+
        /* Set to router ID to the value provided by RIB if there are no peers
         * in the established state and peer count did not change
         */
index b5934fb56e220a67359c29430c08b48a54581e3a..655a4745cba045681bc37cd6cbfb882bfe0fb315 100644 (file)
@@ -709,12 +709,15 @@ void bgp_notify_send_with_data(struct peer *peer, uint8_t code,
                                XMALLOC(MTYPE_TMP, bgp_notify.length * 3);
                        for (i = 0; i < bgp_notify.length; i++)
                                if (first) {
-                                       sprintf(c, " %02x", data[i]);
-                                       strcat(bgp_notify.data, c);
+                                       snprintf(c, sizeof(c), " %02x",
+                                                data[i]);
+                                       strlcat(bgp_notify.data, c,
+                                               bgp_notify.length);
                                } else {
                                        first = 1;
-                                       sprintf(c, "%02x", data[i]);
-                                       strcpy(bgp_notify.data, c);
+                                       snprintf(c, sizeof(c), "%02x", data[i]);
+                                       strlcpy(bgp_notify.data, c,
+                                               bgp_notify.length);
                                }
                }
                bgp_notify_print(peer, &bgp_notify, "sending");
@@ -1700,14 +1703,16 @@ static int bgp_notify_receive(struct peer *peer, bgp_size_t size)
                                XMALLOC(MTYPE_TMP, bgp_notify.length * 3);
                        for (i = 0; i < bgp_notify.length; i++)
                                if (first) {
-                                       sprintf(c, " %02x",
+                                       snprintf(c, sizeof(c), " %02x",
                                                stream_getc(peer->curr));
-                                       strcat(bgp_notify.data, c);
+                                       strlcat(bgp_notify.data, c,
+                                               bgp_notify.length);
                                } else {
                                        first = 1;
-                                       sprintf(c, "%02x",
-                                               stream_getc(peer->curr));
-                                       strcpy(bgp_notify.data, c);
+                                       snprintf(c, sizeof(c), "%02x",
+                                                stream_getc(peer->curr));
+                                       strlcpy(bgp_notify.data, c,
+                                               bgp_notify.length);
                                }
                        bgp_notify.raw_data = (uint8_t *)peer->notify.data;
                }
@@ -2299,6 +2304,9 @@ int bgp_process_packet(struct thread *thread)
                                        __FUNCTION__, peer->host);
                        break;
                default:
+                       /* Suppress uninitialized variable warning */
+                       mprc = 0;
+                       (void)mprc;
                        /*
                         * The message type should have been sanitized before
                         * we ever got here. Receipt of a message with an
index 31243c899dc2219e6709b8998d54d99fd58aa6ac..edaab88286e3d82744bf77a77bbf378ade8d54cf 100644 (file)
@@ -1458,7 +1458,7 @@ int subgroup_announce_check(struct bgp_node *rn, struct bgp_path_info *pi,
        struct bgp *bgp;
        struct attr *piattr;
        char buf[PREFIX_STRLEN];
-       int ret;
+       route_map_result_t ret;
        int transparent;
        int reflect;
        afi_t afi;
@@ -2526,12 +2526,12 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
 
                        /* apply the route-map */
                        if (bgp->adv_cmd_rmap[afi][safi].map) {
-                               int ret = 0;
+                               route_map_result_t ret;
 
                                ret = route_map_apply(
                                        bgp->adv_cmd_rmap[afi][safi].map,
                                        &rn->p, RMAP_BGP, new_select);
-                               if (ret == RMAP_MATCH)
+                               if (ret == RMAP_PERMITMATCH)
                                        bgp_evpn_advertise_type5_route(
                                                bgp, &rn->p, new_select->attr,
                                                afi, safi);
@@ -4557,7 +4557,7 @@ void bgp_static_update(struct bgp *bgp, struct prefix *p,
        struct bgp_path_info rmap_path;
        struct attr attr;
        struct attr *attr_new;
-       int ret;
+       route_map_result_t ret;
 #if ENABLE_BGP_VNC
        int vnc_implicit_withdraw = 0;
 #endif
@@ -4905,7 +4905,7 @@ static void bgp_static_update_safi(struct bgp *bgp, struct prefix *p,
        if (bgp_static->rmap.name) {
                struct attr attr_tmp = attr;
                struct bgp_path_info rmap_path;
-               int ret;
+               route_map_result_t ret;
 
                rmap_path.peer = bgp->peer_self;
                rmap_path.attr = &attr_tmp;
@@ -6567,7 +6567,7 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p,
        struct attr attr;
        struct attr *new_attr;
        afi_t afi;
-       int ret;
+       route_map_result_t ret;
        struct bgp_redist *red;
 
        /* Make default attribute. */
@@ -9082,7 +9082,7 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
                                struct route_map *rmap = output_arg;
                                struct bgp_path_info path;
                                struct attr dummy_attr;
-                               int ret;
+                               route_map_result_t ret;
 
                                bgp_attr_dup(&dummy_attr, pi->attr);
 
index b0ae9d78d165bfb0cd14bb1b531e770f3d1d4100..85cab0d59fe72d1a1dc6f474bbfbed143a72ffa2 100644 (file)
@@ -237,10 +237,9 @@ struct bgp_match_peer_compiled {
 /* Compares the peer specified in the 'match peer' clause with the peer
     received in bgp_path_info->peer. If it is the same, or if the peer structure
     received is a peer_group containing it, returns RMAP_MATCH. */
-static route_map_result_t route_match_peer(void *rule,
-                                          const struct prefix *prefix,
-                                          route_map_object_t type,
-                                          void *object)
+static enum route_map_match_result_t
+route_match_peer(void *rule, const struct prefix *prefix,
+                route_map_object_t type, void *object)
 {
        struct bgp_match_peer_compiled *pc;
        union sockunion *su;
@@ -333,10 +332,9 @@ struct route_map_rule_cmd route_match_peer_cmd = {"peer", route_match_peer,
                                                  route_match_peer_free};
 
 #if defined(HAVE_LUA)
-static route_map_result_t route_match_command(void *rule,
-                                             const struct prefix *prefix,
-                                             route_map_object_t type,
-                                             void *object)
+static enum route_map_match_result_t
+route_match_command(void *rule, const struct prefix *prefix,
+                   route_map_object_t type, void *object)
 {
        int status = RMAP_NOMATCH;
        u_int32_t locpref = 0;
@@ -432,10 +430,9 @@ struct route_map_rule_cmd route_match_command_cmd = {
 
 /* Match function should return 1 if match is success else return
    zero. */
-static route_map_result_t route_match_ip_address(void *rule,
-                                                const struct prefix *prefix,
-                                                route_map_object_t type,
-                                                void *object)
+static enum route_map_match_result_t
+route_match_ip_address(void *rule, const struct prefix *prefix,
+                      route_map_object_t type, void *object)
 {
        struct access_list *alist;
 
@@ -472,10 +469,9 @@ struct route_map_rule_cmd route_match_ip_address_cmd = {
 /* `match ip next-hop IP_ADDRESS' */
 
 /* Match function return 1 if match is success else return zero. */
-static route_map_result_t route_match_ip_next_hop(void *rule,
-                                                 const struct prefix *prefix,
-                                                 route_map_object_t type,
-                                                 void *object)
+static enum route_map_match_result_t
+route_match_ip_next_hop(void *rule, const struct prefix *prefix,
+                       route_map_object_t type, void *object)
 {
        struct access_list *alist;
        struct bgp_path_info *path;
@@ -519,10 +515,9 @@ struct route_map_rule_cmd route_match_ip_next_hop_cmd = {
 /* `match ip route-source ACCESS-LIST' */
 
 /* Match function return 1 if match is success else return zero. */
-static route_map_result_t route_match_ip_route_source(void *rule,
-                                                     const struct prefix *pfx,
-                                                     route_map_object_t type,
-                                                     void *object)
+static enum route_map_match_result_t
+route_match_ip_route_source(void *rule, const struct prefix *pfx,
+                           route_map_object_t type, void *object)
 {
        struct access_list *alist;
        struct bgp_path_info *path;
@@ -571,7 +566,7 @@ struct route_map_rule_cmd route_match_ip_route_source_cmd = {
 
 /* `match ip address prefix-list PREFIX_LIST' */
 
-static route_map_result_t
+static enum route_map_match_result_t
 route_match_ip_address_prefix_list(void *rule, const struct prefix *prefix,
                                   route_map_object_t type, void *object)
 {
@@ -606,7 +601,7 @@ struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd = {
 
 /* `match ip next-hop prefix-list PREFIX_LIST' */
 
-static route_map_result_t
+static enum route_map_match_result_t
 route_match_ip_next_hop_prefix_list(void *rule, const struct prefix *prefix,
                                    route_map_object_t type, void *object)
 {
@@ -648,7 +643,7 @@ struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd = {
 
 /* `match ip next-hop type <blackhole>' */
 
-static route_map_result_t
+static enum route_map_match_result_t
 route_match_ip_next_hop_type(void *rule, const struct prefix *prefix,
                             route_map_object_t type, void *object)
 {
@@ -687,7 +682,7 @@ static struct route_map_rule_cmd route_match_ip_next_hop_type_cmd = {
 
 /* `match ip route-source prefix-list PREFIX_LIST' */
 
-static route_map_result_t
+static enum route_map_match_result_t
 route_match_ip_route_source_prefix_list(void *rule,
                                        const struct prefix *prefix,
                                        route_map_object_t type, void *object)
@@ -737,10 +732,9 @@ struct route_map_rule_cmd route_match_ip_route_source_prefix_list_cmd = {
 /* `match evpn default-route' */
 
 /* Match function should return 1 if match is success else 0 */
-static route_map_result_t route_match_evpn_default_route(void *rule,
-                                                        const struct prefix *p,
-                                                        route_map_object_t
-                                                        type, void *object)
+static enum route_map_match_result_t
+route_match_evpn_default_route(void *rule, const struct prefix *p,
+                              route_map_object_t type, void *object)
 {
        if (type == RMAP_BGP && is_evpn_prefix_default(p))
                return RMAP_MATCH;
@@ -756,10 +750,9 @@ struct route_map_rule_cmd route_match_evpn_default_route_cmd = {
 
 /* Match function should return 1 if match is success else return
    zero. */
-static route_map_result_t route_match_mac_address(void *rule,
-                                                 const struct prefix *prefix,
-                                                 route_map_object_t type,
-                                                 void *object)
+static enum route_map_match_result_t
+route_match_mac_address(void *rule, const struct prefix *prefix,
+                       route_map_object_t type, void *object)
 {
        struct access_list *alist;
        struct prefix p;
@@ -806,9 +799,9 @@ struct route_map_rule_cmd route_match_mac_address_cmd = {
 
 /* Match function should return 1 if match is success else return
    zero. */
-static route_map_result_t route_match_vni(void *rule,
-                                         const struct prefix *prefix,
-                                         route_map_object_t type, void *object)
+static enum route_map_match_result_t
+route_match_vni(void *rule, const struct prefix *prefix,
+               route_map_object_t type, void *object)
 {
        vni_t vni = 0;
        struct bgp_path_info *path = NULL;
@@ -859,10 +852,9 @@ struct route_map_rule_cmd route_match_evpn_vni_cmd = {
 
 /* Match function should return 1 if match is success else return
    zero. */
-static route_map_result_t route_match_evpn_route_type(void *rule,
-                                                     const struct prefix *pfx,
-                                                     route_map_object_t type,
-                                                     void *object)
+static enum route_map_match_result_t
+route_match_evpn_route_type(void *rule, const struct prefix *pfx,
+                           route_map_object_t type, void *object)
 {
        uint8_t route_type = 0;
 
@@ -905,7 +897,7 @@ struct route_map_rule_cmd route_match_evpn_route_type_cmd = {
        route_match_evpn_route_type_compile, route_match_evpn_route_type_free};
 
 /* Route map commands for VRF route leak with source vrf matching */
-static route_map_result_t
+static enum route_map_match_result_t
 route_match_vrl_source_vrf(void *rule, const struct prefix *prefix,
                           route_map_object_t type, void *object)
 {
@@ -954,10 +946,9 @@ struct route_map_rule_cmd route_match_vrl_source_vrf_cmd = {
 /* `match local-preference LOCAL-PREF' */
 
 /* Match function return 1 if match is success else return zero. */
-static route_map_result_t route_match_local_pref(void *rule,
-                                                const struct prefix *prefix,
-                                                route_map_object_t type,
-                                                void *object)
+static enum route_map_match_result_t
+route_match_local_pref(void *rule, const struct prefix *prefix,
+                      route_map_object_t type, void *object)
 {
        uint32_t *local_pref;
        struct bgp_path_info *path;
@@ -1011,10 +1002,9 @@ struct route_map_rule_cmd route_match_local_pref_cmd = {
 /* `match metric METRIC' */
 
 /* Match function return 1 if match is success else return zero. */
-static route_map_result_t route_match_metric(void *rule,
-                                            const struct prefix *prefix,
-                                            route_map_object_t type,
-                                            void *object)
+static enum route_map_match_result_t
+route_match_metric(void *rule, const struct prefix *prefix,
+                  route_map_object_t type, void *object)
 {
        struct rmap_value *rv;
        struct bgp_path_info *path;
@@ -1035,10 +1025,9 @@ struct route_map_rule_cmd route_match_metric_cmd = {
 /* `match as-path ASPATH' */
 
 /* Match function for as-path match.  I assume given object is */
-static route_map_result_t route_match_aspath(void *rule,
-                                            const struct prefix *prefix,
-                                            route_map_object_t type,
-                                            void *object)
+static enum route_map_match_result_t
+route_match_aspath(void *rule, const struct prefix *prefix,
+                  route_map_object_t type, void *object)
 {
 
        struct as_list *as_list;
@@ -1085,10 +1074,9 @@ struct rmap_community {
 };
 
 /* Match function for community match. */
-static route_map_result_t route_match_community(void *rule,
-                                               const struct prefix *prefix,
-                                               route_map_object_t type,
-                                               void *object)
+static enum route_map_match_result_t
+route_match_community(void *rule, const struct prefix *prefix,
+                     route_map_object_t type, void *object)
 {
        struct community_list *list;
        struct bgp_path_info *path;
@@ -1155,10 +1143,9 @@ struct route_map_rule_cmd route_match_community_cmd = {
        route_match_community_free};
 
 /* Match function for lcommunity match. */
-static route_map_result_t route_match_lcommunity(void *rule,
-                                                const struct prefix *prefix,
-                                                route_map_object_t type,
-                                                void *object)
+static enum route_map_match_result_t
+route_match_lcommunity(void *rule, const struct prefix *prefix,
+                      route_map_object_t type, void *object)
 {
        struct community_list *list;
        struct bgp_path_info *path;
@@ -1218,10 +1205,9 @@ struct route_map_rule_cmd route_match_lcommunity_cmd = {
 
 
 /* Match function for extcommunity match. */
-static route_map_result_t route_match_ecommunity(void *rule,
-                                                const struct prefix *prefix,
-                                                route_map_object_t type,
-                                                void *object)
+static enum route_map_match_result_t
+route_match_ecommunity(void *rule, const struct prefix *prefix,
+                      route_map_object_t type, void *object)
 {
        struct community_list *list;
        struct bgp_path_info *path;
@@ -1272,10 +1258,9 @@ struct route_map_rule_cmd route_match_ecommunity_cmd = {
    and `address-family vpnv4'.  */
 
 /* `match origin' */
-static route_map_result_t route_match_origin(void *rule,
-                                            const struct prefix *prefix,
-                                            route_map_object_t type,
-                                            void *object)
+static enum route_map_match_result_t
+route_match_origin(void *rule, const struct prefix *prefix,
+                  route_map_object_t type, void *object)
 {
        uint8_t *origin;
        struct bgp_path_info *path;
@@ -1320,10 +1305,9 @@ struct route_map_rule_cmd route_match_origin_cmd = {
 
 /* match probability  { */
 
-static route_map_result_t route_match_probability(void *rule,
-                                                 const struct prefix *prefix,
-                                                 route_map_object_t type,
-                                                 void *object)
+static enum route_map_match_result_t
+route_match_probability(void *rule, const struct prefix *prefix,
+                       route_map_object_t type, void *object)
 {
        long r = random();
 
@@ -1375,10 +1359,9 @@ struct route_map_rule_cmd route_match_probability_cmd = {
 /* `match interface IFNAME' */
 /* Match function should return 1 if match is success else return
    zero. */
-static route_map_result_t route_match_interface(void *rule,
-                                               const struct prefix *prefix,
-                                               route_map_object_t type,
-                                               void *object)
+static enum route_map_match_result_t
+route_match_interface(void *rule, const struct prefix *prefix,
+                     route_map_object_t type, void *object)
 {
        struct interface *ifp;
        struct bgp_path_info *path;
@@ -1422,9 +1405,9 @@ struct route_map_rule_cmd route_match_interface_cmd = {
 /* `set ip next-hop IP_ADDRESS' */
 
 /* Match function return 1 if match is success else return zero. */
-static route_map_result_t route_match_tag(void *rule,
-                                         const struct prefix *prefix,
-                                         route_map_object_t type, void *object)
+static enum route_map_match_result_t
+route_match_tag(void *rule, const struct prefix *prefix,
+               route_map_object_t type, void *object)
 {
        route_tag_t *tag;
        struct bgp_path_info *path;
@@ -1454,10 +1437,9 @@ struct rmap_ip_nexthop_set {
        int unchanged;
 };
 
-static route_map_result_t route_set_ip_nexthop(void *rule,
-                                              const struct prefix *prefix,
-                                              route_map_object_t type,
-                                              void *object)
+static enum route_map_match_result_t
+route_set_ip_nexthop(void *rule, const struct prefix *prefix,
+                    route_map_object_t type, void *object)
 {
        struct rmap_ip_nexthop_set *rins = rule;
        struct bgp_path_info *path;
@@ -1560,10 +1542,9 @@ struct route_map_rule_cmd route_set_ip_nexthop_cmd = {
 /* `set local-preference LOCAL_PREF' */
 
 /* Set local preference. */
-static route_map_result_t route_set_local_pref(void *rule,
-                                              const struct prefix *prefix,
-                                              route_map_object_t type,
-                                              void *object)
+static enum route_map_match_result_t
+route_set_local_pref(void *rule, const struct prefix *prefix,
+                    route_map_object_t type, void *object)
 {
        struct rmap_value *rv;
        struct bgp_path_info *path;
@@ -1595,10 +1576,9 @@ struct route_map_rule_cmd route_set_local_pref_cmd = {
 /* `set weight WEIGHT' */
 
 /* Set weight. */
-static route_map_result_t route_set_weight(void *rule,
-                                          const struct prefix *prefix,
-                                          route_map_object_t type,
-                                          void *object)
+static enum route_map_match_result_t
+route_set_weight(void *rule, const struct prefix *prefix,
+                route_map_object_t type, void *object)
 {
        struct rmap_value *rv;
        struct bgp_path_info *path;
@@ -1623,10 +1603,9 @@ struct route_map_rule_cmd route_set_weight_cmd = {
 /* `set metric METRIC' */
 
 /* Set metric to attribute. */
-static route_map_result_t route_set_metric(void *rule,
-                                          const struct prefix *prefix,
-                                          route_map_object_t type,
-                                          void *object)
+static enum route_map_match_result_t
+route_set_metric(void *rule, const struct prefix *prefix,
+                route_map_object_t type, void *object)
 {
        struct rmap_value *rv;
        struct bgp_path_info *path;
@@ -1654,10 +1633,9 @@ struct route_map_rule_cmd route_set_metric_cmd = {
 /* `set as-path prepend ASPATH' */
 
 /* For AS path prepend mechanism. */
-static route_map_result_t route_set_aspath_prepend(void *rule,
-                                                  const struct prefix *prefix,
-                                                  route_map_object_t type,
-                                                  void *object)
+static enum route_map_match_result_t
+route_set_aspath_prepend(void *rule, const struct prefix *prefix,
+                        route_map_object_t type, void *object)
 {
        struct aspath *aspath;
        struct aspath *new;
@@ -1717,10 +1695,9 @@ struct route_map_rule_cmd route_set_aspath_prepend_cmd = {
  * one.
  * Make a deep copy of existing AS_PATH, but for the first ASn only.
  */
-static route_map_result_t route_set_aspath_exclude(void *rule,
-                                                  const struct prefix *dummy,
-                                                  route_map_object_t type,
-                                                  void *object)
+static enum route_map_match_result_t
+route_set_aspath_exclude(void *rule, const struct prefix *dummy,
+                        route_map_object_t type, void *object)
 {
        struct aspath *new_path, *exclude_path;
        struct bgp_path_info *path;
@@ -1752,10 +1729,9 @@ struct rmap_com_set {
 };
 
 /* For community set mechanism. */
-static route_map_result_t route_set_community(void *rule,
-                                             const struct prefix *prefix,
-                                             route_map_object_t type,
-                                             void *object)
+static enum route_map_match_result_t
+route_set_community(void *rule, const struct prefix *prefix,
+                   route_map_object_t type, void *object)
 {
        struct rmap_com_set *rcs;
        struct bgp_path_info *path;
@@ -1868,10 +1844,9 @@ struct rmap_lcom_set {
 
 
 /* For lcommunity set mechanism. */
-static route_map_result_t route_set_lcommunity(void *rule,
-                                              const struct prefix *prefix,
-                                              route_map_object_t type,
-                                              void *object)
+static enum route_map_match_result_t
+route_set_lcommunity(void *rule, const struct prefix *prefix,
+                    route_map_object_t type, void *object)
 {
        struct rmap_lcom_set *rcs;
        struct bgp_path_info *path;
@@ -1981,10 +1956,9 @@ struct route_map_rule_cmd route_set_lcommunity_cmd = {
 /* `set large-comm-list (<1-99>|<100-500>|WORD) delete' */
 
 /* For large community set mechanism. */
-static route_map_result_t route_set_lcommunity_delete(void *rule,
-                                                     const struct prefix *pfx,
-                                                     route_map_object_t type,
-                                                     void *object)
+static enum route_map_match_result_t
+route_set_lcommunity_delete(void *rule, const struct prefix *pfx,
+                           route_map_object_t type, void *object)
 {
        struct community_list *list;
        struct lcommunity *merge;
@@ -2065,11 +2039,9 @@ struct route_map_rule_cmd route_set_lcommunity_delete_cmd = {
 /* `set comm-list (<1-99>|<100-500>|WORD) delete' */
 
 /* For community set mechanism. */
-static route_map_result_t route_set_community_delete(
-       void *rule,
-       const struct prefix *prefix,
-       route_map_object_t type,
-       void *object)
+static enum route_map_match_result_t
+route_set_community_delete(void *rule, const struct prefix *prefix,
+                          route_map_object_t type, void *object)
 {
        struct community_list *list;
        struct community *merge;
@@ -2149,10 +2121,9 @@ struct route_map_rule_cmd route_set_community_delete_cmd = {
 /* `set extcommunity rt COMMUNITY' */
 
 /* For community set mechanism.  Used by _rt and _soo. */
-static route_map_result_t route_set_ecommunity(void *rule,
-                                              const struct prefix *prefix,
-                                              route_map_object_t type,
-                                              void *object)
+static enum route_map_match_result_t
+route_set_ecommunity(void *rule, const struct prefix *prefix,
+                    route_map_object_t type, void *object)
 {
        struct ecommunity *ecom;
        struct ecommunity *new_ecom;
@@ -2237,10 +2208,9 @@ struct route_map_rule_cmd route_set_ecommunity_soo_cmd = {
 /* `set origin ORIGIN' */
 
 /* For origin set. */
-static route_map_result_t route_set_origin(void *rule,
-                                          const struct prefix *prefix,
-                                          route_map_object_t type,
-                                          void *object)
+static enum route_map_match_result_t
+route_set_origin(void *rule, const struct prefix *prefix,
+                route_map_object_t type, void *object)
 {
        uint8_t *origin;
        struct bgp_path_info *path;
@@ -2287,10 +2257,9 @@ struct route_map_rule_cmd route_set_origin_cmd = {
 /* `set atomic-aggregate' */
 
 /* For atomic aggregate set. */
-static route_map_result_t route_set_atomic_aggregate(void *rule,
-                                                    const struct prefix *pfx,
-                                                    route_map_object_t type,
-                                                    void *object)
+static enum route_map_match_result_t
+route_set_atomic_aggregate(void *rule, const struct prefix *pfx,
+                          route_map_object_t type, void *object)
 {
        struct bgp_path_info *path;
 
@@ -2326,10 +2295,9 @@ struct aggregator {
        struct in_addr address;
 };
 
-static route_map_result_t route_set_aggregator_as(void *rule,
-                                                 const struct prefix *prefix,
-                                                 route_map_object_t type,
-                                                 void *object)
+static enum route_map_match_result_t
+route_set_aggregator_as(void *rule, const struct prefix *prefix,
+                       route_map_object_t type, void *object)
 {
        struct bgp_path_info *path;
        struct aggregator *aggregator;
@@ -2380,9 +2348,9 @@ struct route_map_rule_cmd route_set_aggregator_as_cmd = {
 };
 
 /* Set tag to object. object must be pointer to struct bgp_path_info */
-static route_map_result_t route_set_tag(void *rule,
-                                       const struct prefix *prefix,
-                                       route_map_object_t type, void *object)
+static enum route_map_match_result_t
+route_set_tag(void *rule, const struct prefix *prefix,
+             route_map_object_t type, void *object)
 {
        route_tag_t *tag;
        struct bgp_path_info *path;
@@ -2405,10 +2373,9 @@ static struct route_map_rule_cmd route_set_tag_cmd = {
 };
 
 /* Set label-index to object. object must be pointer to struct bgp_path_info */
-static route_map_result_t route_set_label_index(void *rule,
-                                               const struct prefix *prefix,
-                                               route_map_object_t type,
-                                               void *object)
+static enum route_map_match_result_t
+route_set_label_index(void *rule, const struct prefix *prefix,
+                     route_map_object_t type, void *object)
 {
        struct rmap_value *rv;
        struct bgp_path_info *path;
@@ -2438,10 +2405,9 @@ static struct route_map_rule_cmd route_set_label_index_cmd = {
 
 /* `match ipv6 address IP_ACCESS_LIST' */
 
-static route_map_result_t route_match_ipv6_address(void *rule,
-                                                  const struct prefix *prefix,
-                                                  route_map_object_t type,
-                                                  void *object)
+static enum route_map_match_result_t
+route_match_ipv6_address(void *rule, const struct prefix *prefix,
+                        route_map_object_t type, void *object)
 {
        struct access_list *alist;
 
@@ -2474,10 +2440,9 @@ struct route_map_rule_cmd route_match_ipv6_address_cmd = {
 
 /* `match ipv6 next-hop IP_ADDRESS' */
 
-static route_map_result_t route_match_ipv6_next_hop(void *rule,
-                                                   const struct prefix *prefix,
-                                                   route_map_object_t type,
-                                                   void *object)
+static enum route_map_match_result_t
+route_match_ipv6_next_hop(void *rule, const struct prefix *prefix,
+                         route_map_object_t type, void *object)
 {
        struct in6_addr *addr = rule;
        struct bgp_path_info *path;
@@ -2526,7 +2491,7 @@ struct route_map_rule_cmd route_match_ipv6_next_hop_cmd = {
 
 /* `match ipv6 address prefix-list PREFIX_LIST' */
 
-static route_map_result_t
+static enum route_map_match_result_t
 route_match_ipv6_address_prefix_list(void *rule, const struct prefix *prefix,
                                     route_map_object_t type, void *object)
 {
@@ -2561,9 +2526,9 @@ struct route_map_rule_cmd route_match_ipv6_address_prefix_list_cmd = {
 
 /* `match ipv6 next-hop type <TYPE>' */
 
-static route_map_result_t
+static enum route_map_match_result_t
 route_match_ipv6_next_hop_type(void *rule, const struct prefix *prefix,
-                             route_map_object_t type, void *object)
+                              route_map_object_t type, void *object)
 {
        struct bgp_path_info *path;
        struct in6_addr *addr = rule;
@@ -2609,10 +2574,9 @@ struct route_map_rule_cmd route_match_ipv6_next_hop_type_cmd = {
 /* `set ipv6 nexthop global IP_ADDRESS' */
 
 /* Set nexthop to object.  ojbect must be pointer to struct attr. */
-static route_map_result_t route_set_ipv6_nexthop_global(void *rule,
-                                                       const struct prefix *p,
-                                                       route_map_object_t type,
-                                                       void *object)
+static enum route_map_match_result_t
+route_set_ipv6_nexthop_global(void *rule, const struct prefix *p,
+                             route_map_object_t type, void *object)
 {
        struct in6_addr *address;
        struct bgp_path_info *path;
@@ -2668,7 +2632,7 @@ struct route_map_rule_cmd route_set_ipv6_nexthop_global_cmd = {
        route_set_ipv6_nexthop_global_free};
 
 /* Set next-hop preference value. */
-static route_map_result_t
+static enum route_map_match_result_t
 route_set_ipv6_nexthop_prefer_global(void *rule, const struct prefix *prefix,
                                     route_map_object_t type, void *object)
 {
@@ -2722,10 +2686,9 @@ struct route_map_rule_cmd route_set_ipv6_nexthop_prefer_global_cmd = {
 /* `set ipv6 nexthop local IP_ADDRESS' */
 
 /* Set nexthop to object.  ojbect must be pointer to struct attr. */
-static route_map_result_t route_set_ipv6_nexthop_local(void *rule,
-                                                      const struct prefix *p,
-                                                      route_map_object_t type,
-                                                      void *object)
+static enum route_map_match_result_t
+route_set_ipv6_nexthop_local(void *rule, const struct prefix *p,
+                            route_map_object_t type, void *object)
 {
        struct in6_addr *address;
        struct bgp_path_info *path;
@@ -2785,10 +2748,9 @@ struct route_map_rule_cmd route_set_ipv6_nexthop_local_cmd = {
 /* `set ipv6 nexthop peer-address' */
 
 /* Set nexthop to object.  ojbect must be pointer to struct attr. */
-static route_map_result_t route_set_ipv6_nexthop_peer(void *rule,
-                                                     const struct prefix *pfx,
-                                                     route_map_object_t type,
-                                                     void *object)
+static enum route_map_match_result_t
+route_set_ipv6_nexthop_peer(void *rule, const struct prefix *pfx,
+                           route_map_object_t type, void *object)
 {
        struct in6_addr peer_address;
        struct bgp_path_info *path;
@@ -2863,10 +2825,9 @@ struct route_map_rule_cmd route_set_ipv6_nexthop_peer_cmd = {
 
 /* `set ipv4 vpn next-hop A.B.C.D' */
 
-static route_map_result_t route_set_vpnv4_nexthop(void *rule,
-                                                 const struct prefix *prefix,
-                                                 route_map_object_t type,
-                                                 void *object)
+static enum route_map_match_result_t
+route_set_vpnv4_nexthop(void *rule, const struct prefix *prefix,
+                       route_map_object_t type, void *object)
 {
        struct in_addr *address;
        struct bgp_path_info *path;
@@ -2903,10 +2864,9 @@ static void *route_set_vpnv4_nexthop_compile(const char *arg)
 
 /* `set ipv6 vpn next-hop A.B.C.D' */
 
-static route_map_result_t route_set_vpnv6_nexthop(void *rule,
-                                                 const struct prefix *prefix,
-                                                 route_map_object_t type,
-                                                 void *object)
+static enum route_map_match_result_t
+route_set_vpnv6_nexthop(void *rule, const struct prefix *prefix,
+                       route_map_object_t type, void *object)
 {
        struct in6_addr *address;
        struct bgp_path_info *path;
@@ -2959,10 +2919,9 @@ struct route_map_rule_cmd route_set_vpnv6_nexthop_cmd = {
 /* `set originator-id' */
 
 /* For origin set. */
-static route_map_result_t route_set_originator_id(void *rule,
-                                                 const struct prefix *prefix,
-                                                 route_map_object_t type,
-                                                 void *object)
+static enum route_map_match_result_t
+route_set_originator_id(void *rule, const struct prefix *prefix,
+                       route_map_object_t type, void *object)
 {
        struct in_addr *address;
        struct bgp_path_info *path;
@@ -4222,10 +4181,10 @@ DEFUN (set_community,
        str = community_str(com, false);
 
        if (additive) {
-               argstr = XCALLOC(MTYPE_TMP,
-                                strlen(str) + strlen(" additive") + 1);
-               strcpy(argstr, str);
-               strcpy(argstr + strlen(str), " additive");
+               size_t argstr_sz = strlen(str) + strlen(" additive") + 1;
+               argstr = XCALLOC(MTYPE_TMP, argstr_sz);
+               strlcpy(argstr, str, argstr_sz);
+               strlcat(argstr, " additive", argstr_sz);
                ret = generic_set_add(vty, VTY_GET_CONTEXT(route_map_index),
                                      "community", argstr);
                XFREE(MTYPE_TMP, argstr);
index aa09026b789ad5630a464016489fd3581584e029..27b6347ab6303301037a74e6e1bd5a33d6bfee84 100644 (file)
@@ -129,8 +129,10 @@ static void print_record(const struct pfx_record *record, struct vty *vty);
 static int is_synchronized(void);
 static int is_running(void);
 static void route_match_free(void *rule);
-static route_map_result_t route_match(void *rule, const struct prefix *prefix,
-                                     route_map_object_t type, void *object);
+static enum route_map_match_result_t route_match(void *rule,
+                                                const struct prefix *prefix,
+                                                route_map_object_t type,
+                                                void *object);
 static void *route_match_compile(const char *arg);
 static void revalidate_bgp_node(struct bgp_node *bgp_node, afi_t afi,
                                safi_t safi);
@@ -213,8 +215,10 @@ static void ipv6_addr_to_host_byte_order(const uint32_t *src, uint32_t *dest)
                dest[i] = ntohl(src[i]);
 }
 
-static route_map_result_t route_match(void *rule, const struct prefix *prefix,
-                                     route_map_object_t type, void *object)
+static enum route_map_match_result_t route_match(void *rule,
+                                                const struct prefix *prefix,
+                                                route_map_object_t type,
+                                                void *object)
 {
        int *rpki_status = rule;
        struct bgp_path_info *path;
index b64c51f34140aef2caad45f8ec96aa954cb4dcbf..21f1dff60df2b1776f00f4989caa7091318cfef0 100644 (file)
@@ -716,7 +716,7 @@ void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw)
        struct bgp_node *rn;
        struct bgp_path_info *ri;
        struct peer *peer;
-       int ret = RMAP_DENYMATCH;
+       route_map_result_t ret = RMAP_DENYMATCH;
        afi_t afi;
        safi_t safi;
 
index a45480fdc27c0d7a65c3978bc27b985893ca9fdb..5e9fc57f59aeeb5edab641a4b3e8f839d31b1c1c 100644 (file)
@@ -1435,15 +1435,29 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
                for (i = 0; i < api.nexthop_num; i++) {
                        api_nh = &api.nexthops[i];
 
-                       if (api_nh->type == NEXTHOP_TYPE_IFINDEX)
+                       switch (api_nh->type) {
+                       case NEXTHOP_TYPE_IFINDEX:
                                nh_buf[0] = '\0';
-                       else {
-                               if (api_nh->type == NEXTHOP_TYPE_IPV4)
-                                       nh_family = AF_INET;
-                               else
-                                       nh_family = AF_INET6;
+                               break;
+                       case NEXTHOP_TYPE_IPV4:
+                       case NEXTHOP_TYPE_IPV4_IFINDEX:
+                               nh_family = AF_INET;
                                inet_ntop(nh_family, &api_nh->gate, nh_buf,
                                          sizeof(nh_buf));
+                               break;
+                       case NEXTHOP_TYPE_IPV6:
+                       case NEXTHOP_TYPE_IPV6_IFINDEX:
+                               nh_family = AF_INET6;
+                               inet_ntop(nh_family, &api_nh->gate, nh_buf,
+                                         sizeof(nh_buf));
+                               break;
+                       case NEXTHOP_TYPE_BLACKHOLE:
+                               strlcpy(nh_buf, "blackhole", sizeof(nh_buf));
+                               break;
+                       default:
+                               /* Note: add new nexthop case */
+                               assert(0);
+                               break;
                        }
 
                        label_buf[0] = '\0';
@@ -2960,6 +2974,9 @@ void bgp_zebra_announce_default(struct bgp *bgp, struct nexthop *nh,
        SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
        api_nh = &api.nexthops[0];
 
+       api.distance = ZEBRA_EBGP_DISTANCE_DEFAULT;
+       SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE);
+
        /* redirect IP */
        if (nh->gate.ipv4.s_addr) {
                char buff[PREFIX_STRLEN];
index ad0900c2b8543f0b8e8f915211812ea84d50a918..b6d32d36eaa585ed625bb904bd4f4feb1672ade6 100644 (file)
@@ -4111,6 +4111,9 @@ static void rfapiProcessPeerDownRt(struct peer *peer,
                timer_service_func = rfapiWithdrawTimerEncap;
                break;
        default:
+               /* Suppress uninitialized variable warning */
+               rt = NULL;
+               timer_service_func = NULL;
                assert(0);
        }
 
index ea3c44478c02d535f2f9affb63db3c6bf7262a11..67f71bc3a5b811a763ba1ff76d10000cea248642 100644 (file)
@@ -70,7 +70,8 @@ an example.)
         --disable-ldpd \
         --enable-fpm \
         --with-pkg-git-version \
-        --with-pkg-extra-version=-MyOwnFRRVersion
+        --with-pkg-extra-version=-MyOwnFRRVersion \
+       SPHINXBUILD=/usr/bin/sphinx-build
     make
     make check
     sudo make install
index 09f12ec43641a3a17af07f0ba1a94cbc658f2c4f..e12bc37256b80973c663aae0769641dfff22b1e6 100644 (file)
@@ -145,30 +145,23 @@ the following env variable can be set::
 
    export TOPOTESTS_CHECK_STDERR=Yes
 
-(The value doesn't matter at this time. The check is if the env variable exists
-or not) There is no pass/fail on this reporting. The Output will be reported to
-the console::
-
-   export TOPOTESTS_CHECK_MEMLEAK="/home/mydir/memleak_"
-
-This will enable the check and output to console and the writing of the
-information to files with the given prefix (followed by testname), ie
-:file:`/home/mydir/memcheck_test_bgp_multiview_topo1.txt` in case of a memory
-leak.
+(The value doesn't matter at this time. The check is whether the env
+variable exists or not.) There is no pass/fail on this reporting; the
+Output will be reported to the console.
 
 Collect Memory Leak Information
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-FRR processes have the capabilities to report remaining memory allocations upon
-exit. To enable the reporting of the memory, define an environment variable
+FRR processes can report unfreed memory allocations upon exit. To
+enable the reporting of memory leaks, define an environment variable
 ``TOPOTESTS_CHECK_MEMLEAK`` with the file prefix, i.e.::
 
    export TOPOTESTS_CHECK_MEMLEAK="/home/mydir/memleak_"
 
-This will enable the check and output to console and the writing of the
-information to files with the given prefix (followed by testname), ie
-:file:`/home/mydir/memcheck_test_bgp_multiview_topo1.txt` in case of a memory
-leak.
+This will enable the check and output to console and the writing of
+the information to files with the given prefix (followed by testname),
+ie :file:`/home/mydir/memcheck_test_bgp_multiview_topo1.txt` in case
+of a memory leak.
 
 Running Topotests with AddressSanitizer
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
index b3b3a47cb03c6bbf64abc2df8742344930f1d7ed..16707c0bddb8a5f083b9157c60dfbe0830e294a6 100644 (file)
@@ -750,7 +750,8 @@ developer will use this convention to allow control of their debugs.
 
 Static Analysis and Sanitizers
 ------------------------------
-Clang/LLVM comes with a variety of tools that can be used to help find bugs in FRR.
+Clang/LLVM and GCC come with a variety of tools that can be used to help find
+bugs in FRR.
 
 clang-analyze
    This is a static analyzer that scans the source code looking for patterns
@@ -794,11 +795,31 @@ All of the above tools are available in the Clang/LLVM toolchain since 3.4.
 AddressSanitizer and ThreadSanitizer are available in recent versions of GCC,
 but are no longer actively maintained. MemorySanitizer is not available in GCC.
 
+.. note::
+
+   The different Sanitizers are mostly incompatible with each other.  Please
+   refer to GCC/LLVM documentation for details.
+
 Additionally, the FRR codebase is regularly scanned with Coverity.
 Unfortunately Coverity does not have the ability to handle scanning pull
 requests, but after code is merged it will send an email notifying project
 members with Coverity access of newly introduced defects.
 
+Executing non-installed dynamic binaries
+----------------------------------------
+
+Since FRR uses the GNU autotools build system, it inherits its shortcomings.
+To execute a binary directly from the build tree under a wrapper like
+`valgrind`, `gdb` or `strace`, use::
+
+   ./libtool --mode=execute valgrind [--valgrind-opts] zebra/zebra [--zebra-opts]
+
+While replacing valgrind/zebra as needed.  The `libtool` script is found in
+the root of the build directory after `./configure` has completed.  Its purpose
+is to correctly set up `LD_LIBRARY_PATH` so that libraries from the build tree
+are used.  (On some systems, `libtool` is also available from PATH, but this is
+not always the case.)
+
 CLI changes
 -----------
 
index 414423ae7c5a222e10bdae770add8dd8577e7aa2..8b0fba5f834e24a360c442a8494950fe48db4a1e 100644 (file)
@@ -232,6 +232,19 @@ is in a vrf, enter the interface command with the vrf keyword at the end.
    or IGMP report is received on this interface and the Group is denied by the
    prefix-list, PIM will ignore the join or report.
 
+.. index:: ip igmp last-member-query-count (1-7)
+.. clicmd:: ip igmp last-member-query-count (1-7)
+
+   Set the IGMP last member query count. The default value is 2. 'no' form of
+   this command is used to to configure back to the default value.
+
+.. index:: ip igmp last-member-query-interval (1-255)
+.. clicmd:: ip igmp last-member-query-interval (1-255)
+
+   Set the IGMP last member query interval in deciseconds. The default value is
+   10 deciseconds. 'no' form of this command is used to to configure back to the
+   default value.
+
 .. _pim-multicast-rib-insertion:
 
 PIM Multicast RIB insertion:
@@ -322,6 +335,12 @@ cause great confusion.
    Display information about installed into the kernel S,G mroutes and in
    addition display data about packet flow for the mroutes.
 
+.. index:: show ip mroute summary
+.. clicmd:: show ip mroute summary
+
+   Display total number of S,G mroutes and number of S,G mroutes installed
+   into the kernel.
+
 .. index:: show ip pim assert
 .. clicmd:: show ip pim assert
 
index 295a26fda9f7a0ba2924dcfbae329a1efa09acb1..ca6b46d3cff2b40a75092c8ff0f20aae890cafa9 100644 (file)
@@ -188,10 +188,6 @@ Validating BGP Updates
     Create a clause for a route map to match prefixes with the specified RPKI
     state.
 
-    **Note** that the matching of invalid prefixes requires that invalid
-    prefixes are considered for best path selection, i.e.,
-    ``bgp bestpath prefix-validate disallow-invalid`` is not enabled.
-
     In the following example, the router prefers valid routes over invalid
     prefixes because invalid routes have a lower local preference.
 
index ee8d5f75827076e60fb609d45f1b320cd0075ac2..60323dcd04db7009a41c1eb9e92a6114c4bb7d1d 100644 (file)
@@ -251,9 +251,9 @@ void eigrp_route_map_update(const char *notused)
 
 /* `match metric METRIC' */
 /* Match function return 1 if match is success else return zero. */
-static route_map_result_t route_match_metric(void *rule, struct prefix *prefix,
-                                            route_map_object_t type,
-                                            void *object)
+static enum route_map_match_result_t
+route_match_metric(void *rule, struct prefix *prefix, route_map_object_t type,
+                  void *object)
 {
        //  uint32_t *metric;
        //  uint32_t  check;
@@ -311,10 +311,9 @@ struct route_map_rule_cmd route_match_metric_cmd = {
 
 /* `match interface IFNAME' */
 /* Match function return 1 if match is success else return zero. */
-static route_map_result_t route_match_interface(void *rule,
-                                               struct prefix *prefix,
-                                               route_map_object_t type,
-                                               void *object)
+static enum route_map_match_result_t
+route_match_interface(void *rule, struct prefix *prefix,
+                     route_map_object_t type, void *object)
 {
        //  struct rip_info *rinfo;
        //  struct interface *ifp;
@@ -360,10 +359,9 @@ struct route_map_rule_cmd route_match_interface_cmd = {
 /* `match ip next-hop IP_ACCESS_LIST' */
 
 /* Match function return 1 if match is success else return zero. */
-static route_map_result_t route_match_ip_next_hop(void *rule,
-                                                 struct prefix *prefix,
-                                                 route_map_object_t type,
-                                                 void *object)
+static enum route_map_match_result_t
+route_match_ip_next_hop(void *rule, struct prefix *prefix,
+                       route_map_object_t type, void *object)
 {
        //  struct access_list *alist;
        //  struct rip_info *rinfo;
@@ -407,7 +405,7 @@ static struct route_map_rule_cmd route_match_ip_next_hop_cmd = {
 
 /* `match ip next-hop prefix-list PREFIX_LIST' */
 
-static route_map_result_t
+static enum route_map_match_result_t
 route_match_ip_next_hop_prefix_list(void *rule, struct prefix *prefix,
                                    route_map_object_t type, void *object)
 {
@@ -452,10 +450,9 @@ static struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd = {
 
 /* Match function should return 1 if match is success else return
    zero. */
-static route_map_result_t route_match_ip_address(void *rule,
-                                                struct prefix *prefix,
-                                                route_map_object_t type,
-                                                void *object)
+static enum route_map_match_result_t
+route_match_ip_address(void *rule, struct prefix *prefix,
+                      route_map_object_t type, void *object)
 {
        struct access_list *alist;
 
@@ -491,7 +488,7 @@ static struct route_map_rule_cmd route_match_ip_address_cmd = {
 
 /* `match ip address prefix-list PREFIX_LIST' */
 
-static route_map_result_t
+static enum route_map_match_result_t
 route_match_ip_address_prefix_list(void *rule, struct prefix *prefix,
                                   route_map_object_t type, void *object)
 {
@@ -526,8 +523,9 @@ static struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd = {
 
 /* `match tag TAG' */
 /* Match function return 1 if match is success else return zero. */
-static route_map_result_t route_match_tag(void *rule, struct prefix *prefix,
-                                         route_map_object_t type, void *object)
+static enum route_map_match_result_t
+route_match_tag(void *rule, struct prefix *prefix, route_map_object_t type,
+               void *object)
 {
        //  unsigned short *tag;
        //  struct rip_info *rinfo;
@@ -568,9 +566,9 @@ struct route_map_rule_cmd route_match_tag_cmd = {
        "tag", route_match_tag, route_match_tag_compile, route_match_tag_free};
 
 /* Set metric to attribute. */
-static route_map_result_t route_set_metric(void *rule, struct prefix *prefix,
-                                          route_map_object_t type,
-                                          void *object)
+static enum route_map_match_result_t
+route_set_metric(void *rule, struct prefix *prefix,
+                route_map_object_t type, void *object)
 {
        //  if (type == RMAP_RIP)
        //    {
@@ -662,10 +660,9 @@ static struct route_map_rule_cmd route_set_metric_cmd = {
 /* `set ip next-hop IP_ADDRESS' */
 
 /* Set nexthop to object.  ojbect must be pointer to struct attr. */
-static route_map_result_t route_set_ip_nexthop(void *rule,
-                                              struct prefix *prefix,
-                                              route_map_object_t type,
-                                              void *object)
+static enum route_map_match_result_t
+route_set_ip_nexthop(void *rule, struct prefix *prefix,
+                    route_map_object_t type, void *object)
 {
        //  struct in_addr *address;
        //  struct rip_info *rinfo;
@@ -718,8 +715,9 @@ static struct route_map_rule_cmd route_set_ip_nexthop_cmd = {
 /* `set tag TAG' */
 
 /* Set tag to object.  ojbect must be pointer to struct attr. */
-static route_map_result_t route_set_tag(void *rule, struct prefix *prefix,
-                                       route_map_object_t type, void *object)
+static enum route_map_match_result_t
+route_set_tag(void *rule, struct prefix *prefix,
+             route_map_object_t type, void *object)
 {
        //  unsigned short *tag;
        //  struct rip_info *rinfo;
index 82005c911ea19db0db484fcede61ed9cf4eeff91..281eaf11bc962c5ff8b72b326cc5ba9e70ec1da3 100644 (file)
@@ -543,7 +543,8 @@ void isis_route_verify_merge(struct isis_area *area,
                                                ISIS_ROUTE_FLAG_ZEBRA_SYNCED
                                        );
                                        continue;
-                               } else {
+                               } else if (CHECK_FLAG(rinfo->flag,
+                                                     ISIS_ROUTE_FLAG_ACTIVE)) {
                                        /* Clear the ZEBRA_SYNCED flag on the L1
                                         * route when L2 wins, otherwise L1
                                         * won't get reinstalled when it
@@ -553,6 +554,11 @@ void isis_route_verify_merge(struct isis_area *area,
                                                mrinfo->flag,
                                                ISIS_ROUTE_FLAG_ZEBRA_SYNCED
                                        );
+                               } else if (
+                                       CHECK_FLAG(
+                                               mrinfo->flag,
+                                               ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) {
+                                       continue;
                                }
                        }
                        mrnode->info = rnode->info;
index d63676256b3b87944789b9b3027951b14ddeeea9..69694f26e4d91ae7fb6ea6daa35d3dd46c1832cd 100644 (file)
 #include "isis_zebra.h"
 #include "isis_routemap.h"
 
-static route_map_result_t route_match_ip_address(void *rule,
-                                                const struct prefix *prefix,
-                                                route_map_object_t type,
-                                                void *object)
+static enum route_map_match_result_t
+route_match_ip_address(void *rule, const struct prefix *prefix,
+                      route_map_object_t type, void *object)
 {
        struct access_list *alist;
 
@@ -81,7 +80,7 @@ static struct route_map_rule_cmd route_match_ip_address_cmd = {
 
 /* ------------------------------------------------------------*/
 
-static route_map_result_t
+static enum route_map_match_result_t
 route_match_ip_address_prefix_list(void *rule, const struct prefix *prefix,
                                   route_map_object_t type, void *object)
 {
@@ -114,10 +113,9 @@ struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd = {
 
 /* ------------------------------------------------------------*/
 
-static route_map_result_t route_match_ipv6_address(void *rule,
-                                                  const struct prefix *prefix,
-                                                  route_map_object_t type,
-                                                  void *object)
+static enum route_map_match_result_t
+route_match_ipv6_address(void *rule, const struct prefix *prefix,
+                        route_map_object_t type, void *object)
 {
        struct access_list *alist;
 
@@ -147,7 +145,7 @@ static struct route_map_rule_cmd route_match_ipv6_address_cmd = {
 
 /* ------------------------------------------------------------*/
 
-static route_map_result_t
+static enum route_map_match_result_t
 route_match_ipv6_address_prefix_list(void *rule, const struct prefix *prefix,
                                     route_map_object_t type, void *object)
 {
@@ -180,10 +178,9 @@ struct route_map_rule_cmd route_match_ipv6_address_prefix_list_cmd = {
 
 /* ------------------------------------------------------------*/
 
-static route_map_result_t route_set_metric(void *rule,
-                                          const struct prefix *prefix,
-                                          route_map_object_t type,
-                                          void *object)
+static enum route_map_match_result_t
+route_set_metric(void *rule, const struct prefix *prefix,
+                route_map_object_t type, void *object)
 {
        uint32_t *metric;
        struct isis_ext_info *info;
index 2476bd2552b84d98c127b529972bf427d197ee0d..431ad9712aeaa064e904344905e07aec83245a80 100644 (file)
@@ -168,7 +168,7 @@ DEFUN (show_lsp_flooding,
                        area->area_tag : "null");
 
                if (lspid) {
-                       struct isis_lsp *lsp = lsp_for_arg(head, lspid);
+                       lsp = lsp_for_arg(head, lspid);
 
                        if (lsp)
                                lsp_print_flooding(vty, lsp);
index 07be68d9aede9be778753614a220877d901375af..bee3b6deb56e5dbb401c75c6f3d525fbf5ab6850 100644 (file)
@@ -272,7 +272,7 @@ int isis_area_destroy(const char *area_tag)
        lsp_db_fini(&area->lspdb[1]);
 
        /* invalidate and verify to delete all routes from zebra */
-       isis_area_invalidate_routes(area, ISIS_LEVEL1 & ISIS_LEVEL2);
+       isis_area_invalidate_routes(area, area->is_type);
        isis_area_verify_routes(area);
 
        spftree_area_del(area);
@@ -738,11 +738,7 @@ DEFUN (clear_isis_neighbor_arg,
  */
 void print_debug(struct vty *vty, int flags, int onoff)
 {
-       char onoffs[4];
-       if (onoff)
-               strcpy(onoffs, "on");
-       else
-               strcpy(onoffs, "off");
+       const char *onoffs = onoff ? "on" : "off";
 
        if (flags & DEBUG_ADJ_PACKETS)
                vty_out(vty,
index 18426e0c517eba127306834a1cd09a1d9e7413e9..e5e06231631c58beed7ca71f3b75cd270290e267 100644 (file)
@@ -1760,10 +1760,10 @@ static int file_write_config(struct vty *vty)
                dirfd = open(".", O_DIRECTORY | O_RDONLY);
        /* if dirfd is invalid, directory sync fails, but we're still OK */
 
-       config_file_sav = XMALLOC(
-               MTYPE_TMP, strlen(config_file) + strlen(CONF_BACKUP_EXT) + 1);
-       strcpy(config_file_sav, config_file);
-       strcat(config_file_sav, CONF_BACKUP_EXT);
+       size_t config_file_sav_sz = strlen(config_file) + strlen(CONF_BACKUP_EXT) + 1;
+       config_file_sav = XMALLOC(MTYPE_TMP, config_file_sav_sz);
+       strlcpy(config_file_sav, config_file, config_file_sav_sz);
+       strlcat(config_file_sav, CONF_BACKUP_EXT, config_file_sav_sz);
 
 
        config_file_tmp = XMALLOC(MTYPE_TMP, strlen(config_file) + 8);
@@ -1962,7 +1962,15 @@ DEFUN (config_hostname,
        struct cmd_token *word = argv[1];
 
        if (!isalnum((int)word->arg[0])) {
-               vty_out(vty, "Please specify string starting with alphabet\n");
+               vty_out(vty,
+                   "Please specify string starting with alphabet or number\n");
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
+       /* With reference to RFC 1123 Section 2.1 */
+       if (strlen(word->arg) > HOSTNAME_LEN) {
+               vty_out(vty, "Hostname length should be less than %d chars\n",
+                       HOSTNAME_LEN);
                return CMD_WARNING_CONFIG_FAILED;
        }
 
@@ -2803,9 +2811,10 @@ void cmd_init(int terminal)
        /* Each node's basic commands. */
        install_element(VIEW_NODE, &show_version_cmd);
        install_element(ENABLE_NODE, &show_startup_config_cmd);
-       install_element(ENABLE_NODE, &debug_memstats_cmd);
 
        if (terminal) {
+               install_element(ENABLE_NODE, &debug_memstats_cmd);
+
                install_element(VIEW_NODE, &config_list_cmd);
                install_element(VIEW_NODE, &config_exit_cmd);
                install_element(VIEW_NODE, &config_quit_cmd);
@@ -2839,9 +2848,10 @@ void cmd_init(int terminal)
        install_element(CONFIG_NODE, &domainname_cmd);
        install_element(CONFIG_NODE, &no_domainname_cmd);
        install_element(CONFIG_NODE, &frr_version_defaults_cmd);
-       install_element(CONFIG_NODE, &debug_memstats_cmd);
 
        if (terminal > 0) {
+               install_element(CONFIG_NODE, &debug_memstats_cmd);
+
                install_element(CONFIG_NODE, &password_cmd);
                install_element(CONFIG_NODE, &no_password_cmd);
                install_element(CONFIG_NODE, &enable_password_cmd);
index d96ec97e67998ddfaac53d531e7bffe192448e10..d6c41e08244cf372a5606f0b68833179e24c4182 100644 (file)
@@ -37,6 +37,17 @@ extern "C" {
 DECLARE_MTYPE(HOST)
 DECLARE_MTYPE(COMPLETION)
 
+/*
+ * From RFC 1123 (Requirements for Internet Hosts), Section 2.1 on hostnames:
+ * One aspect of host name syntax is hereby changed: the restriction on
+ * the first character is relaxed to allow either a letter or a digit.
+ * Host software MUST support this more liberal syntax.
+ *
+ * Host software MUST handle host names of up to 63 characters and
+ * SHOULD handle host names of up to 255 characters.
+ */
+#define HOSTNAME_LEN   255
+
 /* Host configuration variable */
 struct host {
        /* Host name of this router. */
index 8b34d1e3eb907e6848e75ea6af5edbe23d16c61a..9456e1585a9ece96b6dce18447efd5a5ce155e29 100644 (file)
@@ -723,7 +723,7 @@ static enum match_type match_ipv4(const char *str)
                if (str - sp > 3)
                        return no_match;
 
-               strncpy(buf, sp, str - sp);
+               memcpy(buf, sp, str - sp);
                if (atoi(buf) > 255)
                        return no_match;
 
@@ -774,7 +774,7 @@ static enum match_type match_ipv4_prefix(const char *str)
                if (str - sp > 3)
                        return no_match;
 
-               strncpy(buf, sp, str - sp);
+               memcpy(buf, sp, str - sp);
                if (atoi(buf) > 255)
                        return no_match;
 
index 72fd4648ee85ae97962ca288717c43d0b7cbc6c9..3248ceb13b53222e84a143a5a532a73c4cf8d0dd 100644 (file)
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  */
 #include <zebra.h>
+#include "typesafe.h"
 #include "debug.h"
 #include "command.h"
 
-static const struct debug_callbacks *callbacks;
+static struct debug_cb_list_head cb_head;
+
+DECLARE_LIST(debug_cb_list, struct debug_callbacks, item)
 
 /* All code in this section should be reentrant and MT-safe */
 
 DEFUN_NOSH(debug_all, debug_all_cmd, "[no] debug all",
           NO_STR DEBUG_STR "Toggle all debugging output\n")
 {
+       struct debug_callbacks *cb;
+
        bool set = !strmatch(argv[0]->text, "no");
        uint32_t mode = DEBUG_NODE2MODE(vty->node);
 
-       if (callbacks->debug_set_all)
-               callbacks->debug_set_all(mode, set);
+       frr_each (debug_cb_list, &cb_head, cb)
+               cb->debug_set_all(mode, set);
+
        return CMD_SUCCESS;
 }
 
 /* ------------------------------------------------------------------------- */
 
-void debug_init(const struct debug_callbacks *cb)
+void debug_init(struct debug_callbacks *cb)
+{
+       static bool inited = false;
+
+       if (!inited) {
+               inited = true;
+               debug_cb_list_init(&cb_head);
+       }
+
+       debug_cb_list_add_head(&cb_head, cb);
+}
+
+void debug_init_cli(void)
 {
-       callbacks = cb;
        install_element(ENABLE_NODE, &debug_all_cmd);
        install_element(CONFIG_NODE, &debug_all_cmd);
 }
index ace060d0578905fb64a0734da41a63b673c42a45..f25cd426913f8a0bb518df0e77b6e1933c6d060c 100644 (file)
@@ -84,6 +84,7 @@ struct debug {
        const char *desc;
 };
 
+PREDECL_LIST(debug_cb_list)
 /*
  * Callback set for debugging code.
  *
@@ -92,6 +93,11 @@ struct debug {
  *    mode set.
  */
 struct debug_callbacks {
+       /*
+        * Linked list of Callbacks to call
+        */
+       struct debug_cb_list_item item;
+
        /*
         * flags
         *    flags to set on debug flag fields
@@ -233,7 +239,13 @@ struct debug_callbacks {
  *
  * MT-Safe
  */
-void debug_init(const struct debug_callbacks *cb);
+void debug_init(struct debug_callbacks *cb);
+
+/*
+ * Turn on the cli to turn on/off debugs.
+ * Should only be called by libfrr
+ */
+void debug_init_cli(void);
 
 #ifdef __cplusplus
 }
index 5970e70a6bd493230f9b7cb5091cb963277178c5..c60e26085f0c13ecb867cf2a4a81086792f43e90 100644 (file)
@@ -39,6 +39,7 @@
 #include "db.h"
 #include "northbound_cli.h"
 #include "northbound_db.h"
+#include "debug.h"
 
 DEFINE_HOOK(frr_late_init, (struct thread_master * tm), (tm))
 DEFINE_KOOH(frr_early_fini, (), ())
@@ -60,7 +61,7 @@ static char pidfile_default[512];
 #ifdef HAVE_SQLITE3
 static char dbfile_default[512];
 #endif
-static char vtypath_default[256];
+static char vtypath_default[512];
 
 bool debug_memstats_at_exit = false;
 static bool nodetach_term, nodetach_daemon;
@@ -80,8 +81,8 @@ static void opt_extend(const struct optspec *os)
 {
        const struct option *lo;
 
-       strcat(comb_optstr, os->optstr);
-       strcat(comb_helpstr, os->helpstr);
+       strlcat(comb_optstr, os->optstr, sizeof(comb_optstr));
+       strlcat(comb_helpstr, os->helpstr, sizeof(comb_helpstr));
        for (lo = os->longopts; lo->name; lo++)
                memcpy(comb_next_lo++, lo, sizeof(*lo));
 }
@@ -654,6 +655,9 @@ struct thread_master *frr_init(void)
        lib_error_init();
 
        yang_init();
+
+       debug_init_cli();
+
        nb_init(master, di->yang_modules, di->n_yang_modules);
        if (nb_db_init() != NB_OK)
                flog_warn(EC_LIB_NB_DATABASE,
index e8ba9edc128473a18ff9bca2dd6b7a46fd8655f8..0d1efdf3aa1f363147e3ed6e21533bff435d4f45 100644 (file)
@@ -246,7 +246,7 @@ void listnode_move_to_tail(struct list *l, struct listnode *n)
        LISTNODE_ATTACH(l, n);
 }
 
-void listnode_delete(struct list *list, void *val)
+void listnode_delete(struct list *list, const void *val)
 {
        struct listnode *node = listnode_lookup(list, val);
 
@@ -307,7 +307,7 @@ void list_delete(struct list **list)
        *list = NULL;
 }
 
-struct listnode *listnode_lookup(struct list *list, void *data)
+struct listnode *listnode_lookup(struct list *list, const void *data)
 {
        struct listnode *node;
 
index da42aa268827d275a0f215368df081f9a997d761..d23d425d627fee83ac5e61cf036417c811f2dd90 100644 (file)
@@ -180,7 +180,7 @@ extern void listnode_move_to_tail(struct list *list, struct listnode *node);
  * data
  *    data to insert into list
  */
-extern void listnode_delete(struct list *list, void *data);
+extern void listnode_delete(struct list *list, const void *data);
 
 /*
  * Find the listnode corresponding to an element in a list.
@@ -194,7 +194,7 @@ extern void listnode_delete(struct list *list, void *data);
  * Returns:
  *    pointer to listnode storing the given data if found, NULL otherwise
  */
-extern struct listnode *listnode_lookup(struct list *list, void *data);
+extern struct listnode *listnode_lookup(struct list *list, const void *data);
 
 /*
  * Retrieve the element at the head of a list.
index e64c00186be21204ab9137b0034bbeb9dd2b54cd..5e3064a8d8996f74deee58aa5c4b90d003395519 100644 (file)
--- a/lib/log.c
+++ b/lib/log.c
@@ -602,6 +602,8 @@ void zlog_backtrace_sigsafe(int priority, void *program_counter)
                backtrace_symbols_fd(array, size, FD);                         \
        }
 #elif defined(HAVE_PRINTSTACK)
+       size = 0;
+
 #define DUMP(FD)                                                               \
        {                                                                      \
                if (program_counter)                                           \
index dbf90c58d4870975c4fe05d991000ec94aa39f24..8a5cd0ef14db39012978d2f21720d6330ec3a235 100644 (file)
@@ -777,7 +777,7 @@ static void nb_log_callback(const enum nb_event event,
        zlog_debug(
                "northbound callback: event [%s] op [%s] xpath [%s] value [%s]",
                nb_event_name(event), nb_operation_name(operation), xpath,
-               value);
+               value ? value : "(NULL)");
 }
 
 /*
index ae1b0578a004ef473da89b2c97ea8c74a6a2a906..7b7b526af02a52a64f66b98b3f1454341d1c182a 100644 (file)
@@ -1722,8 +1722,8 @@ void nb_cli_init(struct thread_master *tm)
        /* Initialize the shared candidate configuration. */
        vty_shared_candidate_config = nb_config_new(NULL);
 
-       /* Install debug commands */
        debug_init(&nb_dbg_cbs);
+
        install_node(&nb_debug_node, nb_debug_config_write);
        install_element(ENABLE_NODE, &debug_nb_cmd);
        install_element(CONFIG_NODE, &debug_nb_cmd);
index d2a4c3a432351193e2c24fcb4ecb40784924ad78..42d202ddbce13dfe60321cc0b67fbb050b9f2e5a 100644 (file)
@@ -1365,7 +1365,7 @@ void prefix_mcast_inet4_dump(const char *onfail, struct in_addr addr,
        int save_errno = errno;
 
        if (addr.s_addr == INADDR_ANY)
-               strcpy(buf, "*");
+               strlcpy(buf, "*", buf_size);
        else {
                if (!inet_ntop(AF_INET, &addr, buf, buf_size)) {
                        if (onfail)
index 3542994e6513ae0817ff2d7aea36ac938d33f4c3..e8f4a6c1aa4025b1866c22e2aaf2599c5ba59a1f 100644 (file)
@@ -1456,14 +1456,14 @@ int route_map_delete_set(struct route_map_index *index, const char *set_name,
    (note, this includes the description for the "NEXT"
    and "GOTO" frobs now
 
-             Match   |   No Match
-                     |
-    permit    action  |     cont
-                     |
-    ------------------+---------------
-                     |
-    deny      deny    |     cont
-                     |
+          |   Match   |   No Match   | No op
+          |-----------|--------------|-------
+    permit |   action  |     cont     | cont.
+          |           | default:deny | default:permit
+    -------------------+-----------------------
+          |   deny    |     cont     | cont.
+    deny   |           | default:deny | default:permit
+          |-----------|--------------|--------
 
    action)
       -Apply Set statements, accept route
@@ -1497,12 +1497,12 @@ int route_map_delete_set(struct route_map_index *index, const char *set_name,
    We need to make sure our route-map processing matches the above
 */
 
-static route_map_result_t
+static enum route_map_match_result_t
 route_map_apply_match(struct route_map_rule_list *match_list,
                      const struct prefix *prefix, route_map_object_t type,
                      void *object)
 {
-       route_map_result_t ret = RMAP_NOMATCH;
+       enum route_map_match_result_t ret = RMAP_NOMATCH;
        struct route_map_rule *match;
 
 
@@ -1534,7 +1534,8 @@ route_map_result_t route_map_apply(struct route_map *map,
                                   route_map_object_t type, void *object)
 {
        static int recursion = 0;
-       int ret = 0;
+       enum route_map_match_result_t match_ret = RMAP_NOMATCH;
+       route_map_result_t ret = 0;
        struct route_map_index *index;
        struct route_map_rule *set;
 
@@ -1554,24 +1555,33 @@ route_map_result_t route_map_apply(struct route_map *map,
        for (index = map->head; index; index = index->next) {
                /* Apply this index. */
                index->applied++;
-               ret = route_map_apply_match(&index->match_list, prefix, type,
-                                           object);
+               match_ret = route_map_apply_match(&index->match_list, prefix,
+                                                 type, object);
 
                /* Now we apply the matrix from above */
-               if (ret == RMAP_NOMATCH)
+               if (match_ret == RMAP_NOMATCH || match_ret == RMAP_NOOP)
                        /* 'cont' from matrix - continue to next route-map
                         * sequence */
                        continue;
-               else if (ret == RMAP_MATCH) {
+               else if (match_ret == RMAP_MATCH) {
                        if (index->type == RMAP_PERMIT)
                        /* 'action' */
                        {
+                               /* Match succeeded, rmap is of type permit */
+                               ret = RMAP_PERMITMATCH;
+
                                /* permit+match must execute sets */
                                for (set = index->set_list.head; set;
                                     set = set->next)
-                                       ret = (*set->cmd->func_apply)(
-                                               set->value, prefix, type,
-                                               object);
+                                       /*
+                                        * We dont care abt the return value
+                                        * for set cmd.  Almost always,
+                                        * RMAP_OKAY is returned. Rarely
+                                        * do we see RMAP_ERROR
+                                        */
+                                       match_ret = (*set->cmd->func_apply)(
+                                                    set->value, prefix, type,
+                                                    object);
 
                                /* Call another route-map if available */
                                if (index->nextrm) {
@@ -1622,6 +1632,10 @@ route_map_result_t route_map_apply(struct route_map *map,
                        }
                }
        }
+
+       if (match_ret == RMAP_NOOP)
+               return RMAP_PERMITMATCH;
+
        /* Finally route-map does not match at all. */
        return RMAP_DENYMATCH;
 }
index 9969936a6b9fecf684213bf43be015b05c5259bf..41b8428fa15dc9d0c590f823e3918bfa1a7af454 100644 (file)
@@ -34,15 +34,36 @@ DECLARE_MTYPE(ROUTE_MAP_NAME)
 DECLARE_MTYPE(ROUTE_MAP_RULE)
 DECLARE_MTYPE(ROUTE_MAP_COMPILED)
 
+/*
+ * Route-map match or set result "Eg: match evpn vni xx"
+ * route-map match cmd always returns match/nomatch/noop
+ *    match--> found a match
+ *    nomatch--> didnt find a match
+ *    noop--> invalid
+ * route-map set retuns okay/error
+ *    okay --> set was successful
+ *    error --> set was not successful
+ */
+enum route_map_match_result_t {
+       /*
+        * route-map match cmd results
+        */
+       RMAP_MATCH,
+       RMAP_NOMATCH,
+       RMAP_NOOP,
+       /*
+        * route-map set cmd results
+        */
+       RMAP_OKAY,
+       RMAP_ERROR
+};
+
 /* Route map's type. */
 enum route_map_type { RMAP_PERMIT, RMAP_DENY, RMAP_ANY };
 
 typedef enum {
-       RMAP_MATCH,
        RMAP_DENYMATCH,
-       RMAP_NOMATCH,
-       RMAP_ERROR,
-       RMAP_OKAY
+       RMAP_PERMITMATCH
 } route_map_result_t;
 
 typedef enum {
@@ -91,10 +112,10 @@ struct route_map_rule_cmd {
        const char *str;
 
        /* Function for value set or match. */
-       route_map_result_t (*func_apply)(void *rule,
-                                        const struct prefix *prefix,
-                                        route_map_object_t type,
-                                        void *object);
+       enum route_map_match_result_t (*func_apply)(void *rule,
+                                                   const struct prefix *prefix,
+                                                   route_map_object_t type,
+                                                   void *object);
 
        /* Compile argument and return result as void *. */
        void *(*func_compile)(const char *);
index 14be7ab65668216e1dd899696a76ca835c909189..eefd992546a5614e2b10e6ac9030d794452e411e 100644 (file)
@@ -298,6 +298,8 @@ static inline struct route_node *route_table_iter_next(route_table_iter_t *iter)
                return NULL;
 
        default:
+               /* Suppress uninitialized variable warning */
+               node = NULL;
                assert(0);
        }
 
index 0ee9b78b91f9afa77951178dbd734bd003396e08..2d97cca351bfacd76aa18af8dc2810b654c89261 100644 (file)
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -84,7 +84,7 @@ static char *vty_ipv6_accesslist_name = NULL;
 static vector Vvty_serv_thread;
 
 /* Current directory. */
-char *vty_cwd = NULL;
+char vty_cwd[MAXPATHLEN];
 
 /* Login password check. */
 static int no_password_check = 0;
@@ -998,7 +998,7 @@ static void vty_describe_fold(struct vty *vty, int cmd_width,
                if (pos == 0)
                        break;
 
-               strncpy(buf, p, pos);
+               memcpy(buf, p, pos);
                buf[pos] = '\0';
                vty_out(vty, "  %-*s  %s\n", cmd_width, cmd, buf);
 
@@ -1659,7 +1659,7 @@ static struct vty *vty_create(int vty_sock, union sockunion *su)
 
        /* configurable parameters not part of basic init */
        vty->v_timeout = vty_timeout_val;
-       strcpy(vty->address, buf);
+       strlcpy(vty->address, buf, sizeof(vty->address));
        if (no_password_check) {
                if (host.advanced)
                        vty->node = ENABLE_NODE;
@@ -1795,7 +1795,7 @@ struct vty *vty_stdio(void (*atclose)(int isexit))
         */
        vty->node = ENABLE_NODE;
        vty->v_timeout = 0;
-       strcpy(vty->address, "console");
+       strlcpy(vty->address, "console", sizeof(vty->address));
 
        vty_stdio_resume();
        return vty;
@@ -2384,9 +2384,10 @@ static FILE *vty_use_backup_config(const char *fullpath)
        int c;
        char buffer[512];
 
-       fullpath_sav = malloc(strlen(fullpath) + strlen(CONF_BACKUP_EXT) + 1);
-       strcpy(fullpath_sav, fullpath);
-       strcat(fullpath_sav, CONF_BACKUP_EXT);
+       size_t fullpath_sav_sz = strlen(fullpath) + strlen(CONF_BACKUP_EXT) + 1;
+       fullpath_sav = malloc(fullpath_sav_sz);
+       strlcpy(fullpath_sav, fullpath, fullpath_sav_sz);
+       strlcat(fullpath_sav, CONF_BACKUP_EXT, fullpath_sav_sz);
 
        sav = open(fullpath_sav, O_RDONLY);
        if (sav < 0) {
@@ -3055,10 +3056,9 @@ void vty_reset(void)
 
 static void vty_save_cwd(void)
 {
-       char cwd[MAXPATHLEN];
        char *c;
 
-       c = getcwd(cwd, MAXPATHLEN);
+       c = getcwd(vty_cwd, sizeof(vty_cwd));
 
        if (!c) {
                /*
@@ -3072,15 +3072,12 @@ static void vty_save_cwd(void)
                                     SYSCONFDIR, errno);
                        exit(-1);
                }
-               if (getcwd(cwd, MAXPATHLEN) == NULL) {
+               if (getcwd(vty_cwd, sizeof(vty_cwd)) == NULL) {
                        flog_err_sys(EC_LIB_SYSTEM_CALL,
                                     "Failure to getcwd, errno: %d", errno);
                        exit(-1);
                }
        }
-
-       vty_cwd = XMALLOC(MTYPE_TMP, strlen(cwd) + 1);
-       strcpy(vty_cwd, cwd);
 }
 
 char *vty_get_cwd(void)
@@ -3146,7 +3143,7 @@ void vty_init(struct thread_master *master_thread)
 
 void vty_terminate(void)
 {
-       XFREE(MTYPE_TMP, vty_cwd);
+       memset(vty_cwd, 0x00, sizeof(vty_cwd));
 
        if (vtyvec && Vvty_serv_thread) {
                vty_reset();
index 0972590ca695e9dfd70a1102e22dca1301c8b7c7..e9b4f5a58b1797473f6b6f368ff3746a086f105c 100644 (file)
@@ -62,10 +62,13 @@ struct zclient *zclient_new(struct thread_master *master,
                            struct zclient_options *opt)
 {
        struct zclient *zclient;
+       size_t stream_size =
+               MAX(ZEBRA_MAX_PACKET_SIZ, sizeof(struct zapi_route));
+
        zclient = XCALLOC(MTYPE_ZCLIENT, sizeof(struct zclient));
 
-       zclient->ibuf = stream_new(ZEBRA_MAX_PACKET_SIZ);
-       zclient->obuf = stream_new(ZEBRA_MAX_PACKET_SIZ);
+       zclient->ibuf = stream_new(stream_size);
+       zclient->obuf = stream_new(stream_size);
        zclient->wb = buffer_new(0);
        zclient->master = master;
 
index 09f0acad844cbdbb04f6754a654115440b0f1a17..c61c8d4226d8199152c48fd44702f3a27bfc7a53 100644 (file)
@@ -39,7 +39,7 @@
 #include "mlag.h"
 
 /* For input/output buffer to zebra. */
-#define ZEBRA_MAX_PACKET_SIZ          16384
+#define ZEBRA_MAX_PACKET_SIZ          16384U
 
 /* Zebra header size. */
 #define ZEBRA_HEADER_SIZE             10
index 946bbf8cc9423f8fb9a5309f2c79203b4f3f6a16..4fbf70c9db94b34f7064f8cc7958f36ef5259149 100644 (file)
@@ -1018,7 +1018,7 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex,
                                 unsigned int nexthop_num,
                                 struct in6_addr *nexthop, route_tag_t tag)
 {
-       int ret;
+       route_map_result_t ret;
        struct ospf6_route troute;
        struct ospf6_external_info tinfo;
        struct ospf6_route *route, *match;
@@ -1355,7 +1355,7 @@ static void ospf6_redistribute_show_config(struct vty *vty)
 
 
 /* Routemap Functions */
-static route_map_result_t
+static enum route_map_match_result_t
 ospf6_routemap_rule_match_address_prefixlist(void *rule,
                                             const struct prefix *prefix,
                                             route_map_object_t type,
@@ -1395,7 +1395,7 @@ struct route_map_rule_cmd ospf6_routemap_rule_match_address_prefixlist_cmd = {
 /* `match interface IFNAME' */
 /* Match function should return 1 if match is success else return
    zero. */
-static route_map_result_t
+static enum route_map_match_result_t
 ospf6_routemap_rule_match_interface(void *rule, const struct prefix *prefix,
                                    route_map_object_t type, void *object)
 {
@@ -1433,10 +1433,9 @@ struct route_map_rule_cmd ospf6_routemap_rule_match_interface_cmd = {
        ospf6_routemap_rule_match_interface_free};
 
 /* Match function for matching route tags */
-static route_map_result_t ospf6_routemap_rule_match_tag(void *rule,
-                                                       const struct prefix *p,
-                                                       route_map_object_t type,
-                                                       void *object)
+static enum route_map_match_result_t
+ospf6_routemap_rule_match_tag(void *rule, const struct prefix *p,
+                             route_map_object_t type, void *object)
 {
        route_tag_t *tag = rule;
        struct ospf6_route *route = object;
@@ -1453,7 +1452,7 @@ static struct route_map_rule_cmd ospf6_routemap_rule_match_tag_cmd = {
        route_map_rule_tag_free,
 };
 
-static route_map_result_t
+static enum route_map_match_result_t
 ospf6_routemap_rule_set_metric_type(void *rule, const struct prefix *prefix,
                                    route_map_object_t type, void *object)
 {
@@ -1489,7 +1488,7 @@ struct route_map_rule_cmd ospf6_routemap_rule_set_metric_type_cmd = {
        ospf6_routemap_rule_set_metric_type_free,
 };
 
-static route_map_result_t
+static enum route_map_match_result_t
 ospf6_routemap_rule_set_metric(void *rule, const struct prefix *prefix,
                               route_map_object_t type, void *object)
 {
@@ -1524,7 +1523,7 @@ struct route_map_rule_cmd ospf6_routemap_rule_set_metric_cmd = {
        ospf6_routemap_rule_set_metric_free,
 };
 
-static route_map_result_t
+static enum route_map_match_result_t
 ospf6_routemap_rule_set_forwarding(void *rule, const struct prefix *prefix,
                                   route_map_object_t type, void *object)
 {
@@ -1562,10 +1561,9 @@ struct route_map_rule_cmd ospf6_routemap_rule_set_forwarding_cmd = {
        ospf6_routemap_rule_set_forwarding_free,
 };
 
-static route_map_result_t ospf6_routemap_rule_set_tag(void *rule,
-                                                     const struct prefix *p,
-                                                     route_map_object_t type,
-                                                     void *object)
+static enum route_map_match_result_t
+ospf6_routemap_rule_set_tag(void *rule, const struct prefix *p,
+                           route_map_object_t type, void *object)
 {
        route_tag_t *tag = rule;
        struct ospf6_route *route = object;
index ab2d5ae5844cec5584445526bfb5a768baeb76f6..d725837fec5f46b197a309725507c70720b8f456 100644 (file)
@@ -126,10 +126,9 @@ static void ospf_route_map_event(const char *name)
 
 /* `match ip netxthop ' */
 /* Match function return 1 if match is success else return zero. */
-static route_map_result_t route_match_ip_nexthop(void *rule,
-                                                const struct prefix *prefix,
-                                                route_map_object_t type,
-                                                void *object)
+static enum route_map_match_result_t
+route_match_ip_nexthop(void *rule, const struct prefix *prefix,
+                      route_map_object_t type, void *object)
 {
        struct access_list *alist;
        struct external_info *ei = object;
@@ -171,7 +170,7 @@ struct route_map_rule_cmd route_match_ip_nexthop_cmd = {
 
 /* `match ip next-hop prefix-list PREFIX_LIST' */
 
-static route_map_result_t
+static enum route_map_match_result_t
 route_match_ip_next_hop_prefix_list(void *rule, const struct prefix *prefix,
                                    route_map_object_t type, void *object)
 {
@@ -213,10 +212,9 @@ struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd = {
 /* `match ip address IP_ACCESS_LIST' */
 /* Match function should return 1 if match is success else return
    zero. */
-static route_map_result_t route_match_ip_address(void *rule,
-                                                const struct prefix *prefix,
-                                                route_map_object_t type,
-                                                void *object)
+static enum route_map_match_result_t
+route_match_ip_address(void *rule, const struct prefix *prefix,
+                      route_map_object_t type, void *object)
 {
        struct access_list *alist;
        /* struct prefix_ipv4 match; */
@@ -252,7 +250,7 @@ struct route_map_rule_cmd route_match_ip_address_cmd = {
        route_match_ip_address_free};
 
 /* `match ip address prefix-list PREFIX_LIST' */
-static route_map_result_t
+static enum route_map_match_result_t
 route_match_ip_address_prefix_list(void *rule, const struct prefix *prefix,
                                   route_map_object_t type, void *object)
 {
@@ -288,10 +286,9 @@ struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd = {
 /* `match interface IFNAME' */
 /* Match function should return 1 if match is success else return
    zero. */
-static route_map_result_t route_match_interface(void *rule,
-                                               const struct prefix *prefix,
-                                               route_map_object_t type,
-                                               void *object)
+static enum route_map_match_result_t
+route_match_interface(void *rule, const struct prefix *prefix,
+                     route_map_object_t type, void *object)
 {
        struct interface *ifp;
        struct external_info *ei;
@@ -327,9 +324,9 @@ struct route_map_rule_cmd route_match_interface_cmd = {
        route_match_interface_free};
 
 /* Match function return 1 if match is success else return zero. */
-static route_map_result_t route_match_tag(void *rule,
-                                         const struct prefix *prefix,
-                                         route_map_object_t type, void *object)
+static enum route_map_match_result_t
+route_match_tag(void *rule, const struct prefix *prefix,
+               route_map_object_t type, void *object)
 {
        route_tag_t *tag;
        struct external_info *ei;
@@ -358,10 +355,9 @@ struct ospf_metric {
 
 /* `set metric METRIC' */
 /* Set metric to attribute. */
-static route_map_result_t route_set_metric(void *rule,
-                                          const struct prefix *prefix,
-                                          route_map_object_t type,
-                                          void *object)
+static enum route_map_match_result_t
+route_set_metric(void *rule, const struct prefix *prefix,
+                route_map_object_t type, void *object)
 {
        struct ospf_metric *metric;
        struct external_info *ei;
@@ -439,10 +435,9 @@ struct route_map_rule_cmd route_set_metric_cmd = {
 
 /* `set metric-type TYPE' */
 /* Set metric-type to attribute. */
-static route_map_result_t route_set_metric_type(void *rule,
-                                               const struct prefix *prefix,
-                                               route_map_object_t type,
-                                               void *object)
+static enum route_map_match_result_t
+route_set_metric_type(void *rule, const struct prefix *prefix,
+                     route_map_object_t type, void *object)
 {
        uint32_t *metric_type;
        struct external_info *ei;
@@ -489,8 +484,9 @@ struct route_map_rule_cmd route_set_metric_type_cmd = {
        route_set_metric_type_free,
 };
 
-static route_map_result_t route_set_tag(void *rule, const struct prefix *prefix,
-                                       route_map_object_t type, void *object)
+static enum route_map_match_result_t
+route_set_tag(void *rule, const struct prefix *prefix, route_map_object_t type,
+             void *object)
 {
        route_tag_t *tag;
        struct external_info *ei;
index 1488aa88cd4edadbc8f6ec8bcfa37f9807b179d1..e68363663949b8d7c34965fcd2afc11b59d629cf 100644 (file)
@@ -2535,7 +2535,7 @@ DEFUN (show_ip_ospf_mpls_te_link,
        struct interface *ifp = NULL;
        struct listnode *node;
        char *vrf_name = NULL;
-       bool all_vrf;
+       bool all_vrf = false;
        int inst = 0;
        int idx_vrf = 0;
        struct ospf *ospf = NULL;
index c178e367d390a032fcc37df14163950328d8ce69..951402f47fa7b36530104e5f17037244d019563e 100644 (file)
@@ -943,7 +943,7 @@ int ospf_redistribute_check(struct ospf *ospf, struct external_info *ei,
        /* apply route-map if needed */
        red = ospf_redist_lookup(ospf, type, instance);
        if (red && ROUTEMAP_NAME(red)) {
-               int ret;
+               route_map_result_t ret;
 
                ret = route_map_apply(ROUTEMAP(red), (struct prefix *)p,
                                      RMAP_OSPF, ei);
index 52506542bc89657e2065181768556e589bac3b36..fc78b8ed1f54a1d502ccf5428b5debd0bb960219 100644 (file)
@@ -191,7 +191,7 @@ static void *pbr_nhgc_alloc(void *p)
 
        new = XCALLOC(MTYPE_PBR_NHG, sizeof(*new));
 
-       strcpy(new->name, pnhgc->name);
+       strlcpy(new->name, pnhgc->name, sizeof(pnhgc->name));
        new->table_id = pbr_nht_get_next_tableid(false);
 
        DEBUGD(&pbr_dbg_nht, "%s: NHT: %s assigned Table ID: %u",
index c7fc06e541cdbb1eb804b5f664fbdb705110ab1c..2b97dd3822688a232fc79550d88426e95e0a45ba 100644 (file)
@@ -658,6 +658,7 @@ static void igmp_show_interfaces_single(struct pim_instance *pim,
        long oqpi_msec; /* Other Querier Present Interval */
        long qri_msec;
        time_t now;
+       int lmqc;
 
        json_object *json = NULL;
        json_object *json_row = NULL;
@@ -702,8 +703,8 @@ static void igmp_show_interfaces_single(struct pim_instance *pim,
                                pim_ifp->igmp_query_max_response_time_dsec);
 
                        lmqt_msec = PIM_IGMP_LMQT_MSEC(
-                               pim_ifp->igmp_query_max_response_time_dsec,
-                               igmp->querier_robustness_variable);
+                               pim_ifp->igmp_specific_query_max_response_time_dsec,
+                               pim_ifp->igmp_last_member_query_count);
 
                        ohpi_msec =
                                PIM_IGMP_OHPI_DSEC(
@@ -719,6 +720,7 @@ static void igmp_show_interfaces_single(struct pim_instance *pim,
                                        pim_ifp->pim_sock_fd);
                        else
                                mloop = 0;
+                       lmqc = pim_ifp->igmp_last_member_query_count;
 
                        if (uj) {
                                json_row = json_object_new_object();
@@ -743,6 +745,9 @@ static void igmp_show_interfaces_single(struct pim_instance *pim,
                                        json_row,
                                        "timerGroupMembershipIntervalMsec",
                                        gmi_msec);
+                               json_object_int_add(json_row,
+                                                   "lastMemberQueryCount",
+                                                   lmqc);
                                json_object_int_add(json_row,
                                                    "timerLastMemberQueryMsec",
                                                    lmqt_msec);
@@ -809,6 +814,9 @@ static void igmp_show_interfaces_single(struct pim_instance *pim,
                                vty_out(vty,
                                        "Group Membership Interval      : %lis\n",
                                        gmi_msec / 1000);
+                               vty_out(vty,
+                                       "Last Member Query Count        : %d\n",
+                                       lmqc);
                                vty_out(vty,
                                        "Last Member Query Time         : %lis\n",
                                        lmqt_msec / 1000);
@@ -2001,9 +2009,9 @@ static void pim_show_state(struct pim_instance *pim, struct vty *vty,
                ifp_in = pim_if_find_by_vif_index(pim, c_oil->oil.mfcc_parent);
 
                if (ifp_in)
-                       strcpy(in_ifname, ifp_in->name);
+                       strlcpy(in_ifname, ifp_in->name, sizeof(in_ifname));
                else
-                       strcpy(in_ifname, "<iif?>");
+                       strlcpy(in_ifname, "<iif?>", sizeof(in_ifname));
 
                if (src_or_group) {
                        if (strcmp(src_or_group, src_str)
@@ -2085,9 +2093,9 @@ static void pim_show_state(struct pim_instance *pim, struct vty *vty,
                                now - c_oil->oif_creation[oif_vif_index]);
 
                        if (ifp_out)
-                               strcpy(out_ifname, ifp_out->name);
+                               strlcpy(out_ifname, ifp_out->name, sizeof(out_ifname));
                        else
-                               strcpy(out_ifname, "<oif?>");
+                               strlcpy(out_ifname, "<oif?>", sizeof(out_ifname));
 
                        if (uj) {
                                json_ifp_out = json_object_new_object();
@@ -2366,37 +2374,37 @@ static void json_object_pim_upstream_add(json_object *json,
 
 static const char *
 pim_upstream_state2brief_str(enum pim_upstream_state join_state,
-                            char *state_str)
+                            char *state_str, size_t state_str_len)
 {
        switch (join_state) {
        case PIM_UPSTREAM_NOTJOINED:
-               strcpy(state_str, "NotJ");
+               strlcpy(state_str, "NotJ", state_str_len);
                break;
        case PIM_UPSTREAM_JOINED:
-               strcpy(state_str, "J");
+               strlcpy(state_str, "J", state_str_len);
                break;
        default:
-               strcpy(state_str, "Unk");
+               strlcpy(state_str, "Unk", state_str_len);
        }
        return state_str;
 }
 
 static const char *pim_reg_state2brief_str(enum pim_reg_state reg_state,
-                                          char *state_str)
+                                          char *state_str, size_t state_str_len)
 {
        switch (reg_state) {
        case PIM_REG_NOINFO:
-               strcpy(state_str, "RegNI");
+               strlcpy(state_str, "RegNI", state_str_len);
                break;
        case PIM_REG_JOIN:
-               strcpy(state_str, "RegJ");
+               strlcpy(state_str, "RegJ", state_str_len);
                break;
        case PIM_REG_JOIN_PENDING:
        case PIM_REG_PRUNE:
-               strcpy(state_str, "RegP");
+               strlcpy(state_str, "RegP", state_str_len);
                break;
        default:
-               strcpy(state_str, "Unk");
+               strlcpy(state_str, "Unk", state_str_len);
        }
        return state_str;
 }
@@ -2464,13 +2472,13 @@ static void pim_show_upstream(struct pim_instance *pim, struct vty *vty,
                pim_time_timer_to_hhmmss(msdp_reg_timer, sizeof(msdp_reg_timer),
                                         up->t_msdp_reg_timer);
 
-               pim_upstream_state2brief_str(up->join_state, state_str);
+               pim_upstream_state2brief_str(up->join_state, state_str, sizeof(state_str));
                if (up->reg_state != PIM_REG_NOINFO) {
                        char tmp_str[PIM_REG_STATE_STR_LEN];
 
                        sprintf(state_str + strlen(state_str), ",%s",
-                               pim_reg_state2brief_str(up->reg_state,
-                                                       tmp_str));
+                               pim_reg_state2brief_str(up->reg_state, tmp_str,
+                                                       sizeof(tmp_str)));
                }
 
                if (uj) {
@@ -2521,7 +2529,7 @@ static void pim_show_upstream(struct pim_instance *pim, struct vty *vty,
                                pim_upstream_state2str(up->join_state));
                        json_object_string_add(
                                json_row, "regState",
-                               pim_reg_state2str(up->reg_state, state_str));
+                               pim_reg_state2str(up->reg_state, state_str, sizeof(state_str)));
                        json_object_string_add(json_row, "upTime", uptime);
                        json_object_string_add(json_row, "joinTimer",
                                               join_timer);
@@ -5282,9 +5290,9 @@ static void show_mroute(struct pim_instance *pim, struct vty *vty,
                ifp_in = pim_if_find_by_vif_index(pim, c_oil->oil.mfcc_parent);
 
                if (ifp_in)
-                       strcpy(in_ifname, ifp_in->name);
+                       strlcpy(in_ifname, ifp_in->name, sizeof(in_ifname));
                else
-                       strcpy(in_ifname, "<iif?>");
+                       strlcpy(in_ifname, "<iif?>", sizeof(in_ifname));
 
                if (uj) {
 
@@ -5339,9 +5347,9 @@ static void show_mroute(struct pim_instance *pim, struct vty *vty,
                        found_oif = 1;
 
                        if (ifp_out)
-                               strcpy(out_ifname, ifp_out->name);
+                               strlcpy(out_ifname, ifp_out->name, sizeof(out_ifname));
                        else
-                               strcpy(out_ifname, "<oif?>");
+                               strlcpy(out_ifname, "<oif?>", sizeof(out_ifname));
 
                        if (uj) {
                                json_ifp_out = json_object_new_object();
@@ -5399,27 +5407,27 @@ static void show_mroute(struct pim_instance *pim, struct vty *vty,
                        } else {
                                if (c_oil->oif_flags[oif_vif_index]
                                    & PIM_OIF_FLAG_PROTO_PIM) {
-                                       strcpy(proto, "PIM");
+                                       strlcpy(proto, "PIM", sizeof(proto));
                                }
 
                                if (c_oil->oif_flags[oif_vif_index]
                                    & PIM_OIF_FLAG_PROTO_IGMP) {
-                                       strcpy(proto, "IGMP");
+                                       strlcpy(proto, "IGMP", sizeof(proto));
                                }
 
                                if (c_oil->oif_flags[oif_vif_index]
                                    & PIM_OIF_FLAG_PROTO_VXLAN) {
-                                       strcpy(proto, "VxLAN");
+                                       strlcpy(proto, "VxLAN", sizeof(proto));
                                }
 
                                if (c_oil->oif_flags[oif_vif_index]
                                    & PIM_OIF_FLAG_PROTO_SOURCE) {
-                                       strcpy(proto, "SRC");
+                                       strlcpy(proto, "SRC", sizeof(proto));
                                }
 
                                if (c_oil->oif_flags[oif_vif_index]
                                    & PIM_OIF_FLAG_PROTO_STAR) {
-                                       strcpy(proto, "STAR");
+                                       strlcpy(proto, "STAR", sizeof(proto));
                                }
 
                                vty_out(vty,
@@ -5458,9 +5466,9 @@ static void show_mroute(struct pim_instance *pim, struct vty *vty,
                found_oif = 0;
 
                if (ifp_in)
-                       strcpy(in_ifname, ifp_in->name);
+                       strlcpy(in_ifname, ifp_in->name, sizeof(in_ifname));
                else
-                       strcpy(in_ifname, "<iif?>");
+                       strlcpy(in_ifname, "<iif?>", sizeof(in_ifname));
 
                if (uj) {
 
@@ -5487,7 +5495,7 @@ static void show_mroute(struct pim_instance *pim, struct vty *vty,
                        json_object_string_add(json_source, "iif", in_ifname);
                        json_oil = NULL;
                } else {
-                       strcpy(proto, "STATIC");
+                       strlcpy(proto, "STATIC", sizeof(proto));
                }
 
                for (oif_vif_index = 0; oif_vif_index < MAXVIFS;
@@ -5509,9 +5517,9 @@ static void show_mroute(struct pim_instance *pim, struct vty *vty,
                        found_oif = 1;
 
                        if (ifp_out)
-                               strcpy(out_ifname, ifp_out->name);
+                               strlcpy(out_ifname, ifp_out->name, sizeof(out_ifname));
                        else
-                               strcpy(out_ifname, "<oif?>");
+                               strlcpy(out_ifname, "<oif?>", sizeof(out_ifname));
 
                        if (uj) {
                                json_ifp_out = json_object_new_object();
@@ -5753,6 +5761,97 @@ DEFUN (show_ip_mroute_count_vrf_all,
        return CMD_SUCCESS;
 }
 
+static void show_mroute_summary(struct pim_instance *pim, struct vty *vty)
+{
+       struct listnode *node;
+       struct channel_oil *c_oil;
+       struct static_route *s_route;
+       uint32_t starg_sw_mroute_cnt = 0;
+       uint32_t sg_sw_mroute_cnt = 0;
+       uint32_t starg_hw_mroute_cnt = 0;
+       uint32_t sg_hw_mroute_cnt = 0;
+
+       vty_out(vty, "Mroute Type    Installed/Total\n");
+
+       for (ALL_LIST_ELEMENTS_RO(pim->channel_oil_list, node, c_oil)) {
+               if (!c_oil->installed) {
+                       if (c_oil->oil.mfcc_origin.s_addr == INADDR_ANY)
+                               starg_sw_mroute_cnt++;
+                       else
+                               sg_sw_mroute_cnt++;
+               } else {
+                       if (c_oil->oil.mfcc_origin.s_addr == INADDR_ANY)
+                               starg_hw_mroute_cnt++;
+                       else
+                               sg_hw_mroute_cnt++;
+               }
+       }
+
+       for (ALL_LIST_ELEMENTS_RO(pim->static_routes, node, s_route)) {
+               if (!s_route->c_oil.installed) {
+                       if (s_route->c_oil.oil.mfcc_origin.s_addr == INADDR_ANY)
+                               starg_sw_mroute_cnt++;
+                       else
+                               sg_sw_mroute_cnt++;
+               } else {
+                       if (s_route->c_oil.oil.mfcc_origin.s_addr == INADDR_ANY)
+                               starg_hw_mroute_cnt++;
+                       else
+                               sg_hw_mroute_cnt++;
+               }
+       }
+
+       vty_out(vty, "%-20s %d/%d\n", "(*, G)", starg_hw_mroute_cnt,
+               starg_sw_mroute_cnt + starg_hw_mroute_cnt);
+       vty_out(vty, "%-20s %d/%d\n", "(S, G)", sg_hw_mroute_cnt,
+               sg_sw_mroute_cnt + sg_hw_mroute_cnt);
+       vty_out(vty, "------\n");
+       vty_out(vty, "%-20s %d/%d\n", "Total",
+               (starg_hw_mroute_cnt + sg_hw_mroute_cnt),
+               (starg_sw_mroute_cnt +
+                starg_hw_mroute_cnt +
+                sg_sw_mroute_cnt +
+                sg_hw_mroute_cnt));
+}
+
+DEFUN (show_ip_mroute_summary,
+       show_ip_mroute_summary_cmd,
+       "show ip mroute [vrf NAME] summary",
+       SHOW_STR
+       IP_STR
+       MROUTE_STR
+       VRF_CMD_HELP_STR
+       "Summary of all mroutes\n")
+{
+       int idx = 2;
+       struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+
+       if (!vrf)
+               return CMD_WARNING;
+
+       show_mroute_summary(vrf->info, vty);
+       return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_mroute_summary_vrf_all,
+       show_ip_mroute_summary_vrf_all_cmd,
+       "show ip mroute vrf all summary",
+       SHOW_STR
+       IP_STR
+       MROUTE_STR
+       VRF_CMD_HELP_STR
+       "Summary of all mroutes\n")
+{
+       struct vrf *vrf;
+
+       RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
+               vty_out(vty, "VRF: %s\n", vrf->name);
+               show_mroute_summary(vrf->info, vty);
+       }
+
+       return CMD_SUCCESS;
+}
+
 DEFUN (show_ip_rib,
        show_ip_rib_cmd,
        "show ip rib [vrf NAME] A.B.C.D",
@@ -7118,6 +7217,106 @@ DEFUN_HIDDEN (interface_no_ip_igmp_query_max_response_time_dsec,
        return CMD_SUCCESS;
 }
 
+#define IGMP_LAST_MEMBER_QUERY_COUNT_MIN (1)
+#define IGMP_LAST_MEMBER_QUERY_COUNT_MAX (7)
+
+DEFUN (interface_ip_igmp_last_member_query_count,
+       interface_ip_igmp_last_member_query_count_cmd,
+       "ip igmp last-member-query-count (1-7)",
+       IP_STR
+       IFACE_IGMP_STR
+       IFACE_IGMP_LAST_MEMBER_QUERY_COUNT_STR
+       "Last member query count\n")
+{
+       VTY_DECLVAR_CONTEXT(interface, ifp);
+       struct pim_interface *pim_ifp = ifp->info;
+       int last_member_query_count;
+       int ret;
+
+       if (!pim_ifp) {
+               ret = pim_cmd_igmp_start(vty, ifp);
+               if (ret != CMD_SUCCESS)
+                       return ret;
+               pim_ifp = ifp->info;
+       }
+
+       last_member_query_count = atoi(argv[3]->arg);
+
+       pim_ifp->igmp_last_member_query_count = last_member_query_count;
+
+       return CMD_SUCCESS;
+}
+
+DEFUN (interface_no_ip_igmp_last_member_query_count,
+       interface_no_ip_igmp_last_member_query_count_cmd,
+       "no ip igmp last-member-query-count",
+       NO_STR
+       IP_STR
+       IFACE_IGMP_STR
+       IFACE_IGMP_LAST_MEMBER_QUERY_COUNT_STR)
+{
+       VTY_DECLVAR_CONTEXT(interface, ifp);
+       struct pim_interface *pim_ifp = ifp->info;
+
+       if (!pim_ifp)
+               return CMD_SUCCESS;
+
+       pim_ifp->igmp_last_member_query_count =
+               IGMP_DEFAULT_ROBUSTNESS_VARIABLE;
+
+       return CMD_SUCCESS;
+}
+
+#define IGMP_LAST_MEMBER_QUERY_INTERVAL_MIN (1)
+#define IGMP_LAST_MEMBER_QUERY_INTERVAL_MAX (255)
+
+DEFUN (interface_ip_igmp_last_member_query_interval,
+       interface_ip_igmp_last_member_query_interval_cmd,
+       "ip igmp last-member-query-interval (1-255)",
+       IP_STR
+       IFACE_IGMP_STR
+       IFACE_IGMP_LAST_MEMBER_QUERY_INTERVAL_STR
+       "Last member query interval in deciseconds\n")
+{
+       VTY_DECLVAR_CONTEXT(interface, ifp);
+       struct pim_interface *pim_ifp = ifp->info;
+       int last_member_query_interval;
+       int ret;
+
+       if (!pim_ifp) {
+               ret = pim_cmd_igmp_start(vty, ifp);
+               if (ret != CMD_SUCCESS)
+                       return ret;
+               pim_ifp = ifp->info;
+       }
+
+       last_member_query_interval = atoi(argv[3]->arg);
+       pim_ifp->igmp_specific_query_max_response_time_dsec
+               = last_member_query_interval;
+
+       return CMD_SUCCESS;
+}
+
+DEFUN (interface_no_ip_igmp_last_member_query_interval,
+       interface_no_ip_igmp_last_member_query_interval_cmd,
+       "no ip igmp last-member-query-interval",
+       NO_STR
+       IP_STR
+       IFACE_IGMP_STR
+       IFACE_IGMP_LAST_MEMBER_QUERY_INTERVAL_STR)
+{
+       VTY_DECLVAR_CONTEXT(interface, ifp);
+       struct pim_interface *pim_ifp = ifp->info;
+
+       if (!pim_ifp)
+               return CMD_SUCCESS;
+
+       pim_ifp->igmp_specific_query_max_response_time_dsec =
+               IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC;
+
+       return CMD_SUCCESS;
+}
+
 DEFUN (interface_ip_pim_drprio,
        interface_ip_pim_drprio_cmd,
        "ip pim drpriority (1-4294967295)",
@@ -9046,7 +9245,7 @@ static void ip_msdp_show_peers(struct pim_instance *pim, struct vty *vty,
                        pim_time_uptime(timebuf, sizeof(timebuf),
                                        now - mp->uptime);
                } else {
-                       strcpy(timebuf, "-");
+                       strlcpy(timebuf, "-", sizeof(timebuf));
                }
                pim_inet4_dump("<peer?>", mp->peer, peer_str, sizeof(peer_str));
                pim_inet4_dump("<local?>", mp->local, local_str,
@@ -9103,7 +9302,7 @@ static void ip_msdp_show_peers_detail(struct pim_instance *pim, struct vty *vty,
                        pim_time_uptime(timebuf, sizeof(timebuf),
                                        now - mp->uptime);
                } else {
-                       strcpy(timebuf, "-");
+                       strlcpy(timebuf, "-", sizeof(timebuf));
                }
                pim_inet4_dump("<local?>", mp->local, local_str,
                               sizeof(local_str));
@@ -9282,18 +9481,18 @@ static void ip_msdp_show_sa(struct pim_instance *pim, struct vty *vty, bool uj)
                if (sa->flags & PIM_MSDP_SAF_PEER) {
                        pim_inet4_dump("<rp?>", sa->rp, rp_str, sizeof(rp_str));
                        if (sa->up) {
-                               strcpy(spt_str, "yes");
+                               strlcpy(spt_str, "yes", sizeof(spt_str));
                        } else {
-                               strcpy(spt_str, "no");
+                               strlcpy(spt_str, "no", sizeof(spt_str));
                        }
                } else {
-                       strcpy(rp_str, "-");
-                       strcpy(spt_str, "-");
+                       strlcpy(rp_str, "-", sizeof(rp_str));
+                       strlcpy(spt_str, "-", sizeof(spt_str));
                }
                if (sa->flags & PIM_MSDP_SAF_LOCAL) {
-                       strcpy(local_str, "yes");
+                       strlcpy(local_str, "yes", sizeof(local_str));
                } else {
-                       strcpy(local_str, "no");
+                       strlcpy(local_str, "no", sizeof(local_str));
                }
                if (uj) {
                        json_object_object_get_ex(json, grp_str, &json_group);
@@ -9347,19 +9546,19 @@ static void ip_msdp_show_sa_entry_detail(struct pim_msdp_sa *sa,
                pim_inet4_dump("<rp?>", sa->rp, rp_str, sizeof(rp_str));
                pim_inet4_dump("<peer?>", sa->peer, peer_str, sizeof(peer_str));
                if (sa->up) {
-                       strcpy(spt_str, "yes");
+                       strlcpy(spt_str, "yes", sizeof(spt_str));
                } else {
-                       strcpy(spt_str, "no");
+                       strlcpy(spt_str, "no", sizeof(spt_str));
                }
        } else {
-               strcpy(rp_str, "-");
-               strcpy(peer_str, "-");
-               strcpy(spt_str, "-");
+               strlcpy(rp_str, "-", sizeof(rp_str));
+               strlcpy(peer_str, "-", sizeof(peer_str));
+               strlcpy(spt_str, "-", sizeof(spt_str));
        }
        if (sa->flags & PIM_MSDP_SAF_LOCAL) {
-               strcpy(local_str, "yes");
+               strlcpy(local_str, "yes", sizeof(local_str));
        } else {
-               strcpy(local_str, "no");
+               strlcpy(local_str, "no", sizeof(local_str));
        }
        pim_time_timer_to_hhmmss(statetimer, sizeof(statetimer),
                                 sa->sa_state_timer);
@@ -10073,6 +10272,14 @@ void pim_cmd_init(void)
                        &interface_ip_igmp_query_max_response_time_dsec_cmd);
        install_element(INTERFACE_NODE,
                        &interface_no_ip_igmp_query_max_response_time_dsec_cmd);
+       install_element(INTERFACE_NODE,
+                       &interface_ip_igmp_last_member_query_count_cmd);
+       install_element(INTERFACE_NODE,
+                       &interface_no_ip_igmp_last_member_query_count_cmd);
+       install_element(INTERFACE_NODE,
+                       &interface_ip_igmp_last_member_query_interval_cmd);
+       install_element(INTERFACE_NODE,
+                       &interface_no_ip_igmp_last_member_query_interval_cmd);
        install_element(INTERFACE_NODE, &interface_ip_pim_activeactive_cmd);
        install_element(INTERFACE_NODE, &interface_ip_pim_ssm_cmd);
        install_element(INTERFACE_NODE, &interface_no_ip_pim_ssm_cmd);
@@ -10133,6 +10340,8 @@ void pim_cmd_init(void)
        install_element(VIEW_NODE, &show_ip_mroute_vrf_all_cmd);
        install_element(VIEW_NODE, &show_ip_mroute_count_cmd);
        install_element(VIEW_NODE, &show_ip_mroute_count_vrf_all_cmd);
+       install_element(VIEW_NODE, &show_ip_mroute_summary_cmd);
+       install_element(VIEW_NODE, &show_ip_mroute_summary_vrf_all_cmd);
        install_element(VIEW_NODE, &show_ip_rib_cmd);
        install_element(VIEW_NODE, &show_ip_ssmpingd_cmd);
        install_element(VIEW_NODE, &show_debugging_pim_cmd);
index 558f28231ba2278a2ddf9162259f9c1363ead4e4..f5bb316a7ae3b3648d6b7641db30566a700b3187 100644 (file)
@@ -35,6 +35,8 @@
 #define IFACE_IGMP_QUERY_INTERVAL_STR          "IGMP host query interval\n"
 #define IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_STR      "IGMP max query response value (seconds)\n"
 #define IFACE_IGMP_QUERY_MAX_RESPONSE_TIME_DSEC_STR "IGMP max query response value (deciseconds)\n"
+#define IFACE_IGMP_LAST_MEMBER_QUERY_INTERVAL_STR   "IGMP last member query interval\n"
+#define IFACE_IGMP_LAST_MEMBER_QUERY_COUNT_STR      "IGMP last member query count\n"
 #define DEBUG_IGMP_STR                              "IGMP protocol activity\n"
 #define DEBUG_IGMP_EVENTS_STR                       "IGMP protocol events\n"
 #define DEBUG_IGMP_PACKETS_STR                      "IGMP protocol packets\n"
index 08be38c138abe570908e2949650f3152652b172b..7b8f045697884cd7de1a85f7e8c7e841a77b883a 100644 (file)
@@ -131,6 +131,8 @@ struct pim_interface *pim_if_new(struct interface *ifp, bool igmp, bool pim,
                IGMP_QUERY_MAX_RESPONSE_TIME_DSEC;
        pim_ifp->igmp_specific_query_max_response_time_dsec =
                IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC;
+       pim_ifp->igmp_last_member_query_count =
+               IGMP_DEFAULT_ROBUSTNESS_VARIABLE;
 
        /* BSM config on interface: TRUE by default */
        pim_ifp->bsm_enable = true;
index ab138589bd1252e41891a9409a1223ea50585329..1c11e85705189364f398a783d43055808c4b943f 100644 (file)
@@ -88,8 +88,14 @@ struct pim_interface {
        int igmp_query_max_response_time_dsec; /* IGMPv3 Max Response Time in
                                                  dsecs for general queries */
        int igmp_specific_query_max_response_time_dsec; /* IGMPv3 Max Response
-                                                          Time in dsecs for
-                                                          specific queries */
+                                                          Time in dsecs called
+                                                          as last member query
+                                                          interval, defines the
+                                                          maximum response time
+                                                          advertised in IGMP
+                                                          group-specific
+                                                          queries */
+       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 */
 
index b845f54f066d17e6e92246cfa5c6afb2e44e1aa6..bc0460fa0397072ae44198afc94dfbf3774b797b 100644 (file)
@@ -997,7 +997,7 @@ static void group_retransmit_group(struct igmp_group *group)
 
        char query_buf[query_buf_size];
 
-       lmqc = igmp->querier_robustness_variable;
+       lmqc = pim_ifp->igmp_last_member_query_count;
        lmqi_msec = 100 * pim_ifp->igmp_specific_query_max_response_time_dsec;
        lmqt_msec = lmqc * lmqi_msec;
 
@@ -1076,7 +1076,7 @@ static int group_retransmit_sources(struct igmp_group *group,
        igmp = group->group_igmp_sock;
        pim_ifp = igmp->interface->info;
 
-       lmqc = igmp->querier_robustness_variable;
+       lmqc = pim_ifp->igmp_last_member_query_count;
        lmqi_msec = 100 * pim_ifp->igmp_specific_query_max_response_time_dsec;
        lmqt_msec = lmqc * lmqi_msec;
 
@@ -1314,9 +1314,13 @@ 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 */
 
-       lmqc = group->group_igmp_sock->querier_robustness_variable;
+       igmp = group->group_igmp_sock;
+       pim_ifp = igmp->interface->info;
+       lmqc = pim_ifp->igmp_last_member_query_count;
 
        /* lower group timer to lmqt */
        igmp_group_timer_lower_to_lmqt(group);
@@ -1351,7 +1355,7 @@ static void source_query_send_by_flag(struct igmp_group *group,
        igmp = group->group_igmp_sock;
        pim_ifp = igmp->interface->info;
 
-       lmqc = igmp->querier_robustness_variable;
+       lmqc = pim_ifp->igmp_last_member_query_count;
        lmqi_msec = 100 * pim_ifp->igmp_specific_query_max_response_time_dsec;
        lmqt_msec = lmqc * lmqi_msec;
 
@@ -1509,7 +1513,7 @@ void igmp_group_timer_lower_to_lmqt(struct igmp_group *group)
        ifname = ifp->name;
 
        lmqi_dsec = pim_ifp->igmp_specific_query_max_response_time_dsec;
-       lmqc = igmp->querier_robustness_variable;
+       lmqc = pim_ifp->igmp_last_member_query_count;
        lmqt_msec = PIM_IGMP_LMQT_MSEC(
                lmqi_dsec, lmqc); /* lmqt_msec = (100 * lmqi_dsec) * lmqc */
 
@@ -1546,7 +1550,7 @@ void igmp_source_timer_lower_to_lmqt(struct igmp_source *source)
        ifname = ifp->name;
 
        lmqi_dsec = pim_ifp->igmp_specific_query_max_response_time_dsec;
-       lmqc = igmp->querier_robustness_variable;
+       lmqc = pim_ifp->igmp_last_member_query_count;
        lmqt_msec = PIM_IGMP_LMQT_MSEC(
                lmqi_dsec, lmqc); /* lmqt_msec = (100 * lmqi_dsec) * lmqc */
 
index 3287e137193c3eb6083036d9ff0e109b64dc9187..74a3a9836bc6b7436320775f3cdc2c61ffef8f93 100644 (file)
@@ -1078,7 +1078,7 @@ static enum pim_msdp_err pim_msdp_peer_new(struct pim_instance *pim,
        mp->mesh_group_name = XSTRDUP(MTYPE_PIM_MSDP_MG_NAME, mesh_group_name);
        mp->state = PIM_MSDP_INACTIVE;
        mp->fd = -1;
-       strcpy(mp->last_reset, "-");
+       strlcpy(mp->last_reset, "-", sizeof(mp->last_reset));
        /* higher IP address is listener */
        if (ntohl(mp->local.s_addr) > ntohl(mp->peer.s_addr)) {
                mp->flags |= PIM_MSDP_PEERF_LISTENER;
index a823962b23269c2aedc5889f0a9e7e5eeb81b6bd..44b8ecbfea4767c1a8912fe3b7c2fc274eded214 100644 (file)
@@ -1399,23 +1399,24 @@ const char *pim_upstream_state2str(enum pim_upstream_state join_state)
        return "Unknown";
 }
 
-const char *pim_reg_state2str(enum pim_reg_state reg_state, char *state_str)
+const char *pim_reg_state2str(enum pim_reg_state reg_state, char *state_str,
+                             size_t state_str_len)
 {
        switch (reg_state) {
        case PIM_REG_NOINFO:
-               strcpy(state_str, "RegNoInfo");
+               strlcpy(state_str, "RegNoInfo", state_str_len);
                break;
        case PIM_REG_JOIN:
-               strcpy(state_str, "RegJoined");
+               strlcpy(state_str, "RegJoined", state_str_len);
                break;
        case PIM_REG_JOIN_PENDING:
-               strcpy(state_str, "RegJoinPend");
+               strlcpy(state_str, "RegJoinPend", state_str_len);
                break;
        case PIM_REG_PRUNE:
-               strcpy(state_str, "RegPrune");
+               strlcpy(state_str, "RegPrune", state_str_len);
                break;
        default:
-               strcpy(state_str, "RegUnknown");
+               strlcpy(state_str, "RegUnknown", state_str_len);
        }
        return state_str;
 }
@@ -1432,7 +1433,7 @@ static int pim_upstream_register_stop_timer(struct thread *t)
                char state_str[PIM_REG_STATE_STR_LEN];
                zlog_debug("%s: (S,G)=%s[%s] upstream register stop timer %s",
                           __PRETTY_FUNCTION__, up->sg_str, pim->vrf->name,
-                          pim_reg_state2str(up->reg_state, state_str));
+                          pim_reg_state2str(up->reg_state, state_str, sizeof(state_str)));
        }
 
        switch (up->reg_state) {
index 102826ac71ca84af665ad5c73e5986da4352d058..02ae998290579f3a5355e2c054fb76316fe20679 100644 (file)
@@ -283,7 +283,8 @@ void pim_upstream_switch(struct pim_instance *pim, struct pim_upstream *up,
 
 const char *pim_upstream_state2str(enum pim_upstream_state join_state);
 #define PIM_REG_STATE_STR_LEN 12
-const char *pim_reg_state2str(enum pim_reg_state state, char *state_str);
+const char *pim_reg_state2str(enum pim_reg_state state, char *state_str,
+                             size_t state_str_len);
 
 int pim_upstream_inherited_olist_decide(struct pim_instance *pim,
                                        struct pim_upstream *up);
index 8d40f85132acb78fe150578b6413e00e6b4dc59d..468cd56ee55bf315726948b9433ba2b8ca065a99 100644 (file)
@@ -350,6 +350,24 @@ int pim_interface_config_write(struct vty *vty)
                                        ++writes;
                                }
 
+                               /* IF ip igmp last-member_query-count */
+                               if (pim_ifp->igmp_last_member_query_count
+                                   != IGMP_DEFAULT_ROBUSTNESS_VARIABLE) {
+                                       vty_out(vty,
+                                               " ip igmp last-member-query-count %d\n",
+                                               pim_ifp->igmp_last_member_query_count);
+                                       ++writes;
+                               }
+
+                               /* IF ip igmp last-member_query-interval */
+                               if (pim_ifp->igmp_specific_query_max_response_time_dsec
+                                   != IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC) {
+                                       vty_out(vty,
+                                               " ip igmp last-member-query-interval %d\n",
+                                               pim_ifp->igmp_specific_query_max_response_time_dsec);
+                                         ++writes;
+                               }
+
                                /* IF ip igmp join */
                                if (pim_ifp->igmp_join_list) {
                                        struct listnode *node;
index 3216b8f89fda9417eba84d1980cdc033d8e43378..3c1c779bad6f0332cc10c2002f2987400a18c90f 100644 (file)
@@ -42,10 +42,9 @@ struct rip_metric_modifier {
 
 /* `match metric METRIC' */
 /* Match function return 1 if match is success else return zero. */
-static route_map_result_t route_match_metric(void *rule,
-                                            const struct prefix *prefix,
-                                            route_map_object_t type,
-                                            void *object)
+static enum route_map_match_result_t
+route_match_metric(void *rule, const struct prefix *prefix,
+                  route_map_object_t type, void *object)
 {
        uint32_t *metric;
        uint32_t check;
@@ -95,10 +94,9 @@ struct route_map_rule_cmd route_match_metric_cmd = {
 
 /* `match interface IFNAME' */
 /* Match function return 1 if match is success else return zero. */
-static route_map_result_t route_match_interface(void *rule,
-                                               const struct prefix *prefix,
-                                               route_map_object_t type,
-                                               void *object)
+static enum route_map_match_result_t
+route_match_interface(void *rule, const struct prefix *prefix,
+                     route_map_object_t type, void *object)
 {
        struct rip_info *rinfo;
        struct interface *ifp;
@@ -143,10 +141,9 @@ struct route_map_rule_cmd route_match_interface_cmd = {
 /* `match ip next-hop IP_ACCESS_LIST' */
 
 /* Match function return 1 if match is success else return zero. */
-static route_map_result_t route_match_ip_next_hop(void *rule,
-                                                 const struct prefix *prefix,
-                                                 route_map_object_t type,
-                                                 void *object)
+static enum route_map_match_result_t
+route_match_ip_next_hop(void *rule, const struct prefix *prefix,
+                       route_map_object_t type, void *object)
 {
        struct access_list *alist;
        struct rip_info *rinfo;
@@ -190,7 +187,7 @@ static struct route_map_rule_cmd route_match_ip_next_hop_cmd = {
 
 /* `match ip next-hop prefix-list PREFIX_LIST' */
 
-static route_map_result_t
+static enum route_map_match_result_t
 route_match_ip_next_hop_prefix_list(void *rule, const struct prefix *prefix,
                                    route_map_object_t type, void *object)
 {
@@ -235,10 +232,9 @@ static struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd = {
 
 /* Match function should return 1 if match is success else return
    zero. */
-static route_map_result_t route_match_ip_address(void *rule,
-                                                const struct prefix *prefix,
-                                                route_map_object_t type,
-                                                void *object)
+static enum route_map_match_result_t
+route_match_ip_address(void *rule, const struct prefix *prefix,
+                      route_map_object_t type, void *object)
 {
        struct access_list *alist;
 
@@ -274,7 +270,7 @@ static struct route_map_rule_cmd route_match_ip_address_cmd = {
 
 /* `match ip address prefix-list PREFIX_LIST' */
 
-static route_map_result_t
+static enum route_map_match_result_t
 route_match_ip_address_prefix_list(void *rule, const struct prefix *prefix,
                                   route_map_object_t type, void *object)
 {
@@ -309,8 +305,9 @@ static struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd = {
 
 /* `match tag TAG' */
 /* Match function return 1 if match is success else return zero. */
-static route_map_result_t route_match_tag(void *rule, const struct prefix *p,
-                                         route_map_object_t type, void *object)
+static enum route_map_match_result_t
+route_match_tag(void *rule, const struct prefix *p, route_map_object_t type,
+               void *object)
 {
        route_tag_t *tag;
        struct rip_info *rinfo;
@@ -339,10 +336,9 @@ static struct route_map_rule_cmd route_match_tag_cmd = {
 /* `set metric METRIC' */
 
 /* Set metric to attribute. */
-static route_map_result_t route_set_metric(void *rule,
-                                          const struct prefix *prefix,
-                                          route_map_object_t type,
-                                          void *object)
+static enum route_map_match_result_t
+route_set_metric(void *rule, const struct prefix *prefix,
+                route_map_object_t type, void *object)
 {
        if (type == RMAP_RIP) {
                struct rip_metric_modifier *mod;
@@ -438,7 +434,7 @@ static struct route_map_rule_cmd route_set_metric_cmd = {
 /* `set ip next-hop IP_ADDRESS' */
 
 /* Set nexthop to object.  ojbect must be pointer to struct attr. */
-static route_map_result_t route_set_ip_nexthop(void *rule,
+static enum route_map_match_result_t route_set_ip_nexthop(void *rule,
                                               const struct prefix *prefix,
                                               route_map_object_t type,
                                               void *object)
@@ -491,8 +487,9 @@ static struct route_map_rule_cmd route_set_ip_nexthop_cmd = {
 /* `set tag TAG' */
 
 /* Set tag to object.  ojbect must be pointer to struct attr. */
-static route_map_result_t route_set_tag(void *rule, const struct prefix *prefix,
-                                       route_map_object_t type, void *object)
+static enum route_map_match_result_t
+route_set_tag(void *rule, const struct prefix *prefix, route_map_object_t type,
+             void *object)
 {
        route_tag_t *tag;
        struct rip_info *rinfo;
index 0604e272cdfd6800b6318f3746841616de5c6c61..671586cfd96f5d1691eaec9bd3328bfd06d4b2a5 100644 (file)
@@ -38,10 +38,9 @@ struct rip_metric_modifier {
 
 /* `match metric METRIC' */
 /* Match function return 1 if match is success else return zero. */
-static route_map_result_t route_match_metric(void *rule,
-                                            const struct prefix *prefix,
-                                            route_map_object_t type,
-                                            void *object)
+static enum route_map_match_result_t
+route_match_metric(void *rule, const struct prefix *prefix,
+                  route_map_object_t type, void *object)
 {
        uint32_t *metric;
        struct ripng_info *rinfo;
@@ -86,10 +85,9 @@ static struct route_map_rule_cmd route_match_metric_cmd = {
 
 /* `match interface IFNAME' */
 /* Match function return 1 if match is success else return zero. */
-static route_map_result_t route_match_interface(void *rule,
-                                               const struct prefix *prefix,
-                                               route_map_object_t type,
-                                               void *object)
+static enum route_map_match_result_t
+route_match_interface(void *rule, const struct prefix *prefix,
+                     route_map_object_t type, void *object)
 {
        struct ripng_info *rinfo;
        struct interface *ifp;
@@ -129,9 +127,10 @@ static struct route_map_rule_cmd route_match_interface_cmd = {
 
 /* `match tag TAG' */
 /* Match function return 1 if match is success else return zero. */
-static route_map_result_t route_match_tag(void *rule,
-                                         const struct prefix *prefix,
-                                         route_map_object_t type, void *object)
+static enum route_map_match_result_t route_match_tag(void *rule,
+                                               const struct prefix *prefix,
+                                               route_map_object_t type,
+                                               void *object)
 {
        route_tag_t *tag;
        struct ripng_info *rinfo;
@@ -159,10 +158,9 @@ static struct route_map_rule_cmd route_match_tag_cmd = {
 /* `set metric METRIC' */
 
 /* Set metric to attribute. */
-static route_map_result_t route_set_metric(void *rule,
-                                          const struct prefix *prefix,
-                                          route_map_object_t type,
-                                          void *object)
+static enum route_map_match_result_t
+route_set_metric(void *rule, const struct prefix *prefix,
+                route_map_object_t type, void *object)
 {
        if (type == RMAP_RIPNG) {
                struct rip_metric_modifier *mod;
@@ -256,10 +254,9 @@ static struct route_map_rule_cmd route_set_metric_cmd = {
 /* `set ipv6 next-hop local IP_ADDRESS' */
 
 /* Set nexthop to object.  ojbect must be pointer to struct attr. */
-static route_map_result_t route_set_ipv6_nexthop_local(void *rule,
-                                                      const struct prefix *p,
-                                                      route_map_object_t type,
-                                                      void *object)
+static enum route_map_match_result_t
+route_set_ipv6_nexthop_local(void *rule, const struct prefix *p,
+                            route_map_object_t type, void *object)
 {
        struct in6_addr *address;
        struct ripng_info *rinfo;
@@ -310,9 +307,9 @@ static struct route_map_rule_cmd route_set_ipv6_nexthop_local_cmd = {
 /* `set tag TAG' */
 
 /* Set tag to object.  ojbect must be pointer to struct attr. */
-static route_map_result_t route_set_tag(void *rule,
-                                       const struct prefix *prefix,
-                                       route_map_object_t type, void *object)
+static enum route_map_match_result_t
+route_set_tag(void *rule, const struct prefix *prefix, route_map_object_t type,
+             void *object)
 {
        route_tag_t *tag;
        struct ripng_info *rinfo;
index 411689a7a720eeb761419d2483b55a6011d03ed7..71bc43049ab039b3a565fb766718b8cb7d2cd37a 100644 (file)
@@ -2011,26 +2011,26 @@ static char *ripng_route_subtype_print(struct ripng_info *rinfo)
        memset(str, 0, 3);
 
        if (rinfo->suppress)
-               strcat(str, "S");
+               strlcat(str, "S", sizeof(str));
 
        switch (rinfo->sub_type) {
        case RIPNG_ROUTE_RTE:
-               strcat(str, "n");
+               strlcat(str, "n", sizeof(str));
                break;
        case RIPNG_ROUTE_STATIC:
-               strcat(str, "s");
+               strlcat(str, "s", sizeof(str));
                break;
        case RIPNG_ROUTE_DEFAULT:
-               strcat(str, "d");
+               strlcat(str, "d", sizeof(str));
                break;
        case RIPNG_ROUTE_REDISTRIBUTE:
-               strcat(str, "r");
+               strlcat(str, "r", sizeof(str));
                break;
        case RIPNG_ROUTE_INTERFACE:
-               strcat(str, "i");
+               strlcat(str, "i", sizeof(str));
                break;
        default:
-               strcat(str, "?");
+               strlcat(str, "?", sizeof(str));
                break;
        }
 
index cde31df14fece75fe24d222d6f9e8ff28768829c..5f9ecad6946229f8c3db99da2def2165552f7163 100644 (file)
@@ -127,7 +127,7 @@ int static_add_route(afi_t afi, safi_t safi, uint8_t type, struct prefix *p,
        si->tag = tag;
        si->vrf_id = svrf->vrf->vrf_id;
        si->nh_vrf_id = nh_svrf->vrf->vrf_id;
-       strcpy(si->nh_vrfname, nh_svrf->vrf->name);
+       strlcpy(si->nh_vrfname, nh_svrf->vrf->name, sizeof(si->nh_vrfname));
        si->table_id = table_id;
        si->onlink = onlink;
 
index a0b119c3ebaf23679efac8f33af7d252667dd505..baf77d1cb79606b2fe267e6ea85743ccc0369bb8 100644 (file)
@@ -681,7 +681,7 @@ int vtysh_mark_file(const char *filename)
        while (fgets(vty->buf, VTY_BUFSIZ, confp)) {
                lineno++;
                tried = 0;
-               strcpy(vty_buf_copy, vty->buf);
+               strlcpy(vty_buf_copy, vty->buf, VTY_BUFSIZ);
                vty_buf_trimmed = trim(vty_buf_copy);
 
                switch (vty->node) {
@@ -2553,6 +2553,15 @@ DEFUNSH(VTYSH_ALL, vtysh_log_timestamp_precision,
        return CMD_SUCCESS;
 }
 
+DEFUNSH(VTYSH_ALL, vtysh_debug_memstats,
+       vtysh_debug_memstats_cmd, "[no] debug memstats-at-exit",
+       NO_STR
+       "Debug\n"
+       "Print memory statistics at exit\n")
+{
+       return CMD_SUCCESS;
+}
+
 DEFUNSH(VTYSH_ALL, no_vtysh_log_timestamp_precision,
        no_vtysh_log_timestamp_precision_cmd, "no log timestamp precision",
        NO_STR
@@ -2702,9 +2711,10 @@ static void backup_config_file(const char *fbackup)
 {
        char *integrate_sav = NULL;
 
-       integrate_sav = malloc(strlen(fbackup) + strlen(CONF_BACKUP_EXT) + 1);
-       strcpy(integrate_sav, fbackup);
-       strcat(integrate_sav, CONF_BACKUP_EXT);
+       size_t integrate_sav_sz = strlen(fbackup) + strlen(CONF_BACKUP_EXT) + 1;
+       integrate_sav = malloc(integrate_sav_sz);
+       strlcpy(integrate_sav, fbackup, integrate_sav_sz);
+       strlcat(integrate_sav, CONF_BACKUP_EXT, integrate_sav_sz);
 
        /* Move current configuration file to backup config file. */
        if (unlink(integrate_sav) != 0) {
@@ -3428,7 +3438,7 @@ void vtysh_readline_init(void)
 
 char *vtysh_prompt(void)
 {
-       static char buf[100];
+       static char buf[512];
 
        snprintf(buf, sizeof buf, cmd_prompt(vty->node), cmd_hostname_get());
        return buf;
@@ -3848,6 +3858,8 @@ void vtysh_init_vty(void)
        install_element(VIEW_NODE, &vtysh_show_debugging_hashtable_cmd);
        install_element(ENABLE_NODE, &vtysh_debug_all_cmd);
        install_element(CONFIG_NODE, &vtysh_debug_all_cmd);
+       install_element(ENABLE_NODE, &vtysh_debug_memstats_cmd);
+       install_element(CONFIG_NODE, &vtysh_debug_memstats_cmd);
 
        /* misc lib show commands */
        install_element(VIEW_NODE, &vtysh_show_memory_cmd);
index cf94ab643a308f6341939ee046cfa0ce08848355..9c2de0f62b8cf72f23bcd0ad19111a45cc71d52d 100644 (file)
@@ -521,10 +521,10 @@ int vtysh_read_config(const char *config_default_dir)
  */
 void vtysh_config_write(void)
 {
-       char line[81];
+       char line[512];
 
        if (cmd_hostname_get()) {
-               sprintf(line, "hostname %s", cmd_hostname_get());
+               snprintf(line, sizeof(line), "hostname %s", cmd_hostname_get());
                vtysh_config_parse_line(NULL, line);
        }
 
index 322527015bd5b440503fe0d68f69da2b69bfde89..8202e076afb49cf387408d95d38b12f077b3036b 100644 (file)
@@ -245,7 +245,7 @@ static int if_set_prefix_ctx(const struct zebra_dplane_ctx *ctx)
        p = (struct prefix_ipv4 *)dplane_ctx_get_intf_addr(ctx);
 
        memset(&addreq, 0, sizeof(addreq));
-       strncpy((char *)&addreq.ifra_name, dplane_ctx_get_ifname(ctx),
+       strlcpy((char *)&addreq.ifra_name, dplane_ctx_get_ifname(ctx),
                sizeof(addreq.ifra_name));
 
        memset(&addr, 0, sizeof(struct sockaddr_in));
@@ -296,7 +296,7 @@ static int if_unset_prefix_ctx(const struct zebra_dplane_ctx *ctx)
        p = (struct prefix_ipv4 *)dplane_ctx_get_intf_addr(ctx);
 
        memset(&addreq, 0, sizeof(addreq));
-       strncpy((char *)&addreq.ifra_name, dplane_ctx_get_ifname(ctx),
+       strlcpy((char *)&addreq.ifra_name, dplane_ctx_get_ifname(ctx),
                sizeof(addreq.ifra_name));
 
        memset(&addr, 0, sizeof(struct sockaddr_in));
index ccfa7a4a4c38f3111b9eb5f6fbf27aa0e1170986..1f96fa23ea3af4b2c1368c1171ecaa3b33f94395 100644 (file)
@@ -286,7 +286,7 @@ static int if_unset_prefix_ctx(const struct zebra_dplane_ctx *ctx)
 
        p = (struct prefix_ipv4 *)dplane_ctx_get_intf_addr(ctx);
 
-       strncpy(ifreq.ifr_name, dplane_ctx_get_ifname(ctx),
+       strlcpy(ifreq.ifr_name, dplane_ctx_get_ifname(ctx),
                sizeof(ifreq.ifr_name));
 
        memset(&addr, 0, sizeof(struct sockaddr_in));
index 5f4bd3bbc6ef7656b21cebcbcbadcabb97d7ea72..156ce50725ec758d6e99f5594006a9f38912bf1c 100644 (file)
@@ -304,12 +304,13 @@ size_t rta_getattr(caddr_t sap, void *destp, size_t destlen)
 size_t rta_getsdlname(caddr_t sap, void *destp, short *destlen)
 {
        struct sockaddr_dl *sdl = (struct sockaddr_dl *)sap;
-       struct sockaddr *sa = (struct sockaddr *)sap;
        uint8_t *dest = destp;
        size_t tlen, copylen;
 
        copylen = sdl->sdl_nlen;
 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+       struct sockaddr *sa = (struct sockaddr *)sap;
+
        tlen = (sa->sa_len == 0) ? sizeof(ROUNDUP_TYPE) : ROUNDUP(sa->sa_len);
 #else  /* !HAVE_STRUCT_SOCKADDR_SA_LEN */
        tlen = SAROUNDUP(sap);
@@ -522,7 +523,7 @@ static enum zebra_link_type sdl_to_zebra_link_type(unsigned int sdlt)
 int ifm_read(struct if_msghdr *ifm)
 {
        struct interface *ifp = NULL;
-       struct sockaddr_dl *sdl;
+       struct sockaddr_dl *sdl = NULL;
        char ifname[IFNAMSIZ];
        short ifnlen = 0;
        int maskbit;
index b13f1170cd5defa3dc53c1d32b0b3d327b81961b..dfff76664c23803c949d5937619330f4c6970e07 100644 (file)
@@ -574,7 +574,7 @@ int zebra_add_import_table_entry(struct route_node *rn, struct route_entry *re,
        struct route_entry *newre;
        struct route_entry *same;
        struct prefix p;
-       route_map_result_t ret = RMAP_MATCH;
+       route_map_result_t ret = RMAP_PERMITMATCH;
        afi_t afi;
 
        afi = family2afi(rn->p.family);
@@ -583,7 +583,7 @@ int zebra_add_import_table_entry(struct route_node *rn, struct route_entry *re,
                        afi, re->type, re->instance, &rn->p, re->ng.nexthop,
                        re->vrf_id, re->tag, rmap_name);
 
-       if (ret != RMAP_MATCH) {
+       if (ret != RMAP_PERMITMATCH) {
                UNSET_FLAG(re->flags, ZEBRA_FLAG_SELECTED);
                zebra_del_import_table_entry(rn, re);
                return 0;
index 0353c9bb99bb9327282f6a484650817bee274c7f..a54e164d98c64c2d4c1dc21280563fdab05ae77d 100644 (file)
@@ -87,9 +87,12 @@ struct route_entry {
        /* Link list. */
        struct re_list_item next;
 
-       /* Nexthop structure */
+       /* Nexthop structure (from RIB) */
        struct nexthop_group ng;
 
+       /* Nexthop group from FIB (optional) */
+       struct nexthop_group fib_ng;
+
        /* Tag */
        route_tag_t tag;
 
@@ -529,6 +532,16 @@ static inline void rib_tables_iter_cleanup(rib_tables_iter_t *iter)
 DECLARE_HOOK(rib_update, (struct route_node * rn, const char *reason),
             (rn, reason))
 
+/*
+ * Access active nexthop-group, either RIB or FIB version
+ */
+static inline struct nexthop_group *rib_active_nhg(struct route_entry *re)
+{
+       if (re->fib_ng.nexthop)
+               return &(re->fib_ng);
+       else
+               return &(re->ng);
+}
 
 extern void zebra_vty_init(void);
 
index def5bf7d88947db03ff7ec48e67feb78dadf4efe..92c78a4cbb144a4a7dbad1b06312ef1024407d2c 100644 (file)
@@ -813,7 +813,7 @@ static int netlink_route_change_read_multicast(struct nlmsghdr *h,
 
                        sprintf(temp, "%s(%d) ", ifp ? ifp->name : "Unknown",
                                oif[count]);
-                       strcat(oif_list, temp);
+                       strlcat(oif_list, temp, sizeof(oif_list));
                }
                struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(vrf);
                ifp = if_lookup_by_index(iif, vrf);
index 1e36d020a3235a1dc942f6be5d2ac617305871f1..25040a2717dd2a15e818a9d4fdf44db6a984965b 100644 (file)
@@ -75,6 +75,7 @@ zebra_zebra_SOURCES = \
        zebra/zebra_mpls_null.c \
        zebra/zebra_mpls_vty.c \
        zebra/zebra_mroute.c \
+       zebra/zebra_nhg.c \
        zebra/zebra_ns.c \
        zebra/zebra_pbr.c \
        zebra/zebra_ptm.c \
@@ -135,6 +136,7 @@ noinst_HEADERS += \
        zebra/zebra_memory.h \
        zebra/zebra_mpls.h \
        zebra/zebra_mroute.h \
+       zebra/zebra_nhg.h \
        zebra/zebra_ns.h \
        zebra/zebra_pbr.h \
        zebra/zebra_ptm.h \
index 94bfa34b38c127dbf82d54c5d55d0dd3c7741688..49e43f4942e759bee6a440c3a45e67097030ed9b 100644 (file)
@@ -524,6 +524,8 @@ int zsend_redistribute_route(int cmd, struct zserv *client,
        struct nexthop *nexthop;
        int count = 0;
        afi_t afi;
+       size_t stream_size =
+               MAX(ZEBRA_MAX_PACKET_SIZ, sizeof(struct zapi_route));
 
        memset(&api, 0, sizeof(api));
        api.vrf_id = re->vrf_id;
@@ -605,7 +607,7 @@ int zsend_redistribute_route(int cmd, struct zserv *client,
        SET_FLAG(api.message, ZAPI_MESSAGE_MTU);
        api.mtu = re->mtu;
 
-       struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ);
+       struct stream *s = stream_new(stream_size);
 
        /* Encode route and send. */
        if (zapi_route_encode(cmd, s, &api) < 0) {
index 6fc62147c815c6c9ac4663bf1b08c160bdb6f3fa..1707d3a68b6dff3751de6d6606fb31a8efe96379 100644 (file)
@@ -172,6 +172,11 @@ struct zebra_dplane_ctx {
        uint32_t zd_seq;
        uint32_t zd_old_seq;
 
+       /* Some updates may be generated by notifications: allow the
+        * plugin to notice and ignore results from its own notifications.
+        */
+       uint32_t zd_notif_provider;
+
        /* TODO -- internal/sub-operation status? */
        enum zebra_dplane_result zd_remote_status;
        enum zebra_dplane_result zd_kernel_status;
@@ -222,6 +227,8 @@ struct zebra_dplane_provider {
        /* Flags */
        int dp_flags;
 
+       int (*dp_start)(struct zebra_dplane_provider *prov);
+
        int (*dp_fp)(struct zebra_dplane_provider *prov);
 
        int (*dp_fini)(struct zebra_dplane_provider *prov, bool early_p);
@@ -351,7 +358,7 @@ struct thread_master *dplane_get_thread_master(void)
 /*
  * Allocate a dataplane update context
  */
-static struct zebra_dplane_ctx *dplane_ctx_alloc(void)
+struct zebra_dplane_ctx *dplane_ctx_alloc(void)
 {
        struct zebra_dplane_ctx *p;
 
@@ -392,6 +399,7 @@ static void dplane_ctx_free(struct zebra_dplane_ctx **pctx)
        case DPLANE_OP_ROUTE_DELETE:
        case DPLANE_OP_SYS_ROUTE_ADD:
        case DPLANE_OP_SYS_ROUTE_DELETE:
+       case DPLANE_OP_ROUTE_NOTIFY:
 
                /* Free allocated nexthops */
                if ((*pctx)->u.rinfo.zd_ng.nexthop) {
@@ -413,6 +421,7 @@ static void dplane_ctx_free(struct zebra_dplane_ctx **pctx)
        case DPLANE_OP_LSP_INSTALL:
        case DPLANE_OP_LSP_UPDATE:
        case DPLANE_OP_LSP_DELETE:
+       case DPLANE_OP_LSP_NOTIFY:
        {
                zebra_nhlfe_t *nhlfe, *next;
 
@@ -543,6 +552,12 @@ bool dplane_ctx_is_skip_kernel(const struct zebra_dplane_ctx *ctx)
        return CHECK_FLAG(ctx->zd_flags, DPLANE_CTX_FLAG_NO_KERNEL);
 }
 
+void dplane_ctx_set_op(struct zebra_dplane_ctx *ctx, enum dplane_op_e op)
+{
+       DPLANE_CTX_VALID(ctx);
+       ctx->zd_op = op;
+}
+
 enum dplane_op_e dplane_ctx_get_op(const struct zebra_dplane_ctx *ctx)
 {
        DPLANE_CTX_VALID(ctx);
@@ -569,6 +584,9 @@ const char *dplane_op2str(enum dplane_op_e op)
        case DPLANE_OP_ROUTE_DELETE:
                ret = "ROUTE_DELETE";
                break;
+       case DPLANE_OP_ROUTE_NOTIFY:
+               ret = "ROUTE_NOTIFY";
+               break;
 
        case DPLANE_OP_LSP_INSTALL:
                ret = "LSP_INSTALL";
@@ -579,6 +597,9 @@ const char *dplane_op2str(enum dplane_op_e op)
        case DPLANE_OP_LSP_DELETE:
                ret = "LSP_DELETE";
                break;
+       case DPLANE_OP_LSP_NOTIFY:
+               ret = "LSP_NOTIFY";
+               break;
 
        case DPLANE_OP_PW_INSTALL:
                ret = "PW_INSTALL";
@@ -625,6 +646,14 @@ const char *dplane_res2str(enum zebra_dplane_result res)
        return ret;
 }
 
+void dplane_ctx_set_dest(struct zebra_dplane_ctx *ctx,
+                        const struct prefix *dest)
+{
+       DPLANE_CTX_VALID(ctx);
+
+       prefix_copy(&(ctx->u.rinfo.zd_dest), dest);
+}
+
 const struct prefix *dplane_ctx_get_dest(const struct zebra_dplane_ctx *ctx)
 {
        DPLANE_CTX_VALID(ctx);
@@ -632,6 +661,16 @@ const struct prefix *dplane_ctx_get_dest(const struct zebra_dplane_ctx *ctx)
        return &(ctx->u.rinfo.zd_dest);
 }
 
+void dplane_ctx_set_src(struct zebra_dplane_ctx *ctx, const struct prefix *src)
+{
+       DPLANE_CTX_VALID(ctx);
+
+       if (src)
+               prefix_copy(&(ctx->u.rinfo.zd_src), src);
+       else
+               memset(&(ctx->u.rinfo.zd_src), 0, sizeof(struct prefix));
+}
+
 /* Source prefix is a little special - return NULL for "no src prefix" */
 const struct prefix *dplane_ctx_get_src(const struct zebra_dplane_ctx *ctx)
 {
@@ -666,6 +705,13 @@ uint32_t dplane_ctx_get_old_seq(const struct zebra_dplane_ctx *ctx)
        return ctx->zd_old_seq;
 }
 
+void dplane_ctx_set_vrf(struct zebra_dplane_ctx *ctx, vrf_id_t vrf)
+{
+       DPLANE_CTX_VALID(ctx);
+
+       ctx->zd_vrf_id = vrf;
+}
+
 vrf_id_t dplane_ctx_get_vrf(const struct zebra_dplane_ctx *ctx)
 {
        DPLANE_CTX_VALID(ctx);
@@ -673,6 +719,35 @@ vrf_id_t dplane_ctx_get_vrf(const struct zebra_dplane_ctx *ctx)
        return ctx->zd_vrf_id;
 }
 
+bool dplane_ctx_is_from_notif(const struct zebra_dplane_ctx *ctx)
+{
+       DPLANE_CTX_VALID(ctx);
+
+       return (ctx->zd_notif_provider != 0);
+}
+
+uint32_t dplane_ctx_get_notif_provider(const struct zebra_dplane_ctx *ctx)
+{
+       DPLANE_CTX_VALID(ctx);
+
+       return ctx->zd_notif_provider;
+}
+
+void dplane_ctx_set_notif_provider(struct zebra_dplane_ctx *ctx,
+                                      uint32_t id)
+{
+       DPLANE_CTX_VALID(ctx);
+
+       ctx->zd_notif_provider = id;
+}
+
+void dplane_ctx_set_type(struct zebra_dplane_ctx *ctx, int type)
+{
+       DPLANE_CTX_VALID(ctx);
+
+       ctx->u.rinfo.zd_type = type;
+}
+
 int dplane_ctx_get_type(const struct zebra_dplane_ctx *ctx)
 {
        DPLANE_CTX_VALID(ctx);
@@ -687,6 +762,13 @@ int dplane_ctx_get_old_type(const struct zebra_dplane_ctx *ctx)
        return ctx->u.rinfo.zd_old_type;
 }
 
+void dplane_ctx_set_afi(struct zebra_dplane_ctx *ctx, afi_t afi)
+{
+       DPLANE_CTX_VALID(ctx);
+
+       ctx->u.rinfo.zd_afi = afi;
+}
+
 afi_t dplane_ctx_get_afi(const struct zebra_dplane_ctx *ctx)
 {
        DPLANE_CTX_VALID(ctx);
@@ -694,6 +776,13 @@ afi_t dplane_ctx_get_afi(const struct zebra_dplane_ctx *ctx)
        return ctx->u.rinfo.zd_afi;
 }
 
+void dplane_ctx_set_safi(struct zebra_dplane_ctx *ctx, safi_t safi)
+{
+       DPLANE_CTX_VALID(ctx);
+
+       ctx->u.rinfo.zd_safi = safi;
+}
+
 safi_t dplane_ctx_get_safi(const struct zebra_dplane_ctx *ctx)
 {
        DPLANE_CTX_VALID(ctx);
@@ -701,6 +790,13 @@ safi_t dplane_ctx_get_safi(const struct zebra_dplane_ctx *ctx)
        return ctx->u.rinfo.zd_safi;
 }
 
+void dplane_ctx_set_table(struct zebra_dplane_ctx *ctx, uint32_t table)
+{
+       DPLANE_CTX_VALID(ctx);
+
+       ctx->zd_table_id = table;
+}
+
 uint32_t dplane_ctx_get_table(const struct zebra_dplane_ctx *ctx)
 {
        DPLANE_CTX_VALID(ctx);
@@ -715,6 +811,13 @@ route_tag_t dplane_ctx_get_tag(const struct zebra_dplane_ctx *ctx)
        return ctx->u.rinfo.zd_tag;
 }
 
+void dplane_ctx_set_tag(struct zebra_dplane_ctx *ctx, route_tag_t tag)
+{
+       DPLANE_CTX_VALID(ctx);
+
+       ctx->u.rinfo.zd_tag = tag;
+}
+
 route_tag_t dplane_ctx_get_old_tag(const struct zebra_dplane_ctx *ctx)
 {
        DPLANE_CTX_VALID(ctx);
@@ -729,6 +832,13 @@ uint16_t dplane_ctx_get_instance(const struct zebra_dplane_ctx *ctx)
        return ctx->u.rinfo.zd_instance;
 }
 
+void dplane_ctx_set_instance(struct zebra_dplane_ctx *ctx, uint16_t instance)
+{
+       DPLANE_CTX_VALID(ctx);
+
+       ctx->u.rinfo.zd_instance = instance;
+}
+
 uint16_t dplane_ctx_get_old_instance(const struct zebra_dplane_ctx *ctx)
 {
        DPLANE_CTX_VALID(ctx);
@@ -771,6 +881,13 @@ uint8_t dplane_ctx_get_distance(const struct zebra_dplane_ctx *ctx)
        return ctx->u.rinfo.zd_distance;
 }
 
+void dplane_ctx_set_distance(struct zebra_dplane_ctx *ctx, uint8_t distance)
+{
+       DPLANE_CTX_VALID(ctx);
+
+       ctx->u.rinfo.zd_distance = distance;
+}
+
 uint8_t dplane_ctx_get_old_distance(const struct zebra_dplane_ctx *ctx)
 {
        DPLANE_CTX_VALID(ctx);
@@ -778,6 +895,17 @@ uint8_t dplane_ctx_get_old_distance(const struct zebra_dplane_ctx *ctx)
        return ctx->u.rinfo.zd_old_distance;
 }
 
+void dplane_ctx_set_nexthops(struct zebra_dplane_ctx *ctx, struct nexthop *nh)
+{
+       DPLANE_CTX_VALID(ctx);
+
+       if (ctx->u.rinfo.zd_ng.nexthop) {
+               nexthops_free(ctx->u.rinfo.zd_ng.nexthop);
+               ctx->u.rinfo.zd_ng.nexthop = NULL;
+       }
+       copy_nexthops(&(ctx->u.rinfo.zd_ng.nexthop), nh, NULL);
+}
+
 const struct nexthop_group *dplane_ctx_get_ng(
        const struct zebra_dplane_ctx *ctx)
 {
@@ -811,6 +939,13 @@ mpls_label_t dplane_ctx_get_in_label(const struct zebra_dplane_ctx *ctx)
        return ctx->u.lsp.ile.in_label;
 }
 
+void dplane_ctx_set_in_label(struct zebra_dplane_ctx *ctx, mpls_label_t label)
+{
+       DPLANE_CTX_VALID(ctx);
+
+       ctx->u.lsp.ile.in_label = label;
+}
+
 uint8_t dplane_ctx_get_addr_family(const struct zebra_dplane_ctx *ctx)
 {
        DPLANE_CTX_VALID(ctx);
@@ -818,6 +953,14 @@ uint8_t dplane_ctx_get_addr_family(const struct zebra_dplane_ctx *ctx)
        return ctx->u.lsp.addr_family;
 }
 
+void dplane_ctx_set_addr_family(struct zebra_dplane_ctx *ctx,
+                               uint8_t family)
+{
+       DPLANE_CTX_VALID(ctx);
+
+       ctx->u.lsp.addr_family = family;
+}
+
 uint32_t dplane_ctx_get_lsp_flags(const struct zebra_dplane_ctx *ctx)
 {
        DPLANE_CTX_VALID(ctx);
@@ -825,6 +968,14 @@ uint32_t dplane_ctx_get_lsp_flags(const struct zebra_dplane_ctx *ctx)
        return ctx->u.lsp.flags;
 }
 
+void dplane_ctx_set_lsp_flags(struct zebra_dplane_ctx *ctx,
+                             uint32_t flags)
+{
+       DPLANE_CTX_VALID(ctx);
+
+       ctx->u.lsp.flags = flags;
+}
+
 const zebra_nhlfe_t *dplane_ctx_get_nhlfe(const struct zebra_dplane_ctx *ctx)
 {
        DPLANE_CTX_VALID(ctx);
@@ -832,6 +983,24 @@ const zebra_nhlfe_t *dplane_ctx_get_nhlfe(const struct zebra_dplane_ctx *ctx)
        return ctx->u.lsp.nhlfe_list;
 }
 
+zebra_nhlfe_t *dplane_ctx_add_nhlfe(struct zebra_dplane_ctx *ctx,
+                                   enum lsp_types_t lsp_type,
+                                   enum nexthop_types_t nh_type,
+                                   union g_addr *gate,
+                                   ifindex_t ifindex,
+                                   mpls_label_t out_label)
+{
+       zebra_nhlfe_t *nhlfe;
+
+       DPLANE_CTX_VALID(ctx);
+
+       nhlfe = zebra_mpls_lsp_add_nhlfe(&(ctx->u.lsp),
+                                        lsp_type, nh_type, gate,
+                                        ifindex, out_label);
+
+       return nhlfe;
+}
+
 const zebra_nhlfe_t *
 dplane_ctx_get_best_nhlfe(const struct zebra_dplane_ctx *ctx)
 {
@@ -840,6 +1009,16 @@ dplane_ctx_get_best_nhlfe(const struct zebra_dplane_ctx *ctx)
        return ctx->u.lsp.best_nhlfe;
 }
 
+const zebra_nhlfe_t *
+dplane_ctx_set_best_nhlfe(struct zebra_dplane_ctx *ctx,
+                         zebra_nhlfe_t *nhlfe)
+{
+       DPLANE_CTX_VALID(ctx);
+
+       ctx->u.lsp.best_nhlfe = nhlfe;
+       return ctx->u.lsp.best_nhlfe;
+}
+
 uint32_t dplane_ctx_get_lsp_num_ecmp(const struct zebra_dplane_ctx *ctx)
 {
        DPLANE_CTX_VALID(ctx);
@@ -1496,6 +1675,59 @@ done:
        return ret;
 }
 
+/*
+ * Update from an async notification, to bring other fibs up-to-date.
+ */
+enum zebra_dplane_result
+dplane_route_notif_update(struct route_node *rn,
+                         struct route_entry *re,
+                         enum dplane_op_e op,
+                         struct zebra_dplane_ctx *ctx)
+{
+       enum zebra_dplane_result ret = ZEBRA_DPLANE_REQUEST_FAILURE;
+       struct zebra_dplane_ctx *new_ctx = NULL;
+       struct nexthop *nexthop;
+
+       if (rn == NULL || re == NULL)
+               goto done;
+
+       new_ctx = dplane_ctx_alloc();
+       if (new_ctx == NULL)
+               goto done;
+
+       /* Init context with info from zebra data structs */
+       dplane_ctx_route_init(new_ctx, op, rn, re);
+
+       /* For add/update, need to adjust the nexthops so that we match
+        * the notification state, which may not be the route-entry/RIB
+        * state.
+        */
+       if (op == DPLANE_OP_ROUTE_UPDATE ||
+           op == DPLANE_OP_ROUTE_INSTALL) {
+
+               nexthops_free(new_ctx->u.rinfo.zd_ng.nexthop);
+               new_ctx->u.rinfo.zd_ng.nexthop = NULL;
+
+               copy_nexthops(&(new_ctx->u.rinfo.zd_ng.nexthop),
+                             (rib_active_nhg(re))->nexthop, NULL);
+
+               for (ALL_NEXTHOPS(new_ctx->u.rinfo.zd_ng, nexthop))
+                       UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
+
+       }
+
+       /* Capture info about the source of the notification, in 'ctx' */
+       dplane_ctx_set_notif_provider(new_ctx,
+                                     dplane_ctx_get_notif_provider(ctx));
+
+       dplane_route_enqueue(new_ctx);
+
+       ret = ZEBRA_DPLANE_REQUEST_QUEUED;
+
+done:
+       return ret;
+}
+
 /*
  * Enqueue LSP add for the dataplane.
  */
@@ -1529,6 +1761,50 @@ enum zebra_dplane_result dplane_lsp_delete(zebra_lsp_t *lsp)
        return ret;
 }
 
+/* Update or un-install resulting from an async notification */
+enum zebra_dplane_result
+dplane_lsp_notif_update(zebra_lsp_t *lsp,
+                       enum dplane_op_e op,
+                       struct zebra_dplane_ctx *notif_ctx)
+{
+       enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE;
+       int ret = EINVAL;
+       struct zebra_dplane_ctx *ctx = NULL;
+
+       /* Obtain context block */
+       ctx = dplane_ctx_alloc();
+       if (ctx == NULL) {
+               ret = ENOMEM;
+               goto done;
+       }
+
+       ret = dplane_ctx_lsp_init(ctx, op, lsp);
+       if (ret != AOK)
+               goto done;
+
+       /* Capture info about the source of the notification */
+       dplane_ctx_set_notif_provider(
+               ctx,
+               dplane_ctx_get_notif_provider(notif_ctx));
+
+       ret = dplane_route_enqueue(ctx);
+
+done:
+       /* Update counter */
+       atomic_fetch_add_explicit(&zdplane_info.dg_lsps_in, 1,
+                                 memory_order_relaxed);
+
+       if (ret == AOK)
+               result = ZEBRA_DPLANE_REQUEST_QUEUED;
+       else {
+               atomic_fetch_add_explicit(&zdplane_info.dg_lsp_errors, 1,
+                                         memory_order_relaxed);
+               if (ctx)
+                       dplane_ctx_free(&ctx);
+       }
+       return result;
+}
+
 /*
  * Enqueue pseudowire install for the dataplane.
  */
@@ -1823,6 +2099,7 @@ int dplane_show_provs_helper(struct vty *vty, bool detailed)
 int dplane_provider_register(const char *name,
                             enum dplane_provider_prio prio,
                             int flags,
+                            int (*start_fp)(struct zebra_dplane_provider *),
                             int (*fp)(struct zebra_dplane_provider *),
                             int (*fini_fp)(struct zebra_dplane_provider *,
                                            bool early),
@@ -1853,6 +2130,7 @@ int dplane_provider_register(const char *name,
 
        p->dp_priority = prio;
        p->dp_fp = fp;
+       p->dp_start = start_fp;
        p->dp_fini = fini_fp;
        p->dp_data = data;
 
@@ -2045,6 +2323,20 @@ int dplane_provider_work_ready(void)
        return AOK;
 }
 
+/*
+ * Enqueue a context directly to zebra main.
+ */
+void dplane_provider_enqueue_to_zebra(struct zebra_dplane_ctx *ctx)
+{
+       struct dplane_ctx_q temp_list;
+
+       /* Zebra's api takes a list, so we need to use a temporary list */
+       TAILQ_INIT(&temp_list);
+
+       TAILQ_INSERT_TAIL(&temp_list, ctx, zd_q_entries);
+       (zdplane_info.dg_results_cb)(&temp_list);
+}
+
 /*
  * Kernel dataplane provider
  */
@@ -2207,9 +2499,11 @@ static int kernel_dplane_process_func(struct zebra_dplane_provider *prov)
                        res = kernel_dplane_address_update(ctx);
                        break;
 
-               /* Ignore system 'notifications' - the kernel already knows */
+               /* Ignore 'notifications' - no-op */
                case DPLANE_OP_SYS_ROUTE_ADD:
                case DPLANE_OP_SYS_ROUTE_DELETE:
+               case DPLANE_OP_ROUTE_NOTIFY:
+               case DPLANE_OP_LSP_NOTIFY:
                        res = ZEBRA_DPLANE_REQUEST_SUCCESS;
                        break;
 
@@ -2320,7 +2614,7 @@ static void dplane_provider_init(void)
 
        ret = dplane_provider_register("Kernel",
                                       DPLANE_PRIO_KERNEL,
-                                      DPLANE_PROV_FLAGS_DEFAULT,
+                                      DPLANE_PROV_FLAGS_DEFAULT, NULL,
                                       kernel_dplane_process_func,
                                       NULL,
                                       NULL, NULL);
@@ -2333,7 +2627,7 @@ static void dplane_provider_init(void)
        /* Optional test provider ... */
        ret = dplane_provider_register("Test",
                                       DPLANE_PRIO_PRE_KERNEL,
-                                      DPLANE_PROV_FLAGS_DEFAULT,
+                                      DPLANE_PROV_FLAGS_DEFAULT, NULL,
                                       test_dplane_process_func,
                                       test_dplane_shutdown_func,
                                       NULL /* data */, NULL);
@@ -2652,7 +2946,6 @@ static int dplane_thread_loop(struct thread *event)
 
        TAILQ_INIT(&error_list);
 
-
        /* Call through to zebra main */
        (zdplane_info.dg_results_cb)(&work_list);
 
@@ -2717,13 +3010,14 @@ static void zebra_dplane_init_internal(void)
  */
 void zebra_dplane_start(void)
 {
-       /* Start dataplane pthread */
-
+       struct zebra_dplane_provider *prov;
        struct frr_pthread_attr pattr = {
                .start = frr_pthread_attr_default.start,
                .stop = frr_pthread_attr_default.stop
        };
 
+       /* Start dataplane pthread */
+
        zdplane_info.dg_pthread = frr_pthread_new(&pattr, "Zebra dplane thread",
                                                  "Zebra dplane");
 
@@ -2735,6 +3029,23 @@ void zebra_dplane_start(void)
        thread_add_event(zdplane_info.dg_master, dplane_thread_loop, NULL, 0,
                         &zdplane_info.dg_t_update);
 
+       /* Call start callbacks for registered providers */
+
+       DPLANE_LOCK();
+       prov = TAILQ_FIRST(&zdplane_info.dg_providers_q);
+       DPLANE_UNLOCK();
+
+       while (prov) {
+
+               if (prov->dp_start)
+                       (prov->dp_start)(prov);
+
+               /* Locate next provider */
+               DPLANE_LOCK();
+               prov = TAILQ_NEXT(prov, dp_prov_link);
+               DPLANE_UNLOCK();
+       }
+
        frr_pthread_run(zdplane_info.dg_pthread, NULL);
 }
 
index d45628fdd04c9be3dac3ce5053da5e07188dc4fc..6238026bcfcf542979da3a9695fd9b957426918c 100644 (file)
@@ -105,11 +105,13 @@ enum dplane_op_e {
        DPLANE_OP_ROUTE_INSTALL,
        DPLANE_OP_ROUTE_UPDATE,
        DPLANE_OP_ROUTE_DELETE,
+       DPLANE_OP_ROUTE_NOTIFY,
 
        /* LSP update */
        DPLANE_OP_LSP_INSTALL,
        DPLANE_OP_LSP_UPDATE,
        DPLANE_OP_LSP_DELETE,
+       DPLANE_OP_LSP_NOTIFY,
 
        /* Pseudowire update */
        DPLANE_OP_PW_INSTALL,
@@ -139,6 +141,9 @@ void dplane_enable_sys_route_notifs(void);
  */
 TAILQ_HEAD(dplane_ctx_q, zebra_dplane_ctx);
 
+/* Allocate a context object */
+struct zebra_dplane_ctx *dplane_ctx_alloc(void);
+
 /* Return a dataplane results context block after use; the caller's pointer will
  * be cleared.
  */
@@ -169,9 +174,12 @@ void dplane_ctx_set_status(struct zebra_dplane_ctx *ctx,
 const char *dplane_res2str(enum zebra_dplane_result res);
 
 enum dplane_op_e dplane_ctx_get_op(const struct zebra_dplane_ctx *ctx);
+void dplane_ctx_set_op(struct zebra_dplane_ctx *ctx, enum dplane_op_e op);
 const char *dplane_op2str(enum dplane_op_e op);
 
 const struct prefix *dplane_ctx_get_dest(const struct zebra_dplane_ctx *ctx);
+void dplane_ctx_set_dest(struct zebra_dplane_ctx *ctx,
+                        const struct prefix *dest);
 
 /* Retrieve last/current provider id */
 uint32_t dplane_ctx_get_provider(const struct zebra_dplane_ctx *ctx);
@@ -186,29 +194,44 @@ bool dplane_ctx_is_skip_kernel(const struct zebra_dplane_ctx *ctx);
  * to mean "no src prefix"
  */
 const struct prefix *dplane_ctx_get_src(const struct zebra_dplane_ctx *ctx);
+void dplane_ctx_set_src(struct zebra_dplane_ctx *ctx, const struct prefix *src);
 
 bool dplane_ctx_is_update(const struct zebra_dplane_ctx *ctx);
 uint32_t dplane_ctx_get_seq(const struct zebra_dplane_ctx *ctx);
 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);
 
+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);
+uint32_t dplane_ctx_get_notif_provider(const struct zebra_dplane_ctx *ctx);
+
 /* Accessors for route update information */
+void dplane_ctx_set_type(struct zebra_dplane_ctx *ctx, int type);
 int dplane_ctx_get_type(const struct zebra_dplane_ctx *ctx);
 int dplane_ctx_get_old_type(const struct zebra_dplane_ctx *ctx);
+void dplane_ctx_set_afi(struct zebra_dplane_ctx *ctx, afi_t afi);
 afi_t dplane_ctx_get_afi(const struct zebra_dplane_ctx *ctx);
+void dplane_ctx_set_safi(struct zebra_dplane_ctx *ctx, safi_t safi);
 safi_t dplane_ctx_get_safi(const struct zebra_dplane_ctx *ctx);
+void dplane_ctx_set_table(struct zebra_dplane_ctx *ctx, uint32_t table);
 uint32_t dplane_ctx_get_table(const struct zebra_dplane_ctx *ctx);
 route_tag_t dplane_ctx_get_tag(const struct zebra_dplane_ctx *ctx);
+void dplane_ctx_set_tag(struct zebra_dplane_ctx *ctx, route_tag_t tag);
 route_tag_t dplane_ctx_get_old_tag(const struct zebra_dplane_ctx *ctx);
 uint16_t dplane_ctx_get_instance(const struct zebra_dplane_ctx *ctx);
+void dplane_ctx_set_instance(struct zebra_dplane_ctx *ctx, uint16_t instance);
 uint16_t dplane_ctx_get_old_instance(const struct zebra_dplane_ctx *ctx);
 uint32_t dplane_ctx_get_metric(const struct zebra_dplane_ctx *ctx);
 uint32_t dplane_ctx_get_old_metric(const struct zebra_dplane_ctx *ctx);
 uint32_t dplane_ctx_get_mtu(const struct zebra_dplane_ctx *ctx);
 uint32_t dplane_ctx_get_nh_mtu(const struct zebra_dplane_ctx *ctx);
 uint8_t dplane_ctx_get_distance(const struct zebra_dplane_ctx *ctx);
+void dplane_ctx_set_distance(struct zebra_dplane_ctx *ctx, uint8_t distance);
 uint8_t dplane_ctx_get_old_distance(const struct zebra_dplane_ctx *ctx);
 
+void dplane_ctx_set_nexthops(struct zebra_dplane_ctx *ctx, struct nexthop *nh);
 const struct nexthop_group *dplane_ctx_get_ng(
        const struct zebra_dplane_ctx *ctx);
 const struct nexthop_group *dplane_ctx_get_old_ng(
@@ -216,11 +239,26 @@ const struct nexthop_group *dplane_ctx_get_old_ng(
 
 /* Accessors for LSP information */
 mpls_label_t dplane_ctx_get_in_label(const struct zebra_dplane_ctx *ctx);
+void dplane_ctx_set_in_label(struct zebra_dplane_ctx *ctx,
+                            mpls_label_t label);
 uint8_t dplane_ctx_get_addr_family(const struct zebra_dplane_ctx *ctx);
+void dplane_ctx_set_addr_family(struct zebra_dplane_ctx *ctx,
+                               uint8_t family);
 uint32_t dplane_ctx_get_lsp_flags(const struct zebra_dplane_ctx *ctx);
+void dplane_ctx_set_lsp_flags(struct zebra_dplane_ctx *ctx,
+                             uint32_t flags);
 const zebra_nhlfe_t *dplane_ctx_get_nhlfe(const struct zebra_dplane_ctx *ctx);
+zebra_nhlfe_t *dplane_ctx_add_nhlfe(struct zebra_dplane_ctx *ctx,
+                                   enum lsp_types_t lsp_type,
+                                   enum nexthop_types_t nh_type,
+                                   union g_addr *gate,
+                                   ifindex_t ifindex,
+                                   mpls_label_t out_label);
+
 const zebra_nhlfe_t *dplane_ctx_get_best_nhlfe(
        const struct zebra_dplane_ctx *ctx);
+const zebra_nhlfe_t *dplane_ctx_set_best_nhlfe(struct zebra_dplane_ctx *ctx,
+                                              zebra_nhlfe_t *nhlfe);
 uint32_t dplane_ctx_get_lsp_num_ecmp(const struct zebra_dplane_ctx *ctx);
 
 /* Accessors for pseudowire information */
@@ -282,6 +320,13 @@ enum zebra_dplane_result dplane_sys_route_add(struct route_node *rn,
 enum zebra_dplane_result dplane_sys_route_del(struct route_node *rn,
                                              struct route_entry *re);
 
+/* Update from an async notification, to bring other fibs up-to-date */
+enum zebra_dplane_result dplane_route_notif_update(
+       struct route_node *rn,
+       struct route_entry *re,
+       enum dplane_op_e op,
+       struct zebra_dplane_ctx *ctx);
+
 /*
  * Enqueue LSP change operations for the dataplane.
  */
@@ -289,6 +334,11 @@ enum zebra_dplane_result dplane_lsp_add(zebra_lsp_t *lsp);
 enum zebra_dplane_result dplane_lsp_update(zebra_lsp_t *lsp);
 enum zebra_dplane_result dplane_lsp_delete(zebra_lsp_t *lsp);
 
+/* Update or un-install resulting from an async notification */
+enum zebra_dplane_result dplane_lsp_notif_update(zebra_lsp_t *lsp,
+                                                enum dplane_op_e op,
+                                                struct zebra_dplane_ctx *ctx);
+
 /*
  * Enqueue pseudowire operations for the dataplane.
  */
@@ -321,7 +371,6 @@ uint32_t dplane_get_in_queue_len(void);
 int dplane_show_helper(struct vty *vty, bool detailed);
 int dplane_show_provs_helper(struct vty *vty, bool detailed);
 
-
 /*
  * Dataplane providers: modules that process or consume dataplane events.
  */
@@ -363,7 +412,13 @@ enum dplane_provider_prio {
  * then checks the provider's outbound queue for completed work.
  */
 
-/* Providers offer an entry-point for shutdown and cleanup. This is called
+/*
+ * Providers can offer a 'start' callback; if present, the dataplane will
+ * call it when it is starting - when its pthread and event-scheduling
+ * thread_master are available.
+ */
+
+/* Providers can offer an entry-point for shutdown and cleanup. This is called
  * with 'early' during shutdown, to indicate that the dataplane subsystem
  * is allowing work to move through the providers and finish.
  * When called without 'early', the provider should release
@@ -372,6 +427,7 @@ enum dplane_provider_prio {
 int dplane_provider_register(const char *name,
                             enum dplane_provider_prio prio,
                             int flags,
+                            int (*start_fp)(struct zebra_dplane_provider *),
                             int (*fp)(struct zebra_dplane_provider *),
                             int (*fini_fp)(struct zebra_dplane_provider *,
                                            bool early),
@@ -409,10 +465,13 @@ struct zebra_dplane_ctx *dplane_provider_dequeue_in_ctx(
 int dplane_provider_dequeue_in_list(struct zebra_dplane_provider *prov,
                                    struct dplane_ctx_q *listp);
 
-/* Enqueue, maintain associated counter and locking */
+/* Enqueue completed work, maintain associated counter and locking */
 void dplane_provider_enqueue_out_ctx(struct zebra_dplane_provider *prov,
                                     struct zebra_dplane_ctx *ctx);
 
+/* Enqueue a context directly to zebra main. */
+void dplane_provider_enqueue_to_zebra(struct zebra_dplane_ctx *ctx);
+
 /*
  * Initialize the dataplane modules at zebra startup. This is currently called
  * by the rib module. Zebra registers a results callback with the dataplane.
index 5356a7f498de3ef60fc82c2afde806e7b7ccd6ef..5214f1f22d26cb8a7613bdc6b4caa3f4ad8b5204 100644 (file)
@@ -1693,8 +1693,9 @@ static char *snhlfe2str(zebra_snhlfe_t *snhlfe, char *buf, int size)
        case NEXTHOP_TYPE_IPV6_IFINDEX:
                inet_ntop(AF_INET6, &snhlfe->gate.ipv6, buf, size);
                if (snhlfe->ifindex)
-                       strcat(buf,
-                              ifindex2ifname(snhlfe->ifindex, VRF_DEFAULT));
+                       strlcat(buf,
+                               ifindex2ifname(snhlfe->ifindex, VRF_DEFAULT),
+                               size);
                break;
        default:
                break;
@@ -1809,6 +1810,214 @@ void zebra_mpls_lsp_dplane_result(struct zebra_dplane_ctx *ctx)
        dplane_ctx_fini(&ctx);
 }
 
+/*
+ * Process async dplane notifications.
+ */
+void zebra_mpls_process_dplane_notify(struct zebra_dplane_ctx *ctx)
+{
+       struct zebra_vrf *zvrf;
+       zebra_ile_t tmp_ile;
+       struct hash *lsp_table;
+       zebra_lsp_t *lsp;
+       zebra_nhlfe_t *nhlfe;
+       const zebra_nhlfe_t *ctx_nhlfe;
+       struct nexthop *nexthop;
+       const struct nexthop *ctx_nexthop;
+       int start_count = 0, end_count = 0; /* Installed counts */
+       bool changed_p = false;
+       bool is_debug = (IS_ZEBRA_DEBUG_DPLANE | IS_ZEBRA_DEBUG_MPLS);
+
+       if (is_debug)
+               zlog_debug("LSP dplane notif, in-label %u",
+                          dplane_ctx_get_in_label(ctx));
+
+       /* Look for zebra LSP object */
+       zvrf = vrf_info_lookup(VRF_DEFAULT);
+       if (zvrf == NULL)
+               goto done;
+
+       lsp_table = zvrf->lsp_table;
+
+       tmp_ile.in_label = dplane_ctx_get_in_label(ctx);
+       lsp = hash_lookup(lsp_table, &tmp_ile);
+       if (lsp == NULL) {
+               if (is_debug)
+                       zlog_debug("dplane LSP notif: in-label %u not found",
+                                  dplane_ctx_get_in_label(ctx));
+               goto done;
+       }
+
+       /*
+        * The dataplane/forwarding plane is notifying zebra about the state
+        * of the nexthops associated with this LSP. First, we take a
+        * pre-scan pass to determine whether the LSP has transitioned
+        * from installed -> uninstalled. In that case, we need to have
+        * the existing state of the LSP objects available before making
+        * any changes.
+        */
+       for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) {
+               char buf[NEXTHOP_STRLEN];
+
+               nexthop = nhlfe->nexthop;
+               if (!nexthop)
+                       continue;
+
+               if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB))
+                       start_count++;
+
+               ctx_nexthop = NULL;
+               for (ctx_nhlfe = dplane_ctx_get_nhlfe(ctx);
+                    ctx_nhlfe; ctx_nhlfe = ctx_nhlfe->next) {
+
+                       ctx_nexthop = ctx_nhlfe->nexthop;
+                       if (!ctx_nexthop)
+                               continue;
+
+                       if ((ctx_nexthop->type == nexthop->type) &&
+                           nexthop_same(ctx_nexthop, nexthop)) {
+                               /* Matched */
+                               break;
+                       }
+               }
+
+               if (is_debug)
+                       nexthop2str(nexthop, buf, sizeof(buf));
+
+               if (ctx_nhlfe && ctx_nexthop) {
+                       if (is_debug) {
+                               const char *tstr = "";
+
+                               if (!CHECK_FLAG(ctx_nhlfe->flags,
+                                               NHLFE_FLAG_INSTALLED))
+                                       tstr = "not ";
+
+                               zlog_debug("LSP dplane notif: matched nh %s (%sinstalled)",
+                                          buf, tstr);
+                       }
+
+                       /* Test zebra nhlfe install state */
+                       if (CHECK_FLAG(ctx_nhlfe->flags,
+                                      NHLFE_FLAG_INSTALLED)) {
+
+                               if (!CHECK_FLAG(nhlfe->flags,
+                                               NHLFE_FLAG_INSTALLED))
+                                       changed_p = true;
+
+                               /* Update counter */
+                               end_count++;
+                       } else {
+
+                               if (CHECK_FLAG(nhlfe->flags,
+                                              NHLFE_FLAG_INSTALLED))
+                                       changed_p = true;
+                       }
+
+               } else {
+                       /* Not mentioned in lfib set -> uninstalled */
+                       if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED) ||
+                           CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE) ||
+                           CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)) {
+                               changed_p = true;
+                       }
+
+                       if (is_debug)
+                               zlog_debug("LSP dplane notif: no match, nh %s",
+                                          buf);
+               }
+       }
+
+       if (is_debug)
+               zlog_debug("LSP dplane notif: lfib start_count %d, end_count %d%s",
+                          start_count, end_count,
+                          changed_p ? ", changed" : "");
+
+       /*
+        * Has the LSP become uninstalled?
+        */
+       if (start_count > 0 && end_count == 0) {
+               /* Inform other lfibs */
+               dplane_lsp_notif_update(lsp, DPLANE_OP_LSP_DELETE, ctx);
+       }
+
+       /*
+        * Now we take a second pass and bring the zebra
+        * nexthop state into sync with the forwarding-plane state.
+        */
+       for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) {
+               char buf[NEXTHOP_STRLEN];
+
+               nexthop = nhlfe->nexthop;
+               if (!nexthop)
+                       continue;
+
+               ctx_nexthop = NULL;
+               for (ctx_nhlfe = dplane_ctx_get_nhlfe(ctx);
+                    ctx_nhlfe; ctx_nhlfe = ctx_nhlfe->next) {
+
+                       ctx_nexthop = ctx_nhlfe->nexthop;
+                       if (!ctx_nexthop)
+                               continue;
+
+                       if ((ctx_nexthop->type == nexthop->type) &&
+                           nexthop_same(ctx_nexthop, nexthop)) {
+                               /* Matched */
+                               break;
+                       }
+               }
+
+               if (is_debug)
+                       nexthop2str(nexthop, buf, sizeof(buf));
+
+               if (ctx_nhlfe && ctx_nexthop) {
+
+                       /* Bring zebra nhlfe install state into sync */
+                       if (CHECK_FLAG(ctx_nhlfe->flags,
+                                      NHLFE_FLAG_INSTALLED)) {
+
+                               SET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
+
+                       } else {
+
+                               UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
+                       }
+
+                       if (CHECK_FLAG(ctx_nhlfe->nexthop->flags,
+                                      NEXTHOP_FLAG_FIB)) {
+                               SET_FLAG(nhlfe->nexthop->flags,
+                                        NEXTHOP_FLAG_ACTIVE);
+                               SET_FLAG(nhlfe->nexthop->flags,
+                                        NEXTHOP_FLAG_FIB);
+                       } else {
+                               UNSET_FLAG(nhlfe->nexthop->flags,
+                                        NEXTHOP_FLAG_ACTIVE);
+                               UNSET_FLAG(nhlfe->nexthop->flags,
+                                          NEXTHOP_FLAG_FIB);
+                       }
+
+               } else {
+                       /* Not mentioned in lfib set -> uninstalled */
+
+                       UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED);
+                       UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
+                       UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+               }
+       }
+
+       if (end_count > 0) {
+               SET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
+
+               if (changed_p)
+                       dplane_lsp_notif_update(lsp, DPLANE_OP_LSP_UPDATE, ctx);
+
+       } else {
+               UNSET_FLAG(lsp->flags, LSP_FLAG_INSTALLED);
+               clear_nhlfe_installed(lsp);
+       }
+
+done:
+       dplane_ctx_fini(&ctx);
+}
+
 /*
  * Install dynamic LSP entry.
  */
index 3a131e1aaf1224ca637ef7573e1f4370c69ebbfd..d983221cb533fbda2019132e8a0558aefd7adbcd 100644 (file)
@@ -352,6 +352,9 @@ struct zebra_dplane_ctx;
 
 void zebra_mpls_lsp_dplane_result(struct zebra_dplane_ctx *ctx);
 
+/* Process async dplane notifications. */
+void zebra_mpls_process_dplane_notify(struct zebra_dplane_ctx *ctx);
+
 /*
  * Schedule all MPLS label forwarding entries for processing.
  * Called upon changes that may affect one or more of them such as
diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c
new file mode 100644 (file)
index 0000000..caab06d
--- /dev/null
@@ -0,0 +1,511 @@
+/* Zebra Nexthop Group Code.
+ * Copyright (C) 2019 Cumulus Networks, Inc.
+ *                    Donald Sharp
+ *                    Stephen Worley
+ *
+ * This file is part of FRR.
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with FRR; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+#include <zebra.h>
+
+#include "lib/nexthop.h"
+#include "lib/routemap.h"
+
+#include "zebra/connected.h"
+#include "zebra/debug.h"
+#include "zebra/zebra_router.h"
+#include "zebra/zebra_nhg.h"
+#include "zebra/zebra_rnh.h"
+#include "zebra/zebra_routemap.h"
+#include "zebra/rt.h"
+
+static void nexthop_set_resolved(afi_t afi, const struct nexthop *newhop,
+                                struct nexthop *nexthop)
+{
+       struct nexthop *resolved_hop;
+
+       resolved_hop = nexthop_new();
+       SET_FLAG(resolved_hop->flags, NEXTHOP_FLAG_ACTIVE);
+
+       resolved_hop->vrf_id = nexthop->vrf_id;
+       switch (newhop->type) {
+       case NEXTHOP_TYPE_IPV4:
+       case NEXTHOP_TYPE_IPV4_IFINDEX:
+               /* If the resolving route specifies a gateway, use it */
+               resolved_hop->type = newhop->type;
+               resolved_hop->gate.ipv4 = newhop->gate.ipv4;
+
+               if (newhop->ifindex) {
+                       resolved_hop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
+                       resolved_hop->ifindex = newhop->ifindex;
+               }
+               break;
+       case NEXTHOP_TYPE_IPV6:
+       case NEXTHOP_TYPE_IPV6_IFINDEX:
+               resolved_hop->type = newhop->type;
+               resolved_hop->gate.ipv6 = newhop->gate.ipv6;
+
+               if (newhop->ifindex) {
+                       resolved_hop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
+                       resolved_hop->ifindex = newhop->ifindex;
+               }
+               break;
+       case NEXTHOP_TYPE_IFINDEX:
+               /* If the resolving route is an interface route,
+                * it means the gateway we are looking up is connected
+                * to that interface. (The actual network is _not_ onlink).
+                * Therefore, the resolved route should have the original
+                * gateway as nexthop as it is directly connected.
+                *
+                * On Linux, we have to set the onlink netlink flag because
+                * otherwise, the kernel won't accept the route.
+                */
+               resolved_hop->flags |= NEXTHOP_FLAG_ONLINK;
+               if (afi == AFI_IP) {
+                       resolved_hop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
+                       resolved_hop->gate.ipv4 = nexthop->gate.ipv4;
+               } else if (afi == AFI_IP6) {
+                       resolved_hop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
+                       resolved_hop->gate.ipv6 = nexthop->gate.ipv6;
+               }
+               resolved_hop->ifindex = newhop->ifindex;
+               break;
+       case NEXTHOP_TYPE_BLACKHOLE:
+               resolved_hop->type = NEXTHOP_TYPE_BLACKHOLE;
+               resolved_hop->bh_type = nexthop->bh_type;
+               break;
+       }
+
+       if (newhop->flags & NEXTHOP_FLAG_ONLINK)
+               resolved_hop->flags |= NEXTHOP_FLAG_ONLINK;
+
+       /* Copy labels of the resolved route */
+       if (newhop->nh_label)
+               nexthop_add_labels(resolved_hop, newhop->nh_label_type,
+                                  newhop->nh_label->num_labels,
+                                  &newhop->nh_label->label[0]);
+
+       resolved_hop->rparent = nexthop;
+       nexthop_add(&nexthop->resolved, resolved_hop);
+}
+
+/*
+ * Given a nexthop we need to properly recursively resolve
+ * the route.  As such, do a table lookup to find and match
+ * if at all possible.  Set the nexthop->ifindex as appropriate
+ */
+static int nexthop_active(afi_t afi, struct route_entry *re,
+                         struct nexthop *nexthop, struct route_node *top)
+{
+       struct prefix p;
+       struct route_table *table;
+       struct route_node *rn;
+       struct route_entry *match = NULL;
+       int resolved;
+       struct nexthop *newhop;
+       struct interface *ifp;
+       rib_dest_t *dest;
+
+       if ((nexthop->type == NEXTHOP_TYPE_IPV4)
+           || nexthop->type == NEXTHOP_TYPE_IPV6)
+               nexthop->ifindex = 0;
+
+       UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
+       nexthops_free(nexthop->resolved);
+       nexthop->resolved = NULL;
+       re->nexthop_mtu = 0;
+
+       /*
+        * If the kernel has sent us a route, then
+        * by golly gee whiz it's a good route.
+        */
+       if (re->type == ZEBRA_ROUTE_KERNEL || re->type == ZEBRA_ROUTE_SYSTEM)
+               return 1;
+
+       /*
+        * Check to see if we should trust the passed in information
+        * for UNNUMBERED interfaces as that we won't find the GW
+        * address in the routing table.
+        * This check should suffice to handle IPv4 or IPv6 routes
+        * sourced from EVPN routes which are installed with the
+        * next hop as the remote VTEP IP.
+        */
+       if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)) {
+               ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id);
+               if (!ifp) {
+                       if (IS_ZEBRA_DEBUG_RIB_DETAILED)
+                               zlog_debug(
+                                       "\t%s: Onlink and interface: %u[%u] does not exist",
+                                       __PRETTY_FUNCTION__, nexthop->ifindex,
+                                       nexthop->vrf_id);
+                       return 0;
+               }
+               if (connected_is_unnumbered(ifp)) {
+                       if (if_is_operative(ifp))
+                               return 1;
+                       else {
+                               if (IS_ZEBRA_DEBUG_RIB_DETAILED)
+                                       zlog_debug(
+                                               "\t%s: Onlink and interface %s is not operative",
+                                               __PRETTY_FUNCTION__, ifp->name);
+                               return 0;
+                       }
+               }
+               if (!if_is_operative(ifp)) {
+                       if (IS_ZEBRA_DEBUG_RIB_DETAILED)
+                               zlog_debug(
+                                       "\t%s: Interface %s is not unnumbered",
+                                       __PRETTY_FUNCTION__, ifp->name);
+                       return 0;
+               }
+       }
+
+       /* Make lookup prefix. */
+       memset(&p, 0, sizeof(struct prefix));
+       switch (afi) {
+       case AFI_IP:
+               p.family = AF_INET;
+               p.prefixlen = IPV4_MAX_PREFIXLEN;
+               p.u.prefix4 = nexthop->gate.ipv4;
+               break;
+       case AFI_IP6:
+               p.family = AF_INET6;
+               p.prefixlen = IPV6_MAX_PREFIXLEN;
+               p.u.prefix6 = nexthop->gate.ipv6;
+               break;
+       default:
+               assert(afi != AFI_IP && afi != AFI_IP6);
+               break;
+       }
+       /* Lookup table.  */
+       table = zebra_vrf_table(afi, SAFI_UNICAST, nexthop->vrf_id);
+       if (!table) {
+               if (IS_ZEBRA_DEBUG_RIB_DETAILED)
+                       zlog_debug("\t%s: Table not found",
+                                  __PRETTY_FUNCTION__);
+               return 0;
+       }
+
+       rn = route_node_match(table, (struct prefix *)&p);
+       while (rn) {
+               route_unlock_node(rn);
+
+               /* Lookup should halt if we've matched against ourselves ('top',
+                * if specified) - i.e., we cannot have a nexthop NH1 is
+                * resolved by a route NH1. The exception is if the route is a
+                * host route.
+                */
+               if (top && rn == top)
+                       if (((afi == AFI_IP) && (rn->p.prefixlen != 32))
+                           || ((afi == AFI_IP6) && (rn->p.prefixlen != 128))) {
+                               if (IS_ZEBRA_DEBUG_RIB_DETAILED)
+                                       zlog_debug(
+                                               "\t%s: Matched against ourself and prefix length is not max bit length",
+                                               __PRETTY_FUNCTION__);
+                               return 0;
+                       }
+
+               /* Pick up selected route. */
+               /* However, do not resolve over default route unless explicitly
+                * allowed. */
+               if (is_default_prefix(&rn->p)
+                   && !rnh_resolve_via_default(p.family)) {
+                       if (IS_ZEBRA_DEBUG_RIB_DETAILED)
+                               zlog_debug(
+                                       "\t:%s: Resolved against default route",
+                                       __PRETTY_FUNCTION__);
+                       return 0;
+               }
+
+               dest = rib_dest_from_rnode(rn);
+               if (dest && dest->selected_fib
+                   && !CHECK_FLAG(dest->selected_fib->status,
+                                  ROUTE_ENTRY_REMOVED)
+                   && dest->selected_fib->type != ZEBRA_ROUTE_TABLE)
+                       match = dest->selected_fib;
+
+               /* If there is no selected route or matched route is EGP, go up
+                  tree. */
+               if (!match) {
+                       do {
+                               rn = rn->parent;
+                       } while (rn && rn->info == NULL);
+                       if (rn)
+                               route_lock_node(rn);
+
+                       continue;
+               }
+
+               if (match->type == ZEBRA_ROUTE_CONNECT) {
+                       /* Directly point connected route. */
+                       newhop = match->ng.nexthop;
+                       if (newhop) {
+                               if (nexthop->type == NEXTHOP_TYPE_IPV4
+                                   || nexthop->type == NEXTHOP_TYPE_IPV6)
+                                       nexthop->ifindex = newhop->ifindex;
+                       }
+                       return 1;
+               } else if (CHECK_FLAG(re->flags, ZEBRA_FLAG_ALLOW_RECURSION)) {
+                       resolved = 0;
+                       for (ALL_NEXTHOPS(match->ng, newhop)) {
+                               if (!CHECK_FLAG(match->status,
+                                               ROUTE_ENTRY_INSTALLED))
+                                       continue;
+                               if (CHECK_FLAG(newhop->flags,
+                                              NEXTHOP_FLAG_RECURSIVE))
+                                       continue;
+
+                               SET_FLAG(nexthop->flags,
+                                        NEXTHOP_FLAG_RECURSIVE);
+                               SET_FLAG(re->status,
+                                        ROUTE_ENTRY_NEXTHOPS_CHANGED);
+                               nexthop_set_resolved(afi, newhop, nexthop);
+                               resolved = 1;
+                       }
+                       if (resolved)
+                               re->nexthop_mtu = match->mtu;
+                       if (!resolved && IS_ZEBRA_DEBUG_RIB_DETAILED)
+                               zlog_debug("\t%s: Recursion failed to find",
+                                          __PRETTY_FUNCTION__);
+                       return resolved;
+               } else if (re->type == ZEBRA_ROUTE_STATIC) {
+                       resolved = 0;
+                       for (ALL_NEXTHOPS(match->ng, newhop)) {
+                               if (!CHECK_FLAG(match->status,
+                                               ROUTE_ENTRY_INSTALLED))
+                                       continue;
+                               if (CHECK_FLAG(newhop->flags,
+                                              NEXTHOP_FLAG_RECURSIVE))
+                                       continue;
+
+                               SET_FLAG(nexthop->flags,
+                                        NEXTHOP_FLAG_RECURSIVE);
+                               nexthop_set_resolved(afi, newhop, nexthop);
+                               resolved = 1;
+                       }
+                       if (resolved)
+                               re->nexthop_mtu = match->mtu;
+
+                       if (!resolved && IS_ZEBRA_DEBUG_RIB_DETAILED)
+                               zlog_debug(
+                                       "\t%s: Static route unable to resolve",
+                                       __PRETTY_FUNCTION__);
+                       return resolved;
+               } else {
+                       if (IS_ZEBRA_DEBUG_RIB_DETAILED) {
+                               zlog_debug(
+                                       "\t%s: Route Type %s has not turned on recursion",
+                                       __PRETTY_FUNCTION__,
+                                       zebra_route_string(re->type));
+                               if (re->type == ZEBRA_ROUTE_BGP
+                                   && !CHECK_FLAG(re->flags, ZEBRA_FLAG_IBGP))
+                                       zlog_debug(
+                                               "\tEBGP: see \"disable-ebgp-connected-route-check\" or \"disable-connected-check\"");
+                       }
+                       return 0;
+               }
+       }
+       if (IS_ZEBRA_DEBUG_RIB_DETAILED)
+               zlog_debug("\t%s: Nexthop did not lookup in table",
+                          __PRETTY_FUNCTION__);
+       return 0;
+}
+
+/* This function verifies reachability of one given nexthop, which can be
+ * numbered or unnumbered, IPv4 or IPv6. The result is unconditionally stored
+ * in nexthop->flags field. The nexthop->ifindex will be updated
+ * appropriately as well.  An existing route map can turn
+ * (otherwise active) nexthop into inactive, but not vice versa.
+ *
+ * The return value is the final value of 'ACTIVE' flag.
+ */
+static unsigned nexthop_active_check(struct route_node *rn,
+                                    struct route_entry *re,
+                                    struct nexthop *nexthop)
+{
+       struct interface *ifp;
+       route_map_result_t ret = RMAP_PERMITMATCH;
+       int family;
+       char buf[SRCDEST2STR_BUFFER];
+       const struct prefix *p, *src_p;
+       struct zebra_vrf *zvrf;
+
+       srcdest_rnode_prefixes(rn, &p, &src_p);
+
+       if (rn->p.family == AF_INET)
+               family = AFI_IP;
+       else if (rn->p.family == AF_INET6)
+               family = AFI_IP6;
+       else
+               family = 0;
+       switch (nexthop->type) {
+       case NEXTHOP_TYPE_IFINDEX:
+               ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id);
+               if (ifp && if_is_operative(ifp))
+                       SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+               else
+                       UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+               break;
+       case NEXTHOP_TYPE_IPV4:
+       case NEXTHOP_TYPE_IPV4_IFINDEX:
+               family = AFI_IP;
+               if (nexthop_active(AFI_IP, re, nexthop, rn))
+                       SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+               else
+                       UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+               break;
+       case NEXTHOP_TYPE_IPV6:
+               family = AFI_IP6;
+               if (nexthop_active(AFI_IP6, re, nexthop, rn))
+                       SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+               else
+                       UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+               break;
+       case NEXTHOP_TYPE_IPV6_IFINDEX:
+               /* RFC 5549, v4 prefix with v6 NH */
+               if (rn->p.family != AF_INET)
+                       family = AFI_IP6;
+               if (IN6_IS_ADDR_LINKLOCAL(&nexthop->gate.ipv6)) {
+                       ifp = if_lookup_by_index(nexthop->ifindex,
+                                                nexthop->vrf_id);
+                       if (ifp && if_is_operative(ifp))
+                               SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+                       else
+                               UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+               } else {
+                       if (nexthop_active(AFI_IP6, re, nexthop, rn))
+                               SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+                       else
+                               UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+               }
+               break;
+       case NEXTHOP_TYPE_BLACKHOLE:
+               SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+               break;
+       default:
+               break;
+       }
+       if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) {
+               if (IS_ZEBRA_DEBUG_RIB_DETAILED)
+                       zlog_debug("\t%s: Unable to find a active nexthop",
+                                  __PRETTY_FUNCTION__);
+               return 0;
+       }
+
+       /* XXX: What exactly do those checks do? Do we support
+        * e.g. IPv4 routes with IPv6 nexthops or vice versa?
+        */
+       if (RIB_SYSTEM_ROUTE(re) || (family == AFI_IP && p->family != AF_INET)
+           || (family == AFI_IP6 && p->family != AF_INET6))
+               return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+
+       /* The original code didn't determine the family correctly
+        * e.g. for NEXTHOP_TYPE_IFINDEX. Retrieve the correct afi
+        * from the rib_table_info in those cases.
+        * Possibly it may be better to use only the rib_table_info
+        * in every case.
+        */
+       if (!family) {
+               rib_table_info_t *info;
+
+               info = srcdest_rnode_table_info(rn);
+               family = info->afi;
+       }
+
+       memset(&nexthop->rmap_src.ipv6, 0, sizeof(union g_addr));
+
+       zvrf = zebra_vrf_lookup_by_id(nexthop->vrf_id);
+       if (!zvrf) {
+               if (IS_ZEBRA_DEBUG_RIB_DETAILED)
+                       zlog_debug("\t%s: zvrf is NULL", __PRETTY_FUNCTION__);
+               return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+       }
+
+       /* It'll get set if required inside */
+       ret = zebra_route_map_check(family, re->type, re->instance, p, nexthop,
+                                   zvrf, re->tag);
+       if (ret == RMAP_DENYMATCH) {
+               if (IS_ZEBRA_DEBUG_RIB) {
+                       srcdest_rnode2str(rn, buf, sizeof(buf));
+                       zlog_debug(
+                               "%u:%s: Filtering out with NH out %s due to route map",
+                               re->vrf_id, buf,
+                               ifindex2ifname(nexthop->ifindex,
+                                              nexthop->vrf_id));
+               }
+               UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+       }
+       return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+}
+
+/*
+ * Iterate over all nexthops of the given RIB entry and refresh their
+ * ACTIVE flag. re->nexthop_active_num is updated accordingly. If any
+ * nexthop is found to toggle the ACTIVE flag, the whole re structure
+ * is flagged with ROUTE_ENTRY_CHANGED.
+ *
+ * Return value is the new number of active nexthops.
+ */
+int nexthop_active_update(struct route_node *rn, struct route_entry *re)
+{
+       struct nexthop *nexthop;
+       union g_addr prev_src;
+       unsigned int prev_active, new_active;
+       ifindex_t prev_index;
+
+       re->nexthop_active_num = 0;
+       UNSET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
+
+       for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next) {
+               /* No protocol daemon provides src and so we're skipping
+                * tracking it */
+               prev_src = nexthop->rmap_src;
+               prev_active = CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+               prev_index = nexthop->ifindex;
+               /*
+                * We need to respect the multipath_num here
+                * as that what we should be able to install from
+                * a multipath perpsective should not be a data plane
+                * decision point.
+                */
+               new_active = nexthop_active_check(rn, re, nexthop);
+               if (new_active
+                   && re->nexthop_active_num >= zrouter.multipath_num) {
+                       UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
+                       new_active = 0;
+               }
+               if (new_active)
+                       re->nexthop_active_num++;
+               /* Don't allow src setting on IPv6 addr for now */
+               if (prev_active != new_active || prev_index != nexthop->ifindex
+                   || ((nexthop->type >= NEXTHOP_TYPE_IFINDEX
+                        && nexthop->type < NEXTHOP_TYPE_IPV6)
+                       && prev_src.ipv4.s_addr
+                                  != nexthop->rmap_src.ipv4.s_addr)
+                   || ((nexthop->type >= NEXTHOP_TYPE_IPV6
+                        && nexthop->type < NEXTHOP_TYPE_BLACKHOLE)
+                       && !(IPV6_ADDR_SAME(&prev_src.ipv6,
+                                           &nexthop->rmap_src.ipv6)))
+                   || CHECK_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED)) {
+                       SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
+                       SET_FLAG(re->status, ROUTE_ENTRY_NEXTHOPS_CHANGED);
+               }
+       }
+
+       return re->nexthop_active_num;
+}
+
diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h
new file mode 100644 (file)
index 0000000..ff2351c
--- /dev/null
@@ -0,0 +1,29 @@
+/* Zebra Nexthop Group header.
+ * Copyright (C) 2019 Cumulus Networks, Inc.
+ *                    Donald Sharp
+ *                    Stephen Worley
+ *
+ * This file is part of FRR.
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with FRR; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+#ifndef __ZEBRA_NHG_H__
+#define __ZEBRA_NHG_H__
+
+#include "zebra/rib.h"
+
+extern int nexthop_active_update(struct route_node *rn, struct route_entry *re);
+#endif
index b31b6a12508b491073e7a61694bdd4042a6670f4..83eb5f42230f3dbda0a96c0ae74d303e5cab9d27 100644 (file)
@@ -54,6 +54,7 @@
 #include "zebra/zebra_vxlan.h"
 #include "zebra/zapi_msg.h"
 #include "zebra/zebra_dplane.h"
+#include "zebra/zebra_nhg.h"
 
 /*
  * Event, list, and mutex for delivery of dataplane results
@@ -128,7 +129,7 @@ _rnode_zlog(const char *_func, vrf_id_t vrf_id, struct route_node *rn,
                srcdest_rnode2str(rn, buf, sizeof(buf));
 
                if (info->safi == SAFI_MULTICAST)
-                       strcat(buf, " (MRIB)");
+                       strlcat(buf, " (MRIB)", sizeof(buf));
        } else {
                snprintf(buf, sizeof(buf), "{(route_node *) NULL}");
        }
@@ -336,298 +337,6 @@ struct nexthop *route_entry_nexthop_blackhole_add(struct route_entry *re,
        return nexthop;
 }
 
-static void nexthop_set_resolved(afi_t afi, const struct nexthop *newhop,
-                                struct nexthop *nexthop)
-{
-       struct nexthop *resolved_hop;
-
-       resolved_hop = nexthop_new();
-       SET_FLAG(resolved_hop->flags, NEXTHOP_FLAG_ACTIVE);
-
-       resolved_hop->vrf_id = nexthop->vrf_id;
-       switch (newhop->type) {
-       case NEXTHOP_TYPE_IPV4:
-       case NEXTHOP_TYPE_IPV4_IFINDEX:
-               /* If the resolving route specifies a gateway, use it */
-               resolved_hop->type = newhop->type;
-               resolved_hop->gate.ipv4 = newhop->gate.ipv4;
-
-               if (newhop->ifindex) {
-                       resolved_hop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
-                       resolved_hop->ifindex = newhop->ifindex;
-               }
-               break;
-       case NEXTHOP_TYPE_IPV6:
-       case NEXTHOP_TYPE_IPV6_IFINDEX:
-               resolved_hop->type = newhop->type;
-               resolved_hop->gate.ipv6 = newhop->gate.ipv6;
-
-               if (newhop->ifindex) {
-                       resolved_hop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
-                       resolved_hop->ifindex = newhop->ifindex;
-               }
-               break;
-       case NEXTHOP_TYPE_IFINDEX:
-               /* If the resolving route is an interface route,
-                * it means the gateway we are looking up is connected
-                * to that interface. (The actual network is _not_ onlink).
-                * Therefore, the resolved route should have the original
-                * gateway as nexthop as it is directly connected.
-                *
-                * On Linux, we have to set the onlink netlink flag because
-                * otherwise, the kernel won't accept the route.
-                */
-               resolved_hop->flags |= NEXTHOP_FLAG_ONLINK;
-               if (afi == AFI_IP) {
-                       resolved_hop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
-                       resolved_hop->gate.ipv4 = nexthop->gate.ipv4;
-               } else if (afi == AFI_IP6) {
-                       resolved_hop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
-                       resolved_hop->gate.ipv6 = nexthop->gate.ipv6;
-               }
-               resolved_hop->ifindex = newhop->ifindex;
-               break;
-       case NEXTHOP_TYPE_BLACKHOLE:
-               resolved_hop->type = NEXTHOP_TYPE_BLACKHOLE;
-               resolved_hop->bh_type = nexthop->bh_type;
-               break;
-       }
-
-       if (newhop->flags & NEXTHOP_FLAG_ONLINK)
-               resolved_hop->flags |= NEXTHOP_FLAG_ONLINK;
-
-       /* Copy labels of the resolved route */
-       if (newhop->nh_label)
-               nexthop_add_labels(resolved_hop, newhop->nh_label_type,
-                                  newhop->nh_label->num_labels,
-                                  &newhop->nh_label->label[0]);
-
-       resolved_hop->rparent = nexthop;
-       nexthop_add(&nexthop->resolved, resolved_hop);
-}
-
-/*
- * Given a nexthop we need to properly recursively resolve
- * the route.  As such, do a table lookup to find and match
- * if at all possible.  Set the nexthop->ifindex as appropriate
- */
-static int nexthop_active(afi_t afi, struct route_entry *re,
-                         struct nexthop *nexthop,
-                         struct route_node *top)
-{
-       struct prefix p;
-       struct route_table *table;
-       struct route_node *rn;
-       struct route_entry *match = NULL;
-       int resolved;
-       struct nexthop *newhop;
-       struct interface *ifp;
-       rib_dest_t *dest;
-
-       if ((nexthop->type == NEXTHOP_TYPE_IPV4)
-           || nexthop->type == NEXTHOP_TYPE_IPV6)
-               nexthop->ifindex = 0;
-
-       UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
-       nexthops_free(nexthop->resolved);
-       nexthop->resolved = NULL;
-       re->nexthop_mtu = 0;
-
-       /*
-        * If the kernel has sent us a route, then
-        * by golly gee whiz it's a good route.
-        */
-       if (re->type == ZEBRA_ROUTE_KERNEL ||
-           re->type == ZEBRA_ROUTE_SYSTEM)
-               return 1;
-
-       /*
-        * Check to see if we should trust the passed in information
-        * for UNNUMBERED interfaces as that we won't find the GW
-        * address in the routing table.
-        * This check should suffice to handle IPv4 or IPv6 routes
-        * sourced from EVPN routes which are installed with the
-        * next hop as the remote VTEP IP.
-        */
-       if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)) {
-               ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id);
-               if (!ifp) {
-                       if (IS_ZEBRA_DEBUG_RIB_DETAILED)
-                               zlog_debug(
-                                       "\t%s: Onlink and interface: %u[%u] does not exist",
-                                       __PRETTY_FUNCTION__, nexthop->ifindex,
-                                       nexthop->vrf_id);
-                       return 0;
-               }
-               if (connected_is_unnumbered(ifp)) {
-                       if (if_is_operative(ifp))
-                               return 1;
-                       else {
-                               if (IS_ZEBRA_DEBUG_RIB_DETAILED)
-                                       zlog_debug(
-                                               "\t%s: Onlink and interface %s is not operative",
-                                               __PRETTY_FUNCTION__, ifp->name);
-                               return 0;
-                       }
-               }
-               if (!if_is_operative(ifp)) {
-                       if (IS_ZEBRA_DEBUG_RIB_DETAILED)
-                               zlog_debug(
-                                       "\t%s: Interface %s is not unnumbered",
-                                       __PRETTY_FUNCTION__, ifp->name);
-                       return 0;
-               }
-       }
-
-       /* Make lookup prefix. */
-       memset(&p, 0, sizeof(struct prefix));
-       switch (afi) {
-       case AFI_IP:
-               p.family = AF_INET;
-               p.prefixlen = IPV4_MAX_PREFIXLEN;
-               p.u.prefix4 = nexthop->gate.ipv4;
-               break;
-       case AFI_IP6:
-               p.family = AF_INET6;
-               p.prefixlen = IPV6_MAX_PREFIXLEN;
-               p.u.prefix6 = nexthop->gate.ipv6;
-               break;
-       default:
-               assert(afi != AFI_IP && afi != AFI_IP6);
-               break;
-       }
-       /* Lookup table.  */
-       table = zebra_vrf_table(afi, SAFI_UNICAST, nexthop->vrf_id);
-       if (!table) {
-               if (IS_ZEBRA_DEBUG_RIB_DETAILED)
-                       zlog_debug("\t%s: Table not found",
-                                  __PRETTY_FUNCTION__);
-               return 0;
-       }
-
-       rn = route_node_match(table, (struct prefix *)&p);
-       while (rn) {
-               route_unlock_node(rn);
-
-               /* Lookup should halt if we've matched against ourselves ('top',
-                * if specified) - i.e., we cannot have a nexthop NH1 is
-                * resolved by a route NH1. The exception is if the route is a
-                * host route.
-                */
-               if (top && rn == top)
-                       if (((afi == AFI_IP) && (rn->p.prefixlen != 32))
-                           || ((afi == AFI_IP6) && (rn->p.prefixlen != 128))) {
-                               if (IS_ZEBRA_DEBUG_RIB_DETAILED)
-                                       zlog_debug(
-                                               "\t%s: Matched against ourself and prefix length is not max bit length",
-                                               __PRETTY_FUNCTION__);
-                               return 0;
-                       }
-
-               /* Pick up selected route. */
-               /* However, do not resolve over default route unless explicitly
-                * allowed. */
-               if (is_default_prefix(&rn->p)
-                   && !rnh_resolve_via_default(p.family)) {
-                       if (IS_ZEBRA_DEBUG_RIB_DETAILED)
-                               zlog_debug(
-                                       "\t:%s: Resolved against default route",
-                                       __PRETTY_FUNCTION__);
-                       return 0;
-               }
-
-               dest = rib_dest_from_rnode(rn);
-               if (dest && dest->selected_fib
-                   && !CHECK_FLAG(dest->selected_fib->status,
-                                  ROUTE_ENTRY_REMOVED)
-                   && dest->selected_fib->type != ZEBRA_ROUTE_TABLE)
-                       match = dest->selected_fib;
-
-               /* If there is no selected route or matched route is EGP, go up
-                  tree. */
-               if (!match) {
-                       do {
-                               rn = rn->parent;
-                       } while (rn && rn->info == NULL);
-                       if (rn)
-                               route_lock_node(rn);
-
-                       continue;
-               }
-
-               if (match->type == ZEBRA_ROUTE_CONNECT) {
-                       /* Directly point connected route. */
-                       newhop = match->ng.nexthop;
-                       if (newhop) {
-                               if (nexthop->type == NEXTHOP_TYPE_IPV4
-                                   || nexthop->type == NEXTHOP_TYPE_IPV6)
-                                       nexthop->ifindex = newhop->ifindex;
-                       }
-                       return 1;
-               } else if (CHECK_FLAG(re->flags, ZEBRA_FLAG_ALLOW_RECURSION)) {
-                       resolved = 0;
-                       for (ALL_NEXTHOPS(match->ng, newhop)) {
-                               if (!CHECK_FLAG(match->status,
-                                               ROUTE_ENTRY_INSTALLED))
-                                       continue;
-                               if (CHECK_FLAG(newhop->flags,
-                                              NEXTHOP_FLAG_RECURSIVE))
-                                       continue;
-
-                               SET_FLAG(nexthop->flags,
-                                        NEXTHOP_FLAG_RECURSIVE);
-                               SET_FLAG(re->status,
-                                        ROUTE_ENTRY_NEXTHOPS_CHANGED);
-                               nexthop_set_resolved(afi, newhop, nexthop);
-                               resolved = 1;
-                       }
-                       if (resolved)
-                               re->nexthop_mtu = match->mtu;
-                       if (!resolved && IS_ZEBRA_DEBUG_RIB_DETAILED)
-                               zlog_debug("\t%s: Recursion failed to find",
-                                          __PRETTY_FUNCTION__);
-                       return resolved;
-               } else if (re->type == ZEBRA_ROUTE_STATIC) {
-                       resolved = 0;
-                       for (ALL_NEXTHOPS(match->ng, newhop)) {
-                               if (!CHECK_FLAG(match->status,
-                                               ROUTE_ENTRY_INSTALLED))
-                                       continue;
-                               if (CHECK_FLAG(newhop->flags,
-                                              NEXTHOP_FLAG_RECURSIVE))
-                                       continue;
-
-                               SET_FLAG(nexthop->flags,
-                                        NEXTHOP_FLAG_RECURSIVE);
-                               nexthop_set_resolved(afi, newhop, nexthop);
-                               resolved = 1;
-                       }
-                       if (resolved)
-                               re->nexthop_mtu = match->mtu;
-
-                       if (!resolved && IS_ZEBRA_DEBUG_RIB_DETAILED)
-                               zlog_debug(
-                                       "\t%s: Static route unable to resolve",
-                                       __PRETTY_FUNCTION__);
-                       return resolved;
-               } else {
-                       if (IS_ZEBRA_DEBUG_RIB_DETAILED) {
-                               zlog_debug("\t%s: Route Type %s has not turned on recursion",
-                                          __PRETTY_FUNCTION__,
-                                          zebra_route_string(re->type));
-                               if (re->type == ZEBRA_ROUTE_BGP &&
-                                   !CHECK_FLAG(re->flags, ZEBRA_FLAG_IBGP))
-                                       zlog_debug("\tEBGP: see \"disable-ebgp-connected-route-check\" or \"disable-connected-check\"");
-                       }
-                       return 0;
-               }
-       }
-       if (IS_ZEBRA_DEBUG_RIB_DETAILED)
-               zlog_debug("\t%s: Nexthop did not lookup in table",
-                          __PRETTY_FUNCTION__);
-       return 0;
-}
-
 struct route_entry *rib_match(afi_t afi, safi_t safi, vrf_id_t vrf_id,
                              union g_addr *addr, struct route_node **rn_out)
 {
@@ -798,190 +507,6 @@ struct route_entry *rib_lookup_ipv4(struct prefix_ipv4 *p, vrf_id_t vrf_id)
        return NULL;
 }
 
-/* This function verifies reachability of one given nexthop, which can be
- * numbered or unnumbered, IPv4 or IPv6. The result is unconditionally stored
- * in nexthop->flags field. The nexthop->ifindex will be updated
- * appropriately as well.  An existing route map can turn
- * (otherwise active) nexthop into inactive, but not vice versa.
- *
- * The return value is the final value of 'ACTIVE' flag.
- */
-static unsigned nexthop_active_check(struct route_node *rn,
-                                    struct route_entry *re,
-                                    struct nexthop *nexthop)
-{
-       struct interface *ifp;
-       route_map_result_t ret = RMAP_MATCH;
-       int family;
-       char buf[SRCDEST2STR_BUFFER];
-       const struct prefix *p, *src_p;
-       struct zebra_vrf *zvrf;
-
-       srcdest_rnode_prefixes(rn, &p, &src_p);
-
-       if (rn->p.family == AF_INET)
-               family = AFI_IP;
-       else if (rn->p.family == AF_INET6)
-               family = AFI_IP6;
-       else
-               family = 0;
-       switch (nexthop->type) {
-       case NEXTHOP_TYPE_IFINDEX:
-               ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id);
-               if (ifp && if_is_operative(ifp))
-                       SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
-               else
-                       UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
-               break;
-       case NEXTHOP_TYPE_IPV4:
-       case NEXTHOP_TYPE_IPV4_IFINDEX:
-               family = AFI_IP;
-               if (nexthop_active(AFI_IP, re, nexthop, rn))
-                       SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
-               else
-                       UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
-               break;
-       case NEXTHOP_TYPE_IPV6:
-               family = AFI_IP6;
-               if (nexthop_active(AFI_IP6, re, nexthop, rn))
-                       SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
-               else
-                       UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
-               break;
-       case NEXTHOP_TYPE_IPV6_IFINDEX:
-               /* RFC 5549, v4 prefix with v6 NH */
-               if (rn->p.family != AF_INET)
-                       family = AFI_IP6;
-               if (IN6_IS_ADDR_LINKLOCAL(&nexthop->gate.ipv6)) {
-                       ifp = if_lookup_by_index(nexthop->ifindex,
-                                                nexthop->vrf_id);
-                       if (ifp && if_is_operative(ifp))
-                               SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
-                       else
-                               UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
-               } else {
-                       if (nexthop_active(AFI_IP6, re, nexthop, rn))
-                               SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
-                       else
-                               UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
-               }
-               break;
-       case NEXTHOP_TYPE_BLACKHOLE:
-               SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
-               break;
-       default:
-               break;
-       }
-       if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) {
-               if (IS_ZEBRA_DEBUG_RIB_DETAILED)
-                       zlog_debug("\t%s: Unable to find a active nexthop",
-                                  __PRETTY_FUNCTION__);
-               return 0;
-       }
-
-       /* XXX: What exactly do those checks do? Do we support
-        * e.g. IPv4 routes with IPv6 nexthops or vice versa?
-        */
-       if (RIB_SYSTEM_ROUTE(re) || (family == AFI_IP && p->family != AF_INET)
-           || (family == AFI_IP6 && p->family != AF_INET6))
-               return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
-
-       /* The original code didn't determine the family correctly
-        * e.g. for NEXTHOP_TYPE_IFINDEX. Retrieve the correct afi
-        * from the rib_table_info in those cases.
-        * Possibly it may be better to use only the rib_table_info
-        * in every case.
-        */
-       if (!family) {
-               rib_table_info_t *info;
-
-               info = srcdest_rnode_table_info(rn);
-               family = info->afi;
-       }
-
-       memset(&nexthop->rmap_src.ipv6, 0, sizeof(union g_addr));
-
-       zvrf = zebra_vrf_lookup_by_id(nexthop->vrf_id);
-       if (!zvrf) {
-               if (IS_ZEBRA_DEBUG_RIB_DETAILED)
-                       zlog_debug("\t%s: zvrf is NULL", __PRETTY_FUNCTION__);
-               return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
-       }
-
-       /* It'll get set if required inside */
-       ret = zebra_route_map_check(family, re->type, re->instance, p,
-                                   nexthop, zvrf, re->tag);
-       if (ret == RMAP_DENYMATCH) {
-               if (IS_ZEBRA_DEBUG_RIB) {
-                       srcdest_rnode2str(rn, buf, sizeof(buf));
-                       zlog_debug(
-                               "%u:%s: Filtering out with NH out %s due to route map",
-                               re->vrf_id, buf,
-                               ifindex2ifname(nexthop->ifindex,
-                                              nexthop->vrf_id));
-               }
-               UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
-       }
-       return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
-}
-
-/*
- * Iterate over all nexthops of the given RIB entry and refresh their
- * ACTIVE flag. re->nexthop_active_num is updated accordingly. If any
- * nexthop is found to toggle the ACTIVE flag, the whole re structure
- * is flagged with ROUTE_ENTRY_CHANGED.
- *
- * Return value is the new number of active nexthops.
- */
-static int nexthop_active_update(struct route_node *rn, struct route_entry *re)
-{
-       struct nexthop *nexthop;
-       union g_addr prev_src;
-       unsigned int prev_active, new_active;
-       ifindex_t prev_index;
-
-       re->nexthop_active_num = 0;
-       UNSET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
-
-       for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next) {
-               /* No protocol daemon provides src and so we're skipping
-                * tracking it */
-               prev_src = nexthop->rmap_src;
-               prev_active = CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
-               prev_index = nexthop->ifindex;
-               /*
-                * We need to respect the multipath_num here
-                * as that what we should be able to install from
-                * a multipath perpsective should not be a data plane
-                * decision point.
-                */
-               new_active = nexthop_active_check(rn, re, nexthop);
-               if (new_active
-                   && re->nexthop_active_num >= zrouter.multipath_num) {
-                       UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
-                       new_active = 0;
-               }
-               if (new_active)
-                       re->nexthop_active_num++;
-               /* Don't allow src setting on IPv6 addr for now */
-               if (prev_active != new_active || prev_index != nexthop->ifindex
-                   || ((nexthop->type >= NEXTHOP_TYPE_IFINDEX
-                        && nexthop->type < NEXTHOP_TYPE_IPV6)
-                       && prev_src.ipv4.s_addr
-                                  != nexthop->rmap_src.ipv4.s_addr)
-                   || ((nexthop->type >= NEXTHOP_TYPE_IPV6
-                        && nexthop->type < NEXTHOP_TYPE_BLACKHOLE)
-                       && !(IPV6_ADDR_SAME(&prev_src.ipv6,
-                                           &nexthop->rmap_src.ipv6)))
-                   || CHECK_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED)) {
-                       SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
-                       SET_FLAG(re->status, ROUTE_ENTRY_NEXTHOPS_CHANGED);
-               }
-       }
-
-       return re->nexthop_active_num;
-}
-
 /*
  * Is this RIB labeled-unicast? It must be of type BGP and all paths
  * (nexthops) must have a label.
@@ -1062,8 +587,25 @@ void rib_install_kernel(struct route_node *rn, struct route_entry *re,
        switch (ret) {
        case ZEBRA_DPLANE_REQUEST_QUEUED:
                SET_FLAG(re->status, ROUTE_ENTRY_QUEUED);
-               if (old)
+
+               if (old) {
                        SET_FLAG(old->status, ROUTE_ENTRY_QUEUED);
+
+                       /* Free old FIB nexthop group */
+                       if (old->fib_ng.nexthop) {
+                               nexthops_free(old->fib_ng.nexthop);
+                               old->fib_ng.nexthop = NULL;
+                       }
+
+                       if (!RIB_SYSTEM_ROUTE(old)) {
+                               /* Clear old route's FIB flags */
+                               for (ALL_NEXTHOPS(old->ng, nexthop)) {
+                                       UNSET_FLAG(nexthop->flags,
+                                                  NEXTHOP_FLAG_FIB);
+                               }
+                       }
+               }
+
                if (zvrf)
                        zvrf->installs_queued++;
                break;
@@ -1149,6 +691,12 @@ static void rib_uninstall(struct route_node *rn, struct route_entry *re)
 
                dest->selected_fib = NULL;
 
+               /* Free FIB nexthop group, if present */
+               if (re->fib_ng.nexthop) {
+                       nexthops_free(re->fib_ng.nexthop);
+                       re->fib_ng.nexthop = NULL;
+               }
+
                for (ALL_NEXTHOPS(re->ng, nexthop))
                        UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
        }
@@ -1841,21 +1389,239 @@ static void zebra_rib_fixup_system(struct route_node *rn)
 }
 
 /*
- * Route-update results processing after async dataplane update.
+ * Update a route from a dplane context. This consolidates common code
+ * that can be used in processing of results from FIB updates, and in
+ * async notification processing.
+ * The return is 'true' if the installed nexthops changed; 'false' otherwise.
  */
-static void rib_process_result(struct zebra_dplane_ctx *ctx)
+static bool rib_update_re_from_ctx(struct route_entry *re,
+                                  struct route_node *rn,
+                                  struct zebra_dplane_ctx *ctx)
+{
+       char dest_str[PREFIX_STRLEN] = "";
+       char nh_str[NEXTHOP_STRLEN];
+       struct nexthop *nexthop, *ctx_nexthop;
+       bool matched;
+       const struct nexthop_group *ctxnhg;
+       bool is_selected = false; /* Is 're' currently the selected re? */
+       bool changed_p = false; /* Change to nexthops? */
+       rib_dest_t *dest;
+
+       /* Note well: only capturing the prefix string if debug is enabled here;
+        * unconditional log messages will have to generate the string.
+        */
+       if (IS_ZEBRA_DEBUG_RIB)
+               prefix2str(&(rn->p), dest_str, sizeof(dest_str));
+
+       dest = rib_dest_from_rnode(rn);
+       if (dest)
+               is_selected = (re == dest->selected_fib);
+
+       if (IS_ZEBRA_DEBUG_RIB_DETAILED)
+               zlog_debug("update_from_ctx: %u:%s: %sSELECTED",
+                          re->vrf_id, dest_str, (is_selected ? "" : "NOT "));
+
+       /* Update zebra's nexthop FIB flag for each nexthop that was installed.
+        * If the installed set differs from the set requested by the rib/owner,
+        * we use the fib-specific nexthop-group to record the actual FIB
+        * status.
+        */
+
+       /*
+        * First check the fib nexthop-group, if it's present. The comparison
+        * here is quite strict: we require that the fib sets match exactly.
+        */
+       matched = false;
+       do {
+               if (re->fib_ng.nexthop == NULL)
+                       break;
+
+               matched = true;
+
+               /* First check the route's fib nexthops */
+               for (ALL_NEXTHOPS(re->fib_ng, nexthop)) {
+
+                       if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+                               continue;
+
+                       ctx_nexthop = NULL;
+                       for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx),
+                                             ctx_nexthop)) {
+                               if (nexthop_same(ctx_nexthop, nexthop))
+                                       break;
+                       }
+
+                       if (ctx_nexthop == NULL) {
+                               /* Nexthop not in the new installed set */
+                               if (IS_ZEBRA_DEBUG_RIB_DETAILED) {
+                                       nexthop2str(nexthop, nh_str,
+                                                   sizeof(nh_str));
+                                       zlog_debug("update_from_ctx: no match for fib nh %s",
+                                                  nh_str);
+                               }
+
+                               matched = false;
+                               break;
+                       }
+               }
+
+               if (!matched)
+                       break;
+
+               /* Check the new installed set */
+               ctx_nexthop = NULL;
+               for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx), ctx_nexthop)) {
+
+                       if (CHECK_FLAG(ctx_nexthop->flags,
+                                      NEXTHOP_FLAG_RECURSIVE))
+                               continue;
+
+                       /* Compare with the current group's nexthops */
+                       nexthop = NULL;
+                       for (ALL_NEXTHOPS(re->fib_ng, nexthop)) {
+                               if (nexthop_same(nexthop, ctx_nexthop))
+                                       break;
+                       }
+
+                       if (nexthop == NULL) {
+                               /* Nexthop not in the old installed set */
+                               if (IS_ZEBRA_DEBUG_RIB_DETAILED) {
+                                       nexthop2str(ctx_nexthop, nh_str,
+                                                   sizeof(nh_str));
+                                       zlog_debug("update_from_ctx: no fib match for notif nh %s",
+                                                  nh_str);
+                               }
+                               matched = false;
+                               break;
+                       }
+               }
+
+       } while (0);
+
+       /* If the new FIB set matches the existing FIB set, we're done. */
+       if (matched) {
+               if (IS_ZEBRA_DEBUG_RIB)
+                       zlog_debug("%u:%s update_from_ctx(): existing fib nhg, no change",
+                                  re->vrf_id, dest_str);
+               goto done;
+
+       } else if (re->fib_ng.nexthop) {
+               /*
+                * Free stale fib list and move on to check the rib nhg.
+                */
+               if (IS_ZEBRA_DEBUG_RIB)
+                       zlog_debug("%u:%s update_from_ctx(): replacing fib nhg",
+                                  re->vrf_id, dest_str);
+               nexthops_free(re->fib_ng.nexthop);
+               re->fib_ng.nexthop = NULL;
+
+               /* Note that the installed nexthops have changed */
+               changed_p = true;
+       } else {
+               if (IS_ZEBRA_DEBUG_RIB)
+                       zlog_debug("%u:%s update_from_ctx(): no fib nhg",
+                                  re->vrf_id, dest_str);
+       }
+
+       /*
+        * Compare with the rib nexthop group. The comparison here is different:
+        * the RIB group may be a superset of the list installed in the FIB. We
+        * walk the RIB group, looking for the 'installable' candidate
+        * nexthops, and then check those against the set
+        * that is actually installed.
+        */
+       matched = true;
+       for (ALL_NEXTHOPS(re->ng, nexthop)) {
+
+               if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+                       continue;
+
+               if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+                       continue;
+
+               /* Check for a FIB nexthop corresponding to the RIB nexthop */
+               ctx_nexthop = NULL;
+               for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx), ctx_nexthop)) {
+                       if (nexthop_same(ctx_nexthop, nexthop))
+                               break;
+               }
+
+               /* If the FIB doesn't know about the nexthop,
+                * it's not installed
+                */
+               if (ctx_nexthop == NULL) {
+                       if (IS_ZEBRA_DEBUG_RIB_DETAILED) {
+                               nexthop2str(nexthop, nh_str, sizeof(nh_str));
+                               zlog_debug("update_from_ctx: no notif match for rib nh %s",
+                                          nh_str);
+                       }
+                       matched = false;
+
+                       if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB))
+                               changed_p = true;
+
+                       UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
+                       break;
+               }
+
+               if (CHECK_FLAG(ctx_nexthop->flags, NEXTHOP_FLAG_FIB)) {
+                       if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB))
+                               changed_p = true;
+
+                       SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
+               } else {
+                       if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB))
+                               changed_p = true;
+
+                       UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
+               }
+       }
+
+       /* If all nexthops were processed, we're done */
+       if (matched) {
+               if (IS_ZEBRA_DEBUG_RIB)
+                       zlog_debug("%u:%s update_from_ctx(): rib nhg matched, changed '%s'",
+                                  re->vrf_id, dest_str,
+                                  (changed_p ? "true" : "false"));
+               goto done;
+       }
+
+       /* FIB nexthop set differs from the RIB set:
+        * create a fib-specific nexthop-group
+        */
+       if (IS_ZEBRA_DEBUG_RIB)
+               zlog_debug("%u:%s update_from_ctx(): changed %s, adding new fib nhg",
+                          re->vrf_id, dest_str,
+                          (changed_p ? "true" : "false"));
+
+       ctxnhg = dplane_ctx_get_ng(ctx);
+
+       if (ctxnhg->nexthop)
+               copy_nexthops(&(re->fib_ng.nexthop), ctxnhg->nexthop, NULL);
+       else {
+               /* Bit of a special case when the fib has _no_ installed
+                * nexthops.
+                */
+               nexthop = nexthop_new();
+               nexthop->type = NEXTHOP_TYPE_IPV4;
+               nexthop_add(&(re->fib_ng.nexthop), nexthop);
+       }
+
+done:
+       return changed_p;
+}
+
+/*
+ * Helper to locate a zebra route-node from a dplane context. This is used
+ * when processing dplane results, e.g. Note well: the route-node is returned
+ * with a ref held - route_unlock_node() must be called eventually.
+ */
+static struct route_node *
+rib_find_rn_from_ctx(const struct zebra_dplane_ctx *ctx)
 {
        struct route_table *table = NULL;
-       struct zebra_vrf *zvrf = NULL;
        struct route_node *rn = NULL;
-       struct route_entry *re = NULL, *old_re = NULL, *rib;
-       bool is_update = false;
-       struct nexthop *nexthop, *ctx_nexthop;
-       char dest_str[PREFIX_STRLEN] = "";
-       enum dplane_op_e op;
-       enum zebra_dplane_result status;
        const struct prefix *dest_pfx, *src_pfx;
-       uint32_t seq;
 
        /* Locate rn and re(s) from ctx */
 
@@ -1865,7 +1631,7 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx)
                                              dplane_ctx_get_table(ctx));
        if (table == NULL) {
                if (IS_ZEBRA_DEBUG_DPLANE) {
-                       zlog_debug("Failed to process dplane results: no table for afi %d, safi %d, vrf %u",
+                       zlog_debug("Failed to find route for ctx: no table for afi %d, safi %d, vrf %u",
                                   dplane_ctx_get_afi(ctx),
                                   dplane_ctx_get_safi(ctx),
                                   dplane_ctx_get_vrf(ctx));
@@ -1873,8 +1639,35 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx)
                goto done;
        }
 
-       zvrf = vrf_info_lookup(dplane_ctx_get_vrf(ctx));
+       dest_pfx = dplane_ctx_get_dest(ctx);
+       src_pfx = dplane_ctx_get_src(ctx);
+
+       rn = srcdest_rnode_get(table, dest_pfx,
+                              src_pfx ? (struct prefix_ipv6 *)src_pfx : NULL);
+
+done:
+       return rn;
+}
+
+
+
+/*
+ * Route-update results processing after async dataplane update.
+ */
+static void rib_process_result(struct zebra_dplane_ctx *ctx)
+{
+       struct zebra_vrf *zvrf = NULL;
+       struct route_node *rn = NULL;
+       struct route_entry *re = NULL, *old_re = NULL, *rib;
+       bool is_update = false;
+       char dest_str[PREFIX_STRLEN] = "";
+       enum dplane_op_e op;
+       enum zebra_dplane_result status;
+       const struct prefix *dest_pfx, *src_pfx;
+       uint32_t seq;
+       bool fib_changed = false;
 
+       zvrf = vrf_info_lookup(dplane_ctx_get_vrf(ctx));
        dest_pfx = dplane_ctx_get_dest(ctx);
 
        /* Note well: only capturing the prefix string if debug is enabled here;
@@ -1883,9 +1676,8 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx)
        if (IS_ZEBRA_DEBUG_DPLANE)
                prefix2str(dest_pfx, dest_str, sizeof(dest_str));
 
-       src_pfx = dplane_ctx_get_src(ctx);
-       rn = srcdest_rnode_get(table, dplane_ctx_get_dest(ctx),
-                              src_pfx ? (struct prefix_ipv6 *)src_pfx : NULL);
+       /* Locate rn and re(s) from ctx */
+       rn = rib_find_rn_from_ctx(ctx);
        if (rn == NULL) {
                if (IS_ZEBRA_DEBUG_DPLANE) {
                        zlog_debug("Failed to process dplane results: no route for %u:%s",
@@ -1979,34 +1771,25 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx)
                                UNSET_FLAG(old_re->status,
                                           ROUTE_ENTRY_INSTALLED);
                        }
-                       /* Update zebra nexthop FIB flag for each
-                        * nexthop that was installed.
-                        */
-                       for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx),
-                                             ctx_nexthop)) {
-
-                               if (!re)
-                                       continue;
 
-                               for (ALL_NEXTHOPS(re->ng, nexthop)) {
-                                       if (nexthop_same(ctx_nexthop, nexthop))
-                                               break;
+                       /* Update zebra route based on the results in
+                        * the context struct.
+                        */
+                       if (re) {
+                               fib_changed =
+                                       rib_update_re_from_ctx(re, rn, ctx);
+
+                               if (!fib_changed) {
+                                       if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
+                                               zlog_debug("%u:%s no fib change for re",
+                                                          dplane_ctx_get_vrf(
+                                                                  ctx),
+                                                          dest_str);
                                }
 
-                               if (nexthop == NULL)
-                                       continue;
-
-                               if (CHECK_FLAG(nexthop->flags,
-                                              NEXTHOP_FLAG_RECURSIVE))
-                                       continue;
-
-                               if (CHECK_FLAG(ctx_nexthop->flags,
-                                              NEXTHOP_FLAG_FIB))
-                                       SET_FLAG(nexthop->flags,
-                                                NEXTHOP_FLAG_FIB);
-                               else
-                                       UNSET_FLAG(nexthop->flags,
-                                                  NEXTHOP_FLAG_FIB);
+                               /* Redistribute */
+                               redistribute_update(dest_pfx, src_pfx,
+                                                   re, NULL);
                        }
 
                        /*
@@ -2023,19 +1806,6 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx)
                        if (zvrf)
                                zvrf->installs++;
 
-                       /* Redistribute */
-                       /*
-                        * TODO -- still calling the redist api using the
-                        * route_entries, and there's a corner-case here:
-                        * if there's no client for the 'new' route, a redist
-                        * deleting the 'old' route will be sent. But if the
-                        * 'old' context info was stale, 'old_re' will be
-                        * NULL here and that delete will not be sent.
-                        */
-                       if (re)
-                               redistribute_update(dest_pfx, src_pfx,
-                                                   re, old_re);
-
                        /* Notify route owner */
                        zsend_route_notify_owner_ctx(ctx, ZAPI_ROUTE_INSTALLED);
 
@@ -2110,6 +1880,179 @@ done:
        dplane_ctx_fini(&ctx);
 }
 
+/*
+ * Handle notification from async dataplane: the dataplane has detected
+ * some change to a route, and notifies zebra so that the control plane
+ * can reflect that change.
+ */
+static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx)
+{
+       struct route_node *rn = NULL;
+       struct route_entry *re = NULL;
+       struct nexthop *nexthop;
+       char dest_str[PREFIX_STRLEN] = "";
+       const struct prefix *dest_pfx, *src_pfx;
+       rib_dest_t *dest;
+       bool fib_changed = false;
+       bool debug_p = IS_ZEBRA_DEBUG_DPLANE | IS_ZEBRA_DEBUG_RIB;
+       int start_count, end_count;
+       dest_pfx = dplane_ctx_get_dest(ctx);
+
+       /* Note well: only capturing the prefix string if debug is enabled here;
+        * unconditional log messages will have to generate the string.
+        */
+       if (debug_p)
+               prefix2str(dest_pfx, dest_str, sizeof(dest_str));
+
+       /* Locate rn and re(s) from ctx */
+       rn = rib_find_rn_from_ctx(ctx);
+       if (rn == NULL) {
+               if (debug_p) {
+                       zlog_debug("Failed to process dplane notification: no routes for %u:%s",
+                                  dplane_ctx_get_vrf(ctx), dest_str);
+               }
+               goto done;
+       }
+
+       dest = rib_dest_from_rnode(rn);
+       srcdest_rnode_prefixes(rn, &dest_pfx, &src_pfx);
+
+       if (debug_p)
+               zlog_debug("%u:%s Processing dplane notif ctx %p",
+                          dplane_ctx_get_vrf(ctx), dest_str, ctx);
+
+       /*
+        * Take a pass through the routes, look for matches with the context
+        * info.
+        */
+       RNODE_FOREACH_RE(rn, re) {
+               if (rib_route_match_ctx(re, ctx, false /*!update*/))
+                       break;
+       }
+
+       /* No match? Nothing we can do */
+       if (re == NULL) {
+               if (debug_p)
+                       zlog_debug("%u:%s Unable to process dplane notification: no entry for type %s",
+                                  dplane_ctx_get_vrf(ctx), dest_str,
+                                  zebra_route_string(
+                                          dplane_ctx_get_type(ctx)));
+
+               goto done;
+       }
+
+       /* Is this a notification that ... matters? We only really care about
+        * the route that is currently selected for installation.
+        */
+       if (re != dest->selected_fib) {
+               /* TODO -- don't skip processing entirely? We might like to
+                * at least report on the event.
+                */
+               if (debug_p)
+                       zlog_debug("%u:%s dplane notif, but type %s not selected_fib",
+                                  dplane_ctx_get_vrf(ctx), dest_str,
+                                  zebra_route_string(
+                                          dplane_ctx_get_type(ctx)));
+               goto done;
+       }
+
+       /* We'll want to determine whether the installation status of the
+        * route has changed: we'll check the status before processing,
+        * and then again if there's been a change.
+        */
+       start_count = 0;
+       for (ALL_NEXTHOPS_PTR(rib_active_nhg(re), nexthop)) {
+               if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB))
+                       start_count++;
+       }
+
+       /* Update zebra's nexthop FIB flags based on the context struct's
+        * nexthops.
+        */
+       fib_changed = rib_update_re_from_ctx(re, rn, ctx);
+
+       if (!fib_changed) {
+               if (debug_p)
+                       zlog_debug("%u:%s No change from dplane notification",
+                                  dplane_ctx_get_vrf(ctx), dest_str);
+
+               goto done;
+       }
+
+       /*
+        * Perform follow-up work if the actual status of the prefix
+        * changed.
+        */
+
+       end_count = 0;
+       for (ALL_NEXTHOPS_PTR(rib_active_nhg(re), nexthop)) {
+               if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB))
+                       end_count++;
+       }
+
+       /* Various fib transitions: changed nexthops; from installed to
+        * not-installed; or not-installed to installed.
+        */
+       if (start_count > 0 && end_count > 0) {
+
+               /* Changed nexthops - update kernel/others */
+               dplane_route_notif_update(rn, re,
+                                         DPLANE_OP_ROUTE_UPDATE, ctx);
+
+       } else if (start_count == 0 && end_count > 0) {
+               if (debug_p)
+                       zlog_debug("%u:%s installed transition from dplane notification",
+                                  dplane_ctx_get_vrf(ctx), dest_str);
+
+               /* We expect this to be the selected route, so we want
+                * to tell others about this transistion.
+                */
+               SET_FLAG(re->status, ROUTE_ENTRY_INSTALLED);
+
+               /* Changed nexthops - update kernel/others */
+               dplane_route_notif_update(rn, re, DPLANE_OP_ROUTE_INSTALL, ctx);
+
+               /* Redistribute, lsp, and nht update */
+               redistribute_update(dest_pfx, src_pfx, re, NULL);
+
+               zebra_rib_evaluate_rn_nexthops(
+                       rn, zebra_router_get_next_sequence());
+
+               zebra_rib_evaluate_mpls(rn);
+
+       } else if (start_count > 0 && end_count == 0) {
+               if (debug_p)
+                       zlog_debug("%u:%s un-installed transition from dplane notification",
+                                  dplane_ctx_get_vrf(ctx), dest_str);
+
+               /* Transition from _something_ installed to _nothing_
+                * installed.
+                */
+               /* We expect this to be the selected route, so we want
+                * to tell others about this transistion.
+                */
+               UNSET_FLAG(re->status, ROUTE_ENTRY_INSTALLED);
+
+               /* Changed nexthops - update kernel/others */
+               dplane_route_notif_update(rn, re, DPLANE_OP_ROUTE_DELETE, ctx);
+
+               /* Redistribute, lsp, and nht update */
+               redistribute_delete(dest_pfx, src_pfx, re);
+
+               zebra_rib_evaluate_rn_nexthops(
+                       rn, zebra_router_get_next_sequence());
+
+               zebra_rib_evaluate_mpls(rn);
+       }
+
+done:
+       if (rn)
+               route_unlock_node(rn);
+
+       /* Return context to dataplane module */
+       dplane_ctx_fini(&ctx);
+}
+
 /* Take a list of route_node structs and return 1, if there was a record
  * picked from it and processed by rib_process(). Don't process more,
  * than one RN record; operate only in the specified sub-queue.
@@ -2133,6 +2076,7 @@ static unsigned int process_subq(struct list *subq, uint8_t qindex)
 
        if (IS_ZEBRA_DEBUG_RIB_DETAILED) {
                char buf[SRCDEST2STR_BUFFER];
+
                srcdest_rnode2str(rnode, buf, sizeof(buf));
                zlog_debug("%u:%s: rn %p dequeued from sub-queue %u",
                           zvrf ? zvrf_id(zvrf) : 0, buf, rnode, qindex);
@@ -2468,6 +2412,8 @@ void rib_unlink(struct route_node *rn, struct route_entry *re)
                dest->selected_fib = NULL;
 
        nexthops_free(re->ng.nexthop);
+       nexthops_free(re->fib_ng.nexthop);
+
        XFREE(MTYPE_RE, re);
 }
 
@@ -2704,15 +2650,9 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
                apply_mask_ipv6(src_p);
 
        /* Set default distance by route type. */
-       if (re->distance == 0) {
+       if (re->distance == 0)
                re->distance = route_distance(re->type);
 
-               /* iBGP distance is 200. */
-               if (re->type == ZEBRA_ROUTE_BGP
-                   && CHECK_FLAG(re->flags, ZEBRA_FLAG_IBGP))
-                       re->distance = 200;
-       }
-
        /* Lookup route node.*/
        rn = srcdest_rnode_get(table, p, src_p);
 
@@ -3331,13 +3271,40 @@ static int rib_process_dplane_results(struct thread *thread)
                        case DPLANE_OP_ROUTE_INSTALL:
                        case DPLANE_OP_ROUTE_UPDATE:
                        case DPLANE_OP_ROUTE_DELETE:
-                               rib_process_result(ctx);
+                       {
+                               /* Bit of special case for route updates
+                                * that were generated by async notifications:
+                                * we don't want to continue processing these
+                                * in the rib.
+                                */
+                               if (dplane_ctx_get_notif_provider(ctx) == 0)
+                                       rib_process_result(ctx);
+                               else
+                                       dplane_ctx_fini(&ctx);
+                       }
+                       break;
+
+                       case DPLANE_OP_ROUTE_NOTIFY:
+                               rib_process_dplane_notify(ctx);
                                break;
 
                        case DPLANE_OP_LSP_INSTALL:
                        case DPLANE_OP_LSP_UPDATE:
                        case DPLANE_OP_LSP_DELETE:
-                               zebra_mpls_lsp_dplane_result(ctx);
+                       {
+                               /* Bit of special case for LSP updates
+                                * that were generated by async notifications:
+                                * we don't want to continue processing these.
+                                */
+                               if (dplane_ctx_get_notif_provider(ctx) == 0)
+                                       zebra_mpls_lsp_dplane_result(ctx);
+                               else
+                                       dplane_ctx_fini(&ctx);
+                       }
+                       break;
+
+                       case DPLANE_OP_LSP_NOTIFY:
+                               zebra_mpls_process_dplane_notify(ctx);
                                break;
 
                        case DPLANE_OP_PW_INSTALL:
index 2917d0e7a8ff19c8604df1a70609d137db79ecc0..a8389f2adf4bc36040396d307dfb9f6fa6e392a8 100644 (file)
@@ -400,7 +400,7 @@ static int zebra_rnh_apply_nht_rmap(afi_t afi, struct zebra_vrf *zvrf,
 {
        int at_least_one = 0;
        struct nexthop *nexthop;
-       int ret;
+       route_map_result_t ret;
 
        if (prn && re) {
                for (nexthop = re->ng.nexthop; nexthop;
@@ -1132,7 +1132,7 @@ static int send_client(struct rnh *rnh, struct zserv *client, rnh_type_t type,
 static void print_nh(struct nexthop *nexthop, struct vty *vty)
 {
        char buf[BUFSIZ];
-       struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT);
+       struct zebra_ns *zns = zebra_ns_lookup(nexthop->vrf_id);
 
        switch (nexthop->type) {
        case NEXTHOP_TYPE_IPV4:
index f48bf3b0338999fd4fbe9b6329bc4c613cc3957a..51a644178776d494dae0aadbca8a908d7abb6818 100644 (file)
@@ -136,9 +136,9 @@ static int zebra_route_match_delete(struct vty *vty, const char *command,
 /* 'match tag TAG'
  * Match function return 1 if match is success else return 0
  */
-static route_map_result_t route_match_tag(void *rule,
-                                         const struct prefix *prefix,
-                                         route_map_object_t type, void *object)
+static enum route_map_match_result_t
+route_match_tag(void *rule, const struct prefix *prefix,
+               route_map_object_t type, void *object)
 {
        route_tag_t *tag;
        struct nh_rmap_obj *nh_data;
@@ -162,10 +162,9 @@ static struct route_map_rule_cmd route_match_tag_cmd = {
 
 /* `match interface IFNAME' */
 /* Match function return 1 if match is success else return zero. */
-static route_map_result_t route_match_interface(void *rule,
-                                               const struct prefix *prefix,
-                                               route_map_object_t type,
-                                               void *object)
+static enum route_map_match_result_t
+route_match_interface(void *rule, const struct prefix *prefix,
+                     route_map_object_t type, void *object)
 {
        struct nh_rmap_obj *nh_data;
        char *ifname = rule;
@@ -1025,10 +1024,9 @@ DEFPY (show_ipv6_protocol_nht,
 /* `match ip next-hop IP_ACCESS_LIST' */
 
 /* Match function return 1 if match is success else return zero. */
-static route_map_result_t route_match_ip_next_hop(void *rule,
-                                                 const struct prefix *prefix,
-                                                 route_map_object_t type,
-                                                 void *object)
+static enum route_map_match_result_t
+route_match_ip_next_hop(void *rule, const struct prefix *prefix,
+                       route_map_object_t type, void *object)
 {
        struct access_list *alist;
        struct nh_rmap_obj *nh_data;
@@ -1083,7 +1081,7 @@ static struct route_map_rule_cmd route_match_ip_next_hop_cmd = {
 
 /* `match ip next-hop prefix-list PREFIX_LIST' */
 
-static route_map_result_t
+static enum route_map_match_result_t
 route_match_ip_next_hop_prefix_list(void *rule, const struct prefix *prefix,
                                    route_map_object_t type, void *object)
 {
@@ -1139,10 +1137,9 @@ static struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd = {
 
 /* Match function should return 1 if match is success else return
    zero. */
-static route_map_result_t route_match_address(afi_t afi, void *rule,
-                                             const struct prefix *prefix,
-                                             route_map_object_t type,
-                                             void *object)
+static enum route_map_match_result_t
+route_match_address(afi_t afi, void *rule, const struct prefix *prefix,
+                   route_map_object_t type, void *object)
 {
        struct access_list *alist;
 
@@ -1158,19 +1155,16 @@ static route_map_result_t route_match_address(afi_t afi, void *rule,
        return RMAP_NOMATCH;
 }
 
-static route_map_result_t route_match_ip_address(void *rule,
-                                                const struct prefix *prefix,
-                                                route_map_object_t type,
-                                                void *object)
+static enum route_map_match_result_t
+route_match_ip_address(void *rule, const struct prefix *prefix,
+                      route_map_object_t type, void *object)
 {
        return route_match_address(AFI_IP, rule, prefix, type, object);
 }
 
-static route_map_result_t route_match_ipv6_address(void *rule,
-                                                  const struct prefix *prefix,
-                                                  route_map_object_t type,
-                                                  void *object)
-
+static enum route_map_match_result_t
+route_match_ipv6_address(void *rule, const struct prefix *prefix,
+                        route_map_object_t type, void *object)
 {
        return route_match_address(AFI_IP6, rule, prefix, type, object);
 }
@@ -1200,7 +1194,7 @@ static struct route_map_rule_cmd route_match_ipv6_address_cmd = {
 
 /* `match ip address prefix-list PREFIX_LIST' */
 
-static route_map_result_t
+static enum route_map_match_result_t
 route_match_address_prefix_list(void *rule, const struct prefix *prefix,
                        route_map_object_t type, void *object, afi_t afi)
 {
@@ -1218,7 +1212,7 @@ route_match_address_prefix_list(void *rule, const struct prefix *prefix,
        return RMAP_NOMATCH;
 }
 
-static route_map_result_t
+static enum route_map_match_result_t
 route_match_ip_address_prefix_list(void *rule, const struct prefix *prefix,
                                   route_map_object_t type, void *object)
 {
@@ -1241,7 +1235,7 @@ static struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd = {
        route_match_address_prefix_list_compile,
        route_match_address_prefix_list_free};
 
-static route_map_result_t
+static enum route_map_match_result_t
 route_match_ipv6_address_prefix_list(void *rule, const struct prefix *prefix,
                                        route_map_object_t type, void *object)
 {
@@ -1256,7 +1250,7 @@ static struct route_map_rule_cmd route_match_ipv6_address_prefix_list_cmd = {
 
 /* `match ip address prefix-len PREFIXLEN' */
 
-static route_map_result_t
+static enum route_map_match_result_t
 route_match_address_prefix_len(void *rule, const struct prefix *prefix,
                               route_map_object_t type, void *object)
 {
@@ -1307,7 +1301,7 @@ static struct route_map_rule_cmd route_match_ipv6_address_prefix_len_cmd = {
 
 /* `match ip nexthop prefix-len PREFIXLEN' */
 
-static route_map_result_t
+static enum route_map_match_result_t
 route_match_ip_nexthop_prefix_len(void *rule, const struct prefix *prefix,
                                  route_map_object_t type, void *object)
 {
@@ -1347,10 +1341,9 @@ static struct route_map_rule_cmd route_match_ip_nexthop_prefix_len_cmd = {
 
 /* `match source-protocol PROTOCOL' */
 
-static route_map_result_t route_match_source_protocol(void *rule,
-                                                     const struct prefix *p,
-                                                     route_map_object_t type,
-                                                     void *object)
+static enum route_map_match_result_t
+route_match_source_protocol(void *rule, const struct prefix *p,
+                           route_map_object_t type, void *object)
 {
        uint32_t *rib_type = (uint32_t *)rule;
        struct nh_rmap_obj *nh_data;
@@ -1389,10 +1382,9 @@ static struct route_map_rule_cmd route_match_source_protocol_cmd = {
        route_match_source_protocol_compile, route_match_source_protocol_free};
 
 /* `source-instance` */
-static route_map_result_t route_match_source_instance(void *rule,
-                                                     const struct prefix *p,
-                                                     route_map_object_t type,
-                                                     void *object)
+static enum route_map_match_result_t
+route_match_source_instance(void *rule, const struct prefix *p,
+                           route_map_object_t type, void *object)
 {
        uint8_t *instance = (uint8_t *)rule;
        struct nh_rmap_obj *nh_data;
@@ -1432,8 +1424,9 @@ static struct route_map_rule_cmd route_match_source_instance_cmd = {
 /* `set src A.B.C.D' */
 
 /* Set src. */
-static route_map_result_t route_set_src(void *rule, const struct prefix *prefix,
-                                       route_map_object_t type, void *object)
+static enum route_map_match_result_t
+route_set_src(void *rule, const struct prefix *prefix, route_map_object_t type,
+             void *object)
 {
        struct nh_rmap_obj *nh_data;
 
@@ -1699,7 +1692,7 @@ zebra_route_map_check(int family, int rib_type, uint8_t instance,
                      struct zebra_vrf *zvrf, route_tag_t tag)
 {
        struct route_map *rmap = NULL;
-       route_map_result_t ret = RMAP_MATCH;
+       route_map_result_t ret = RMAP_PERMITMATCH;
        struct nh_rmap_obj nh_obj;
 
        nh_obj.nexthop = nexthop;
@@ -1745,7 +1738,7 @@ zebra_import_table_route_map_check(int family, int re_type, uint8_t instance,
                                   const char *rmap_name)
 {
        struct route_map *rmap = NULL;
-       route_map_result_t ret = RMAP_DENYMATCH;
+       enum route_map_match_result_t ret = RMAP_DENYMATCH;
        struct nh_rmap_obj nh_obj;
 
        nh_obj.nexthop = nexthop;
@@ -1771,7 +1764,7 @@ route_map_result_t zebra_nht_route_map_check(afi_t afi, int client_proto,
                                             struct nexthop *nexthop)
 {
        struct route_map *rmap = NULL;
-       route_map_result_t ret = RMAP_MATCH;
+       route_map_result_t ret = RMAP_PERMITMATCH;
        struct nh_rmap_obj nh_obj;
 
        nh_obj.nexthop = nexthop;
index ece8f40dcf52ee6819b1c545b54d3a74d41771a7..257fb168d2f926746cb9c661a6670355d6a133bd 100644 (file)
@@ -382,7 +382,8 @@ static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn,
 }
 
 static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
-                             struct route_entry *re, json_object *json)
+                             struct route_entry *re, json_object *json,
+                             bool is_fib)
 {
        struct nexthop *nexthop;
        int len = 0;
@@ -394,11 +395,20 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
        time_t uptime;
        struct tm *tm;
        rib_dest_t *dest = rib_dest_from_rnode(rn);
+       struct nexthop_group *nhg;
 
        uptime = monotime(NULL);
        uptime -= re->uptime;
        tm = gmtime(&uptime);
 
+       /* If showing fib information, use the fib view of the
+        * nexthops.
+        */
+       if (is_fib)
+               nhg = rib_active_nhg(re);
+       else
+               nhg = &(re->ng);
+
        if (json) {
                json_route = json_object_new_object();
                json_nexthops = json_object_new_array();
@@ -455,7 +465,7 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
 
                json_object_string_add(json_route, "uptime", buf);
 
-               for (ALL_NEXTHOPS(re->ng, nexthop)) {
+               for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
                        json_nexthop = json_object_new_object();
 
                        json_object_int_add(json_nexthop, "flags",
@@ -625,8 +635,8 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
        }
 
        /* Nexthop information. */
-       for (ALL_NEXTHOPS(re->ng, nexthop)) {
-               if (nexthop == re->ng.nexthop) {
+       for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
+               if (nexthop == nhg->nexthop) {
                        /* Prefix information. */
                        len = vty_out(vty, "%c", zebra_route_char(re->type));
                        if (re->instance)
@@ -779,7 +789,7 @@ static void vty_show_ip_route_detail_json(struct vty *vty,
                 */
                if (use_fib && re != dest->selected_fib)
                        continue;
-               vty_show_ip_route(vty, rn, re, json_prefix);
+               vty_show_ip_route(vty, rn, re, json_prefix, use_fib);
        }
 
        prefix2str(&rn->p, buf, sizeof(buf));
@@ -865,7 +875,7 @@ static void do_show_route_helper(struct vty *vty, struct zebra_vrf *zvrf,
                                }
                        }
 
-                       vty_show_ip_route(vty, rn, re, json_prefix);
+                       vty_show_ip_route(vty, rn, re, json_prefix, use_fib);
                }
 
                if (json_prefix) {
@@ -1552,7 +1562,7 @@ DEFUN (show_ipv6_mroute,
                                vty_out(vty, SHOW_ROUTE_V6_HEADER);
                                first = 0;
                        }
-                       vty_show_ip_route(vty, rn, re, NULL);
+                       vty_show_ip_route(vty, rn, re, NULL, false);
                }
        return CMD_SUCCESS;
 }
@@ -1584,7 +1594,7 @@ DEFUN (show_ipv6_mroute_vrf_all,
                                        vty_out(vty, SHOW_ROUTE_V6_HEADER);
                                        first = 0;
                                }
-                               vty_show_ip_route(vty, rn, re, NULL);
+                               vty_show_ip_route(vty, rn, re, NULL, false);
                        }
        }
        return CMD_SUCCESS;
index fbb5af875db20fd9c14db0f4e49d72bda7f4219a..49fb302ba82e71eb163d5bd09d523097ba40a539 100644 (file)
@@ -682,6 +682,8 @@ static int zserv_handle_client_fail(struct thread *thread)
 static struct zserv *zserv_client_create(int sock)
 {
        struct zserv *client;
+       size_t stream_size =
+               MAX(ZEBRA_MAX_PACKET_SIZ, sizeof(struct zapi_route));
        int i;
        afi_t afi;
 
@@ -691,8 +693,8 @@ static struct zserv *zserv_client_create(int sock)
        client->sock = sock;
        client->ibuf_fifo = stream_fifo_new();
        client->obuf_fifo = stream_fifo_new();
-       client->ibuf_work = stream_new(ZEBRA_MAX_PACKET_SIZ);
-       client->obuf_work = stream_new(ZEBRA_MAX_PACKET_SIZ);
+       client->ibuf_work = stream_new(stream_size);
+       client->obuf_work = stream_new(stream_size);
        pthread_mutex_init(&client->ibuf_mtx, NULL);
        pthread_mutex_init(&client->obuf_mtx, NULL);
        client->wb = buffer_new(0);