]> git.proxmox.com Git - mirror_frr.git/commitdiff
Merge pull request #3678 from chiragshah6/evpn_dev1
authorRuss White <russ@riw.us>
Tue, 29 Jan 2019 15:05:50 +0000 (10:05 -0500)
committerGitHub <noreply@github.com>
Tue, 29 Jan 2019 15:05:50 +0000 (10:05 -0500)
zebra: EVPN fix duplicate address detection remote macip add case

38 files changed:
bgpd/bgp_evpn.c
bgpd/bgp_evpn.h
bgpd/bgp_routemap.c
bgpd/bgp_vty.c
bgpd/bgp_zebra.c
bgpd/bgpd.c
bgpd/bgpd.h
configure.ac
doc/developer/building-libyang.rst
doc/developer/modules.rst
doc/user/installation.rst
include/linux/if_addr.h [new file with mode: 0644]
include/subdir.am
lib/if.h
lib/route_types.pl
lib/termtable.c
lib/yang.c
lib/zclient.h
ospf6d/ospf6_interface.c
ospf6d/ospf6_interface.h
ospfd/ospf_errors.c
ospfd/ospf_errors.h
ospfd/ospf_packet.c
tests/bgpd/test_peer_attr.py
yang/libyang_plugins/subdir.am
zebra/connected.c
zebra/connected.h
zebra/if_ioctl.c
zebra/if_ioctl_solaris.c
zebra/if_netlink.c
zebra/kernel_socket.c
zebra/rt_socket.c
zebra/zebra_fpm_netlink.c
zebra/zebra_rib.c
zebra/zebra_rnh.c
zebra/zebra_vty.c
zebra/zebra_vxlan.c
zebra/zebra_vxlan_private.h

index 7f6d34808f1f9eb26aabd833c70adba79f799b17..c74d7829bd527f620c5289281b3b89e566d7dda4 100644 (file)
@@ -887,17 +887,26 @@ static void add_mac_mobility_to_attr(uint32_t seq_num, struct attr *attr)
 
 /* Install EVPN route into zebra. */
 static int evpn_zebra_install(struct bgp *bgp, struct bgpevpn *vpn,
-                             struct prefix_evpn *p,
-                             struct in_addr remote_vtep_ip, uint8_t flags,
-                             uint32_t seq)
+                             struct prefix_evpn *p, struct bgp_path_info *pi)
 {
        int ret;
+       uint8_t flags;
 
-       if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE)
-               ret = bgp_zebra_send_remote_macip(bgp, vpn, p, remote_vtep_ip,
-                                                 1, flags, seq);
-       else
+       if (p->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) {
+               flags = 0;
+               if (pi->attr->sticky)
+                       SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
+               if (pi->attr->default_gw)
+                       SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
+               if (is_evpn_prefix_ipaddr_v6(p) &&
+                   pi->attr->router_flag)
+                       SET_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG);
+               ret = bgp_zebra_send_remote_macip(
+                       bgp, vpn, p, pi->attr->nexthop, 1, flags,
+                       mac_mobility_seqnum(pi->attr));
+       } else {
                ret = bgp_zebra_send_remote_vtep(bgp, vpn, p, 1);
+       }
 
        return ret;
 }
@@ -1121,11 +1130,9 @@ static int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn,
 {
        struct bgp_path_info *old_select, *new_select;
        struct bgp_path_info_pair old_and_new;
-       struct prefix_evpn *evp;
        afi_t afi = AFI_L2VPN;
        safi_t safi = SAFI_EVPN;
        int ret = 0;
-       uint8_t flags = 0;
 
        /* Compute the best path. */
        bgp_best_selection(bgp, rn, &bgp->maxpaths[afi][safi], &old_and_new,
@@ -1133,7 +1140,6 @@ static int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn,
        old_select = old_and_new.old;
        new_select = old_and_new.new;
 
-       evp = (struct prefix_evpn *)&rn->p;
        /* If the best path hasn't changed - see if there is still something to
         * update
         * to zebra RIB.
@@ -1144,20 +1150,10 @@ static int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn,
            && !CHECK_FLAG(rn->flags, BGP_NODE_USER_CLEAR)
            && !CHECK_FLAG(old_select->flags, BGP_PATH_ATTR_CHANGED)
            && !bgp_addpath_is_addpath_used(&bgp->tx_addpath, afi, safi)) {
-               if (bgp_zebra_has_route_changed(rn, old_select)) {
-                       if (old_select->attr->sticky)
-                               SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
-                       if (old_select->attr->default_gw)
-                               SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
-                       if (is_evpn_prefix_ipaddr_v6(evp) &&
-                           old_select->attr->router_flag)
-                               SET_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG);
-
+               if (bgp_zebra_has_route_changed(rn, old_select))
                        ret = evpn_zebra_install(
                                bgp, vpn, (struct prefix_evpn *)&rn->p,
-                               old_select->attr->nexthop, flags,
-                               mac_mobility_seqnum(old_select->attr));
-               }
+                               old_select);
                UNSET_FLAG(old_select->flags, BGP_PATH_MULTIPATH_CHG);
                bgp_zebra_clear_route_change_flags(rn);
                return ret;
@@ -1182,18 +1178,9 @@ static int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn,
 
        if (new_select && new_select->type == ZEBRA_ROUTE_BGP
            && new_select->sub_type == BGP_ROUTE_IMPORTED) {
-               flags = 0;
-               if (new_select->attr->sticky)
-                       SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
-               if (new_select->attr->default_gw)
-                       SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
-               if (is_evpn_prefix_ipaddr_v6(evp) &&
-                   new_select->attr->router_flag)
-                       SET_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG);
-
                ret = evpn_zebra_install(bgp, vpn, (struct prefix_evpn *)&rn->p,
-                                        new_select->attr->nexthop, flags,
-                                        mac_mobility_seqnum(new_select->attr));
+                                        new_select);
+
                /* If an old best existed and it was a "local" route, the only
                 * reason
                 * it would be supplanted is due to MAC mobility procedures. So,
@@ -1698,6 +1685,27 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
        return route_change;
 }
 
+static void evpn_zebra_reinstall_best_route(struct bgp *bgp,
+               struct bgpevpn *vpn, struct bgp_node *rn)
+{
+       struct bgp_path_info *tmp_ri;
+       struct bgp_path_info *curr_select = NULL;
+
+       for (tmp_ri = bgp_node_get_bgp_path_info(rn);
+            tmp_ri; tmp_ri = tmp_ri->next) {
+               if (CHECK_FLAG(tmp_ri->flags, BGP_PATH_SELECTED)) {
+                       curr_select = tmp_ri;
+                       break;
+               }
+       }
+
+       if (curr_select && curr_select->type == ZEBRA_ROUTE_BGP
+                       && curr_select->sub_type == BGP_ROUTE_IMPORTED)
+               evpn_zebra_install(bgp, vpn,
+                               (struct prefix_evpn *)&rn->p,
+                               curr_select);
+}
+
 /*
  * If the local route was not selected evict it and tell zebra to re-add
  * the best remote dest.
@@ -1717,9 +1725,6 @@ static void evpn_cleanup_local_non_best_route(struct bgp *bgp,
                                              struct bgp_node *rn,
                                              struct bgp_path_info *local_pi)
 {
-       struct bgp_path_info *tmp_pi;
-       struct bgp_path_info *curr_select = NULL;
-       uint8_t flags = 0;
        char buf[PREFIX_STRLEN];
 
        /* local path was not picked as the winner; kick it out */
@@ -1731,24 +1736,7 @@ static void evpn_cleanup_local_non_best_route(struct bgp *bgp,
        bgp_path_info_reap(rn, local_pi);
 
        /* tell zebra to re-add the best remote path */
-       for (tmp_pi = bgp_node_get_bgp_path_info(rn);
-            tmp_pi; tmp_pi = tmp_pi->next) {
-               if (CHECK_FLAG(tmp_pi->flags, BGP_PATH_SELECTED)) {
-                       curr_select = tmp_pi;
-                       break;
-               }
-       }
-       if (curr_select &&
-           curr_select->type == ZEBRA_ROUTE_BGP
-           && curr_select->sub_type == BGP_ROUTE_IMPORTED) {
-               if (curr_select->attr->sticky)
-                       SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
-               if (curr_select->attr->default_gw)
-                       SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
-               evpn_zebra_install(bgp, vpn, (struct prefix_evpn *)&rn->p,
-                                  curr_select->attr->nexthop, flags,
-                                  mac_mobility_seqnum(curr_select->attr));
-       }
+       evpn_zebra_reinstall_best_route(bgp, vpn, rn);
 }
 
 /*
@@ -5324,10 +5312,11 @@ int bgp_filter_evpn_routes_upon_martian_nh_change(struct bgp *bgp)
  * Handle del of a local MACIP.
  */
 int bgp_evpn_local_macip_del(struct bgp *bgp, vni_t vni, struct ethaddr *mac,
-                            struct ipaddr *ip)
+                            struct ipaddr *ip, int state)
 {
        struct bgpevpn *vpn;
        struct prefix_evpn p;
+       struct bgp_node *rn;
 
        /* Lookup VNI hash - should exist. */
        vpn = bgp_evpn_lookup_vni(bgp, vni);
@@ -5338,9 +5327,16 @@ int bgp_evpn_local_macip_del(struct bgp *bgp, vni_t vni, struct ethaddr *mac,
                return -1;
        }
 
-       /* Remove EVPN type-2 route and schedule for processing. */
        build_evpn_type2_prefix(&p, mac, ip);
-       delete_evpn_route(bgp, vpn, &p);
+       if (state == ZEBRA_NEIGH_ACTIVE) {
+               /* Remove EVPN type-2 route and schedule for processing. */
+               delete_evpn_route(bgp, vpn, &p);
+       } else {
+               /* Re-instate the current remote best path if any */
+               rn = bgp_node_lookup(vpn->route_table, (struct prefix *)&p);
+               if (rn)
+                       evpn_zebra_reinstall_best_route(bgp, vpn, rn);
+       }
 
        return 0;
 }
index 8728fdcab7633278c0c3c1ff4076f67b72eec03a..5c3d4ce3aa9a1f60a56b1dc99651b43731d9b703 100644 (file)
@@ -129,7 +129,8 @@ extern int bgp_evpn_unimport_route(struct bgp *bgp, afi_t afi, safi_t safi,
                                   struct prefix *p, struct bgp_path_info *ri);
 extern int bgp_filter_evpn_routes_upon_martian_nh_change(struct bgp *bgp);
 extern int bgp_evpn_local_macip_del(struct bgp *bgp, vni_t vni,
-                                   struct ethaddr *mac, struct ipaddr *ip);
+                                   struct ethaddr *mac, struct ipaddr *ip,
+                                       int state);
 extern int bgp_evpn_local_macip_add(struct bgp *bgp, vni_t vni,
                                    struct ethaddr *mac, struct ipaddr *ip,
                                    uint8_t flags, uint32_t seq);
