]> git.proxmox.com Git - mirror_frr.git/blobdiff - bgpd/bgp_route.c
Merge pull request #12199 from tewok/frr-routes-table-columns
[mirror_frr.git] / bgpd / bgp_route.c
index 3324eb73def4be0d701886956b6ff05eb1f78e2b..693616e6d59fe7b7b104183f368dd5390745497c 100644 (file)
@@ -72,6 +72,7 @@
 #include "bgpd/bgp_addpath.h"
 #include "bgpd/bgp_mac.h"
 #include "bgpd/bgp_network.h"
+#include "bgpd/bgp_orr.h"
 #include "bgpd/bgp_trace.h"
 #include "bgpd/bgp_rpki.h"
 
@@ -102,10 +103,6 @@ DEFINE_HOOK(bgp_rpki_prefix_status,
             const struct prefix *prefix),
            (peer, attr, prefix));
 
-/* Render dest to prefix_rd based on safi */
-static const struct prefix_rd *bgp_rd_from_dest(const struct bgp_dest *dest,
-                                               safi_t safi);
-
 /* Extern from bgp_dump.c */
 extern const char *bgp_origin_str[];
 extern const char *bgp_origin_long_str[];
@@ -567,6 +564,7 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
                             enum bgp_path_selection_reason *reason)
 {
        const struct prefix *new_p;
+       struct prefix exist_p;
        struct attr *newattr, *existattr;
        enum bgp_peer_sort new_sort;
        enum bgp_peer_sort exist_sort;
@@ -599,6 +597,11 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
        bool new_origin, exist_origin;
        struct bgp_path_info *bpi_ultimate;
 
+       struct bgp_orr_group *orr_group = NULL;
+       struct listnode *node;
+       struct bgp_orr_igp_metric *igp_metric = NULL;
+       struct list *orr_group_igp_metric_info = NULL;
+
        *paths_eq = 0;
 
        /* 0. Null check. */
@@ -874,6 +877,49 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
                return 0;
        }
 
