]> git.proxmox.com Git - mirror_frr.git/blobdiff - bgpd/bgpd.c
Merge pull request #12798 from donaldsharp/rib_match_multicast
[mirror_frr.git] / bgpd / bgpd.c
index 1fd394a8496685f7136ce8d8a793a3ff865dcff9..f2250f98c3a821c9b45e365cad17b8e97a5f5de3 100644 (file)
@@ -1,21 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
 /* BGP-4, BGP-4+ daemon program
  * Copyright (C) 1996, 97, 98, 99, 2000 Kunihiro Ishiguro
- *
- * This file is part of GNU Zebra.
- *
- * GNU Zebra is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * GNU Zebra is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; see the file COPYING; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
 #include <zebra.h>
@@ -568,7 +553,7 @@ void bgp_tcp_keepalive_unset(struct bgp *bgp)
 }
 
 /* BGP confederation configuration.  */
-void bgp_confederation_id_set(struct bgp *bgp, as_t as)
+void bgp_confederation_id_set(struct bgp *bgp, as_t as, const char *as_str)
 {
        struct peer *peer;
        struct listnode *node, *nnode;
@@ -580,6 +565,9 @@ void bgp_confederation_id_set(struct bgp *bgp, as_t as)
        /* Remember - were we doing confederation before? */
        already_confed = bgp_config_check(bgp, BGP_CONFIG_CONFEDERATION);
        bgp->confed_id = as;
+       if (bgp->confed_id_pretty)
+               XFREE(MTYPE_BGP, bgp->confed_id_pretty);
+       bgp->confed_id_pretty = XSTRDUP(MTYPE_BGP, as_str);
        bgp_config_set(bgp, BGP_CONFIG_CONFEDERATION);
 
        /* If we were doing confederation already, this is just an external
@@ -632,6 +620,7 @@ void bgp_confederation_id_unset(struct bgp *bgp)
        struct listnode *node, *nnode;
 
        bgp->confed_id = 0;
+       XFREE(MTYPE_BGP, bgp->confed_id_pretty);
        bgp_config_unset(bgp, BGP_CONFIG_CONFEDERATION);
 
        for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
@@ -659,14 +648,14 @@ bool bgp_confederation_peers_check(struct bgp *bgp, as_t as)
                return false;
 
        for (i = 0; i < bgp->confed_peers_cnt; i++)
-               if (bgp->confed_peers[i] == as)
+               if (bgp->confed_peers[i].as == as)
                        return true;
 
        return false;
 }
 
 /* Add an AS to the confederation set.  */
-void bgp_confederation_peers_add(struct bgp *bgp, as_t as)
+void bgp_confederation_peers_add(struct bgp *bgp, as_t as, const char *as_str)
 {
        struct peer *peer;
        struct listnode *node, *nnode;
@@ -677,11 +666,13 @@ void bgp_confederation_peers_add(struct bgp *bgp, as_t as)
        if (bgp_confederation_peers_check(bgp, as))
                return;
 
-       bgp->confed_peers =
-               XREALLOC(MTYPE_BGP_CONFED_LIST, bgp->confed_peers,
-                        (bgp->confed_peers_cnt + 1) * sizeof(as_t));
+       bgp->confed_peers = XREALLOC(MTYPE_BGP_CONFED_LIST, bgp->confed_peers,
+                                    (bgp->confed_peers_cnt + 1) *
+                                            sizeof(struct as_confed));
 
-       bgp->confed_peers[bgp->confed_peers_cnt] = as;
+       bgp->confed_peers[bgp->confed_peers_cnt].as = as;
+       bgp->confed_peers[bgp->confed_peers_cnt].as_pretty =
+               XSTRDUP(MTYPE_BGP, as_str);
        bgp->confed_peers_cnt++;
 
        if (bgp_config_check(bgp, BGP_CONFIG_CONFEDERATION)) {
@@ -718,9 +709,15 @@ void bgp_confederation_peers_remove(struct bgp *bgp, as_t as)
                return;
 
        for (i = 0; i < bgp->confed_peers_cnt; i++)
-               if (bgp->confed_peers[i] == as)
-                       for (j = i + 1; j < bgp->confed_peers_cnt; j++)
-                               bgp->confed_peers[j - 1] = bgp->confed_peers[j];
+               if (bgp->confed_peers[i].as == as) {
+                       XFREE(MTYPE_BGP, bgp->confed_peers[i].as_pretty);
+                       for (j = i + 1; j < bgp->confed_peers_cnt; j++) {
+                               bgp->confed_peers[j - 1].as =
+                                       bgp->confed_peers[j].as;
+                               bgp->confed_peers[j - 1].as_pretty =
+                                       bgp->confed_peers[j].as_pretty;
+                       }
+               }
 
        bgp->confed_peers_cnt--;
 
@@ -729,9 +726,9 @@ void bgp_confederation_peers_remove(struct bgp *bgp, as_t as)
                        XFREE(MTYPE_BGP_CONFED_LIST, bgp->confed_peers);
                bgp->confed_peers = NULL;
        } else
-               bgp->confed_peers =
-                       XREALLOC(MTYPE_BGP_CONFED_LIST, bgp->confed_peers,
-                                bgp->confed_peers_cnt * sizeof(as_t));
+               bgp->confed_peers = XREALLOC(
+                       MTYPE_BGP_CONFED_LIST, bgp->confed_peers,
+                       bgp->confed_peers_cnt * sizeof(struct as_confed));
 
        /* Now reset any peer who's remote AS has just been removed from the
           CONFED */
@@ -1156,6 +1153,7 @@ static void peer_free(struct peer *peer)
 
        XFREE(MTYPE_PEER_DESC, peer->desc);
        XFREE(MTYPE_BGP_PEER_HOST, peer->host);
+       XFREE(MTYPE_BGP_PEER_HOST, peer->hostname);
        XFREE(MTYPE_BGP_PEER_HOST, peer->domainname);
        XFREE(MTYPE_BGP_PEER_IFNAME, peer->ifname);
 
@@ -1177,6 +1175,8 @@ static void peer_free(struct peer *peer)
 
        XFREE(MTYPE_PEER_CONF_IF, peer->conf_if);
 
+       XFREE(MTYPE_BGP_SOFT_VERSION, peer->soft_version);
+
        /* Remove BFD configuration. */
        if (peer->bfd_config)
                bgp_peer_remove_bfd_config(peer);
@@ -1184,6 +1184,11 @@ static void peer_free(struct peer *peer)
        FOREACH_AFI_SAFI (afi, safi)
                bgp_addpath_set_peer_type(peer, afi, safi, BGP_ADDPATH_NONE);
 
+       if (peer->change_local_as_pretty)
+               XFREE(MTYPE_BGP, peer->change_local_as_pretty);
+       if (peer->as_pretty)
+               XFREE(MTYPE_BGP, peer->as_pretty);
+
        bgp_unlock(peer->bgp);
 
        memset(peer, 0, sizeof(struct peer));
@@ -1765,7 +1770,7 @@ void bgp_recalculate_all_bestpaths(struct bgp *bgp)
 struct peer *peer_create(union sockunion *su, const char *conf_if,
                         struct bgp *bgp, as_t local_as, as_t remote_as,
                         int as_type, struct peer_group *group,
-                        bool config_node)
+                        bool config_node, const char *as_str)
 {
        int active;
        struct peer *peer;
@@ -1790,6 +1795,9 @@ struct peer *peer_create(union sockunion *su, const char *conf_if,
        }
        peer->local_as = local_as;
        peer->as = remote_as;
+       /* internal and external values do not use as_pretty */
+       if (as_str && asn_str2asn(as_str, NULL))
+               peer->as_pretty = XSTRDUP(MTYPE_BGP, as_str);
        peer->as_type = as_type;
        peer->local_id = bgp->router_id;
        peer->v_holdtime = bgp->default_holdtime;
@@ -1893,7 +1901,8 @@ bool bgp_afi_safi_peer_exists(struct bgp *bgp, afi_t afi, safi_t safi)
 }
 
 /* Change peer's AS number.  */
-void peer_as_change(struct peer *peer, as_t as, int as_specified)
+void peer_as_change(struct peer *peer, as_t as, int as_specified,
+                   const char *as_str)
 {
        enum bgp_peer_sort origtype, newtype;
 
@@ -1908,6 +1917,12 @@ void peer_as_change(struct peer *peer, as_t as, int as_specified)
        }
        origtype = peer_sort_lookup(peer);
        peer->as = as;
+       if (as_specified == AS_SPECIFIED && as_str) {
+               if (peer->as_pretty)
+                       XFREE(MTYPE_BGP, peer->as_pretty);
+               peer->as_pretty = XSTRDUP(MTYPE_BGP, as_str);
+       } else if (peer->as_type == AS_UNSPECIFIED && peer->as_pretty)
+               XFREE(MTYPE_BGP, peer->as_pretty);
        peer->as_type = as_specified;
 
        if (bgp_config_check(peer->bgp, BGP_CONFIG_CONFEDERATION)
@@ -1965,7 +1980,7 @@ void peer_as_change(struct peer *peer, as_t as, int as_specified)
 /* If peer does not exist, create new one.  If peer already exists,
    set AS number to the peer.  */
 int peer_remote_as(struct bgp *bgp, union sockunion *su, const char *conf_if,
-                  as_t *as, int as_type)
+                  as_t *as, int as_type, const char *as_str)
 {
        struct peer *peer;
        as_t local_as;
@@ -2019,7 +2034,7 @@ int peer_remote_as(struct bgp *bgp, union sockunion *su, const char *conf_if,
                /* Existing peer's AS number change. */
                if (((peer->as_type == AS_SPECIFIED) && peer->as != *as)
                    || (peer->as_type != as_type))
-                       peer_as_change(peer, *as, as_type);
+                       peer_as_change(peer, *as, as_type, as_str);
        } else {
                if (conf_if)
                        return BGP_ERR_NO_INTERFACE_CONFIG;
@@ -2034,7 +2049,7 @@ int peer_remote_as(struct bgp *bgp, union sockunion *su, const char *conf_if,
                        local_as = bgp->as;
 
                peer_create(su, conf_if, bgp, local_as, *as, as_type, NULL,
-                           true);
+                           true, as_str);
        }
 
        return 0;
@@ -2059,6 +2074,13 @@ const char *bgp_get_name_by_role(uint8_t role)
        return "unknown";
 }
 
+enum asnotation_mode bgp_get_asnotation(struct bgp *bgp)
+{
+       if (!bgp)
+               return ASNOTATION_PLAIN;
+       return bgp->asnotation;
+}
+
 static void peer_group2peer_config_copy_af(struct peer_group *group,
                                           struct peer *peer, afi_t afi,
                                           safi_t safi)
@@ -2630,6 +2652,7 @@ int peer_delete(struct peer *peer)
 
        XFREE(MTYPE_BGP_PEER_HOST, peer->hostname);
        XFREE(MTYPE_BGP_PEER_HOST, peer->domainname);
+       XFREE(MTYPE_BGP_SOFT_VERSION, peer->soft_version);
 
        peer_unlock(peer); /* initial reference */
 
@@ -2773,6 +2796,13 @@ static void peer_group2peer_config_copy(struct peer_group *group,
                if (CHECK_FLAG(conf->flags, PEER_FLAG_CAPABILITY_ENHE))
                        SET_FLAG(peer->flags, PEER_FLAG_CAPABILITY_ENHE);
 
+       /* capability software-version apply */
+       if (!CHECK_FLAG(peer->flags_override,
+                       PEER_FLAG_CAPABILITY_SOFT_VERSION))
+               if (CHECK_FLAG(conf->flags, PEER_FLAG_CAPABILITY_SOFT_VERSION))
+                       SET_FLAG(peer->flags,
+                                PEER_FLAG_CAPABILITY_SOFT_VERSION);
+
        /* password apply */
        if (!CHECK_FLAG(peer->flags_override, PEER_FLAG_PASSWORD))
                PEER_STR_ATTR_INHERIT(peer, group, password,
@@ -2808,7 +2838,7 @@ static void peer_group2peer_config_copy(struct peer_group *group,
 
 /* Peer group's remote AS configuration.  */
 int peer_group_remote_as(struct bgp *bgp, const char *group_name, as_t *as,
-                        int as_type)
+                        int as_type, const char *as_str)
 {
        struct peer_group *group;
        struct peer *peer;
@@ -2824,12 +2854,12 @@ int peer_group_remote_as(struct bgp *bgp, const char *group_name, as_t *as,
 
        /* When we setup peer-group AS number all peer group member's AS
           number must be updated to same number.  */
-       peer_as_change(group->conf, *as, as_type);
+       peer_as_change(group->conf, *as, as_type, as_str);
 
        for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
                if (((peer->as_type == AS_SPECIFIED) && peer->as != *as)
                    || (peer->as_type != as_type))
-                       peer_as_change(peer, *as, as_type);
+                       peer_as_change(peer, *as, as_type, as_str);
        }
 
        return 0;
@@ -3136,7 +3166,7 @@ int peer_group_bind(struct bgp *bgp, union sockunion *su, struct peer *peer,
                }
 
                peer = peer_create(su, NULL, bgp, bgp->as, group->conf->as,
-                                  group->conf->as_type, group, true);
+                                  group->conf->as_type, group, true, NULL);
 
                peer = peer_lock(peer); /* group->peer list reference */
                listnode_add(group->peer, peer);
@@ -3188,23 +3218,37 @@ static void bgp_vrf_string_name_delete(void *data)
 
 /* BGP instance creation by `router bgp' commands. */
 static struct bgp *bgp_create(as_t *as, const char *name,
-                             enum bgp_instance_type inst_type)
+                             enum bgp_instance_type inst_type,
+                             const char *as_pretty,
+                             enum asnotation_mode asnotation)
 {
        struct bgp *bgp;
        afi_t afi;
        safi_t safi;
 
        bgp = XCALLOC(MTYPE_BGP, sizeof(struct bgp));
+       bgp->as = *as;
+       if (as_pretty)
+               bgp->as_pretty = XSTRDUP(MTYPE_BGP, as_pretty);
+       else
+               bgp->as_pretty = XSTRDUP(MTYPE_BGP, asn_asn2asplain(*as));
+
+       if (asnotation != ASNOTATION_UNDEFINED) {
+               bgp->asnotation = asnotation;
+               SET_FLAG(bgp->config, BGP_CONFIG_ASNOTATION);
+       } else
+               asn_str2asn_notation(bgp->as_pretty, NULL, &bgp->asnotation);
 
        if (BGP_DEBUG(zebra, ZEBRA)) {
                if (inst_type == BGP_INSTANCE_TYPE_DEFAULT)
-                       zlog_debug("Creating Default VRF, AS %u", *as);
+                       zlog_debug("Creating Default VRF, AS %s",
+                                  bgp->as_pretty);
                else
-                       zlog_debug("Creating %s %s, AS %u",
+                       zlog_debug("Creating %s %s, AS %s",
                                   (inst_type == BGP_INSTANCE_TYPE_VRF)
                                           ? "VRF"
                                           : "VIEW",
-                                  name, *as);
+                                  name, bgp->as_pretty);
        }
 
        /* Default the EVPN VRF to the default one */
@@ -3281,7 +3325,6 @@ static struct bgp *bgp_create(as_t *as, const char *name,
        bgp->condition_check_period = DEFAULT_CONDITIONAL_ROUTES_POLL_TIME;
        bgp_addpath_init_bgp_data(&bgp->tx_addpath);
        bgp->fast_convergence = false;
-       bgp->as = *as;
        bgp->llgr_stale_time = BGP_DEFAULT_LLGR_STALE_TIME;
 
 #ifdef ENABLE_BGP_VNC
@@ -3518,7 +3561,8 @@ int bgp_lookup_by_as_name_type(struct bgp **bgp_val, as_t *as, const char *name,
 
 /* Called from VTY commands. */
 int bgp_get(struct bgp **bgp_val, as_t *as, const char *name,
-           enum bgp_instance_type inst_type)
+           enum bgp_instance_type inst_type, const char *as_pretty,
+           enum asnotation_mode asnotation)
 {
        struct bgp *bgp;
        struct vrf *vrf = NULL;
@@ -3528,7 +3572,7 @@ int bgp_get(struct bgp **bgp_val, as_t *as, const char *name,
        if (ret || *bgp_val)
                return ret;
 
-       bgp = bgp_create(as, name, inst_type);
+       bgp = bgp_create(as, name, inst_type, as_pretty, asnotation);
 
        /*
         * view instances will never work inside of a vrf
@@ -3922,8 +3966,13 @@ void bgp_free(struct bgp *bgp)
                dir = BGP_VPN_POLICY_DIR_TOVPN;
                if (bgp->vpn_policy[afi].rtlist[dir])
                        ecommunity_free(&bgp->vpn_policy[afi].rtlist[dir]);
+               if (bgp->vpn_policy[afi].tovpn_rd_pretty)
+                       XFREE(MTYPE_BGP, bgp->vpn_policy[afi].tovpn_rd_pretty);
        }
 
+       bgp_confederation_id_unset(bgp);
+
+       XFREE(MTYPE_BGP, bgp->as_pretty);
        XFREE(MTYPE_BGP, bgp->name);
        XFREE(MTYPE_BGP, bgp->name_pretty);
        XFREE(MTYPE_BGP, bgp->snmp_stats);
@@ -4028,7 +4077,7 @@ struct peer *peer_create_bind_dynamic_neighbor(struct bgp *bgp,
 
        /* Create peer first; we've already checked group config is valid. */
        peer = peer_create(su, NULL, bgp, bgp->as, group->conf->as,
-                          group->conf->as_type, group, true);
+                          group->conf->as_type, group, true, NULL);
        if (!peer)
                return NULL;
 
@@ -4212,6 +4261,26 @@ bool bgp_path_attribute_discard(struct peer *peer, char *buf, size_t size)
        return false;
 }
 
+bool bgp_path_attribute_treat_as_withdraw(struct peer *peer, char *buf,
+                                         size_t size)
+{
+       if (!buf)
+               return false;
+
+       buf[0] = '\0';
+
+       for (unsigned int i = 0; i < BGP_ATTR_MAX; i++) {
+               if (peer->withdraw_attrs[i])
+                       snprintf(buf + strlen(buf), size - strlen(buf), "%s%d",
+                                (strlen(buf) > 0) ? " " : "", i);
+       }
+
+       if (strlen(buf) > 0)
+               return true;
+
+       return false;
+}
+
 /* If peer is configured at least one address family return 1. */
 bool peer_active(struct peer *peer)
 {
@@ -4365,6 +4434,7 @@ static const struct peer_flag_action peer_flag_action_list[] = {
        {PEER_FLAG_PORT, 0, peer_change_reset},
        {PEER_FLAG_AIGP, 0, peer_change_none},
        {PEER_FLAG_GRACEFUL_SHUTDOWN, 0, peer_change_none},
+       {PEER_FLAG_CAPABILITY_SOFT_VERSION, 0, peer_change_reset},
        {0, 0, 0}};
 
 static const struct peer_flag_action peer_af_flag_action_list[] = {
@@ -4566,6 +4636,9 @@ void bgp_shutdown_enable(struct bgp *bgp, const char *msg)
 /* Disable global administrative shutdown of all peers of BGP instance */
 void bgp_shutdown_disable(struct bgp *bgp)
 {
+       const struct listnode *node;
+       struct peer *peer;
+
        /* do nothing if not shut down. */
        if (!CHECK_FLAG(bgp->flags, BGP_FLAG_SHUTDOWN))
                return;
@@ -4576,6 +4649,9 @@ void bgp_shutdown_disable(struct bgp *bgp)
 
        /* clear the BGP instances shutdown flag */
        UNSET_FLAG(bgp->flags, BGP_FLAG_SHUTDOWN);
+
+       for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer))
+               bgp_timer_set(peer);
 }
 
 /* Change specified peer flag. */
@@ -6211,7 +6287,7 @@ int peer_allowas_in_unset(struct peer *peer, afi_t afi, safi_t safi)
 }
 
 int peer_local_as_set(struct peer *peer, as_t as, bool no_prepend,
-                     bool replace_as)
+                     bool replace_as, const char *as_str)
 {
        bool old_no_prepend, old_replace_as;
        struct bgp *bgp = peer->bgp;
@@ -6236,6 +6312,9 @@ int peer_local_as_set(struct peer *peer, as_t as, bool no_prepend,
            && old_replace_as == replace_as)
                return 0;
        peer->change_local_as = as;
+       if (as_str)
+               peer->change_local_as_pretty = XSTRDUP(MTYPE_BGP, as_str);
+
        (void)peer_sort(peer);
 
        /* Check if handling a regular peer. */
@@ -6269,6 +6348,9 @@ int peer_local_as_set(struct peer *peer, as_t as, bool no_prepend,
                COND_FLAG(member->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS,
                          replace_as);
                member->change_local_as = as;
+               if (as_str)
+                       member->change_local_as_pretty =
+                               XSTRDUP(MTYPE_BGP, as_str);
        }
 
        return 0;
@@ -6294,6 +6376,7 @@ int peer_local_as_unset(struct peer *peer)
                peer_flag_unset(peer, PEER_FLAG_LOCAL_AS_NO_PREPEND);
                peer_flag_unset(peer, PEER_FLAG_LOCAL_AS_REPLACE_AS);
                peer->change_local_as = 0;
+               XFREE(MTYPE_BGP, peer->change_local_as_pretty);
        }
 
        /* Check if handling a regular peer. */
@@ -6324,6 +6407,7 @@ int peer_local_as_unset(struct peer *peer)
                UNSET_FLAG(member->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
                UNSET_FLAG(member->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS);
                member->change_local_as = 0;
+               XFREE(MTYPE_BGP, member->change_local_as_pretty);
 
                /* Send notification or stop peer depending on state. */
                if (BGP_IS_VALID_STATE_FOR_NOTIF(member->status)) {
@@ -8007,7 +8091,7 @@ static void bgp_instasn_autocomplete(vector comps, struct cmd_token *token)
 {
        struct listnode *next, *next2;
        struct bgp *bgp, *bgp2;
-       char buf[11];
+       char buf[ASN_STRING_MAX_SIZE];
 
        for (ALL_LIST_ELEMENTS_RO(bm->bgp, next, bgp)) {
                /* deduplicate */
@@ -8020,7 +8104,7 @@ static void bgp_instasn_autocomplete(vector comps, struct cmd_token *token)
                if (bgp2 != bgp)
                        continue;
 
-               snprintf(buf, sizeof(buf), "%u", bgp->as);
+               snprintf(buf, sizeof(buf), "%s", bgp->as_pretty);
                vector_set(comps, XSTRDUP(MTYPE_COMPLETION, buf));
        }
 }