index d7ee2aa19ff44c89aa808461517501acfdfe35e5..4953032f97bcd4dec6d0d04037907b2027e6a702 100644 (file)
@@ -3325,12 +3325,18 @@ static void bgp_route_map_process_update(struct bgp *bgp, const char *rmap_name,
                               != 0)
                        continue;
 
+               /* Make sure the route-map is populated here if not already done */
+               bgp->adv_cmd_rmap[afi][safi].map = map;
+
                if (BGP_DEBUG(zebra, ZEBRA))
                        zlog_debug(
                                "Processing route_map %s update on advertise type5 route command",
                                rmap_name);
-               bgp_evpn_withdraw_type5_routes(bgp, afi, safi);
-               bgp_evpn_advertise_type5_routes(bgp, afi, safi);
+
+               if (route_update) {
+                       bgp_evpn_withdraw_type5_routes(bgp, afi, safi);
+                       bgp_evpn_advertise_type5_routes(bgp, afi, safi);
+               }
        }
 }
 
index c6e48cc16083d97fdfc7061c8ef0e2ed40a01f43..43adf342473c4b82ec84752d63d6c32e61b899ff 100644 (file)
@@ -22,6 +22,7 @@
 
 #include "command.h"
 #include "lib/json.h"
+#include "lib/zclient.h"
 #include "prefix.h"
 #include "plist.h"
 #include "buffer.h"
@@ -897,7 +898,7 @@ DEFUN_HIDDEN (no_bgp_local_mac,
                return CMD_WARNING;
        }
 
-       rv = bgp_evpn_local_macip_del(bgp, vni, &mac, &ip);
+       rv = bgp_evpn_local_macip_del(bgp, vni, &mac, &ip, ZEBRA_NEIGH_ACTIVE);
        if (rv < 0) {
                vty_out(vty, "Internal error\n");
                return CMD_WARNING;
@@ -2846,13 +2847,11 @@ static int peer_remote_as_vty(struct vty *vty, const char *peer_str,
        switch (ret) {
        case BGP_ERR_PEER_GROUP_MEMBER:
                vty_out(vty,
-                       "%% Peer-group AS %u. Cannot configure remote-as for member\n",
-                       as);
+                       "%% Peer-group member cannot override remote-as of peer-group\n");
                return CMD_WARNING_CONFIG_FAILED;
        case BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT:
                vty_out(vty,
-                       "%% The AS# can not be changed from %u to %s, peer-group members must be all internal or all external\n",
-                       as, as_str);
+                       "%% Peer-group members must be all internal or all external\n");
                return CMD_WARNING_CONFIG_FAILED;
        }
        return bgp_vty_return(vty, ret);
@@ -2973,7 +2972,7 @@ static int peer_conf_interface_get(struct vty *vty, const char *conf_if,
        if (!CHECK_FLAG(peer->flags_invert, PEER_FLAG_CAPABILITY_ENHE)) {
                SET_FLAG(peer->flags, PEER_FLAG_CAPABILITY_ENHE);
                SET_FLAG(peer->flags_invert, PEER_FLAG_CAPABILITY_ENHE);
-               UNSET_FLAG(peer->flags_override, PEER_FLAG_CAPABILITY_ENHE);
+               SET_FLAG(peer->flags_override, PEER_FLAG_CAPABILITY_ENHE);
        }
 
        if (peer_group_name) {
@@ -9212,8 +9211,8 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
                                ? " replace-as"
                                : "");
        }