+       /* If a BGP speaker supports ACCEPT_OWN and is configured for the
+        * extensions defined in this document, the following step is inserted
+        * after the LOCAL_PREF comparison step in the BGP decision process:
+        *      When comparing a pair of routes for a BGP destination, the
+        *      route with the ACCEPT_OWN community attached is preferred over
+        *      the route that does not have the community.
+        * This extra step MUST only be invoked during the best path selection
+        * process of VPN-IP routes.
+        */
+       if (safi == SAFI_MPLS_VPN &&
+           (CHECK_FLAG(new->peer->af_flags[afi][safi], PEER_FLAG_ACCEPT_OWN) ||
+            CHECK_FLAG(exist->peer->af_flags[afi][safi],
+                       PEER_FLAG_ACCEPT_OWN))) {
+               bool new_accept_own = false;
+               bool exist_accept_own = false;
+               uint32_t accept_own = COMMUNITY_ACCEPT_OWN;
+
+               if (newattr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES))
+                       new_accept_own = community_include(
+                               bgp_attr_get_community(newattr), accept_own);
+               if (existattr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES))
+                       exist_accept_own = community_include(
+                               bgp_attr_get_community(existattr), accept_own);
+
+               if (new_accept_own && !exist_accept_own) {
+                       *reason = bgp_path_selection_accept_own;
+                       if (debug)
+                               zlog_debug(
+                                       "%s: %s wins over %s due to accept-own",
+                                       pfx_buf, new_buf, exist_buf);
+                       return 1;
+               }
+
+               if (!new_accept_own && exist_accept_own) {
+                       *reason = bgp_path_selection_accept_own;
+                       if (debug)
+                               zlog_debug(
+                                       "%s: %s loses to %s due to accept-own",
+                                       pfx_buf, new_buf, exist_buf);
+                       return 0;
+               }
+       }
+
        /* 3. Local route check. We prefer:
         *  - BGP_ROUTE_STATIC
         *  - BGP_ROUTE_AGGREGATE
@@ -1061,6 +1107,49 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
        if (exist->extra)
                existm = exist->extra->igpmetric;
 
+       if (new->peer->orr_group_name[afi][safi]) {
+               ret = str2prefix(new->peer->host, &exist_p);
+               orr_group = bgp_orr_group_lookup_by_name(
+                       bgp, afi, safi, new->peer->orr_group_name[afi][safi]);
+               if (orr_group) {
+                       orr_group_igp_metric_info = orr_group->igp_metric_info;
+                       if (orr_group_igp_metric_info) {
+                               for (ALL_LIST_ELEMENTS_RO(
+                                            orr_group_igp_metric_info, node,
+                                            igp_metric)) {
+                                       if (ret &&
+                                           prefix_cmp(&exist_p,
+                                                      &igp_metric->prefix) ==
+                                                   0) {
+                                               newm = igp_metric->igp_metric;
+                                               break;
+                                       }
+                               }
+                       }
+               }
+       }
+       if (exist->peer->orr_group_name[afi][safi]) {
+               ret = str2prefix(exist->peer->host, &exist_p);
+               orr_group = bgp_orr_group_lookup_by_name(
+                       bgp, afi, safi, exist->peer->orr_group_name[afi][safi]);
+               if (orr_group) {
+                       orr_group_igp_metric_info = orr_group->igp_metric_info;
+                       if (orr_group_igp_metric_info) {
+                               for (ALL_LIST_ELEMENTS_RO(
+                                            orr_group_igp_metric_info, node,
+                                            igp_metric)) {
+                                       if (ret &&
+                                           prefix_cmp(&exist_p,
+                                                      &igp_metric->prefix) ==
+                                                   0) {
+                                               existm = igp_metric->igp_metric;
+                                               break;
+                                       }
+                               }
+                       }
+               }
+       }
+
        if (newm < existm) {
                if (debug && peer_sort_ret < 0)
                        zlog_debug(
@@ -3833,6 +3922,60 @@ static void bgp_attr_add_no_export_community(struct attr *attr)
        bgp_attr_set_community(attr, new);
 }
 
+static bool bgp_accept_own(struct peer *peer, afi_t afi, safi_t safi,
+                          struct attr *attr, const struct prefix *prefix,
+                          int *sub_type)
+{
+       struct listnode *node, *nnode;
+       struct bgp *bgp;
+       bool accept_own_found = false;
+
+       if (safi != SAFI_MPLS_VPN)
+               return false;
+
+       /* Processing of the ACCEPT_OWN community is enabled by configuration */
+       if (!CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_ACCEPT_OWN))
+               return false;
+
+       /* The route in question carries the ACCEPT_OWN community */
+       if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES)) {
+               struct community *comm = bgp_attr_get_community(attr);
+
+               if (community_include(comm, COMMUNITY_ACCEPT_OWN))
+                       accept_own_found = true;
+       }
+
+       /* The route in question is targeted to one or more destination VRFs
+        * on the router (as determined by inspecting the Route Target(s)).
+        */
+       for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
+               if (bgp->inst_type != BGP_INSTANCE_TYPE_VRF)
+                       continue;
+
+               if (accept_own_found &&
+                   ecommunity_include(
+                           bgp->vpn_policy[afi]
+                                   .rtlist[BGP_VPN_POLICY_DIR_TOVPN],
+                           bgp_attr_get_ecommunity(attr))) {
+                       if (bgp_debug_update(peer, prefix, NULL, 1))
+                               zlog_debug(
+                                       "%pBP prefix %pFX has ORIGINATOR_ID, but it's accepted due to ACCEPT_OWN",
+                                       peer, prefix);
+
+                       /* Treat this route as imported, because it's leaked
+                        * already from another VRF, and we got an updated
+                        * version from route-reflector with ACCEPT_OWN
+                        * community.
+                        */
+                       *sub_type = BGP_ROUTE_IMPORTED;
+
+                       return true;
+               }
+       }
+
+       return false;
+}
+
 int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
               struct attr *attr, afi_t afi, safi_t safi, int type,
               int sub_type, struct prefix_rd *prd, mpls_label_t *label,
@@ -3857,6 +4000,7 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
        bool force_evpn_import = false;
        safi_t orig_safi = safi;
        bool leak_success = true;
+       int allowas_in = 0;
 
        if (frrtrace_enabled(frr_bgp, process_update)) {
                char pfxprint[PREFIX2STR_BUFFER];
@@ -3902,6 +4046,10 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
            && peer != bgp->peer_self)
                bgp_adj_in_set(dest, peer, attr, addpath_id);
 
+       /* Update permitted loop count */
+       if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN))
+               allowas_in = peer->allowas_in[afi][safi];
+
        /* Check previously received route. */
        for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next)
                if (pi->peer == peer && pi->type == type
@@ -3911,8 +4059,8 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
 
        /* AS path local-as loop check. */
        if (peer->change_local_as) {
-               if (peer->allowas_in[afi][safi])
-                       aspath_loop_count = peer->allowas_in[afi][safi];
+               if (allowas_in)
+                       aspath_loop_count = allowas_in;
                else if (!CHECK_FLAG(peer->flags,
                                     PEER_FLAG_LOCAL_AS_NO_PREPEND))
                        aspath_loop_count = 1;
@@ -3935,23 +4083,30 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
 
        /* AS path loop check. */
        if (do_loop_check) {
-               if (aspath_loop_check(attr->aspath, bgp->as)
-                           > peer->allowas_in[afi][safi]
-                   || (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION)
-                       && aspath_loop_check(attr->aspath, bgp->confed_id)
-                                  > peer->allowas_in[afi][safi])) {
+               if (aspath_loop_check(attr->aspath, bgp->as) > allowas_in ||
+                   (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION) &&
+                    (aspath_loop_check(attr->aspath, bgp->confed_id) >
+                     allowas_in))) {
                        peer->stat_pfx_aspath_loop++;
                        reason = "as-path contains our own AS;";
                        goto filtered;
                }
        }
 
-       /* Route reflector originator ID check.  */
+       /* Route reflector originator ID check. If ACCEPT_OWN mechanism is
+        * enabled, then take care of that too.
+        */
+       bool accept_own = false;
+
        if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)
            && IPV4_ADDR_SAME(&bgp->router_id, &attr->originator_id)) {
-               peer->stat_pfx_originator_loop++;
-               reason = "originator is us;";
-               goto filtered;
+               accept_own =
+                       bgp_accept_own(peer, afi, safi, attr, p, &sub_type);
+               if (!accept_own) {
+                       peer->stat_pfx_originator_loop++;
+                       reason = "originator is us;";
+                       goto filtered;
+               }
        }
 
        /* Route reflector cluster ID check.  */
@@ -4449,8 +4604,13 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
                                bgp_path_info_unset_flag(dest, pi,
                                                         BGP_PATH_VALID);
                        }
-               } else
+               } else {
+                       if (accept_own)
+                               bgp_path_info_set_flag(dest, pi,
+                                                      BGP_PATH_ACCEPT_OWN);
+
                        bgp_path_info_set_flag(dest, pi, BGP_PATH_VALID);
+               }
 
 #ifdef ENABLE_BGP_VNC
                if (safi == SAFI_MPLS_VPN) {
@@ -4500,8 +4660,7 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
                }
                if ((SAFI_MPLS_VPN == safi)
                    && (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)) {
-
-                       leak_success = vpn_leak_to_vrf_update(bgp, pi);
+                       leak_success = vpn_leak_to_vrf_update(bgp, pi, prd);
                }
 
 #ifdef ENABLE_BGP_VNC
@@ -4609,8 +4768,12 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
                        }
                        bgp_path_info_unset_flag(dest, new, BGP_PATH_VALID);
                }
-       } else
+       } else {
+               if (accept_own)
+                       bgp_path_info_set_flag(dest, new, BGP_PATH_ACCEPT_OWN);
+
                bgp_path_info_set_flag(dest, new, BGP_PATH_VALID);
+       }
 
        /* Addpath ID */
        new->addpath_rx_id = addpath_id;