-       /* peer type internal, external, confed-internal or confed-external */
-       if (p->as == p->local_as) {
+       /* peer type internal or confed-internal */
+       if ((p->as == p->local_as) || (p->as_type == AS_INTERNAL)) {
                if (use_json) {
                        if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
                                json_object_boolean_true_add(
@@ -9227,7 +9226,8 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
                        else
                                vty_out(vty, "internal link\n");
                }
-       } else {
+       /* peer type external or confed-external */
+       } else if (p->as || (p->as_type == AS_EXTERNAL)) {
                if (use_json) {
                        if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
                                json_object_boolean_true_add(
@@ -9241,6 +9241,12 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
                        else
                                vty_out(vty, "external link\n");
                }
+       } else {
+               if (use_json)
+                       json_object_boolean_true_add(json_neigh,
+                                                    "nbrUnspecifiedLink");
+               else
+                       vty_out(vty, "unspecified link\n");
        }
 
        /* Description. */
@@ -11006,6 +11012,7 @@ static void bgp_show_all_instances_neighbors_vty(struct vty *vty,
                        bgp_show_neighbor(vty, bgp, show_all, NULL, NULL,
                                          use_json, json);
                }
+               json_object_free(json);
        }
 
        if (use_json) {
index 3c4b219466ce37d643cb77eb16151b8aa733a39d..17de9433815967d8442711f640a56b8c9de39e8e 100644 (file)
@@ -2480,6 +2480,7 @@ static int bgp_zebra_process_local_macip(int command, struct zclient *zclient,
        char buf1[INET6_ADDRSTRLEN];
        uint8_t flags = 0;
        uint32_t seqnum = 0;
+       int state = 0;
 
        memset(&ip, 0, sizeof(ip));
        s = zclient->ibuf;
@@ -2503,6 +2504,8 @@ static int bgp_zebra_process_local_macip(int command, struct zclient *zclient,
        if (command == ZEBRA_MACIP_ADD) {
                flags = stream_getc(s);
                seqnum = stream_getl(s);
+       } else {
+               state = stream_getl(s);
        }
 
        bgp = bgp_lookup_by_vrf_id(vrf_id);
@@ -2510,16 +2513,17 @@ static int bgp_zebra_process_local_macip(int command, struct zclient *zclient,
                return 0;
 
        if (BGP_DEBUG(zebra, ZEBRA))
-               zlog_debug("%u:Recv MACIP %s flags 0x%x MAC %s IP %s VNI %u seq %u",
+               zlog_debug("%u:Recv MACIP %s flags 0x%x MAC %s IP %s VNI %u seq %u state %d",
                           vrf_id, (command == ZEBRA_MACIP_ADD) ? "Add" : "Del",
                           flags, prefix_mac2str(&mac, buf, sizeof(buf)),
-                          ipaddr2str(&ip, buf1, sizeof(buf1)), vni, seqnum);
+                          ipaddr2str(&ip, buf1, sizeof(buf1)), vni, seqnum,
+                          state);
 
        if (command == ZEBRA_MACIP_ADD)
                return bgp_evpn_local_macip_add(bgp, vni, &mac, &ip,
                                                flags, seqnum);
        else
-               return bgp_evpn_local_macip_del(bgp, vni, &mac, &ip);
+               return bgp_evpn_local_macip_del(bgp, vni, &mac, &ip, state);
 }
 
 static void bgp_zebra_process_local_ip_prefix(int cmd, struct zclient *zclient,
index 0b6e05fff60709379362c9a936da892ad018eab4..28f6239b8a420460cbf9014c90556b8ddd9a9e0a 100644 (file)
@@ -1001,7 +1001,26 @@ static inline bgp_peer_sort_t peer_calc_sort(struct peer *peer)
 
                return BGP_PEER_EBGP;
        } else {
-               if (peer->as_type != AS_SPECIFIED)
+               if (peer->as_type == AS_UNSPECIFIED) {
+                       /* check if in peer-group with AS information */
+                       if (peer->group
+                           && (peer->group->conf->as_type != AS_UNSPECIFIED)) {
+                               if (peer->group->conf->as_type
+                                   == AS_SPECIFIED) {
+                                       if (peer->local_as
+                                           == peer->group->conf->as)
+                                               return BGP_PEER_IBGP;
+                                       else
+                                               return BGP_PEER_EBGP;
+                               } else if (peer->group->conf->as_type
+                                          == AS_INTERNAL)
+                                       return BGP_PEER_IBGP;
+                               else
+                                       return BGP_PEER_EBGP;
+                       }
+                       /* no AS information anywhere, let caller know */
+                       return BGP_PEER_UNSPECIFIED;
+               } else if (peer->as_type != AS_SPECIFIED)
                        return (peer->as_type == AS_INTERNAL ? BGP_PEER_IBGP
                                                             : BGP_PEER_EBGP);
 
@@ -1711,20 +1730,32 @@ int peer_remote_as(struct bgp *bgp, union sockunion *su, const char *conf_if,
 
                /* When this peer is a member of peer-group.  */
                if (peer->group) {
-                       if (peer->group->conf->as) {
+                       /* peer-group already has AS number/internal/external */
+                       if (peer->group->conf->as
+                           || peer->group->conf->as_type) {
                                /* Return peer group's AS number.  */
                                *as = peer->group->conf->as;
                                return BGP_ERR_PEER_GROUP_MEMBER;
                        }
-                       if (peer_sort(peer->group->conf) == BGP_PEER_IBGP) {
-                               if ((as_type != AS_INTERNAL)
-                                   && (bgp->as != *as)) {
+
+                       bgp_peer_sort_t peer_sort_type =
+                                               peer_sort(peer->group->conf);
+
+                       /* Explicit AS numbers used, compare AS numbers */
+                       if (as_type == AS_SPECIFIED) {
+                               if (((peer_sort_type == BGP_PEER_IBGP)
+                                   && (bgp->as != *as))
+                                   || ((peer_sort_type == BGP_PEER_EBGP)
+                                   && (bgp->as == *as))) {
                                        *as = peer->as;
                                        return BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT;
                                }
                        } else {
-                               if ((as_type != AS_EXTERNAL)
-                                   && (bgp->as == *as)) {
+                               /* internal/external used, compare as-types */
+                               if (((peer_sort_type == BGP_PEER_IBGP)
+                                   && (as_type != AS_INTERNAL))
+                                   || ((peer_sort_type == BGP_PEER_EBGP)
+                                   && (as_type != AS_EXTERNAL)))  {
                                        *as = peer->as;
                                        return BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT;
                                }
@@ -2688,6 +2719,7 @@ int peer_group_bind(struct bgp *bgp, union sockunion *su, struct peer *peer,
                if (peer->as_type == AS_UNSPECIFIED) {
                        peer->as_type = group->conf->as_type;
                        peer->as = group->conf->as;
+                       peer->sort = group->conf->sort;
                }
 
                if (!group->conf->as) {
@@ -7020,14 +7052,17 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp,
 
        /* capability extended-nexthop */
        if (peergroup_flag_check(peer, PEER_FLAG_CAPABILITY_ENHE)) {
-               if (CHECK_FLAG(peer->flags_invert, PEER_FLAG_CAPABILITY_ENHE))
-                       vty_out(vty,
-                               " no neighbor %s capability extended-nexthop\n",
-                               addr);
-               else
-                       vty_out(vty,
-                               " neighbor %s capability extended-nexthop\n",
-                               addr);
+               if (!peer->conf_if) {
+                       if (CHECK_FLAG(peer->flags_invert,
+                                      PEER_FLAG_CAPABILITY_ENHE))
+                               vty_out(vty,
+                                       " no neighbor %s capability extended-nexthop\n",
+                                       addr);
+                       else
+                               vty_out(vty,
+                                       " neighbor %s capability extended-nexthop\n",
+                                       addr);
+               }
        }
 
        /* dont-capability-negotiation */
index 484fc105e808dccee102462faad766bdf0776e9d..58ae119af1f075fe59823060654be8da37c9a6fb 100644 (file)
@@ -646,7 +646,8 @@ struct bgp_filter {
 /* IBGP/EBGP identifier.  We also have a CONFED peer, which is to say,
    a peer who's AS is part of our Confederation.  */
 typedef enum {
-       BGP_PEER_IBGP = 1,
+       BGP_PEER_UNSPECIFIED,
+       BGP_PEER_IBGP,
        BGP_PEER_EBGP,
        BGP_PEER_INTERNAL,
        BGP_PEER_CONFED,
index 4a17b3686f7a80e894130a2d9e0f039fc321d23e..afdc6336b0251c668badaeb3916d24350958aebc 100755 (executable)
@@ -1610,6 +1610,24 @@ AC_CHECK_MEMBER([struct lyd_node.priv], [], [
   ])
 ], [[#include <libyang/libyang.h>]])
 
+ac_ld_flag_save="$LDFLAGS"
+LDFLAGS="$LDFLAGS $libyang_LIBS"
+AC_CHECK_FUNC([ly_register_types], [
+  libyang_ext_builtin=true
+  AC_DEFINE([LIBYANG_EXT_BUILTIN], [1], [have ly_register_types()])
+], [
+  libyang_ext_builtin=false
+  AC_MSG_WARN([===== old libyang (before 0.16.74) detected =====])
+  AC_MSG_WARN([The available version of libyang does not seem to support])
+  AC_MSG_WARN([built-in YANG extension modules.  This will cause "make check"])
+  AC_MSG_WARN([to fail and may create installation and version mismatch issues.])
+  AC_MSG_WARN([Support for the old mechanism will be removed at some point.])
+  AC_MSG_WARN([Please update libyang to version 0.16.74 or newer.])
+  AC_MSG_WARN([===== old libyang (before 0.16.74) detected =====])
+])
+AM_CONDITIONAL([LIBYANG_EXT_BUILTIN], [$libyang_ext_builtin])
+LDFLAGS="$ac_ld_flag_save"
+
 dnl ---------------
 dnl configuration rollbacks
 dnl ---------------
index 005b6ba78680a49ac39d13e226934c8d2e69bded..c45c294b75295db8640da9422235c04e2a093fc7 100644 (file)
@@ -4,6 +4,13 @@ The libyang library can be installed from third-party packages available `here
 Note: the libyang dev/devel packages need to be installed in addition
 to the libyang core package in order to build FRR successfully.
 
+.. warning::
+   libyang ABI version 0.16.74 or newer will be required to build FRR in the
+   near future since it significantly eases build and installation
+   considerations.  "0.16-r3" is equal to 0.16.105 and will work, "0.16-r2"
+   is equal to 0.16.52 and will stop working.  The CI artifacts will be
+   updated shortly.
+
 For example, for CentOS 7.x:
 
 .. code-block:: shell
@@ -21,6 +28,14 @@ or Ubuntu 18.04:
    sudo apt install libpcre3-dev
    sudo dpkg -i libyang-dev_0.16.46_amd64.deb libyang_0.16.46_amd64.deb
 
+.. note::
+   For Debian-based systems, the official libyang package requires recent
+   versions of swig (3.0.12) and debhelper (11) which are only available in
+   Debian buster (10).  However, libyang packages built on Debian buster can
+   be installed on both Debian jessie (8) and Debian stretch (9), as well as
+   various Ubuntu systems.  The python3-yang package will not work, but the
+   other packages (libyang-dev is the one needed for FRR) will.
+
 Alternatively, libyang can be built and installed manually by following
 the steps below:
 
index 99c79462abd57b6c721c808241f7ab40af0d50b6..763d8b1b8d5a1636448e01358adb7378a4717e36 100644 (file)
@@ -53,6 +53,14 @@ Basic boilerplate:
 
     #include "hook.h"
     #include "module.h"
+    #include "libfrr.h"
+    #include "thread.h"
+
+    static int module_late_init(struct thread_master *master)
+    {
+        /* Do initialization stuff here */
+        return 0;
+    }
 
     static int
     module_init (void)
index ebca53ea32ea48134c434e4bd1778da8046f64ff..4e1582ccd8f8a2a57b924b6e89d1f61fd24c05b8 100644 (file)
@@ -335,6 +335,9 @@ options to the configuration script.
    Look for libyang plugins in `dir` [`prefix`/lib/frr/libyang_plugins].
    Note that the FRR libyang plugins will be installed here.
 
+   This option is meaningless with libyang 0.16.74 or newer and will be
+   removed once support for older libyang versions is dropped.
+
 When it's desired to run FRR without installing it in the system, it's possible
 to configure it as follows to look for YANG modules and libyang plugins in the
 compile directory:
diff --git a/include/linux/if_addr.h b/include/linux/if_addr.h
new file mode 100644 (file)
index 0000000..a924606
--- /dev/null
@@ -0,0 +1,69 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef __LINUX_IF_ADDR_H
+#define __LINUX_IF_ADDR_H
+
+#include <linux/types.h>
+#include <linux/netlink.h>
+
+struct ifaddrmsg {
+       __u8            ifa_family;
+       __u8            ifa_prefixlen;  /* The prefix length            */
+       __u8            ifa_flags;      /* Flags                        */
+       __u8            ifa_scope;      /* Address scope                */
+       __u32           ifa_index;      /* Link index                   */
+};
+
+/*
+ * Important comment:
+ * IFA_ADDRESS is prefix address, rather than local interface address.
+ * It makes no difference for normally configured broadcast interfaces,
+ * but for point-to-point IFA_ADDRESS is DESTINATION address,
+ * local address is supplied in IFA_LOCAL attribute.
+ *
+ * IFA_FLAGS is a u32 attribute that extends the u8 field ifa_flags.
+ * If present, the value from struct ifaddrmsg will be ignored.
+ */
+enum {
+       IFA_UNSPEC,
+       IFA_ADDRESS,
+       IFA_LOCAL,
+       IFA_LABEL,
+       IFA_BROADCAST,
+       IFA_ANYCAST,
+       IFA_CACHEINFO,
+       IFA_MULTICAST,
+       IFA_FLAGS,
+       IFA_RT_PRIORITY,  /* u32, priority/metric for prefix route */
+       __IFA_MAX,
+};
+
+#define IFA_MAX (__IFA_MAX - 1)
+
+/* ifa_flags */
+#define IFA_F_SECONDARY                0x01
+#define IFA_F_TEMPORARY                IFA_F_SECONDARY
+
+#define        IFA_F_NODAD             0x02
+#define IFA_F_OPTIMISTIC       0x04
+#define IFA_F_DADFAILED                0x08
+#define        IFA_F_HOMEADDRESS       0x10
+#define IFA_F_DEPRECATED       0x20
+#define IFA_F_TENTATIVE                0x40
+#define IFA_F_PERMANENT                0x80
+#define IFA_F_MANAGETEMPADDR   0x100
+#define IFA_F_NOPREFIXROUTE    0x200
+#define IFA_F_MCAUTOJOIN       0x400
+#define IFA_F_STABLE_PRIVACY   0x800
+
+struct ifa_cacheinfo {
+       __u32   ifa_prefered;
+       __u32   ifa_valid;
+       __u32   cstamp; /* created timestamp, hundredths of seconds */
+       __u32   tstamp; /* updated timestamp, hundredths of seconds */
+};
+
+/* backwards compatibility for userspace */
+#define IFA_RTA(r)  ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrmsg))))
+#define IFA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifaddrmsg))
+
+#endif
index 731785d4b4dd61ffdfe802197d8abf8601e5f69e..0d7fed28529e12bcf0f6fe869640363dd974908c 100644 (file)
@@ -1,4 +1,5 @@
 noinst_HEADERS += \
+       include/linux/if_addr.h \
        include/linux/if_bridge.h \
        include/linux/if_link.h \
        include/linux/lwtunnel.h \
index 166bfa92b52b610e7ae95ca1627018e72204ee11..5b46ed820462db746164896767af1b66193fc32b 100644 (file)
--- a/lib/if.h
+++ b/lib/if.h
@@ -341,6 +341,8 @@ DECLARE_QOBJ_TYPE(interface)
 DECLARE_HOOK(if_add, (struct interface * ifp), (ifp))
 DECLARE_KOOH(if_del, (struct interface * ifp), (ifp))
 
+#define METRIC_MAX (~0)
+
 /* Connected address structure. */
 struct connected {
        /* Attached interface. */
@@ -388,6 +390,13 @@ struct connected {
 
        /* Label for Linux 2.2.X and upper. */
        char *label;
+
+       /*
+        * Used for setting the connected route's cost. If the metric
+        * here is set to METRIC_MAX the connected route falls back to
+        * "struct interface"
+        */
+       uint32_t metric;
 };
 
 /* Nbr Connected address structure. */
index 66384fe4492af8e3f59037dbf7c178557308e295..7435272761c631f5ddd69121ee4a0684363f9462 100755 (executable)
@@ -121,7 +121,7 @@ sub codelist {
        }
        $str =~ s/ $//;
        push @lines, $str . "\\n\" \\\n";
-       push @lines, "  \"       > - selected route, * - FIB route\\n\\n\"";
+       push @lines, "  \"       > - selected route, * - FIB route, q - queued route, f - failed route\\n\\n\"";
        return join("", @lines);
 }
 
index 4f5f9ff218ef724de1e9e40c3b6966b3c21d57ea..01468b820363645e746a3f0ef53753f04b523941 100644 (file)
@@ -163,7 +163,7 @@ static struct ttable_cell *ttable_insert_row_va(struct ttable *tt, int i,
 
        orig = res;
 
-       while (res) {
+       while (res && col < tt->ncols) {
                section = strsep(&res, "|");
                row[col].text = XSTRDUP(MTYPE_TTABLE, section);
                row[col].style = tt->style.cell;
index 71b41c35d8225a660650a573549b1c93617c12a2..f62a8163f9760e0cd70d558529491ce154dbbdd7 100644 (file)
@@ -26,6 +26,8 @@
 #include "yang_translator.h"
 #include "northbound.h"
 
+#include <libyang/user_types.h>
+
 DEFINE_MTYPE(LIB, YANG_MODULE, "YANG module")
 DEFINE_MTYPE(LIB, YANG_DATA, "YANG data structure")
 
@@ -639,8 +641,18 @@ static void ly_log_cb(LY_LOG_LEVEL level, const char *msg, const char *path)
                zlog(priority, "libyang: %s", msg);
 }
 
+#if CONFDATE > 20190401
+CPP_NOTICE("lib/yang: time to remove non-LIBYANG_EXT_BUILTIN support")
+#endif
+
+#ifdef LIBYANG_EXT_BUILTIN
+extern struct lytype_plugin_list frr_user_types[];
+#endif
+
 void yang_init(void)
 {
+#ifndef LIBYANG_EXT_BUILTIN
+CPP_NOTICE("lib/yang: deprecated libyang <0.16.74 extension loading in use!")
        static char ly_plugin_dir[PATH_MAX];
        const char *const *ly_loaded_plugins;
        const char *ly_plugin;
@@ -650,11 +662,20 @@ void yang_init(void)
        snprintf(ly_plugin_dir, sizeof(ly_plugin_dir), "%s=%s",
                 "LIBYANG_USER_TYPES_PLUGINS_DIR", LIBYANG_PLUGINS_PATH);
        putenv(ly_plugin_dir);
+#endif
 
        /* Initialize libyang global parameters that affect all containers. */
        ly_set_log_clb(ly_log_cb, 1);
        ly_log_options(LY_LOLOG | LY_LOSTORE);
 
+#ifdef LIBYANG_EXT_BUILTIN
+       if (ly_register_types(frr_user_types, "frr_user_types")) {
+               flog_err(EC_LIB_LIBYANG_PLUGIN_LOAD,
+                        "ly_register_types() failed");
+               exit(1);
+       }
+#endif
+
        /* Initialize libyang container for native models. */
        ly_native_ctx =
                ly_ctx_new(YANG_MODELS_PATH, LY_CTX_DISABLE_SEARCHDIR_CWD);
@@ -665,6 +686,7 @@ void yang_init(void)
        ly_ctx_set_module_imp_clb(ly_native_ctx, yang_module_imp_clb, NULL);
        ly_ctx_set_priv_dup_clb(ly_native_ctx, ly_dup_cb);
 
+#ifndef LIBYANG_EXT_BUILTIN
        /* Detect if the required libyang plugin(s) were loaded successfully. */
        ly_loaded_plugins = ly_get_loaded_plugins();
        for (size_t i = 0; (ly_plugin = ly_loaded_plugins[i]); i++) {
@@ -678,6 +700,7 @@ void yang_init(void)
                         "%s: failed to load frr_user_types.so", __func__);
                exit(1);
        }
+#endif
 
        yang_translator_init();
 }
index 95f0a990b21c53cbbf1e26c4a061a2d5c52e4a0d..8a3423cdd8c16f23d97d3aac4cff311608a7ee80 100644 (file)
@@ -426,6 +426,8 @@ enum zapi_iptable_notify_owner {
 #define ZEBRA_MACIP_TYPE_ROUTER_FLAG           0x04 /* Router Flag - proxy NA */
 #define ZEBRA_MACIP_TYPE_OVERRIDE_FLAG         0x08 /* Override Flag */
 
+enum zebra_neigh_state { ZEBRA_NEIGH_INACTIVE = 0, ZEBRA_NEIGH_ACTIVE = 1 };
+
 struct zclient_options {
        bool receive_notify;
 };
index 2bfa4201cbce5bed54f907745c25223ba198f630..dd08144daaf33ece08b4f7a3dcc6e9c21fbf074a 100644 (file)
@@ -246,6 +246,7 @@ void ospf6_interface_delete(struct ospf6_interface *oi)
        THREAD_OFF(oi->thread_send_hello);
        THREAD_OFF(oi->thread_send_lsupdate);
        THREAD_OFF(oi->thread_send_lsack);
+       THREAD_OFF(oi->thread_sso);
 
        ospf6_lsdb_remove_all(oi->lsdb);
        ospf6_lsdb_remove_all(oi->lsupdate_list);
@@ -291,6 +292,7 @@ void ospf6_interface_disable(struct ospf6_interface *oi)
        THREAD_OFF(oi->thread_send_hello);
        THREAD_OFF(oi->thread_send_lsupdate);
        THREAD_OFF(oi->thread_send_lsack);
+       THREAD_OFF(oi->thread_sso);
 
        THREAD_OFF(oi->thread_network_lsa);
        THREAD_OFF(oi->thread_link_lsa);
@@ -381,9 +383,9 @@ void ospf6_interface_state_update(struct interface *ifp)
        if (if_is_operative(ifp)
            && (ospf6_interface_get_linklocal_address(oi->interface)
                || if_is_loopback(oi->interface)))
-               thread_add_event(master, interface_up, oi, 0, NULL);
+               thread_execute(master, interface_up, oi, 0);
        else
-               thread_add_event(master, interface_down, oi, 0, NULL);
+               thread_execute(master, interface_down, oi, 0);
 
        return;
 }
@@ -679,6 +681,12 @@ int interface_up(struct thread *thread)
        oi = (struct ospf6_interface *)THREAD_ARG(thread);
        assert(oi && oi->interface);
 
+       /*
+        * Remove old pointer. If this thread wasn't a timer this
+        * operation won't make a difference, because it is already NULL.
+        */
+       oi->thread_sso = NULL;
+
        if (IS_OSPF6_DEBUG_INTERFACE)
                zlog_debug("Interface Event %s: [InterfaceUp]",
                           oi->interface->name);
@@ -721,6 +729,22 @@ int interface_up(struct thread *thread)
                return 0;
        }
 
+#ifdef __FreeBSD__
+       /*
+        * XXX: Schedule IPv6 group join for later, otherwise we might
+        * lose the multicast group registration caused by IPv6 group
+        * leave race.
+        */
+       if (oi->sso_try_cnt == 0) {
+               oi->sso_try_cnt++;
+               zlog_info("Scheduling %s for sso", oi->interface->name);
+               thread_add_timer(master, interface_up, oi,
+                                OSPF6_INTERFACE_SSO_RETRY_INT,
+                                &oi->thread_sso);
+               return 0;
+       }
+#endif /* __FreeBSD__ */
+
        /* Join AllSPFRouters */
        if (ospf6_sso(oi->interface->ifindex, &allspfrouters6, IPV6_JOIN_GROUP)
            < 0) {
@@ -729,7 +753,8 @@ int interface_up(struct thread *thread)
                                "Scheduling %s for sso retry, trial count: %d",
                                oi->interface->name, oi->sso_try_cnt);
                        thread_add_timer(master, interface_up, oi,
-                                        OSPF6_INTERFACE_SSO_RETRY_INT, NULL);
+                                        OSPF6_INTERFACE_SSO_RETRY_INT,
+                                        &oi->thread_sso);
                }
                return 0;
        }
@@ -830,6 +855,9 @@ int interface_down(struct thread *thread)
        /* Stop Hellos */
        THREAD_OFF(oi->thread_send_hello);
 
+       /* Stop trying to set socket options. */
+       THREAD_OFF(oi->thread_sso);
+
        /* Leave AllSPFRouters */
        if (oi->state > OSPF6_INTERFACE_DOWN)
                ospf6_sso(oi->interface->ifindex, &allspfrouters6,
@@ -1602,6 +1630,7 @@ DEFUN (ipv6_ospf6_passive,
 
        SET_FLAG(oi->flag, OSPF6_INTERFACE_PASSIVE);
        THREAD_OFF(oi->thread_send_hello);
+       THREAD_OFF(oi->thread_sso);
 
        for (ALL_LIST_ELEMENTS(oi->neighbor_list, node, nnode, on)) {
                THREAD_OFF(on->inactivity_timer);
@@ -1631,7 +1660,7 @@ DEFUN (no_ipv6_ospf6_passive,
 
        UNSET_FLAG(oi->flag, OSPF6_INTERFACE_PASSIVE);
        THREAD_OFF(oi->thread_send_hello);
-       oi->thread_send_hello = NULL;
+       THREAD_OFF(oi->thread_sso);
        thread_add_event(master, ospf6_hello_send, oi, 0,
                         &oi->thread_send_hello);
 
@@ -1791,8 +1820,8 @@ DEFUN (ipv6_ospf6_network,
        }
 
        /* Reset the interface */
-       thread_add_event(master, interface_down, oi, 0, NULL);
-       thread_add_event(master, interface_up, oi, 0, NULL);
+       thread_execute(master, interface_down, oi, 0);
+       thread_execute(master, interface_up, oi, 0);
 
        return CMD_SUCCESS;
 }
@@ -1825,8 +1854,8 @@ DEFUN (no_ipv6_ospf6_network,
        oi->type = type;
 
        /* Reset the interface */
-       thread_add_event(master, interface_down, oi, 0, NULL);
-       thread_add_event(master, interface_up, oi, 0, NULL);
+       thread_execute(master, interface_down, oi, 0);
+       thread_execute(master, interface_up, oi, 0);
 
        return CMD_SUCCESS;
 }
@@ -1969,8 +1998,8 @@ static void ospf6_interface_clear(struct vty *vty, struct interface *ifp)
                zlog_debug("Interface %s: clear by reset", ifp->name);
 
        /* Reset the interface */
-       thread_add_event(master, interface_down, oi, 0, NULL);
-       thread_add_event(master, interface_up, oi, 0, NULL);
+       thread_execute(master, interface_down, oi, 0);
+       thread_execute(master, interface_up, oi, 0);
 }
 
 /* Clear interface */
index 8fd43f099a03c0b3bca4c549e4d3afdc543afc88..e0c39a29b40a83e9bb8c0be28bb4e71a3d828f70 100644 (file)
@@ -80,6 +80,7 @@ struct ospf6_interface {
 
        /* Interface socket setting trial counter, resets on success */
        uint8_t sso_try_cnt;
+       struct thread *thread_sso;
 
        /* OSPF6 Interface flag */
        char flag;
index 566fc29202d13c121433d9970d5a5836230b3127..b912a80692e08ab86ebed53cfcfcdf4f4e9adc31 100644 (file)
@@ -169,6 +169,15 @@ static struct log_ref ferr_ospf_err[] = {
                .description = "OSPF has attempted to change states when it should not be able to",
                .suggestion = "Gather log files and open an issue",
        },
+       {
+               .code = EC_OSPF_LARGE_HELLO,
+               .title = "OSPF Encountered a Large Hello",
+               .description = "OSPF attempted to send a Hello larger than MTU "
+                                          "but did not",
+               .suggestion = "Too many neighbors configured on a single interface."
+                                         " Suggestion is to decrease the number of neighbors on"
+                                         " a single interface/subnet"
+       },
        {
                .code = END_FERR,
        }
index cea649a6f49a6993d7cfd308e0ad2eb1f4cb32b3..726f7d9c8b31e4f3f76425233249fc0b5ab04472 100644 (file)
@@ -47,6 +47,7 @@ enum ospf_log_refs {
        EC_OSPF_LSA_MISSING,
        EC_OSPF_PTP_NEIGHBOR,
        EC_OSPF_LSA_SIZE,
+       EC_OSPF_LARGE_HELLO,
 };
 
 extern void ospf_error_init(void);
index 136683b074ca15ac18932048614f69b273181648..30f5a2a80e54030326f12a74805477a17b56a41c 100644 (file)
@@ -3309,6 +3309,16 @@ static int ospf_make_hello(struct ospf_interface *oi, struct stream *s)
                                                                                .prefix4))
                                                                flag = 1;
 
+                                                       /* Hello packet overflows interface MTU. */
+                                                       if (length + sizeof(uint32_t)
+                                                               > ospf_packet_max(oi)) {
+                                                               flog_err(
+                                                                       EC_OSPF_LARGE_HELLO,
+                                                                       "Oversized Hello packet!"
+                                                                       " Larger than MTU. Not sending it out");
+                                                               return 0;
+                                                       }
+
                                                        stream_put_ipv4(
                                                                s,
                                                                nbr->router_id
@@ -3578,6 +3588,11 @@ static void ospf_hello_send_sub(struct ospf_interface *oi, in_addr_t addr)
 
        /* Prepare OSPF Hello body. */
        length += ospf_make_hello(oi, op->s);
+       if (length == OSPF_HEADER_SIZE) {
+               /* Hello overshooting MTU */
+               ospf_packet_free(op);
+               return;
+       }
 
        /* Fill OSPF header. */
        ospf_fill_header(oi, op->s, length);
index bafd131b78b8cb844a302feb897bca8bec917eb6..44068605eee8a0a178cf799084340f699a965eb2 100644 (file)
@@ -9,7 +9,7 @@ class TestFlag(frrtest.TestMultiOut):
 TestFlag.okfail('peer\\advertisement-interval')
 TestFlag.okfail('peer\\capability dynamic')
 TestFlag.okfail('peer\\capability extended-nexthop')
-TestFlag.okfail('peer\\capability extended-nexthop')
+#TestFlag.okfail('peer\\capability extended-nexthop')
 TestFlag.okfail('peer\\description')
 TestFlag.okfail('peer\\disable-connected-check')
 TestFlag.okfail('peer\\dont-capability-negotiate')
index 956d22587c0bd150baeda3c4ce5c2e5ff9e87f9e..716478908342d2ede059e0b376c65f0bc44b3825 100644 (file)
@@ -1,7 +1,12 @@
 #
 # libyang user types
 #
+
+if LIBYANG_EXT_BUILTIN
+lib_libfrr_la_SOURCES += yang/libyang_plugins/frr_user_types.c
+else
 libyang_plugins_LTLIBRARIES += yang/libyang_plugins/frr_user_types.la
+endif
 
 yang_libyang_plugins_frr_user_types_la_CFLAGS = $(WERROR)
 yang_libyang_plugins_frr_user_types_la_LDFLAGS = -avoid-version -module -shared -export-dynamic
index ab66eb3324aa86208f22d61d5beb2189365342b7..c449855f6dfb40901485e334a6b60a2544887ea9 100644 (file)
@@ -209,6 +209,7 @@ void connected_up(struct interface *ifp, struct connected *ifc)
                .ifindex = ifp->ifindex,
                .vrf_id = ifp->vrf_id,
        };
+       uint32_t metric;
 
        if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL))
                return;
@@ -243,11 +244,13 @@ void connected_up(struct interface *ifp, struct connected *ifc)
                break;
        }
 
+       metric = (ifc->metric < (uint32_t)METRIC_MAX) ?
+                               ifc->metric : ifp->metric;
        rib_add(afi, SAFI_UNICAST, ifp->vrf_id, ZEBRA_ROUTE_CONNECT, 0, 0, &p,
-               NULL, &nh, RT_TABLE_MAIN, ifp->metric, 0, 0, 0);
+               NULL, &nh, RT_TABLE_MAIN, metric, 0, 0, 0);
 
        rib_add(afi, SAFI_MULTICAST, ifp->vrf_id, ZEBRA_ROUTE_CONNECT, 0, 0, &p,
-               NULL, &nh, RT_TABLE_MAIN, ifp->metric, 0, 0, 0);
+               NULL, &nh, RT_TABLE_MAIN, metric, 0, 0, 0);
 
        if (IS_ZEBRA_DEBUG_RIB_DETAILED) {
                char buf[PREFIX_STRLEN];
@@ -276,7 +279,7 @@ void connected_up(struct interface *ifp, struct connected *ifc)
 /* Add connected IPv4 route to the interface. */
 void connected_add_ipv4(struct interface *ifp, int flags, struct in_addr *addr,
                        uint16_t prefixlen, struct in_addr *broad,
-                       const char *label)
+                       const char *label, uint32_t metric)
 {
        struct prefix_ipv4 *p;
        struct connected *ifc;
@@ -288,6 +291,7 @@ void connected_add_ipv4(struct interface *ifp, int flags, struct in_addr *addr,
        ifc = connected_new();
        ifc->ifp = ifp;
        ifc->flags = flags;
+       ifc->metric = metric;
        /* If we get a notification from the kernel,
         * we can safely assume the address is known to the kernel */
        SET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED);
@@ -500,7 +504,7 @@ void connected_delete_ipv4(struct interface *ifp, int flags,
 /* Add connected IPv6 route to the interface. */
 void connected_add_ipv6(struct interface *ifp, int flags, struct in6_addr *addr,
                        struct in6_addr *broad, uint16_t prefixlen,
-                       const char *label)
+                       const char *label, uint32_t metric)
 {
        struct prefix_ipv6 *p;
        struct connected *ifc;
@@ -512,6 +516,7 @@ void connected_add_ipv6(struct interface *ifp, int flags, struct in6_addr *addr,
        ifc = connected_new();
        ifc->ifp = ifp;
        ifc->flags = flags;
+       ifc->metric = metric;
        /* If we get a notification from the kernel,
         * we can safely assume the address is known to the kernel */
        SET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED);
index 415ecfd96518148a67f450d22e408e504df4c49d..faba30b0d5c653a30a9e4208070cf9115295f905 100644 (file)
@@ -36,7 +36,8 @@ extern struct connected *connected_check_ptp(struct interface *ifp,
 
 extern void connected_add_ipv4(struct interface *ifp, int flags,
                               struct in_addr *addr, uint16_t prefixlen,
-                              struct in_addr *broad, const char *label);
+                              struct in_addr *broad, const char *label,
+                              uint32_t metric);
 
 extern void connected_delete_ipv4(struct interface *ifp, int flags,
                                  struct in_addr *addr, uint16_t prefixlen,
@@ -49,7 +50,8 @@ extern void connected_down(struct interface *ifp, struct connected *ifc);
 
 extern void connected_add_ipv6(struct interface *ifp, int flags,
                               struct in6_addr *address, struct in6_addr *broad,
-                              uint16_t prefixlen, const char *label);
+                              uint16_t prefixlen, const char *label,
+                              uint32_t metric);
 extern void connected_delete_ipv6(struct interface *ifp,
                                  struct in6_addr *address,
                                  struct in6_addr *broad, uint16_t prefixlen);
index df79d285a3609e3807523928be4dc83978b13290..debc151d752dd770beb6b4537b9438a3e6c95e37 100644 (file)
@@ -236,7 +236,8 @@ static int if_getaddrs(void)
                        }
 
                        connected_add_ipv4(ifp, flags, &addr->sin_addr,
-                                          prefixlen, dest_pnt, NULL);
+                                          prefixlen, dest_pnt, NULL,
+                                          METRIC_MAX);
                }
                if (ifap->ifa_addr->sa_family == AF_INET6) {
                        struct sockaddr_in6 *addr;
@@ -258,7 +259,7 @@ static int if_getaddrs(void)
 #endif
 
                        connected_add_ipv6(ifp, flags, &addr->sin6_addr, NULL,
-                                          prefixlen, NULL);
+                                          prefixlen, NULL, METRIC_MAX);
                }
        }
 
index 0206d4938efda498eb908772f28b574a8cb56396..2c29930c3f661d2ab80b6141d63e9b682bc05dbf 100644 (file)
@@ -302,10 +302,11 @@ static int if_get_addr(struct interface *ifp, struct sockaddr *addr,
        /* Set address to the interface. */
        if (af == AF_INET)
                connected_add_ipv4(ifp, flags, &SIN(addr)->sin_addr, prefixlen,
-                                  (struct in_addr *)dest_pnt, label);
+                                  (struct in_addr *)dest_pnt, label,
+                                  METRIC_MAX);
        else if (af == AF_INET6)
                connected_add_ipv6(ifp, flags, &SIN6(addr)->sin6_addr, NULL,
-                                  prefixlen, label);
+                                  prefixlen, label, METRIC_MAX);
 
        return 0;
 }
index 0cecce5e74b79c961f0a2d1821e6089518355fa8..47087d4ce01c5a6c0e589c3a606281e1ca58c4ec 100644 (file)
@@ -924,6 +924,7 @@ int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup)
        uint8_t flags = 0;
        char *label = NULL;
        struct zebra_ns *zns;
+       uint32_t metric = METRIC_MAX;
 
        zns = zebra_ns_lookup(ns_id);
        ifa = NLMSG_DATA(h);
@@ -1032,6 +1033,9 @@ int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup)
        if (label && strcmp(ifp->name, label) == 0)
                label = NULL;
 
+       if (tb[IFA_RT_PRIORITY])
+               metric = *(uint32_t *)RTA_DATA(tb[IFA_RT_PRIORITY]);
+
        /* Register interface address to the interface. */
        if (ifa->ifa_family == AF_INET) {
                if (ifa->ifa_prefixlen > IPV4_MAX_BITLEN) {
@@ -1044,7 +1048,8 @@ int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup)
                if (h->nlmsg_type == RTM_NEWADDR)
                        connected_add_ipv4(ifp, flags, (struct in_addr *)addr,
                                           ifa->ifa_prefixlen,
-                                          (struct in_addr *)broad, label);
+                                          (struct in_addr *)broad, label,
+                                          metric);
                else
                        connected_delete_ipv4(
                                ifp, flags, (struct in_addr *)addr,
@@ -1070,7 +1075,8 @@ int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup)
                                connected_add_ipv6(ifp, flags,
                                                   (struct in6_addr *)addr,
                                                   (struct in6_addr *)broad,
-                                                  ifa->ifa_prefixlen, label);
+                                                  ifa->ifa_prefixlen, label,
+                                                  metric);
                } else
                        connected_delete_ipv6(ifp, (struct in6_addr *)addr,
                                              (struct in6_addr *)broad,
index f3561cc19d3f7d6836c0482e6f17810520560bad..acd7f911dcefbf62888908f7305a67387ad1bc87 100644 (file)
@@ -906,7 +906,8 @@ int ifam_read(struct ifa_msghdr *ifam)
                        connected_add_ipv4(ifp, flags, &addr.sin.sin_addr,
                                           ip_masklen(mask.sin.sin_addr),
                                           &brd.sin.sin_addr,
-                                          (isalias ? ifname : NULL));
+                                          (isalias ? ifname : NULL),
+                                          METRIC_MAX);
                else
                        connected_delete_ipv4(ifp, flags, &addr.sin.sin_addr,
                                              ip_masklen(mask.sin.sin_addr),
@@ -923,7 +924,8 @@ int ifam_read(struct ifa_msghdr *ifam)
                        connected_add_ipv6(ifp, flags, &addr.sin6.sin6_addr,
                                           NULL,
                                           ip6_masklen(mask.sin6.sin6_addr),
-                                          (isalias ? ifname : NULL));
+                                          (isalias ? ifname : NULL),
+                                          METRIC_MAX);
                else
                        connected_delete_ipv6(ifp, &addr.sin6.sin6_addr, NULL,
                                              ip6_masklen(mask.sin6.sin6_addr));
index abcff22b6b183f315370370bdcd4629ad3c9ad7d..f25259f300cef721a1edf47fb91a57d07d212a93 100644 (file)
@@ -92,10 +92,9 @@ static int kernel_rtm(int cmd, const struct prefix *p,
         */
        if (cmd != RTM_ADD && cmd != RTM_DELETE) {
                if (IS_ZEBRA_DEBUG_KERNEL)
-                       zlog_debug("%s: %s odd command %s for flags %d",
+                       zlog_debug("%s: %s odd command %s",
                                   __func__, prefix_buf,
-                                  lookup_msg(rtm_type_str, cmd, NULL),
-                                  nexthop->flags);
+                                  lookup_msg(rtm_type_str, cmd, NULL));
                return 0;
        }
 
@@ -308,8 +307,7 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx)
 
        if (dplane_ctx_get_src(ctx) != NULL) {
                zlog_err("route add: IPv6 sourcedest routes unsupported!");
-               res = ZEBRA_DPLANE_REQUEST_FAILURE;
-               goto done;
+               return ZEBRA_DPLANE_REQUEST_FAILURE;
        }
 
        frr_elevate_privs(&zserv_privs) {
@@ -341,8 +339,6 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx)
                }
        } /* Elevated privs */
 
-done:
-
        return res;
 }
 
index 207cbc0992221a9c2de839ff69a7cf9c23467813..28333526a7cf83c03ec8dddad822246aedceec23 100644 (file)
@@ -276,7 +276,7 @@ static int netlink_route_info_fill(netlink_route_info_t *ri, int cmd,
                if ((cmd == RTM_NEWROUTE
                     && CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
                    || (cmd == RTM_DELROUTE
-                       && CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB))) {
+                       && CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED))) {
                        netlink_route_info_add_nh(ri, nexthop);
                }
        }
index 0dc8a05e9c6d66742b9eeb34d4fde4769ef5b633..c66b78cc9dafa294cdc52a71a8211c9549c3db95 100644 (file)
@@ -566,8 +566,8 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
                } else if (CHECK_FLAG(re->flags, ZEBRA_FLAG_ALLOW_RECURSION)) {
                        resolved = 0;
                        for (ALL_NEXTHOPS(match->ng, newhop)) {
-                               if (!CHECK_FLAG(newhop->flags,
-                                               NEXTHOP_FLAG_FIB))
+                               if (!CHECK_FLAG(match->status,
+                                               ROUTE_ENTRY_INSTALLED))
                                        continue;
                                if (CHECK_FLAG(newhop->flags,
                                               NEXTHOP_FLAG_RECURSIVE))
@@ -592,8 +592,8 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
                } else if (re->type == ZEBRA_ROUTE_STATIC) {
                        resolved = 0;
                        for (ALL_NEXTHOPS(match->ng, newhop)) {
-                               if (!CHECK_FLAG(newhop->flags,
-                                               NEXTHOP_FLAG_FIB))
+                               if (!CHECK_FLAG(match->status,
+                                               ROUTE_ENTRY_INSTALLED))
                                        continue;
 
                                if (set) {
@@ -637,7 +637,6 @@ struct route_entry *rib_match(afi_t afi, safi_t safi, vrf_id_t vrf_id,
        struct route_table *table;
        struct route_node *rn;
        struct route_entry *match = NULL;
-       struct nexthop *newhop;
 
        /* Lookup table.  */
        table = zebra_vrf_table(afi, safi, vrf_id);
@@ -677,14 +676,8 @@ struct route_entry *rib_match(afi_t afi, safi_t safi, vrf_id_t vrf_id,
                                route_lock_node(rn);
                } else {
                        if (match->type != ZEBRA_ROUTE_CONNECT) {
-                               int found = 0;
-                               for (ALL_NEXTHOPS(match->ng, newhop))
-                                       if (CHECK_FLAG(newhop->flags,
-                                                      NEXTHOP_FLAG_FIB)) {
-                                               found = 1;
-                                               break;
-                                       }
-                               if (!found)
+                               if (!CHECK_FLAG(match->status,
+                                               ROUTE_ENTRY_INSTALLED))
                                        return NULL;
                        }
 
@@ -774,7 +767,6 @@ struct route_entry *rib_lookup_ipv4(struct prefix_ipv4 *p, vrf_id_t vrf_id)
        struct route_table *table;
        struct route_node *rn;
        struct route_entry *match = NULL;
-       struct nexthop *nexthop;
        rib_dest_t *dest;
 
        /* Lookup table.  */
@@ -802,9 +794,8 @@ struct route_entry *rib_lookup_ipv4(struct prefix_ipv4 *p, vrf_id_t vrf_id)
        if (match->type == ZEBRA_ROUTE_CONNECT)
                return match;
 
-       for (ALL_NEXTHOPS(match->ng, nexthop))
-               if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB))
-                       return match;
+       if (CHECK_FLAG(match->status, ROUTE_ENTRY_INSTALLED))
+               return match;
 
        return NULL;
 }
@@ -1089,6 +1080,9 @@ 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)
+                       SET_FLAG(old->status, ROUTE_ENTRY_QUEUED);
                if (zvrf)
                        zvrf->installs_queued++;
                break;
@@ -1119,6 +1113,7 @@ void rib_uninstall_kernel(struct route_node *rn, struct route_entry *re)
        struct zebra_vrf *zvrf = vrf_info_lookup(re->vrf_id);
 
        if (info->safi != SAFI_UNICAST) {
+               UNSET_FLAG(re->status, ROUTE_ENTRY_INSTALLED);
                for (ALL_NEXTHOPS(re->ng, nexthop))
                        UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
                return;
@@ -1171,6 +1166,8 @@ static void rib_uninstall(struct route_node *rn, struct route_entry *re)
 
                if (!RIB_SYSTEM_ROUTE(re))
                        rib_uninstall_kernel(rn, re);
+               else
+                       UNSET_FLAG(re->status, ROUTE_ENTRY_INSTALLED);
 
                dest->selected_fib = NULL;
 
@@ -1301,6 +1298,7 @@ static void rib_process_del_fib(struct zebra_vrf *zvrf, struct route_node *rn,
        if (!RIB_SYSTEM_ROUTE(old))
                rib_uninstall_kernel(rn, old);
        else {
+               UNSET_FLAG(old->status, ROUTE_ENTRY_INSTALLED);
                /*
                 * We are setting this to NULL here
                 * because that is what we traditionally
@@ -1381,6 +1379,7 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf,
 
                                rib_install_kernel(rn, new, old);
                        } else {
+                               UNSET_FLAG(new->status, ROUTE_ENTRY_INSTALLED);
                                /*
                                 * We do not need to install the
                                 * selected route because it
@@ -1400,7 +1399,13 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf,
                                if (RIB_SYSTEM_ROUTE(new)) {
                                        if (!RIB_SYSTEM_ROUTE(old))
                                                rib_uninstall_kernel(rn, old);
+                                       else
+                                               UNSET_FLAG(
+                                                       old->status,
+                                                       ROUTE_ENTRY_INSTALLED);
                                } else {
+                                       UNSET_FLAG(old->status,
+                                                  ROUTE_ENTRY_INSTALLED);
                                        for (nexthop = old->ng.nexthop; nexthop;
                                             nexthop = nexthop->next)
                                                UNSET_FLAG(nexthop->flags,
@@ -1437,8 +1442,10 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf,
 
                        if (!RIB_SYSTEM_ROUTE(old))
                                rib_uninstall_kernel(rn, old);
-                       else
+                       else {
+                               UNSET_FLAG(old->status, ROUTE_ENTRY_INSTALLED);
                                dest->selected_fib = NULL;
+                       }
                }
        } else {
                /*
@@ -1450,18 +1457,9 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf,
                 * is ready
                 * to add routes.
                 */
-               if (!RIB_SYSTEM_ROUTE(new)) {
-                       bool in_fib = false;
-
-                       for (ALL_NEXTHOPS(new->ng, nexthop))
-                               if (CHECK_FLAG(nexthop->flags,
-                                              NEXTHOP_FLAG_FIB)) {
-                                       in_fib = true;
-                                       break;
-                               }
-                       if (!in_fib)
-                               rib_install_kernel(rn, new, NULL);
-               }
+               if (!RIB_SYSTEM_ROUTE(new)
+                   && !CHECK_FLAG(new->status, ROUTE_ENTRY_INSTALLED))
+                       rib_install_kernel(rn, new, NULL);
        }
 
        /* Update prior route. */
@@ -1902,44 +1900,48 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx)
        /*
         * Check sequence number(s) to detect stale results before continuing
         */
-       if (re && (re->dplane_sequence != dplane_ctx_get_seq(ctx))) {
-               if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
-                       zlog_debug("%u:%s Stale dplane result for re %p",
-                                  dplane_ctx_get_vrf(ctx), dest_str, re);
-               }
-               re = NULL;
-       }
-
-       if (old_re &&
-           (old_re->dplane_sequence != dplane_ctx_get_old_seq(ctx))) {
-               if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) {
-                       zlog_debug("%u:%s Stale dplane result for old_re %p",
-                                  dplane_ctx_get_vrf(ctx), dest_str, old_re);
-               }
-               old_re = NULL;
-       }
-
-       /*
-        * Here's sort of a tough one: the route update result is stale.
-        * Is it better to use the context block info to generate
-        * redist and owner notification, or is it better to wait
-        * for the up-to-date result to arrive?
-        */
-       if (re == NULL) {
-               /* TODO -- for now, only expose up-to-date results */
-               goto done;
+       if (re) {
+               if (re->dplane_sequence != dplane_ctx_get_seq(ctx)) {
+                       if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
+                               zlog_debug("%u:%s Stale dplane result for re %p",
+                                          dplane_ctx_get_vrf(ctx),
+                                          dest_str, re);
+               } else
+                       UNSET_FLAG(re->status, ROUTE_ENTRY_QUEUED);
+       }
+
+       if (old_re) {
+               if (old_re->dplane_sequence != dplane_ctx_get_old_seq(ctx)) {
+                       if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
+                               zlog_debug("%u:%s Stale dplane result for old_re %p",
+                                          dplane_ctx_get_vrf(ctx),
+                                          dest_str, old_re);
+               } else
+                       UNSET_FLAG(re->status, ROUTE_ENTRY_QUEUED);
        }
 
        switch (op) {
        case DPLANE_OP_ROUTE_INSTALL:
        case DPLANE_OP_ROUTE_UPDATE:
                if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) {
+                       if (re) {
+                               UNSET_FLAG(re->status, ROUTE_ENTRY_FAILED);
+                               SET_FLAG(re->status, ROUTE_ENTRY_INSTALLED);
+                       }
+                       if (old_re) {
+                               UNSET_FLAG(old_re->status, ROUTE_ENTRY_FAILED);
+                               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;
@@ -1976,15 +1978,21 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx)
                         * 'old' context info was stale, 'old_re' will be
                         * NULL here and that delete will not be sent.
                         */
-                       redistribute_update(dest_pfx, src_pfx, re, old_re);
+                       if (re)
+                               redistribute_update(dest_pfx, src_pfx,
+                                                   re, old_re);
 
                        /* Notify route owner */
-                       zsend_route_notify_owner(re, dest_pfx,
-                                                ZAPI_ROUTE_INSTALLED);
+                       zsend_route_notify_owner_ctx(ctx, ZAPI_ROUTE_INSTALLED);
 
                } else {
-                       zsend_route_notify_owner(re, dest_pfx,
-                                                ZAPI_ROUTE_FAIL_INSTALL);
+                       if (re)
+                               SET_FLAG(re->status, ROUTE_ENTRY_FAILED);
+                       if (old_re)
+                               SET_FLAG(old_re->status, ROUTE_ENTRY_FAILED);
+                       if (re)
+                               zsend_route_notify_owner(re, dest_pfx,
+                                                        ZAPI_ROUTE_FAIL_INSTALL);
 
                        zlog_warn("%u:%s: Route install failed",
                                  dplane_ctx_get_vrf(ctx),
@@ -1993,17 +2001,25 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx)
                }
                break;
        case DPLANE_OP_ROUTE_DELETE:
+               if (re)
+                       SET_FLAG(re->status, ROUTE_ENTRY_FAILED);
                /*
                 * In the delete case, the zebra core datastructs were
                 * updated (or removed) at the time the delete was issued,
                 * so we're just notifying the route owner.
                 */
                if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) {
+                       if (re) {
+                               UNSET_FLAG(re->status, ROUTE_ENTRY_INSTALLED);
+                               UNSET_FLAG(re->status, ROUTE_ENTRY_FAILED);
+                       }
                        zsend_route_notify_owner_ctx(ctx, ZAPI_ROUTE_REMOVED);
 
                        if (zvrf)
                                zvrf->removals++;
                } else {
+                       if (re)
+                               SET_FLAG(re->status, ROUTE_ENTRY_FAILED);
                        zsend_route_notify_owner_ctx(ctx,
                                                     ZAPI_ROUTE_REMOVE_FAIL);
 
@@ -2527,7 +2543,7 @@ void _route_entry_dump(const char *func, union prefixconstptr pp,
                           (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)
                                    ? "ACTIVE "
                                    : ""),
-                          (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)
+                          (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)
                                    ? "FIB "
                                    : ""),
                           (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)
@@ -2708,9 +2724,11 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
        }
 
        /* If this route is kernel route, set FIB flag to the route. */
-       if (RIB_SYSTEM_ROUTE(re))
+       if (RIB_SYSTEM_ROUTE(re)) {
+               SET_FLAG(re->status, ROUTE_ENTRY_INSTALLED);
                for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next)
                        SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
+       }
 
        /* Link new re to node.*/
        if (IS_ZEBRA_DEBUG_RIB) {
@@ -2847,6 +2865,7 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
                                        rn, fib, fib->type);
                        }
                        if (allow_delete) {
+                               UNSET_FLAG(fib->status, ROUTE_ENTRY_INSTALLED);
                                /* Unset flags. */
                                for (rtnh = fib->ng.nexthop; rtnh;
                                     rtnh = rtnh->next)
@@ -3093,6 +3112,7 @@ void rib_sweep_table(struct route_table *table)
                         * to a different spot (ie startup )
                         * this decision needs to be revisited
                         */
+                       SET_FLAG(re->status, ROUTE_ENTRY_INSTALLED);
                        for (ALL_NEXTHOPS(re->ng, nexthop))
                                SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
 
index 317a7cdecad5c0b52a50fc27acf98b84ce181169..52637c6062d01ee4679cb17ec3f198f1bdf34f66 100644 (file)
@@ -370,14 +370,10 @@ static void zebra_rnh_eval_import_check_entry(vrf_id_t vrfid, afi_t afi,
        struct zserv *client;
        char bufn[INET6_ADDRSTRLEN];
        struct listnode *node;
-       struct nexthop *nexthop;
 
        if (re && (rnh->state == NULL)) {
-               for (ALL_NEXTHOPS(re->ng, nexthop))
-                       if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)) {
-                               state_changed = 1;
-                               break;
-                       }
+               if (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED))
+                       state_changed = 1;
        } else if (!re && (rnh->state != NULL))
                state_changed = 1;
 
@@ -511,9 +507,10 @@ static void zebra_rnh_process_pbr_tables(afi_t afi, struct route_node *nrn,
  * check in a couple of places, so this is a single home for the logic we
  * use.
  */
-static bool rnh_nexthop_valid(const struct nexthop *nh)
+static bool rnh_nexthop_valid(const struct route_entry *re,
+                             const struct nexthop *nh)
 {
-       return (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_FIB)
+       return (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)
                && CHECK_FLAG(nh->flags, NEXTHOP_FLAG_ACTIVE));
 }
 
@@ -566,7 +563,7 @@ zebra_rnh_resolve_nexthop_entry(struct zebra_vrf *zvrf, afi_t afi,
                         * have an installed nexthop to be useful.
                         */
                        for (ALL_NEXTHOPS(re->ng, nexthop)) {
-                               if (rnh_nexthop_valid(nexthop))
+                               if (rnh_nexthop_valid(re, nexthop))
                                        break;
                        }
 
@@ -820,6 +817,7 @@ static void copy_state(struct rnh *rnh, struct route_entry *re,
        state->distance = re->distance;
        state->metric = re->metric;
        state->vrf_id = re->vrf_id;
+       state->status = re->status;
 
        route_entry_copy_nexthops(state, re->ng.nexthop);
        rnh->state = state;
@@ -895,7 +893,7 @@ static int send_client(struct rnh *rnh, struct zserv *client, rnh_type_t type,
                nump = stream_get_endp(s);
                stream_putc(s, 0);
                for (ALL_NEXTHOPS(re->ng, nh))
-                       if (rnh_nexthop_valid(nh)) {
+                       if (rnh_nexthop_valid(re, nh)) {
                                stream_putl(s, nh->vrf_id);
                                stream_putc(s, nh->type);
                                switch (nh->type) {
index 87b279b1e9cdd44b99920e719cf6acbeac835653..14288d7bc4b3714880863e17c9f8db7800bd206c 100644 (file)
@@ -161,6 +161,28 @@ DEFUN (show_ip_rpf_addr,
        return CMD_SUCCESS;
 }
 
+static char re_status_output_char(struct route_entry *re, struct nexthop *nhop)
+{
+       if (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)) {
+               if (!CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_DUPLICATE))
+                       return '*';
+               else
+                       return ' ';
+       }
+
+       if (CHECK_FLAG(re->status, ROUTE_ENTRY_FAILED)) {
+               if (CHECK_FLAG(re->status, ROUTE_ENTRY_QUEUED))
+                       return 'q';
+
+               return 'f';
+       }
+
+       if (CHECK_FLAG(re->status, ROUTE_ENTRY_QUEUED))
+               return 'q';
+
+       return ' ';
+}
+
 /* New RIB.  Detailed information for IPv4 route. */
 static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn,
                                     int mcast)
@@ -229,12 +251,7 @@ static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn,
                        char addrstr[32];
 
                        vty_out(vty, "  %c%s",
-                               CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)
-                                       ? CHECK_FLAG(nexthop->flags,
-                                                    NEXTHOP_FLAG_DUPLICATE)
-                                                 ? ' '
-                                                 : '*'
-                                       : ' ',
+                               re_status_output_char(re, nexthop),
                                nexthop->rparent ? "  " : "");
 
                        switch (nexthop->type) {
@@ -389,6 +406,19 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
                if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED))
                        json_object_boolean_true_add(json_route, "selected");
 
+               json_object_int_add(json_route, "distance",
+                                   re->distance);
+               json_object_int_add(json_route, "metric", re->metric);
+
+               if (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED))
+                       json_object_boolean_true_add(json_route, "installed");
+
+               if (CHECK_FLAG(re->status, ROUTE_ENTRY_FAILED))
+                       json_object_boolean_true_add(json_route, "failed");
+
+               if (CHECK_FLAG(re->status, ROUTE_ENTRY_QUEUED))
+                       json_object_boolean_true_add(json_route, "queued");
+
                if (re->type != ZEBRA_ROUTE_CONNECT) {
                        json_object_int_add(json_route, "distance",
                                            re->distance);
@@ -596,23 +626,18 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
                                CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED)
                                        ? '>'
                                        : ' ',
-                               CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)
-                                       ? '*'
-                                       : ' ',
+                               re_status_output_char(re, nexthop),
                                srcdest_rnode2str(rn, buf, sizeof buf));
 
                        /* Distance and metric display. */
-                       if (re->type != ZEBRA_ROUTE_CONNECT)
+                       if (((re->type == ZEBRA_ROUTE_CONNECT) &&
+                            (re->distance || re->metric)) ||
+                           (re->type != ZEBRA_ROUTE_CONNECT))
                                len += vty_out(vty, " [%u/%u]", re->distance,
                                               re->metric);
                } else {
                        vty_out(vty, "  %c%*c",
-                               CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)
-                                       ? CHECK_FLAG(nexthop->flags,
-                                                    NEXTHOP_FLAG_DUPLICATE)
-                                                 ? ' '
-                                                 : '*'
-                                       : ' ',
+                               re_status_output_char(re, nexthop),
                                len - 3 + (2 * nexthop_level(nexthop)), ' ');
                }
 
@@ -1409,21 +1434,20 @@ static void vty_show_ip_route_summary_prefix(struct vty *vty,
                         * In case of ECMP, count only once.
                         */
                        cnt = 0;
+                       if (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)) {
+                               fib_cnt[ZEBRA_ROUTE_TOTAL]++;
+                               fib_cnt[re->type]++;
+                       }
                        for (nexthop = re->ng.nexthop; (!cnt && nexthop);
                             nexthop = nexthop->next) {
                                cnt++;
                                rib_cnt[ZEBRA_ROUTE_TOTAL]++;
                                rib_cnt[re->type]++;
-                               if (CHECK_FLAG(nexthop->flags,
-                                              NEXTHOP_FLAG_FIB)) {
-                                       fib_cnt[ZEBRA_ROUTE_TOTAL]++;
-                                       fib_cnt[re->type]++;
-                               }
                                if (re->type == ZEBRA_ROUTE_BGP
                                    && CHECK_FLAG(re->flags, ZEBRA_FLAG_IBGP)) {
                                        rib_cnt[ZEBRA_ROUTE_IBGP]++;
-                                       if (CHECK_FLAG(nexthop->flags,
-                                                      NEXTHOP_FLAG_FIB))
+                                       if (CHECK_FLAG(re->status,
+                                                      ROUTE_ENTRY_INSTALLED))
                                                fib_cnt[ZEBRA_ROUTE_IBGP]++;
                                }
                        }
index 512e70989f253d266aca8db43007ef9b9382e5a7..49af4a9205c7971c2ac1b61b52028d7e3f4caca7 100644 (file)
@@ -81,7 +81,7 @@ static void zvni_print_hash(struct hash_backet *backet, void *ctxt[]);
 
 static int zvni_macip_send_msg_to_client(vni_t vni, struct ethaddr *macaddr,
                                         struct ipaddr *ip, uint8_t flags,
-                                        uint32_t seq, uint16_t cmd);
+                                        uint32_t seq, int state, uint16_t cmd);
 static unsigned int neigh_hash_keymake(void *p);
 static void *zvni_neigh_alloc(void *p);
 static zebra_neigh_t *zvni_neigh_add(zebra_vni_t *zvni, struct ipaddr *ip,
@@ -97,7 +97,7 @@ static int zvni_neigh_send_add_to_client(vni_t vni, struct ipaddr *ip,
                                         uint8_t flags, uint32_t seq);
 static int zvni_neigh_send_del_to_client(vni_t vni, struct ipaddr *ip,
                                         struct ethaddr *macaddr,
-                                        uint8_t flags);
+                                        uint8_t flags, int state);
 static int zvni_neigh_install(zebra_vni_t *zvni, zebra_neigh_t *n);
 static int zvni_neigh_uninstall(zebra_vni_t *zvni, zebra_neigh_t *n);
 static zebra_vni_t *zvni_from_svi(struct interface *ifp,
@@ -2047,7 +2047,7 @@ static void zvni_print_hash_detail(struct hash_backet *backet, void *data)
  */
 static int zvni_macip_send_msg_to_client(vni_t vni, struct ethaddr *macaddr,
                                         struct ipaddr *ip, uint8_t flags,
-                                        uint32_t seq, uint16_t cmd)
+                                        uint32_t seq, int state, uint16_t cmd)
 {
        char buf[ETHER_ADDR_STRLEN];
        char buf2[INET6_ADDRSTRLEN];
@@ -2081,6 +2081,8 @@ static int zvni_macip_send_msg_to_client(vni_t vni, struct ethaddr *macaddr,
        if (cmd == ZEBRA_MACIP_ADD) {
                stream_putc(s, flags); /* sticky mac/gateway mac */
                stream_putl(s, seq); /* sequence number */
+       } else {
+               stream_putl(s, state); /* state - active/inactive */
        }
 
 
@@ -2219,7 +2221,7 @@ static void zvni_neigh_del_hash_entry(struct hash_backet *backet, void *arg)
                && IPV4_ADDR_SAME(&n->r_vtep_ip, &wctx->r_vtep_ip))) {
                if (wctx->upd_client && (n->flags & ZEBRA_NEIGH_LOCAL))
                        zvni_neigh_send_del_to_client(wctx->zvni->vni, &n->ip,
-                                                     &n->emac, 0);
+                                                     &n->emac, 0, n->state);
 
                if (wctx->uninstall)
                        zvni_neigh_uninstall(wctx->zvni, n);
@@ -2355,7 +2357,7 @@ static void zvni_process_neigh_on_local_mac_del(zebra_vni_t *zvni,
                                ZEBRA_NEIGH_SET_INACTIVE(n);
                                n->loc_seq = 0;
                                zvni_neigh_send_del_to_client(zvni->vni, &n->ip,
-                                                             &n->emac, 0);
+                                     &n->emac, 0, ZEBRA_NEIGH_ACTIVE);
                        }
                }
        }
@@ -2386,7 +2388,7 @@ static void zvni_process_neigh_on_remote_mac_add(zebra_vni_t *zvni,
                                ZEBRA_NEIGH_SET_INACTIVE(n);
                                n->loc_seq = 0;
                                zvni_neigh_send_del_to_client(zvni->vni, &n->ip,
-                                                             &n->emac, 0);
+                                             &n->emac, 0, ZEBRA_NEIGH_ACTIVE);
                        }
                }
        }
@@ -2419,17 +2421,18 @@ static int zvni_neigh_send_add_to_client(vni_t vni, struct ipaddr *ip,
                SET_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG);
 
        return zvni_macip_send_msg_to_client(vni, macaddr, ip, flags,
-                                            seq, ZEBRA_MACIP_ADD);
+                            seq, ZEBRA_NEIGH_ACTIVE, ZEBRA_MACIP_ADD);
 }
 
 /*
  * Inform BGP about local neighbor deletion.
  */
 static int zvni_neigh_send_del_to_client(vni_t vni, struct ipaddr *ip,
-                                        struct ethaddr *macaddr, uint8_t flags)
+                                        struct ethaddr *macaddr, uint8_t flags,
+                                        int state)
 {
        return zvni_macip_send_msg_to_client(vni, macaddr, ip, flags,
-                                            0, ZEBRA_MACIP_DEL);
+                                            0, state, ZEBRA_MACIP_DEL);
 }
 
 /*
@@ -2750,7 +2753,7 @@ static int zvni_gw_macip_del(struct interface *ifp, zebra_vni_t *zvni,
 
        /* Remove neighbor from BGP. */
        zvni_neigh_send_del_to_client(zvni->vni, &n->ip, &n->emac,
-                                     ZEBRA_MACIP_TYPE_GW);
+                                     ZEBRA_MACIP_TYPE_GW, ZEBRA_NEIGH_ACTIVE);
 
        /* Delete this neighbor entry. */
        zvni_neigh_del(zvni, n);
@@ -2964,7 +2967,7 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni,
                         */
                        if (IS_ZEBRA_NEIGH_ACTIVE(n))
                                zvni_neigh_send_del_to_client(zvni->vni, &n->ip,
-                                                             &n->emac, 0);
+                                             &n->emac, 0, n->state);
                        old_zmac = zvni_mac_lookup(zvni, &n->emac);
                        if (old_zmac) {
                                old_mac_seq = CHECK_FLAG(old_zmac->flags,
@@ -3320,7 +3323,7 @@ static int zvni_mac_send_add_to_client(vni_t vni, struct ethaddr *macaddr,
                SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
 
        return zvni_macip_send_msg_to_client(vni, macaddr, NULL, flags,
-                                            seq, ZEBRA_MACIP_ADD);
+                            seq, ZEBRA_NEIGH_ACTIVE, ZEBRA_MACIP_ADD);
 }
 
 /*
@@ -3329,7 +3332,7 @@ static int zvni_mac_send_add_to_client(vni_t vni, struct ethaddr *macaddr,
 static int zvni_mac_send_del_to_client(vni_t vni, struct ethaddr *macaddr)
 {
        return zvni_macip_send_msg_to_client(vni, macaddr, NULL, 0 /* flags */,
-                                            0 /* seq */, ZEBRA_MACIP_DEL);
+                            0 /* seq */, ZEBRA_NEIGH_ACTIVE, ZEBRA_MACIP_DEL);
 }
 
 /*
@@ -5260,7 +5263,7 @@ static void process_remote_macip_add(vni_t vni,
                                    IS_ZEBRA_NEIGH_ACTIVE(n))
                                        zvni_neigh_send_del_to_client(
                                                zvni->vni, &n->ip,
-                                               &n->emac, 0);
+                                               &n->emac, 0, n->state);
 
                                /* update neigh list for macs */
                                old_mac = zvni_mac_lookup(zvni, &n->emac);
@@ -7079,8 +7082,8 @@ int zebra_vxlan_handle_kernel_neigh_del(struct interface *ifp,
        }
 
        /* Remove neighbor from BGP. */
-       if (IS_ZEBRA_NEIGH_ACTIVE(n))
-               zvni_neigh_send_del_to_client(zvni->vni, &n->ip, &n->emac, 0);
+       zvni_neigh_send_del_to_client(zvni->vni, &n->ip, &n->emac,
+                       0, n->state);
 
        /* Delete this neighbor entry. */
        zvni_neigh_del(zvni, n);
index 3be7dc012ac2839bb4939f258c25a84c4e0e2495..cae0d62bb307910e890ff8a324c1658a1e98c9b8 100644 (file)
@@ -313,11 +313,9 @@ struct rmac_walk_ctx {
        struct json_object *json;
 };
 
-enum zebra_neigh_state { ZEBRA_NEIGH_INACTIVE = 0, ZEBRA_NEIGH_ACTIVE = 1 };
+#define IS_ZEBRA_NEIGH_ACTIVE(n) (n->state == ZEBRA_NEIGH_ACTIVE)
 
-#define IS_ZEBRA_NEIGH_ACTIVE(n) n->state == ZEBRA_NEIGH_ACTIVE
-
-#define IS_ZEBRA_NEIGH_INACTIVE(n) n->state == ZEBRA_NEIGH_INACTIVE
+#define IS_ZEBRA_NEIGH_INACTIVE(n) (n->state == ZEBRA_NEIGH_INACTIVE)
 
 #define ZEBRA_NEIGH_SET_ACTIVE(n) n->state = ZEBRA_NEIGH_ACTIVE