@@ -4656,7 +4819,7 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
        }
        if ((SAFI_MPLS_VPN == safi)
            && (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)) {
-               leak_success = vpn_leak_to_vrf_update(bgp, new);
+               leak_success = vpn_leak_to_vrf_update(bgp, new, prd);
        }
 #ifdef ENABLE_BGP_VNC
        if (SAFI_MPLS_VPN == safi) {
@@ -6377,7 +6540,8 @@ static void bgp_static_update_safi(struct bgp *bgp, const struct prefix *p,
 
                        if (SAFI_MPLS_VPN == safi
                            && bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) {
-                               vpn_leak_to_vrf_update(bgp, pi);
+                               vpn_leak_to_vrf_update(bgp, pi,
+                                                      &bgp_static->prd);
                        }
 #ifdef ENABLE_BGP_VNC
                        rfapiProcessUpdate(pi->peer, NULL, p, &bgp_static->prd,
@@ -6417,7 +6581,7 @@ static void bgp_static_update_safi(struct bgp *bgp, const struct prefix *p,
 
        if (SAFI_MPLS_VPN == safi
            && bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) {
-               vpn_leak_to_vrf_update(bgp, new);
+               vpn_leak_to_vrf_update(bgp, new, &bgp_static->prd);
        }
 #ifdef ENABLE_BGP_VNC
        rfapiProcessUpdate(new->peer, NULL, p, &bgp_static->prd, new->attr, afi,
@@ -8776,6 +8940,8 @@ const char *bgp_path_selection_reason2str(enum bgp_path_selection_reason reason)
                return "Weight";
        case bgp_path_selection_local_pref:
                return "Local Pref";
+       case bgp_path_selection_accept_own:
+               return "Accept Own";
        case bgp_path_selection_local_route:
                return "Local Route";
        case bgp_path_selection_confed_as_path:
@@ -8873,6 +9039,8 @@ static void route_vty_short_status_out(struct vty *vty,
                vty_out(vty, "I");
        else if (rpki_state == RPKI_NOTFOUND)
                vty_out(vty, "N");
+       else
+               vty_out(vty, " ");
 
        /* Route status display. */
        if (CHECK_FLAG(path->flags, BGP_PATH_REMOVED))
@@ -11852,8 +12020,8 @@ static void bgp_show_path_info(const struct prefix_rd *pfx_rd,
 /*
  * Return rd based on safi
  */
-static const struct prefix_rd *bgp_rd_from_dest(const struct bgp_dest *dest,
-                                               safi_t safi)
+const struct prefix_rd *bgp_rd_from_dest(const struct bgp_dest *dest,
+                                        safi_t safi)
 {
        switch (safi) {
        case SAFI_MPLS_VPN:
@@ -11862,7 +12030,6 @@ static const struct prefix_rd *bgp_rd_from_dest(const struct bgp_dest *dest,
                return (struct prefix_rd *)(bgp_dest_get_prefix(dest));
        default:
                return NULL;
-
        }
 }
 
@@ -12196,8 +12363,10 @@ DEFUN (show_ip_bgp_large_community,
                return CMD_WARNING;
 
        if (argv_find(argv, argc, "AA:BB:CC", &idx)) {
-               if (argv_find(argv, argc, "exact-match", &idx))
+               if (argv_find(argv, argc, "exact-match", &idx)) {
+                       argc--;
                        exact_match = 1;
+               }
                return bgp_show_lcommunity(vty, bgp, argc, argv,
                                        exact_match, afi, safi, uj);
        } else
@@ -12404,6 +12573,7 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd,
           |alias ALIAS_NAME\
           |A.B.C.D/M longer-prefixes\
           |X:X::X:X/M longer-prefixes\
+         |optimal-route-reflection [WORD$orr_group_name]\
           ] [json$uj [detail$detail] | wide$wide]",
       SHOW_STR IP_STR BGP_STR BGP_INSTANCE_HELP_STR BGP_AFI_HELP_STR
              BGP_SAFI_WITH_LABEL_HELP_STR
@@ -12452,6 +12622,8 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd,
       "Display route and more specific routes\n"
       "IPv6 prefix\n"
       "Display route and more specific routes\n"
+      "Display Optimal Route Reflection RR Clients\n"
+      "ORR Group name\n"
       JSON_STR
       "Display detailed version of JSON output\n"
       "Increase table width for longer prefixes\n")
@@ -12468,6 +12640,7 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd,
        uint16_t show_flags = 0;
        enum rpki_states rpki_target_state = RPKI_NOT_BEING_USED;
        struct prefix p;
+       bool orr_group = false;
 
        if (uj) {
                argc--;
@@ -12642,12 +12815,18 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd,
                output_arg = &p;
        }
 
+       if (argv_find(argv, argc, "optimal-route-reflection", &idx))
+               orr_group = true;
+
        if (!all) {
                /* show bgp: AFI_IP6, show ip bgp: AFI_IP */
                if (community)
                        return bgp_show_community(vty, bgp, community,
                                                  exact_match, afi, safi,
                                                  show_flags);
+               else if (orr_group)
+                       return bgp_show_orr(vty, bgp, afi, safi, orr_group_name,
+                                           show_flags);
                else
                        return bgp_show(vty, bgp, afi, safi, sh_type,
                                        output_arg, show_flags,
@@ -12693,6 +12872,11 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd,
                                                        vty, abgp, community,
                                                        exact_match, afi, safi,
                                                        show_flags);
+                                       else if (orr_group)
+                                               bgp_show_orr(vty, bgp, afi,
+                                                            safi,
+                                                            orr_group_name,
+                                                            show_flags);
                                        else
                                                bgp_show(vty, abgp, afi, safi,
                                                         sh_type, output_arg,
@@ -12732,6 +12916,11 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd,
                                                        vty, abgp, community,
                                                        exact_match, afi, safi,
                                                        show_flags);
+                                       else if (orr_group)
+                                               bgp_show_orr(vty, bgp, afi,
+                                                            safi,
+                                                            orr_group_name,
+                                                            show_flags);
                                        else
                                                bgp_show(vty, abgp, afi, safi,
                                                         sh_type, output_arg,