bgp_route.c
上传用户:xiaozhuqw
上传日期:2009-11-15
资源大小:1338k
文件大小:275k
- /* BGP routing information
- Copyright (C) 1996, 97, 98, 99 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 GNU Zebra; see the file COPYING. If not, write to the Free
- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- 02111-1307, USA. */
- #include <zebra.h>
- #include "prefix.h"
- #include "linklist.h"
- #include "memory.h"
- #include "command.h"
- #include "stream.h"
- #include "filter.h"
- #include "str.h"
- #include "log.h"
- #include "routemap.h"
- #include "buffer.h"
- #include "sockunion.h"
- #include "plist.h"
- #include "thread.h"
- #include "bgpd/bgpd.h"
- #include "bgpd/bgp_table.h"
- #include "bgpd/bgp_route.h"
- #include "bgpd/bgp_attr.h"
- #include "bgpd/bgp_debug.h"
- #include "bgpd/bgp_aspath.h"
- #include "bgpd/bgp_regex.h"
- #include "bgpd/bgp_community.h"
- #include "bgpd/bgp_ecommunity.h"
- #include "bgpd/bgp_clist.h"
- #include "bgpd/bgp_packet.h"
- #include "bgpd/bgp_filter.h"
- #include "bgpd/bgp_fsm.h"
- #include "bgpd/bgp_mplsvpn.h"
- #include "bgpd/bgp_nexthop.h"
- #include "bgpd/bgp_damp.h"
- #include "bgpd/bgp_advertise.h"
- #include "bgpd/bgp_zebra.h"
- #include "bgpd/bgp_vty.h"
- /* Extern from bgp_dump.c */
- extern char *bgp_origin_str[];
- extern char *bgp_origin_long_str[];
- struct bgp_node *
- bgp_afi_node_get (struct bgp *bgp, afi_t afi, safi_t safi, struct prefix *p,
- struct prefix_rd *prd)
- {
- struct bgp_node *rn;
- struct bgp_node *prn = NULL;
- struct bgp_table *table;
- if (safi == SAFI_MPLS_VPN)
- {
- prn = bgp_node_get (bgp->rib[afi][safi], (struct prefix *) prd);
- if (prn->info == NULL)
- prn->info = bgp_table_init ();
- else
- bgp_unlock_node (prn);
- table = prn->info;
- }
- else
- table = bgp->rib[afi][safi];
- rn = bgp_node_get (table, p);
- if (safi == SAFI_MPLS_VPN)
- rn->prn = prn;
- return rn;
- }
- /* Allocate new bgp info structure. */
- struct bgp_info *
- bgp_info_new ()
- {
- struct bgp_info *new;
- new = XMALLOC (MTYPE_BGP_ROUTE, sizeof (struct bgp_info));
- memset (new, 0, sizeof (struct bgp_info));
- return new;
- }
- /* Free bgp route information. */
- void
- bgp_info_free (struct bgp_info *binfo)
- {
- if (binfo->attr)
- bgp_attr_unintern (binfo->attr);
- if (binfo->damp_info)
- bgp_damp_info_free (binfo->damp_info, 0);
- XFREE (MTYPE_BGP_ROUTE, binfo);
- }
- void
- bgp_info_add (struct bgp_node *rn, struct bgp_info *ri)
- {
- struct bgp_info *top;
- top = rn->info;
- ri->next = rn->info;
- ri->prev = NULL;
- if (top)
- top->prev = ri;
- rn->info = ri;
- }
- void
- bgp_info_delete (struct bgp_node *rn, struct bgp_info *ri)
- {
- if (ri->next)
- ri->next->prev = ri->prev;
- if (ri->prev)
- ri->prev->next = ri->next;
- else
- rn->info = ri->next;
- }
- /* Get MED value. If MED value is missing and "bgp bestpath
- missing-as-worst" is specified, treat it as the worst value. */
- u_int32_t
- bgp_med_value (struct attr *attr, struct bgp *bgp)
- {
- if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
- return attr->med;
- else
- {
- if (bgp_flag_check (bgp, BGP_FLAG_MED_MISSING_AS_WORST))
- return 4294967295ul;
- else
- return 0;
- }
- }
- /* Compare two bgp route entity. br is preferable then return 1. */
- int
- bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist)
- {
- u_int32_t new_pref;
- u_int32_t exist_pref;
- u_int32_t new_med;
- u_int32_t exist_med;
- struct in_addr new_id;
- struct in_addr exist_id;
- int new_cluster;
- int exist_cluster;
- int internal_as_route = 0;
- int confed_as_route = 0;
- int cost_community = 0;
- int ret;
- /* 0. Null check. */
- if (new == NULL)
- return 0;
- if (exist == NULL)
- return 1;
- /* 1. Weight check. */
- if (new->attr->weight > exist->attr->weight)
- return 1;
- if (new->attr->weight < exist->attr->weight)
- return 0;
- /* 2. Local preference check. */
- if (new->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
- new_pref = new->attr->local_pref;
- else
- new_pref = bgp->default_local_pref;
- if (exist->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
- exist_pref = exist->attr->local_pref;
- else
- exist_pref = bgp->default_local_pref;
-
- if (new_pref > exist_pref)
- return 1;
- if (new_pref < exist_pref)
- return 0;
- /* 3. Local route check. */
- if (new->sub_type == BGP_ROUTE_STATIC)
- return 1;
- if (exist->sub_type == BGP_ROUTE_STATIC)
- return 0;
- if (new->sub_type == BGP_ROUTE_REDISTRIBUTE)
- return 1;
- if (exist->sub_type == BGP_ROUTE_REDISTRIBUTE)
- return 0;
- if (new->sub_type == BGP_ROUTE_AGGREGATE)
- return 1;
- if (exist->sub_type == BGP_ROUTE_AGGREGATE)
- return 0;
- /* 4. AS path length check. */
- if (! bgp_flag_check (bgp, BGP_FLAG_ASPATH_IGNORE))
- {
- if (new->attr->aspath->count < exist->attr->aspath->count)
- return 1;
- if (new->attr->aspath->count > exist->attr->aspath->count)
- return 0;
- }
- /* 5. Origin check. */
- if (new->attr->origin < exist->attr->origin)
- return 1;
- if (new->attr->origin > exist->attr->origin)
- return 0;
- /* 6. MED check. */
- internal_as_route = (new->attr->aspath->length == 0
- && exist->attr->aspath->length == 0);
- confed_as_route = (new->attr->aspath->length > 0
- && exist->attr->aspath->length > 0
- && new->attr->aspath->count == 0
- && exist->attr->aspath->count == 0);
-
- if (bgp_flag_check (bgp, BGP_FLAG_ALWAYS_COMPARE_MED)
- || (bgp_flag_check (bgp, BGP_FLAG_MED_CONFED)
- && confed_as_route)
- || aspath_cmp_left (new->attr->aspath, exist->attr->aspath)
- || aspath_cmp_left_confed (new->attr->aspath, exist->attr->aspath)
- || internal_as_route)
- {
- new_med = bgp_med_value (new->attr, bgp);
- exist_med = bgp_med_value (exist->attr, bgp);
- if (new_med < exist_med)
- return 1;
- if (new_med > exist_med)
- return 0;
- }
- /* 7. Peer type check. */
- if (peer_sort (new->peer) == BGP_PEER_EBGP
- && peer_sort (exist->peer) == BGP_PEER_IBGP)
- return 1;
- if (peer_sort (new->peer) == BGP_PEER_EBGP
- && peer_sort (exist->peer) == BGP_PEER_CONFED)
- return 1;
- if (peer_sort (new->peer) == BGP_PEER_IBGP
- && peer_sort (exist->peer) == BGP_PEER_EBGP)
- return 0;
- if (peer_sort (new->peer) == BGP_PEER_CONFED
- && peer_sort (exist->peer) == BGP_PEER_EBGP)
- return 0;
- /* 8. IGP metric check. */
- if (new->igpmetric < exist->igpmetric)
- return 1;
- if (new->igpmetric > exist->igpmetric)
- return 0;
- /* 9. cost community check. */
- if (! bgp_flag_check (bgp, BGP_FLAG_COST_COMMUNITY_IGNORE))
- {
- cost_community = ecommunity_cost_cmp (new->attr->ecommunity,
- exist->attr->ecommunity, ECOMMUNITY_COST_POI_IGP);
- if (cost_community > 0)
- return 1;
- if (cost_community < 0)
- return 0;
- }
- /* 10. Maximum path check. */
- /* 11. If both paths are external, prefer the path that was received
- first (the oldest one). This step minimizes route-flap, since a
- newer path won't displace an older one, even if it was the
- preferred route based on the additional decision criteria below. */
- if (! bgp_flag_check (bgp, BGP_FLAG_COMPARE_ROUTER_ID)
- && peer_sort (new->peer) == BGP_PEER_EBGP
- && peer_sort (exist->peer) == BGP_PEER_EBGP)
- {
- if (CHECK_FLAG (new->flags, BGP_INFO_SELECTED))
- return 1;
- if (CHECK_FLAG (exist->flags, BGP_INFO_SELECTED))
- return 0;
- }
- /* 12. Rourter-ID comparision. */
- if (new->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
- new_id.s_addr = new->attr->originator_id.s_addr;
- else
- new_id.s_addr = new->peer->remote_id.s_addr;
- if (exist->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
- exist_id.s_addr = exist->attr->originator_id.s_addr;
- else
- exist_id.s_addr = exist->peer->remote_id.s_addr;
- if (ntohl (new_id.s_addr) < ntohl (exist_id.s_addr))
- return 1;
- if (ntohl (new_id.s_addr) > ntohl (exist_id.s_addr))
- return 0;
- /* 13. Cluster length comparision. */
- if (new->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST))
- new_cluster = new->attr->cluster->length;
- else
- new_cluster = 0;
- if (exist->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST))
- exist_cluster = exist->attr->cluster->length;
- else
- exist_cluster = 0;
- if (new_cluster < exist_cluster)
- return 1;
- if (new_cluster > exist_cluster)
- return 0;
- /* 14. Neighbor address comparision. */
- ret = sockunion_cmp (new->peer->su_remote, exist->peer->su_remote);
- if (ret == 1)
- return 0;
- if (ret == -1)
- return 1;
- return 1;
- }
- enum filter_type
- bgp_input_filter (struct peer *peer, struct prefix *p, struct attr *attr,
- afi_t afi, safi_t safi)
- {
- struct bgp_filter *filter;
- filter = &peer->filter[afi][safi];
- if (DISTRIBUTE_IN_NAME (filter))
- if (access_list_apply (DISTRIBUTE_IN (filter), p) == FILTER_DENY)
- return FILTER_DENY;
- if (PREFIX_LIST_IN_NAME (filter))
- if (prefix_list_apply (PREFIX_LIST_IN (filter), p) == PREFIX_DENY)
- return FILTER_DENY;
-
- if (FILTER_LIST_IN_NAME (filter))
- if (as_list_apply (FILTER_LIST_IN (filter), attr->aspath)== AS_FILTER_DENY)
- return FILTER_DENY;
- return FILTER_PERMIT;
- }
- enum filter_type
- bgp_output_filter (struct peer *peer, struct prefix *p, struct attr *attr,
- afi_t afi, safi_t safi)
- {
- struct bgp_filter *filter;
- filter = &peer->filter[afi][safi];
- if (DISTRIBUTE_OUT_NAME (filter))
- if (access_list_apply (DISTRIBUTE_OUT (filter), p) == FILTER_DENY)
- return FILTER_DENY;
- if (PREFIX_LIST_OUT_NAME (filter))
- if (prefix_list_apply (PREFIX_LIST_OUT (filter), p) == PREFIX_DENY)
- return FILTER_DENY;
- if (FILTER_LIST_OUT_NAME (filter))
- if (as_list_apply (FILTER_LIST_OUT (filter), attr->aspath) == AS_FILTER_DENY)
- return FILTER_DENY;
- return FILTER_PERMIT;
- }
- /* If community attribute includes no_export then return 1. */
- int
- bgp_community_filter (struct peer *peer, struct attr *attr)
- {
- if (attr->community)
- {
- /* NO_ADVERTISE check. */
- if (community_include (attr->community, COMMUNITY_NO_ADVERTISE))
- return 1;
- /* NO_EXPORT check. */
- if (peer_sort (peer) == BGP_PEER_EBGP &&
- community_include (attr->community, COMMUNITY_NO_EXPORT))
- return 1;
- /* NO_EXPORT_SUBCONFED check. */
- if (peer_sort (peer) == BGP_PEER_EBGP
- || peer_sort (peer) == BGP_PEER_CONFED)
- if (community_include (attr->community, COMMUNITY_NO_EXPORT_SUBCONFED))
- return 1;
- }
- return 0;
- }
- /* Route reflection loop check. */
- static int
- bgp_cluster_filter (struct peer *peer, struct attr *attr)
- {
- struct in_addr cluster_id;
- if (attr->cluster)
- {
- if (peer->bgp->config & BGP_CONFIG_CLUSTER_ID)
- cluster_id = peer->bgp->cluster_id;
- else
- cluster_id = peer->bgp->router_id;
-
- if (cluster_loop_check (attr->cluster, cluster_id))
- return 1;
- }
- return 0;
- }
- int
- bgp_input_modifier (struct peer *peer, struct prefix *p, struct attr *attr,
- afi_t afi, safi_t safi)
- {
- struct bgp_filter *filter;
- struct bgp_info info;
- route_map_result_t ret;
- filter = &peer->filter[afi][safi];
- /* Apply default weight value. */
- if (CHECK_FLAG (peer->af_config[afi][safi], PEER_AF_CONFIG_WEIGHT))
- attr->weight = peer->weight[afi][safi];
- else
- attr->weight = 0;
- /* Route map apply. */
- if (ROUTE_MAP_IN_NAME (filter))
- {
- /* Duplicate current value to new strucutre for modification. */
- info.peer = peer;
- info.attr = attr;
- SET_FLAG (peer->rmap_type, PEER_RMAP_TYPE_IN);
- /* Apply BGP route map to the attribute. */
- ret = route_map_apply (ROUTE_MAP_IN (filter), p, RMAP_BGP, &info);
- peer->rmap_type = 0;
- if (ret == RMAP_DENYMATCH)
- {
- /* Free newly generated AS path and community by route-map. */
- bgp_attr_flush (attr);
- return RMAP_DENY;
- }
- }
- return RMAP_PERMIT;
- }
- int
- bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
- struct attr *attr, afi_t afi, safi_t safi)
- {
- int ret;
- char buf[SU_ADDRSTRLEN];
- struct bgp_filter *filter;
- struct bgp_info info;
- struct peer *from;
- struct bgp *bgp;
- struct attr dummy_attr;
- int transparent;
- int reflect;
- from = ri->peer;
- filter = &peer->filter[afi][safi];
- bgp = peer->bgp;
-
- #ifdef DISABLE_BGP_ANNOUNCE
- return 0;
- #endif
- /* Do not send back route to sender. */
- if (from == peer)
- return 0;
- /* Aggregate-address suppress check. */
- if (ri->suppress)
- if (! UNSUPPRESS_MAP_NAME (filter))
- return 0;
- /* Default route check. */
- if (CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_DEFAULT_ORIGINATE))
- {
- if (p->family == AF_INET && p->u.prefix4.s_addr == INADDR_ANY)
- return 0;
- #ifdef HAVE_IPV6
- else if (p->family == AF_INET6 && p->prefixlen == 0)
- return 0;
- #endif /* HAVE_IPV6 */
- }
- /* Transparency check. */
- if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)
- && CHECK_FLAG (from->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT))
- transparent = 1;
- else
- transparent = 0;
- /* If community is not disabled check the no-export and local. */
- if (! transparent && bgp_community_filter (peer, ri->attr))
- return 0;
- /* If the attribute has originator-id and it is same as remote
- peer's id. */
- if (ri->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID))
- {
- if (IPV4_ADDR_SAME (&peer->remote_id, &ri->attr->originator_id))
- {
- if (BGP_DEBUG (filter, FILTER))
- zlog (peer->log, LOG_INFO,
- "%s [Update:SEND] %s/%d originator-id is same as remote router-id",
- peer->host,
- inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
- p->prefixlen);
- return 0;
- }
- }
-
- /* ORF prefix-list filter check */
- if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_ADV)
- && (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_RCV)
- || CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_OLD_RCV)))
- if (peer->orf_plist[afi][safi])
- {
- if (prefix_list_apply (peer->orf_plist[afi][safi], p) == PREFIX_DENY)
- return 0;
- }
- /* Output filter check. */
- if (bgp_output_filter (peer, p, ri->attr, afi, safi) == FILTER_DENY)
- {
- if (BGP_DEBUG (filter, FILTER))
- zlog (peer->log, LOG_INFO,
- "%s [Update:SEND] %s/%d is filtered",
- peer->host,
- inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
- p->prefixlen);
- return 0;
- }
- #ifdef BGP_SEND_ASPATH_CHECK
- /* AS path loop check. */
- if (aspath_loop_check (ri->attr->aspath, peer->as))
- {
- if (BGP_DEBUG (filter, FILTER))
- zlog (peer->log, LOG_INFO,
- "%s [Update:SEND] suppress announcement to peer AS %d is AS path.",
- peer->host, peer->as);
- return 0;
- }
- #endif /* BGP_SEND_ASPATH_CHECK */
- /* If we're a CONFED we need to loop check the CONFED ID too */
- if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
- {
- if (aspath_loop_check(ri->attr->aspath, bgp->confed_id))
- {
- if (BGP_DEBUG (filter, FILTER))
- zlog (peer->log, LOG_INFO,
- "%s [Update:SEND] suppress announcement to peer AS %d is AS path.",
- peer->host,
- bgp->confed_id);
- return 0;
- }
- }
- /* Route-Reflect check. */
- if (peer_sort (from) == BGP_PEER_IBGP && peer_sort (peer) == BGP_PEER_IBGP)
- reflect = 1;
- else
- reflect = 0;
- /* IBGP reflection check. */
- if (reflect)
- {
- /* A route from a Client peer. */
- if (CHECK_FLAG (from->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT))
- {
- /* Reflect to all the Non-Client peers and also to the
- Client peers other than the originator. Originator check
- is already done. So there is noting to do. */
- /* no bgp client-to-client reflection check. */
- if (bgp_flag_check (bgp, BGP_FLAG_NO_CLIENT_TO_CLIENT))
- if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT))
- return 0;
- }
- else
- {
- /* A route from a Non-client peer. Reflect to all other
- clients. */
- if (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT))
- return 0;
- }
- }
- /* For modify attribute, copy it to temporary structure. */
- *attr = *ri->attr;
- /* If local-preference is not set. */
- if ((peer_sort (peer) == BGP_PEER_IBGP
- || peer_sort (peer) == BGP_PEER_CONFED)
- && (! (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))))
- {
- attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
- attr->local_pref = bgp->default_local_pref;
- }
- /* Remove MED if its an EBGP peer - will get overwritten by route-maps */
- if (peer_sort (peer) == BGP_PEER_EBGP
- && attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
- {
- if (ri->peer != bgp->peer_self && ! transparent
- && ! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MED_UNCHANGED))
- attr->flag &= ~(ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC));
- }
- /* next-hop-set */
- if (transparent || reflect
- || (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_UNCHANGED)
- && ((p->family == AF_INET && attr->nexthop.s_addr)
- #ifdef HAVE_IPV6
- || (p->family == AF_INET6 && ri->peer != bgp->peer_self)
- #endif /* HAVE_IPV6 */
- )))
- {
- /* NEXT-HOP Unchanged. */
- }
- else if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_SELF)
- || (p->family == AF_INET && attr->nexthop.s_addr == 0)
- #ifdef HAVE_IPV6
- || (p->family == AF_INET6 && ri->peer == bgp->peer_self)
- #endif /* HAVE_IPV6 */
- || (peer_sort (peer) == BGP_PEER_EBGP
- && bgp_multiaccess_check_v4 (attr->nexthop, peer->host) == 0))
- {
- /* Set IPv4 nexthop. */
- if (p->family == AF_INET)
- {
- if (safi == SAFI_MPLS_VPN)
- memcpy (&attr->mp_nexthop_global_in, &peer->nexthop.v4, IPV4_MAX_BYTELEN);
- else
- memcpy (&attr->nexthop, &peer->nexthop.v4, IPV4_MAX_BYTELEN);
- }
- #ifdef HAVE_IPV6
- /* Set IPv6 nexthop. */
- if (p->family == AF_INET6)
- {
- /* IPv6 global nexthop must be included. */
- memcpy (&attr->mp_nexthop_global, &peer->nexthop.v6_global,
- IPV6_MAX_BYTELEN);
- attr->mp_nexthop_len = 16;
- }
- #endif /* HAVE_IPV6 */
- }
- #ifdef HAVE_IPV6
- if (p->family == AF_INET6)
- {
- /* Link-local address should not be transit to different peer. */
- attr->mp_nexthop_len = 16;
- /* Set link-local address for shared network peer. */
- if (peer->shared_network
- && ! IN6_IS_ADDR_UNSPECIFIED (&peer->nexthop.v6_local))
- {
- memcpy (&attr->mp_nexthop_local, &peer->nexthop.v6_local,
- IPV6_MAX_BYTELEN);
- attr->mp_nexthop_len = 32;
- }
- /* If bgpd act as BGP-4+ route-reflector, do not send link-local
- address.*/
- if (reflect)
- attr->mp_nexthop_len = 16;
- /* If BGP-4+ link-local nexthop is not link-local nexthop. */
- if (! IN6_IS_ADDR_LINKLOCAL (&peer->nexthop.v6_local))
- attr->mp_nexthop_len = 16;
- }
- #endif /* HAVE_IPV6 */
- /* If this is EBGP peer and remove-private-AS is set. */
- if (peer_sort (peer) == BGP_PEER_EBGP
- && peer_af_flag_check (peer, afi, safi, PEER_FLAG_REMOVE_PRIVATE_AS)
- && aspath_private_as_check (attr->aspath))
- attr->aspath = aspath_empty_get ();
- /* Route map & unsuppress-map apply. */
- if (ROUTE_MAP_OUT_NAME (filter)
- || ri->suppress)
- {
- info.peer = peer;
- info.attr = attr;
- /* The route reflector is not allowed to modify the attributes
- of the reflected IBGP routes. */
- if (peer_sort (from) == BGP_PEER_IBGP
- && peer_sort (peer) == BGP_PEER_IBGP)
- {
- dummy_attr = *attr;
- info.attr = &dummy_attr;
- }
- SET_FLAG (peer->rmap_type, PEER_RMAP_TYPE_OUT);
- if (ri->suppress)
- ret = route_map_apply (UNSUPPRESS_MAP (filter), p, RMAP_BGP, &info);
- else
- ret = route_map_apply (ROUTE_MAP_OUT (filter), p, RMAP_BGP, &info);
- peer->rmap_type = 0;
- if (ret == RMAP_DENYMATCH)
- {
- bgp_attr_flush (attr);
- return 0;
- }
- }
- return 1;
- }
- int
- bgp_process (struct bgp *bgp, struct bgp_node *rn, afi_t afi, safi_t safi)
- {
- struct prefix *p;
- struct bgp_info *ri;
- struct bgp_info *new_select;
- struct bgp_info *old_select;
- struct listnode *nn;
- struct peer *peer;
- struct attr attr;
- struct bgp_info *ri1;
- struct bgp_info *ri2;
- p = &rn->p;
- /* bgp deterministic-med */
- new_select = NULL;
- if (bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED))
- for (ri1 = rn->info; ri1; ri1 = ri1->next)
- {
- if (CHECK_FLAG (ri1->flags, BGP_INFO_DMED_CHECK))
- continue;
- if (BGP_INFO_HOLDDOWN (ri1))
- continue;
- new_select = ri1;
- if (ri1->next)
- for (ri2 = ri1->next; ri2; ri2 = ri2->next)
- {
- if (CHECK_FLAG (ri2->flags, BGP_INFO_DMED_CHECK))
- continue;
- if (BGP_INFO_HOLDDOWN (ri2))
- continue;
- if (aspath_cmp_left (ri1->attr->aspath, ri2->attr->aspath)
- || aspath_cmp_left_confed (ri1->attr->aspath,
- ri2->attr->aspath))
- {
- if (bgp_info_cmp (bgp, ri2, new_select))
- {
- UNSET_FLAG (new_select->flags, BGP_INFO_DMED_SELECTED);
- new_select = ri2;
- }
- SET_FLAG (ri2->flags, BGP_INFO_DMED_CHECK);
- }
- }
- SET_FLAG (new_select->flags, BGP_INFO_DMED_CHECK);
- SET_FLAG (new_select->flags, BGP_INFO_DMED_SELECTED);
- }
- /* Check old selected route and new selected route. */
- old_select = NULL;
- new_select = NULL;
- for (ri = rn->info; ri; ri = ri->next)
- {
- if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED))
- old_select = ri;
- if (BGP_INFO_HOLDDOWN (ri))
- continue;
- if (bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED)
- && (! CHECK_FLAG (ri->flags, BGP_INFO_DMED_SELECTED)))
- {
- UNSET_FLAG (ri->flags, BGP_INFO_DMED_CHECK);
- continue;
- }
- UNSET_FLAG (ri->flags, BGP_INFO_DMED_CHECK);
- UNSET_FLAG (ri->flags, BGP_INFO_DMED_SELECTED);
- if (bgp_info_cmp (bgp, ri, new_select))
- new_select = ri;
- }
- /* Nothing to do. */
- if (old_select && old_select == new_select)
- {
- if (! CHECK_FLAG (old_select->flags, BGP_INFO_ATTR_CHANGED))
- {
- if (CHECK_FLAG (old_select->flags, BGP_INFO_IGP_CHANGED))
- bgp_zebra_announce (p, old_select, bgp);
- return 0;
- }
- }
- if (old_select)
- UNSET_FLAG (old_select->flags, BGP_INFO_SELECTED);
- if (new_select)
- {
- SET_FLAG (new_select->flags, BGP_INFO_SELECTED);
- UNSET_FLAG (new_select->flags, BGP_INFO_ATTR_CHANGED);
- }
- /* Check each BGP peer. */
- LIST_LOOP (bgp->peer, peer, nn)
- {
- /* Announce route to Established peer. */
- if (peer->status != Established)
- continue;
- /* Address family configuration check. */
- if (! peer->afc_nego[afi][safi])
- continue;
- /* First update is deferred until ORF or ROUTE-REFRESH is received */
- if (CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_WAIT_REFRESH))
- continue;
- /* Announcement to peer->conf. If the route is filtered,
- withdraw it. */
- if (new_select
- && bgp_announce_check (new_select, peer, p, &attr, afi, safi))
- bgp_adj_out_set (rn, peer, p, &attr, afi, safi, new_select);
- else
- bgp_adj_out_unset (rn, peer, p, afi, safi);
- }
- /* FIB update. */
- if (safi == SAFI_UNICAST && ! bgp->name &&
- ! bgp_option_check (BGP_OPT_NO_FIB))
- {
- if (new_select
- && new_select->type == ZEBRA_ROUTE_BGP
- && new_select->sub_type == BGP_ROUTE_NORMAL)
- bgp_zebra_announce (p, new_select, bgp);
- else
- {
- /* Withdraw the route from the kernel. */
- if (old_select
- && old_select->type == ZEBRA_ROUTE_BGP
- && old_select->sub_type == BGP_ROUTE_NORMAL)
- bgp_zebra_withdraw (p, old_select);
- }
- }
- return 0;
- }
- int
- bgp_maximum_prefix_restart_timer (struct thread *thread)
- {
- struct peer *peer;
- peer = THREAD_ARG (thread);
- peer->t_pmax_restart = NULL;
- if (BGP_DEBUG (events, EVENTS))
- zlog_info ("%s Maximum-prefix restart timer expired, restore peering", peer->host);
- peer_clear (peer);
- return 0;
- }
- int
- bgp_maximum_prefix_overflow (struct peer *peer, afi_t afi, safi_t safi, int always)
- {
- if (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX))
- return 0;
- if (peer->pcount[afi][safi] > peer->pmax[afi][safi])
- {
- if (CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_PREFIX_LIMIT)
- && ! always)
- return 0;
- zlog (peer->log, LOG_INFO,
- "%%MAXPFXEXCEED: No. of %s prefix received from %s %ld exceed, limit %ld",
- afi_safi_print (afi, safi), peer->host, peer->pcount[afi][safi],
- peer->pmax[afi][safi]);
- SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_PREFIX_LIMIT);
- if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING))
- return 0;
- {
- char ndata[7];
- ndata[0] = (u_char)(afi >> 8);
- ndata[1] = (u_char) afi;
- ndata[3] = (u_char)(peer->pmax[afi][safi] >> 24);
- ndata[4] = (u_char)(peer->pmax[afi][safi] >> 16);
- ndata[5] = (u_char)(peer->pmax[afi][safi] >> 8);
- ndata[6] = (u_char)(peer->pmax[afi][safi]);
- if (safi == SAFI_MPLS_VPN)
- safi = BGP_SAFI_VPNV4;
- ndata[2] = (u_char) safi;
- SET_FLAG (peer->sflags, PEER_STATUS_PREFIX_OVERFLOW);
- bgp_notify_send_with_data (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_MAX_PREFIX, ndata, 7);
- }
- /* restart timer start */
- if (peer->pmax_restart[afi][safi])
- {
- peer->v_pmax_restart = peer->pmax_restart[afi][safi] * 60;
- if (BGP_DEBUG (events, EVENTS))
- zlog_info ("%s Maximum-prefix restart timer started for %d secs",
- peer->host, peer->v_pmax_restart);
- BGP_TIMER_ON (peer->t_pmax_restart, bgp_maximum_prefix_restart_timer,
- peer->v_pmax_restart);
- }
- return 1;
- }
- else
- UNSET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_PREFIX_LIMIT);
- if (peer->pcount[afi][safi] > (peer->pmax[afi][safi] * peer->pmax_threshold[afi][safi] / 100))
- {
- if (CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_PREFIX_THRESHOLD)
- && ! always)
- return 0;
- zlog (peer->log, LOG_INFO,
- "%%MAXPFX: No. of %s prefix received from %s reaches %ld, max %ld",
- afi_safi_print (afi, safi), peer->host, peer->pcount[afi][safi],
- peer->pmax[afi][safi]);
- SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_PREFIX_THRESHOLD);
- }
- else
- UNSET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_PREFIX_THRESHOLD);
- return 0;
- }
- void
- bgp_rib_remove (struct bgp_node *rn, struct bgp_info *ri, struct peer *peer,
- afi_t afi, safi_t safi)
- {
- if (! CHECK_FLAG (ri->flags, BGP_INFO_HISTORY))
- {
- if (! CHECK_FLAG (ri->flags, BGP_INFO_STALE))
- peer->pcount[afi][safi]--;
- bgp_aggregate_decrement (peer->bgp, &rn->p, ri, afi, safi);
- UNSET_FLAG (ri->flags, BGP_INFO_VALID);
- bgp_process (peer->bgp, rn, afi, safi);
- }
- bgp_info_delete (rn, ri);
- bgp_info_free (ri);
- bgp_unlock_node (rn);
- }
- void
- bgp_rib_withdraw (struct bgp_node *rn, struct bgp_info *ri, struct peer *peer,
- afi_t afi, safi_t safi, int force)
- {
- int valid;
- int status = BGP_DAMP_NONE;
- if (! CHECK_FLAG (ri->flags, BGP_INFO_HISTORY))
- {
- peer->pcount[afi][safi]--;
- bgp_aggregate_decrement (peer->bgp, &rn->p, ri, afi, safi);
- }
- if (! force)
- {
- if (CHECK_FLAG (peer->bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)
- && peer_sort (peer) == BGP_PEER_EBGP)
- status = bgp_damp_withdraw (ri, rn, afi, safi, 0);
- if (status == BGP_DAMP_SUPPRESSED)
- return;
- }
- valid = CHECK_FLAG (ri->flags, BGP_INFO_VALID);
- UNSET_FLAG (ri->flags, BGP_INFO_VALID);
- bgp_process (peer->bgp, rn, afi, safi);
- if (valid)
- SET_FLAG (ri->flags, BGP_INFO_VALID);
- if (status != BGP_DAMP_USED)
- {
- bgp_info_delete (rn, ri);
- bgp_info_free (ri);
- bgp_unlock_node (rn);
- }
- }
- int
- bgp_update (struct peer *peer, struct prefix *p, struct attr *attr,
- afi_t afi, safi_t safi, int type, int sub_type,
- struct prefix_rd *prd, u_char *tag, int soft_reconfig)
- {
- int ret;
- int aspath_loop_count = 0;
- struct bgp_node *rn;
- struct bgp *bgp;
- struct attr new_attr;
- struct attr *attr_new;
- struct bgp_info *ri;
- struct bgp_info *new;
- char *reason;
- char buf[SU_ADDRSTRLEN];
- bgp = peer->bgp;
- rn = bgp_afi_node_get (bgp, afi, safi, p, prd);
- /* When peer's soft reconfiguration enabled. Record input packet in
- Adj-RIBs-In. */
- if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG)
- && peer != bgp->peer_self && ! soft_reconfig)
- bgp_adj_in_set (rn, peer, attr);
- /* Check previously received route. */
- for (ri = rn->info; ri; ri = ri->next)
- if (ri->peer == peer && ri->type == type && ri->sub_type == sub_type)
- break;
- /* AS path local-as loop check. */
- if (peer->change_local_as)
- {
- if (! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
- aspath_loop_count = 1;
- if (aspath_loop_check (attr->aspath, peer->change_local_as) > aspath_loop_count)
- {
- reason = "as-path contains our own AS;";
- goto filtered;
- }
- }
- /* AS path 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]))
- {
- reason = "as-path contains our own AS;";
- goto filtered;
- }
- /* Route reflector originator ID check. */
- if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID)
- && IPV4_ADDR_SAME (&bgp->router_id, &attr->originator_id))
- {
- reason = "originator is us;";
- goto filtered;
- }
- /* Route reflector cluster ID check. */
- if (bgp_cluster_filter (peer, attr))
- {
- reason = "reflected from the same cluster;";
- goto filtered;
- }
- /* Apply incoming filter. */
- if (bgp_input_filter (peer, p, attr, afi, safi) == FILTER_DENY)
- {
- reason = "filter;";
- goto filtered;
- }
- /* Apply incoming route-map. */
- new_attr = *attr;
- if (bgp_input_modifier (peer, p, &new_attr, afi, safi) == RMAP_DENY)
- {
- reason = "route-map;";
- goto filtered;
- }
- /* IPv4 unicast next hop check. */
- if (afi == AFI_IP && safi == SAFI_UNICAST)
- {
- /* If the peer is EBGP and nexthop is not on connected route,
- discard it. */
- if (peer_sort (peer) == BGP_PEER_EBGP && peer->ttl == 1
- && ! bgp_nexthop_check_ebgp (afi, &new_attr)
- && ! CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK))
- {
- reason = "non-connected next-hop;";
- goto filtered;
- }
- /* Next hop must not be 0.0.0.0 nor Class E address. Next hop
- must not be my own address. */
- if (bgp_nexthop_self (afi, &new_attr)
- || new_attr.nexthop.s_addr == 0
- || ntohl (new_attr.nexthop.s_addr) >= 0xe0000000)
- {
- reason = "martian next-hop;";
- goto filtered;
- }
- }
- attr_new = bgp_attr_intern (&new_attr);
- /* If the update is implicit withdraw. */
- if (ri)
- {
- ri->uptime = time (NULL);
- /* Same attribute comes in. */
- if (attrhash_cmp (ri->attr, attr_new))
- {
- UNSET_FLAG (ri->flags, BGP_INFO_ATTR_CHANGED);
- if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)
- && peer_sort (peer) == BGP_PEER_EBGP
- && CHECK_FLAG (ri->flags, BGP_INFO_HISTORY))
- {
- if (BGP_DEBUG (update, UPDATE_IN))
- zlog (peer->log, LOG_INFO, "%s rcvd %s/%d",
- peer->host,
- inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
- p->prefixlen);
- peer->pcount[afi][safi]++;
- ret = bgp_damp_update (ri, rn, afi, safi);
- if (ret != BGP_DAMP_SUPPRESSED)
- {
- bgp_aggregate_increment (bgp, p, ri, afi, safi);
- bgp_process (bgp, rn, afi, safi);
- }
- }
- else
- {
- if (BGP_DEBUG (update, UPDATE_IN))
- zlog (peer->log, LOG_INFO,
- "%s rcvd %s/%d...duplicate ignored",
- peer->host,
- inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
- p->prefixlen);
- /* graceful restart STALE flag unset. */
- if (CHECK_FLAG (ri->flags, BGP_INFO_STALE))
- {
- UNSET_FLAG (ri->flags, BGP_INFO_STALE);
- peer->pcount[afi][safi]++;
- }
- }
- bgp_unlock_node (rn);
- bgp_attr_unintern (attr_new);
- return 0;
- }
- /* Received Logging. */
- if (BGP_DEBUG (update, UPDATE_IN))
- zlog (peer->log, LOG_INFO, "%s rcvd %s/%d",
- peer->host,
- inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
- p->prefixlen);
- /* graceful restart STALE flag unset. */
- if (CHECK_FLAG (ri->flags, BGP_INFO_STALE))
- {
- UNSET_FLAG (ri->flags, BGP_INFO_STALE);
- peer->pcount[afi][safi]++;
- }
- /* The attribute is changed. */
- SET_FLAG (ri->flags, BGP_INFO_ATTR_CHANGED);
- /* Update bgp route dampening information. */
- if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)
- && peer_sort (peer) == BGP_PEER_EBGP)
- {
- /* This is implicit withdraw so we should update dampening
- information. */
- if (! CHECK_FLAG (ri->flags, BGP_INFO_HISTORY))
- bgp_damp_withdraw (ri, rn, afi, safi, 1);
- else
- peer->pcount[afi][safi]++;
- }
-
- bgp_aggregate_decrement (bgp, p, ri, afi, safi);
- /* Update to new attribute. */
- bgp_attr_unintern (ri->attr);
- ri->attr = attr_new;
- /* Update MPLS tag. */
- if (safi == SAFI_MPLS_VPN)
- memcpy (ri->tag, tag, 3);
- /* Update bgp route dampening information. */
- if (CHECK_FLAG (bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)
- && peer_sort (peer) == BGP_PEER_EBGP)
- {
- /* Now we do normal update dampening. */
- ret = bgp_damp_update (ri, rn, afi, safi);
- if (ret == BGP_DAMP_SUPPRESSED)
- {
- bgp_unlock_node (rn);
- return 0;
- }
- }
- /* Nexthop reachability check. */
- if ((afi == AFI_IP || afi == AFI_IP6)
- && safi == SAFI_UNICAST
- && (peer_sort (peer) == BGP_PEER_IBGP
- || (peer_sort (peer) == BGP_PEER_EBGP && peer->ttl != 1)
- || CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)))
- {
- if (bgp_nexthop_lookup (afi, peer, ri, NULL, NULL))
- SET_FLAG (ri->flags, BGP_INFO_VALID);
- else
- UNSET_FLAG (ri->flags, BGP_INFO_VALID);
- }
- else
- SET_FLAG (ri->flags, BGP_INFO_VALID);
- /* Process change. */
- bgp_aggregate_increment (bgp, p, ri, afi, safi);
- bgp_process (bgp, rn, afi, safi);
- bgp_unlock_node (rn);
- return 0;
- }
- /* Received Logging. */
- if (BGP_DEBUG (update, UPDATE_IN))
- {
- zlog (peer->log, LOG_INFO, "%s rcvd %s/%d",
- peer->host,
- inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
- p->prefixlen);
- }
- /* Increment prefix counter */
- peer->pcount[afi][safi]++;
- /* Make new BGP info. */
- new = bgp_info_new ();
- new->type = type;
- new->sub_type = sub_type;
- new->peer = peer;
- new->attr = attr_new;
- new->uptime = time (NULL);
- /* Update MPLS tag. */
- if (safi == SAFI_MPLS_VPN)
- memcpy (new->tag, tag, 3);
- /* Nexthop reachability check. */
- if ((afi == AFI_IP || afi == AFI_IP6)
- && safi == SAFI_UNICAST
- && (peer_sort (peer) == BGP_PEER_IBGP
- || (peer_sort (peer) == BGP_PEER_EBGP && peer->ttl != 1)
- || CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)))
- {
- if (bgp_nexthop_lookup (afi, peer, new, NULL, NULL))
- SET_FLAG (new->flags, BGP_INFO_VALID);
- else
- UNSET_FLAG (new->flags, BGP_INFO_VALID);
- }
- else
- SET_FLAG (new->flags, BGP_INFO_VALID);
- /* Aggregate address increment. */
- bgp_aggregate_increment (bgp, p, new, afi, safi);
-
- /* Register new BGP information. */
- bgp_info_add (rn, new);
- /* If maximum prefix count is configured and current prefix
- count exeed it. */
- if (bgp_maximum_prefix_overflow (peer, afi, safi, 0))
- return -1;
- /* Process change. */
- bgp_process (bgp, rn, afi, safi);
- return 0;
- /* This BGP update is filtered. Log the reason then update BGP
- entry. */
- filtered:
- if (BGP_DEBUG (update, UPDATE_IN))
- zlog (peer->log, LOG_INFO,
- "%s rcvd UPDATE about %s/%d -- DENIED due to: %s",
- peer->host,
- inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
- p->prefixlen, reason);
- if (ri)
- bgp_rib_withdraw (rn, ri, peer, afi, safi, 1);
- bgp_unlock_node (rn);
- return 0;
- }
- int
- bgp_withdraw (struct peer *peer, struct prefix *p, struct attr *attr,
- int afi, int safi, int type, int sub_type, struct prefix_rd *prd,
- u_char *tag)
- {
- struct bgp *bgp;
- char buf[SU_ADDRSTRLEN];
- struct bgp_node *rn;
- struct bgp_info *ri;
- bgp = peer->bgp;
- /* Logging. */
- if (BGP_DEBUG (update, UPDATE_IN))
- zlog (peer->log, LOG_INFO, "%s rcvd UPDATE about %s/%d -- withdrawn",
- peer->host,
- inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
- p->prefixlen);
- /* Lookup node. */
- rn = bgp_afi_node_get (bgp, afi, safi, p, prd);
- /* If peer is soft reconfiguration enabled. Record input packet for
- further calculation. */
- if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG)
- && peer != bgp->peer_self)
- bgp_adj_in_unset (rn, peer);
- /* Lookup withdrawn route. */
- for (ri = rn->info; ri; ri = ri->next)
- if (ri->peer == peer && ri->type == type && ri->sub_type == sub_type)
- break;
- /* Withdraw specified route from routing table. */
- if (ri && ! CHECK_FLAG (ri->flags, BGP_INFO_HISTORY))
- bgp_rib_withdraw (rn, ri, peer, afi, safi, 0);
- else if (BGP_DEBUG (update, UPDATE_IN))
- zlog (peer->log, LOG_INFO,
- "%s Can't find the route %s/%d", peer->host,
- inet_ntop (p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
- p->prefixlen);
- /* Unlock bgp_node_get() lock. */
- bgp_unlock_node (rn);
- return 0;
- }
- void
- bgp_default_originate (struct peer *peer, afi_t afi, safi_t safi, int withdraw)
- {
- struct bgp *bgp;
- struct attr attr;
- struct aspath *aspath;
- struct prefix p;
- struct bgp_info binfo;
- struct peer *from;
- int ret = RMAP_DENYMATCH;
- bgp = peer->bgp;
- from = bgp->peer_self;
- bgp_attr_default_set (&attr, BGP_ORIGIN_IGP);
- aspath = attr.aspath;
- attr.local_pref = bgp->default_local_pref;
- memcpy (&attr.nexthop, &peer->nexthop.v4, IPV4_MAX_BYTELEN);
- if (afi == AFI_IP)
- str2prefix ("0.0.0.0/0", &p);
- #ifdef HAVE_IPV6
- else if (afi == AFI_IP6)
- {
- str2prefix ("::/0", &p);
- /* IPv6 global nexthop must be included. */
- memcpy (&attr.mp_nexthop_global, &peer->nexthop.v6_global,
- IPV6_MAX_BYTELEN);
- attr.mp_nexthop_len = 16;
-
- /* If the peer is on shared nextwork and we have link-local
- nexthop set it. */
- if (peer->shared_network
- && !IN6_IS_ADDR_UNSPECIFIED (&peer->nexthop.v6_local))
- {
- memcpy (&attr.mp_nexthop_local, &peer->nexthop.v6_local,
- IPV6_MAX_BYTELEN);
- attr.mp_nexthop_len = 32;
- }
- }
- #endif /* HAVE_IPV6 */
- else
- return;
- if (peer->default_rmap[afi][safi].name)
- {
- binfo.peer = bgp->peer_self;
- binfo.attr = &attr;
- ret = route_map_apply (peer->default_rmap[afi][safi].map, &p,
- RMAP_BGP, &binfo);
- if (ret == RMAP_DENYMATCH)
- {
- bgp_attr_flush (&attr);
- withdraw = 1;
- }
- }
- if (withdraw)
- {
- if (CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_DEFAULT_ORIGINATE))
- bgp_default_withdraw_send (peer, afi, safi);
- UNSET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_DEFAULT_ORIGINATE);
- }
- else
- {
- SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_DEFAULT_ORIGINATE);
- bgp_default_update_send (peer, &attr, afi, safi, from);
- }
- aspath_unintern (aspath);
- }
- static void
- bgp_announce_table (struct peer *peer, afi_t afi, safi_t safi,
- struct bgp_table *table)
- {
- struct bgp_node *rn;
- struct bgp_info *ri;
- struct attr attr;
- if (! table)
- table = peer->bgp->rib[afi][safi];
- if (safi != SAFI_MPLS_VPN
- && CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE))
- bgp_default_originate (peer, afi, safi, 0);
- for (rn = bgp_table_top (table); rn; rn = bgp_route_next(rn))
- for (ri = rn->info; ri; ri = ri->next)
- if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED) && ri->peer != peer)
- {
- if (bgp_announce_check (ri, peer, &rn->p, &attr, afi, safi))
- bgp_adj_out_set (rn, peer, &rn->p, &attr, afi, safi, ri);
- else
- bgp_adj_out_unset (rn, peer, &rn->p, afi, safi);
- }
- }
- void
- bgp_announce_route (struct peer *peer, afi_t afi, safi_t safi)
- {
- struct bgp_node *rn;
- struct bgp_table *table;
- if (peer->status != Established)
- return;
- if (! peer->afc_nego[afi][safi])
- return;
- /* First update is deferred until ORF or ROUTE-REFRESH is received */
- if (CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_WAIT_REFRESH))
- return;
- if (safi != SAFI_MPLS_VPN)
- bgp_announce_table (peer, afi, safi, NULL);
- else
- for (rn = bgp_table_top (peer->bgp->rib[afi][safi]); rn;
- rn = bgp_route_next(rn))
- if ((table = (rn->info)) != NULL)
- bgp_announce_table (peer, afi, safi, table);
- if (! peer->t_routeadv[afi][safi])
- bgp_routeadv_timer (peer, afi, safi);
- }
- void
- bgp_announce_route_all (struct peer *peer)
- {
- afi_t afi;
- safi_t safi;
-
- for (afi = AFI_IP; afi < AFI_MAX; afi++)
- for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
- bgp_announce_route (peer, afi, safi);
- }
- static void
- bgp_soft_reconfig_table (struct peer *peer, afi_t afi, safi_t safi,
- struct bgp_table *table)
- {
- int ret;
- struct bgp_node *rn;
- struct bgp_adj_in *ain;
- if (! table)
- table = peer->bgp->rib[afi][safi];
- for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
- for (ain = rn->adj_in; ain; ain = ain->next)
- {
- if (ain->peer == peer)
- {
- ret = bgp_update (peer, &rn->p, ain->attr, afi, safi,
- ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
- NULL, NULL, 1);
- if (ret < 0)
- {
- bgp_unlock_node (rn);
- return;
- }
- continue;
- }
- }
- }
- void
- bgp_soft_reconfig_in (struct peer *peer, afi_t afi, safi_t safi)
- {
- struct bgp_node *rn;
- struct bgp_table *table;
- if (peer->status != Established)
- return;
- if (safi != SAFI_MPLS_VPN)
- bgp_soft_reconfig_table (peer, afi, safi, NULL);
- else
- for (rn = bgp_table_top (peer->bgp->rib[afi][safi]); rn;
- rn = bgp_route_next (rn))
- if ((table = rn->info) != NULL)
- bgp_soft_reconfig_table (peer, afi, safi, table);
- }
- static void
- bgp_clear_route_table (struct peer *peer, afi_t afi, safi_t safi,
- struct bgp_table *table)
- {
- struct bgp_node *rn;
- struct bgp_adj_in *ain;
- struct bgp_adj_out *aout;
- struct bgp_info *ri;
- if (! table)
- table = peer->bgp->rib[afi][safi];
- for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
- {
- for (ri = rn->info; ri; ri = ri->next)
- if (ri->peer == peer)
- {
- /* graceful restart STALE flag set. */
- if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT)
- && peer->nsf[afi][safi]
- && ! CHECK_FLAG (ri->flags, BGP_INFO_STALE)
- && ! CHECK_FLAG (ri->flags, BGP_INFO_HISTORY)
- && ! CHECK_FLAG (ri->flags, BGP_INFO_DAMPED))
- {
- SET_FLAG (ri->flags, BGP_INFO_STALE);
- peer->pcount[afi][safi]--;
- }
- else
- bgp_rib_remove (rn, ri, peer, afi, safi);
- break;
- }
- for (ain = rn->adj_in; ain; ain = ain->next)
- if (ain->peer == peer)
- {
- bgp_adj_in_remove (rn, ain);
- bgp_unlock_node (rn);
- break;
- }
- for (aout = rn->adj_out; aout; aout = aout->next)
- if (aout->peer == peer)
- {
- bgp_adj_out_remove (rn, aout, peer, afi, safi);
- bgp_unlock_node (rn);
- break;
- }
- }
- }
- void
- bgp_clear_route (struct peer *peer, afi_t afi, safi_t safi)
- {
- struct bgp_node *rn;
- struct bgp_table *table;
- if (safi != SAFI_MPLS_VPN)
- bgp_clear_route_table (peer, afi, safi, NULL);
- else
- for (rn = bgp_table_top (peer->bgp->rib[afi][safi]); rn;
- rn = bgp_route_next (rn))
- if ((table = rn->info) != NULL)
- bgp_clear_route_table (peer, afi, safi, table);
- }
-
- void
- bgp_clear_route_all (struct peer *peer)
- {
- afi_t afi;
- safi_t safi;
- for (afi = AFI_IP; afi < AFI_MAX; afi++)
- for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
- bgp_clear_route (peer, afi, safi);
- }
- void
- bgp_clear_adj_in (struct peer *peer, afi_t afi, safi_t safi)
- {
- struct bgp_table *table;
- struct bgp_node *rn;
- struct bgp_adj_in *ain;
- table = peer->bgp->rib[afi][safi];
- for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
- for (ain = rn->adj_in; ain ; ain = ain->next)
- if (ain->peer == peer)
- {
- bgp_adj_in_remove (rn, ain);
- bgp_unlock_node (rn);
- break;
- }
- }
- void
- bgp_clear_stale_route (struct peer *peer, afi_t afi, safi_t safi)
- {
- struct bgp_node *rn;
- struct bgp_info *ri;
- struct bgp_table *table;
- table = peer->bgp->rib[afi][safi];
- for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
- {
- for (ri = rn->info; ri; ri = ri->next)
- if (ri->peer == peer)
- {
- if (CHECK_FLAG (ri->flags, BGP_INFO_STALE))
- bgp_rib_remove (rn, ri, peer, afi, safi);
- break;
- }
- }
- }
- /* Delete all kernel routes. */
- void
- bgp_terminate ()
- {
- struct bgp *bgp;
- struct listnode *nn;
- struct bgp_node *rn;
- struct bgp_table *table;
- struct bgp_info *ri;
- LIST_LOOP (bm->bgp, bgp, nn)
- {
- table = bgp->rib[AFI_IP][SAFI_UNICAST];
- for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
- for (ri = rn->info; ri; ri = ri->next)
- if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED)
- && ri->type == ZEBRA_ROUTE_BGP
- && ri->sub_type == BGP_ROUTE_NORMAL)
- bgp_zebra_withdraw (&rn->p, ri);
- table = bgp->rib[AFI_IP6][SAFI_UNICAST];
- for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
- for (ri = rn->info; ri; ri = ri->next)
- if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED)
- && ri->type == ZEBRA_ROUTE_BGP
- && ri->sub_type == BGP_ROUTE_NORMAL)
- bgp_zebra_withdraw (&rn->p, ri);
- }
- }
- void
- bgp_reset ()
- {
- vty_reset ();
- bgp_zclient_reset ();
- access_list_reset ();
- prefix_list_reset ();
- }
- /* Parse NLRI stream. Withdraw NLRI is recognized by NULL attr
- value. */
- int
- bgp_nlri_parse (struct peer *peer, struct attr *attr, struct bgp_nlri *packet)
- {
- u_char *pnt;
- u_char *lim;
- struct prefix p;
- int psize;
- int ret;
- /* Check peer status. */
- if (peer->status != Established)
- return 0;
-
- pnt = packet->nlri;
- lim = pnt + packet->length;
- for (; pnt < lim; pnt += psize)
- {
- /* Clear prefix structure. */
- memset (&p, 0, sizeof (struct prefix));
- /* Fetch prefix length. */
- p.prefixlen = *pnt++;
- p.family = afi2family (packet->afi);
-
- /* Already checked in nlri_sanity_check(). We do double check
- here. */
- if ((packet->afi == AFI_IP && p.prefixlen > 32)
- || (packet->afi == AFI_IP6 && p.prefixlen > 128))
- return -1;
- /* Packet size overflow check. */
- psize = PSIZE (p.prefixlen);
- /* When packet overflow occur return immediately. */
- if (pnt + psize > lim)
- return -1;
- /* Fetch prefix from NLRI packet. */
- memcpy (&p.u.prefix, pnt, psize);
- /* Check address. */
- if (packet->afi == AFI_IP && packet->safi == SAFI_UNICAST)
- {
- if (IN_CLASSD (ntohl (p.u.prefix4.s_addr)))
- {
- zlog (peer->log, LOG_ERR,
- "IPv4 unicast NLRI is multicast address %s",
- inet_ntoa (p.u.prefix4));
- bgp_notify_send (peer,
- BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_INVAL_NETWORK);
- return -1;
- }
- }
- #ifdef HAVE_IPV6
- /* Check address. */
- if (packet->afi == AFI_IP6 && packet->safi == SAFI_UNICAST)
- {
- if (IN6_IS_ADDR_LINKLOCAL (&p.u.prefix6))
- {
- char buf[BUFSIZ];
- zlog (peer->log, LOG_WARNING,
- "IPv6 link-local NLRI received %s ignore this NLRI",
- inet_ntop (AF_INET6, &p.u.prefix6, buf, BUFSIZ));
- continue;
- }
- }
- #endif /* HAVE_IPV6 */
- /* Normal process. */
- if (attr)
- ret = bgp_update (peer, &p, attr, packet->afi, packet->safi,
- ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, NULL, 0);
- else
- ret = bgp_withdraw (peer, &p, attr, packet->afi, packet->safi,
- ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, NULL);
- /* Address family configuration mismatch or maximum-prefix count
- overflow. */
- if (ret < 0)
- return -1;
- }
- /* Packet length consistency check. */
- if (pnt != lim)
- return -1;
- return 0;
- }
- /* NLRI encode syntax check routine. */
- int
- bgp_nlri_sanity_check (struct peer *peer, int afi, u_char *pnt,
- bgp_size_t length)
- {
- u_char *end;
- u_char prefixlen;
- int psize;
- end = pnt + length;
- /* RFC1771 6.3 The NLRI field in the UPDATE message is checked for
- syntactic validity. If the field is syntactically incorrect,
- then the Error Subcode is set to Invalid Network Field. */
- while (pnt < end)
- {
- prefixlen = *pnt++;
-
- /* Prefix length check. */
- if ((afi == AFI_IP && prefixlen > 32)
- || (afi == AFI_IP6 && prefixlen > 128))
- {
- plog_err (peer->log,
- "%s [Error] Update packet error (wrong prefix length %d)",
- peer->host, prefixlen);
- bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_INVAL_NETWORK);
- return -1;
- }
- /* Packet size overflow check. */
- psize = PSIZE (prefixlen);
- if (pnt + psize > end)
- {
- plog_err (peer->log,
- "%s [Error] Update packet error"
- " (prefix data overflow prefix size is %d)",
- peer->host, psize);
- bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_INVAL_NETWORK);
- return -1;
- }
- pnt += psize;
- }
- /* Packet length consistency check. */
- if (pnt != end)
- {
- plog_err (peer->log,
- "%s [Error] Update packet error"
- " (prefix length mismatch with total length)",
- peer->host);
- bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
- BGP_NOTIFY_UPDATE_INVAL_NETWORK);
- return -1;
- }
- return 0;
- }
- struct bgp_static *
- bgp_static_new ()
- {
- struct bgp_static *new;
- new = XMALLOC (MTYPE_BGP_STATIC, sizeof (struct bgp_static));
- memset (new, 0, sizeof (struct bgp_static));
- return new;
- }
- void
- bgp_static_free (struct bgp_static *bgp_static)
- {
- if (bgp_static->rmap.name)
- free (bgp_static->rmap.name);
- XFREE (MTYPE_BGP_STATIC, bgp_static);
- }
- void
- bgp_static_update (struct bgp *bgp, struct prefix *p,
- struct bgp_static *bgp_static, afi_t afi, safi_t safi)
- {
- struct bgp_node *rn;
- struct bgp_info *ri;
- struct bgp_info *new;
- struct bgp_info info;
- struct attr attr;
- struct attr attr_tmp;
- struct attr *attr_new;
- int ret;
- rn = bgp_afi_node_get (bgp, afi, safi, p, NULL);
- bgp_attr_default_set (&attr, BGP_ORIGIN_IGP);
- if (bgp_static)
- {
- attr.nexthop = bgp_static->igpnexthop;
- attr.med = bgp_static->igpmetric;
- attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
- }
- /* Apply route-map. */
- if (bgp_static->rmap.name)
- {
- attr_tmp = attr;
- info.peer = bgp->peer_self;
- info.attr = &attr_tmp;
- ret = route_map_apply (bgp_static->rmap.map, p, RMAP_BGP, &info);
- if (ret == RMAP_DENYMATCH)
- {
- /* Free uninterned attribute. */
- bgp_attr_flush (&attr_tmp);
- /* Unintern original. */
- aspath_unintern (attr.aspath);
- bgp_static_withdraw (bgp, p, afi, safi);
- return;
- }
- attr_new = bgp_attr_intern (&attr_tmp);
- }
- else
- attr_new = bgp_attr_intern (&attr);
- for (ri = rn->info; ri; ri = ri->next)
- if (ri->peer == bgp->peer_self && ri->type == ZEBRA_ROUTE_BGP
- && ri->sub_type == BGP_ROUTE_STATIC)
- break;
- if (ri)
- {
- if (attrhash_cmp (ri->attr, attr_new))
- {
- bgp_unlock_node (rn);
- bgp_attr_unintern (attr_new);
- aspath_unintern (attr.aspath);
- return;
- }
- else
- {
- /* The attribute is changed. */
- SET_FLAG (ri->flags, BGP_INFO_ATTR_CHANGED);
- /* Rewrite BGP route information. */
- bgp_aggregate_decrement (bgp, p, ri, afi, safi);
- bgp_attr_unintern (ri->attr);
- ri->attr = attr_new;
- ri->uptime = time (NULL);
- /* Process change. */
- bgp_aggregate_increment (bgp, p, ri, afi, safi);
- bgp_process (bgp, rn, afi, safi);
- bgp_unlock_node (rn);
- aspath_unintern (attr.aspath);
- return;
- }
- }
- /* Make new BGP info. */
- new = bgp_info_new ();
- new->type = ZEBRA_ROUTE_BGP;
- new->sub_type = BGP_ROUTE_STATIC;
- new->peer = bgp->peer_self;
- SET_FLAG (new->flags, BGP_INFO_VALID);
- new->attr = attr_new;
- new->uptime = time (NULL);
- /* Aggregate address increment. */
- bgp_aggregate_increment (bgp, p, new, afi, safi);
-
- /* Register new BGP information. */
- bgp_info_add (rn, new);
- /* Process change. */
- bgp_process (bgp, rn, afi, safi);
- /* Unintern original. */
- aspath_unintern (attr.aspath);
- }
- void
- bgp_static_update_vpnv4 (struct bgp *bgp, struct prefix *p, u_int16_t afi,
- u_char safi, struct prefix_rd *prd, u_char *tag)
- {
- struct bgp_node *rn;
- struct bgp_info *new;
- rn = bgp_afi_node_get (bgp, afi, safi, p, prd);
- /* Make new BGP info. */
- new = bgp_info_new ();
- new->type = ZEBRA_ROUTE_BGP;
- new->sub_type = BGP_ROUTE_STATIC;
- new->peer = bgp->peer_self;
- new->attr = bgp_attr_default_intern (BGP_ORIGIN_IGP);
- SET_FLAG (new->flags, BGP_INFO_VALID);
- new->uptime = time (NULL);
- memcpy (new->tag, tag, 3);
- /* Aggregate address increment. */
- bgp_aggregate_increment (bgp, p, (struct bgp_info *) new, afi, safi);
-
- /* Register new BGP information. */
- bgp_info_add (rn, (struct bgp_info *) new);
- /* Process change. */
- bgp_process (bgp, rn, afi, safi);
- }
- void
- bgp_static_withdraw (struct bgp *bgp, struct prefix *p, afi_t afi,
- safi_t safi)
- {
- struct bgp_node *rn;
- struct bgp_info *ri;
- rn = bgp_afi_node_get (bgp, afi, safi, p, NULL);
- /* Check selected route and self inserted route. */
- for (ri = rn->info; ri; ri = ri->next)
- if (ri->peer == bgp->peer_self
- && ri->type == ZEBRA_ROUTE_BGP
- && ri->sub_type == BGP_ROUTE_STATIC)
- break;
- /* Withdraw static BGP route from routing table. */
- if (ri)
- {
- bgp_aggregate_decrement (bgp, p, ri, afi, safi);
- UNSET_FLAG (ri->flags, BGP_INFO_VALID);
- bgp_process (bgp, rn, afi, safi);
- bgp_info_delete (rn, ri);
- bgp_info_free (ri);
- bgp_unlock_node (rn);
- }
- /* Unlock bgp_node_lookup. */
- bgp_unlock_node (rn);
- }
- void
- bgp_static_withdraw_vpnv4 (struct bgp *bgp, struct prefix *p, u_int16_t afi,
- u_char safi, struct prefix_rd *prd, u_char *tag)
- {
- struct bgp_node *rn;
- struct bgp_info *ri;
- rn = bgp_afi_node_get (bgp, afi, safi, p, prd);
- /* Check selected route and self inserted route. */
- for (ri = rn->info; ri; ri = ri->next)
- if (ri->peer == bgp->peer_self
- && ri->type == ZEBRA_ROUTE_BGP
- && ri->sub_type == BGP_ROUTE_STATIC)
- break;
- /* Withdraw static BGP route from routing table. */
- if (ri)
- {
- bgp_aggregate_decrement (bgp, p, ri, afi, safi);
- UNSET_FLAG (ri->flags, BGP_INFO_VALID);
- bgp_process (bgp, rn, afi, safi);
- bgp_info_delete (rn, ri);
- bgp_info_free (ri);
- bgp_unlock_node (rn);
- }
- /* Unlock bgp_node_lookup. */
- bgp_unlock_node (rn);
- }
- /* Configure static BGP network. When user don't run zebra, static
- route should be installed as valid. */
- int
- bgp_static_set (struct vty *vty, struct bgp *bgp, char *ip_str, u_int16_t afi,
- u_char safi, char *rmap, int backdoor)
- {
- int ret;
- struct prefix p;
- struct bgp_static *bgp_static;
- struct bgp_node *rn;
- int need_update = 0;
- /* Convert IP prefix string to struct prefix. */
- ret = str2prefix (ip_str, &p);
- if (! ret)
- {
- vty_out (vty, "%% Malformed prefix%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
- #ifdef HAVE_IPV6
- if (afi == AFI_IP6 && IN6_IS_ADDR_LINKLOCAL (&p.u.prefix6))
- {
- vty_out (vty, "%% Malformed prefix (link-local address)%s",
- VTY_NEWLINE);
- return CMD_WARNING;
- }
- #endif /* HAVE_IPV6 */
- apply_mask (&p);
- /* Set BGP static route configuration. */
- rn = bgp_node_get (bgp->route[afi][safi], &p);
- if (rn->info)
- {
- /* Configuration change. */
- bgp_static = rn->info;
- /* Check previous routes are installed into BGP. */
- if (! bgp_static->backdoor && bgp_static->valid)
- need_update = 1;
- bgp_static->backdoor = backdoor;
- if (rmap)
- {
- if (bgp_static->rmap.name)
- free (bgp_static->rmap.name);
- bgp_static->rmap.name = strdup (rmap);
- bgp_static->rmap.map = route_map_lookup_by_name (rmap);
- }
- else
- {
- if (bgp_static->rmap.name)
- free (bgp_static->rmap.name);
- bgp_static->rmap.name = NULL;
- bgp_static->rmap.map = NULL;
- bgp_static->valid = 0;
- }
- bgp_unlock_node (rn);
- }
- else
- {
- /* New configuration. */
- bgp_static = bgp_static_new ();
- bgp_static->backdoor = backdoor;
- bgp_static->valid = 0;
- bgp_static->igpmetric = 0;
- bgp_static->igpnexthop.s_addr = 0;
- if (rmap)
- {
- if (bgp_static->rmap.name)
- free (bgp_static->rmap.name);
- bgp_static->rmap.name = strdup (rmap);
- bgp_static->rmap.map = route_map_lookup_by_name (rmap);
- }
- rn->info = bgp_static;
- }
- /* If BGP scan is not enabled, we should install this route here. */
- if (! bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK))
- {
- bgp_static->valid = 1;
- if (need_update)
- bgp_static_withdraw (bgp, &p, afi, safi);
- if (! bgp_static->backdoor)
- bgp_static_update (bgp, &p, bgp_static, afi, safi);
- }
- return CMD_SUCCESS;
- }
- /* Configure static BGP network. */
- int
- bgp_static_unset (struct vty *vty, struct bgp *bgp, char *ip_str,
- u_int16_t afi, u_char safi)
- {
- int ret;
- struct prefix p;
- struct bgp_static *bgp_static;
- struct bgp_node *rn;
- /* Convert IP prefix string to struct prefix. */
- ret = str2prefix (ip_str, &p);
- if (! ret)
- {
- vty_out (vty, "%% Malformed prefix%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
- #ifdef HAVE_IPV6
- if (afi == AFI_IP6 && IN6_IS_ADDR_LINKLOCAL (&p.u.prefix6))
- {
- vty_out (vty, "%% Malformed prefix (link-local address)%s",
- VTY_NEWLINE);
- return CMD_WARNING;
- }
- #endif /* HAVE_IPV6 */
- apply_mask (&p);
- rn = bgp_node_lookup (bgp->route[afi][safi], &p);
- if (! rn)
- {
- vty_out (vty, "%% Can't find specified static route configuration.%s",
- VTY_NEWLINE);
- return CMD_WARNING;
- }
- bgp_static = rn->info;
- /* Update BGP RIB. */
- if (! bgp_static->backdoor)
- bgp_static_withdraw (bgp, &p, afi, safi);
- /* Clear configuration. */
- bgp_static_free (bgp_static);
- rn->info = NULL;
- bgp_unlock_node (rn);
- bgp_unlock_node (rn);
- return CMD_SUCCESS;
- }
- /* Called from bgp_delete(). Delete all static routes from the BGP
- instance. */
- void
- bgp_static_delete (struct bgp *bgp)
- {
- afi_t afi;
- safi_t safi;
- struct bgp_node *rn;
- struct bgp_node *rm;
- struct bgp_table *table;
- struct bgp_static *bgp_static;
- for (afi = AFI_IP; afi < AFI_MAX; afi++)
- for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
- for (rn = bgp_table_top (bgp->route[afi][safi]); rn; rn = bgp_route_next (rn))
- if (rn->info != NULL)
- {
- if (safi == SAFI_MPLS_VPN)
- {
- table = rn->info;
- for (rm = bgp_table_top (table); rm; rm = bgp_route_next (rm))
- {
- bgp_static = rn->info;
- bgp_static_withdraw_vpnv4 (bgp, &rm->p,
- AFI_IP, SAFI_MPLS_VPN,
- (struct prefix_rd *)&rn->p,
- bgp_static->tag);
- bgp_static_free (bgp_static);
- rn->info = NULL;
- bgp_unlock_node (rn);
- }
- }
- else
- {
- bgp_static = rn->info;
- bgp_static_withdraw (bgp, &rn->p, afi, safi);
- bgp_static_free (bgp_static);
- rn->info = NULL;
- bgp_unlock_node (rn);
- }
- }
- }
- int
- bgp_static_set_vpnv4 (struct vty *vty, char *ip_str, char *rd_str,
- char *tag_str)
- {
- int ret;
- struct prefix p;
- struct prefix_rd prd;
- struct bgp *bgp;
- struct bgp_node *prn;
- struct bgp_node *rn;
- struct bgp_table *table;
- struct bgp_static *bgp_static;
- u_char tag[3];
- bgp = vty->index;
- ret = str2prefix (ip_str, &p);
- if (! ret)
- {
- vty_out (vty, "%% Malformed prefix%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
- apply_mask (&p);
- ret = str2prefix_rd (rd_str, &prd);
- if (! ret)
- {
- vty_out (vty, "%% Malformed rd%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
- ret = str2tag (tag_str, tag);
- if (! ret)
- {
- vty_out (vty, "%% Malformed tag%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
- prn = bgp_node_get (bgp->route[AFI_IP][SAFI_MPLS_VPN],
- (struct prefix *)&prd);
- if (prn->info == NULL)
- prn->info = bgp_table_init ();
- else
- bgp_unlock_node (prn);
- table = prn->info;
- rn = bgp_node_get (table, &p);
- if (rn->info)
- {
- vty_out (vty, "%% Same network configuration exists%s", VTY_NEWLINE);
- bgp_unlock_node (rn);
- }
- else
- {
- /* New configuration. */
- bgp_static = bgp_static_new ();
- bgp_static->valid = 1;
- memcpy (bgp_static->tag, tag, 3);
- rn->info = bgp_static;
- bgp_static_update_vpnv4 (bgp, &p, AFI_IP, SAFI_MPLS_VPN, &prd, tag);
- }
- return CMD_SUCCESS;
- }
- /* Configure static BGP network. */
- int
- bgp_static_unset_vpnv4 (struct vty *vty, char *ip_str, char *rd_str,
- char *tag_str)
- {
- int ret;
- struct bgp *bgp;
- struct prefix p;
- struct prefix_rd prd;
- struct bgp_node *prn;
- struct bgp_node *rn;
- struct bgp_table *table;
- struct bgp_static *bgp_static;
- u_char tag[3];
- bgp = vty->index;
- /* Convert IP prefix string to struct prefix. */
- ret = str2prefix (ip_str, &p);
- if (! ret)
- {
- vty_out (vty, "%% Malformed prefix%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
- apply_mask (&p);
- ret = str2prefix_rd (rd_str, &prd);
- if (! ret)
- {
- vty_out (vty, "%% Malformed rd%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
- ret = str2tag (tag_str, tag);
- if (! ret)
- {
- vty_out (vty, "%% Malformed tag%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
- prn = bgp_node_get (bgp->route[AFI_IP][SAFI_MPLS_VPN],
- (struct prefix *)&prd);
- if (prn->info == NULL)
- prn->info = bgp_table_init ();
- else
- bgp_unlock_node (prn);
- table = prn->info;
- rn = bgp_node_lookup (table, &p);
- if (rn)
- {
- bgp_static_withdraw_vpnv4 (bgp, &p, AFI_IP, SAFI_MPLS_VPN, &prd, tag);
- bgp_static = rn->info;
- bgp_static_free (bgp_static);
- rn->info = NULL;
- bgp_unlock_node (rn);
- bgp_unlock_node (rn);
- }
- else
- vty_out (vty, "%% Can't find the route%s", VTY_NEWLINE);
- return CMD_SUCCESS;
- }
- DEFUN (bgp_network,
- bgp_network_cmd,
- "network A.B.C.D/M",
- "Specify a network to announce via BGPn"
- "IP prefix <network>/<length>, e.g., 35.0.0.0/8n")
- {
- return bgp_static_set (vty, vty->index, argv[0],
- AFI_IP, bgp_node_safi (vty), NULL, 0);
- }
- DEFUN (bgp_network_route_map,
- bgp_network_route_map_cmd,
- "network A.B.C.D/M route-map WORD",
- "Specify a network to announce via BGPn"
- "IP prefix <network>/<length>, e.g., 35.0.0.0/8n"
- "Route-map to modify the attributesn"
- "Name of the route mapn")
- {
- return bgp_static_set (vty, vty->index, argv[0],
- AFI_IP, bgp_node_safi (vty), argv[1], 0);
- }
- DEFUN (bgp_network_backdoor,
- bgp_network_backdoor_cmd,
- "network A.B.C.D/M backdoor",
- "Specify a network to announce via BGPn"
- "IP prefix <network>/<length>, e.g., 35.0.0.0/8n"
- "Specify a BGP backdoor routen")
- {
- return bgp_static_set (vty, vty->index, argv[0], AFI_IP, SAFI_UNICAST, NULL, 1);
- }
- DEFUN (bgp_network_mask,
- bgp_network_mask_cmd,
- "network A.B.C.D mask A.B.C.D",
- "Specify a network to announce via BGPn"
- "Network numbern"
- "Network maskn"
- "Network maskn")
- {
- int ret;
- char prefix_str[BUFSIZ];
- ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str);
- if (! ret)
- {
- vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
- return bgp_static_set (vty, vty->index, prefix_str,
- AFI_IP, bgp_node_safi (vty), NULL, 0);
- }
- DEFUN (bgp_network_mask_route_map,
- bgp_network_mask_route_map_cmd,
- "network A.B.C.D mask A.B.C.D route-map WORD",
- "Specify a network to announce via BGPn"
- "Network numbern"
- "Network maskn"
- "Network maskn"
- "Route-map to modify the attributesn"
- "Name of the route mapn")
- {
- int ret;
- char prefix_str[BUFSIZ];
- ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str);
- if (! ret)
- {
- vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
- return bgp_static_set (vty, vty->index, prefix_str,
- AFI_IP, bgp_node_safi (vty), argv[2], 0);
- }
- DEFUN (bgp_network_mask_backdoor,
- bgp_network_mask_backdoor_cmd,
- "network A.B.C.D mask A.B.C.D backdoor",
- "Specify a network to announce via BGPn"
- "Network numbern"
- "Network maskn"
- "Network maskn"
- "Specify a BGP backdoor routen")
- {
- int ret;
- char prefix_str[BUFSIZ];
- ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str);
- if (! ret)
- {
- vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
- return bgp_static_set (vty, vty->index, prefix_str, AFI_IP, SAFI_UNICAST, NULL, 1);
- }
- DEFUN (bgp_network_mask_natural,
- bgp_network_mask_natural_cmd,
- "network A.B.C.D",
- "Specify a network to announce via BGPn"
- "Network numbern")
- {
- int ret;
- char prefix_str[BUFSIZ];
- ret = netmask_str2prefix_str (argv[0], NULL, prefix_str);
- if (! ret)
- {
- vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
- return bgp_static_set (vty, vty->index, prefix_str,
- AFI_IP, bgp_node_safi (vty), NULL, 0);
- }
- DEFUN (bgp_network_mask_natural_route_map,
- bgp_network_mask_natural_route_map_cmd,
- "network A.B.C.D route-map WORD",
- "Specify a network to announce via BGPn"
- "Network numbern"
- "Route-map to modify the attributesn"
- "Name of the route mapn")
- {
- int ret;
- char prefix_str[BUFSIZ];
- ret = netmask_str2prefix_str (argv[0], NULL, prefix_str);
- if (! ret)
- {
- vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
- return bgp_static_set (vty, vty->index, prefix_str,
- AFI_IP, bgp_node_safi (vty), argv[1], 0);
- }
- DEFUN (bgp_network_mask_natural_backdoor,
- bgp_network_mask_natural_backdoor_cmd,
- "network A.B.C.D backdoor",
- "Specify a network to announce via BGPn"
- "Network numbern"
- "Specify a BGP backdoor routen")
- {
- int ret;
- char prefix_str[BUFSIZ];
- ret = netmask_str2prefix_str (argv[0], NULL, prefix_str);
- if (! ret)
- {
- vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
- return bgp_static_set (vty, vty->index, prefix_str, AFI_IP, SAFI_UNICAST, NULL, 1);
- }
- DEFUN (no_bgp_network,
- no_bgp_network_cmd,
- "no network A.B.C.D/M",
- NO_STR
- "Specify a network to announce via BGPn"
- "IP prefix <network>/<length>, e.g., 35.0.0.0/8n")
- {
- return bgp_static_unset (vty, vty->index, argv[0], AFI_IP,
- bgp_node_safi (vty));
- }
- ALIAS (no_bgp_network,
- no_bgp_network_route_map_cmd,
- "no network A.B.C.D/M route-map WORD",
- NO_STR
- "Specify a network to announce via BGPn"
- "IP prefix <network>/<length>, e.g., 35.0.0.0/8n"
- "Route-map to modify the attributesn"
- "Name of the route mapn");
- ALIAS (no_bgp_network,
- no_bgp_network_backdoor_cmd,
- "no network A.B.C.D/M backdoor",
- NO_STR
- "Specify a network to announce via BGPn"
- "IP prefix <network>/<length>, e.g., 35.0.0.0/8n"
- "Specify a BGP backdoor routen");
- DEFUN (no_bgp_network_mask,
- no_bgp_network_mask_cmd,
- "no network A.B.C.D mask A.B.C.D",
- NO_STR
- "Specify a network to announce via BGPn"
- "Network numbern"
- "Network maskn"
- "Network maskn")
- {
- int ret;
- char prefix_str[BUFSIZ];
- ret = netmask_str2prefix_str (argv[0], argv[1], prefix_str);
- if (! ret)
- {
- vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
- return bgp_static_unset (vty, vty->index, prefix_str, AFI_IP,
- bgp_node_safi (vty));
- }
- ALIAS (no_bgp_network_mask,
- no_bgp_network_mask_route_map_cmd,
- "no network A.B.C.D mask A.B.C.D route-map WORD",
- NO_STR
- "Specify a network to announce via BGPn"
- "Network numbern"
- "Network maskn"
- "Network maskn"
- "Route-map to modify the attributesn"
- "Name of the route mapn");
- ALIAS (no_bgp_network_mask,
- no_bgp_network_mask_backdoor_cmd,
- "no network A.B.C.D mask A.B.C.D backdoor",
- NO_STR
- "Specify a network to announce via BGPn"
- "Network numbern"
- "Network maskn"
- "Network maskn"
- "Specify a BGP backdoor routen");
- DEFUN (no_bgp_network_mask_natural,
- no_bgp_network_mask_natural_cmd,
- "no network A.B.C.D",
- NO_STR
- "Specify a network to announce via BGPn"
- "Network numbern")
- {
- int ret;
- char prefix_str[BUFSIZ];
- ret = netmask_str2prefix_str (argv[0], NULL, prefix_str);
- if (! ret)
- {
- vty_out (vty, "%% Inconsistent address and mask%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
- return bgp_static_unset (vty, vty->index, prefix_str, AFI_IP,
- bgp_node_safi (vty));
- }
- ALIAS (no_bgp_network_mask_natural,
- no_bgp_network_mask_natural_route_map_cmd,
- "no network A.B.C.D route-map WORD",
- NO_STR
- "Specify a network to announce via BGPn"
- "Network numbern"
- "Route-map to modify the attributesn"
- "Name of the route mapn");
- ALIAS (no_bgp_network_mask_natural,
- no_bgp_network_mask_natural_backdoor_cmd,
- "no network A.B.C.D backdoor",
- NO_STR
- "Specify a network to announce via BGPn"
- "Network numbern"
- "Specify a BGP backdoor routen");
- #ifdef HAVE_IPV6
- DEFUN (ipv6_bgp_network,
- ipv6_bgp_network_cmd,
- "network X:X::X:X/M",
- "Specify a network to announce via BGPn"
- "IPv6 prefix <network>/<length>n")
- {
- return bgp_static_set (vty, vty->index, argv[0], AFI_IP6, SAFI_UNICAST, NULL, 0);
- }
- DEFUN (ipv6_bgp_network_route_map,
- ipv6_bgp_network_route_map_cmd,
- "network X:X::X:X/M route-map WORD",
- "Specify a network to announce via BGPn"
- "IPv6 prefix <network>/<length>n"
- "Route-map to modify the attributesn"
- "Name of the route mapn")
- {
- return bgp_static_set (vty, vty->index, argv[0], AFI_IP6,
- bgp_node_safi (vty), argv[1], 0);
- }
- DEFUN (no_ipv6_bgp_network,
- no_ipv6_bgp_network_cmd,
- "no network X:X::X:X/M",
- NO_STR
- "Specify a network to announce via BGPn"
- "IPv6 prefix <network>/<length>n")
- {
- return bgp_static_unset (vty, vty->index, argv[0], AFI_IP6, SAFI_UNICAST);
- }
- ALIAS (no_ipv6_bgp_network,
- no_ipv6_bgp_network_route_map_cmd,
- "no network X:X::X:X/M route-map WORD",
- NO_STR
- "Specify a network to announce via BGPn"
- "IPv6 prefix <network>/<length>n"
- "Route-map to modify the attributesn"
- "Name of the route mapn");
- ALIAS (ipv6_bgp_network,
- old_ipv6_bgp_network_cmd,
- "ipv6 bgp network X:X::X:X/M",
- IPV6_STR
- BGP_STR
- "Specify a network to announce via BGPn"
- "IPv6 prefix <network>/<length>, e.g., 3ffe::/16n");
- ALIAS (no_ipv6_bgp_network,
- old_no_ipv6_bgp_network_cmd,
- "no ipv6 bgp network X:X::X:X/M",
- NO_STR
- IPV6_STR
- BGP_STR
- "Specify a network to announce via BGPn"
- "IPv6 prefix <network>/<length>, e.g., 3ffe::/16n");
- #endif /* HAVE_IPV6 */
- /* Aggreagete address:
- advertise-map Set condition to advertise attribute
- as-set Generate AS set path information
- attribute-map Set attributes of aggregate
- route-map Set parameters of aggregate
- summary-only Filter more specific routes from updates
- suppress-map Conditionally filter more specific routes from updates
- <cr>
- */
- struct bgp_aggregate
- {
- /* Summary-only flag. */
- u_char summary_only;
- /* AS set generation. */
- u_char as_set;
- /* Route-map for aggregated route. */
- struct route_map *map;
- /* Suppress-count. */
- unsigned long count;
- /* SAFI configuration. */
- safi_t safi;
- };
- struct bgp_aggregate *
- bgp_aggregate_new ()
- {
- struct bgp_aggregate *new;
- new = XMALLOC (MTYPE_BGP_AGGREGATE, sizeof (struct bgp_aggregate));
- memset (new, 0, sizeof (struct bgp_aggregate));
- return new;
- }
- void
- bgp_aggregate_free (struct bgp_aggregate *aggregate)
- {
- XFREE (MTYPE_BGP_AGGREGATE, aggregate);
- }
- void
- bgp_aggregate_route (struct bgp *bgp, struct prefix *p, struct bgp_info *rinew,
- afi_t afi, safi_t safi, struct bgp_info *del,
- struct bgp_aggregate *aggregate)
- {
- struct bgp_table *table;
- struct bgp_node *top;
- struct bgp_node *rn;
- u_char origin;
- struct aspath *aspath = NULL;
- struct aspath *asmerge = NULL;
- struct community *community = NULL;
- struct community *commerge = NULL;
- struct in_addr nexthop;
- u_int32_t med = 0;
- struct bgp_info *ri;
- struct bgp_info *new;
- int first = 1;
- unsigned long match = 0;
- /* Record adding route's nexthop and med. */
- if (rinew)
- {
- nexthop = rinew->attr->nexthop;
- med = rinew->attr->med;
- }
- /* ORIGIN attribute: If at least one route among routes that are
- aggregated has ORIGIN with the value INCOMPLETE, then the
- aggregated route must have the ORIGIN attribute with the value
- INCOMPLETE. Otherwise, if at least one route among routes that
- are aggregated has ORIGIN with the value EGP, then the aggregated
- route must have the origin attribute with the value EGP. In all
- other case the value of the ORIGIN attribute of the aggregated
- route is INTERNAL. */
- origin = BGP_ORIGIN_IGP;
- table = bgp->rib[afi][safi];
- top = bgp_node_get (table, p);
- for (rn = bgp_node_get (table, p); rn; rn = bgp_route_next_until (rn, top))
- if (rn->p.prefixlen > p->prefixlen)
- {
- match = 0;
- for (ri = rn->info; ri; ri = ri->next)
- {
- if (BGP_INFO_HOLDDOWN (ri))
- continue;
- if (del && ri == del)
- continue;
- if (! rinew && first)
- {
- nexthop = ri->attr->nexthop;
- med = ri->attr->med;
- first = 0;
- }
- #ifdef AGGREGATE_NEXTHOP_CHECK
- if (! IPV4_ADDR_SAME (&ri->attr->nexthop, &nexthop)
- || ri->attr->med != med)
- {
- if (aspath)
- aspath_free (aspath);
- if (community)
- community_free (community);
- bgp_unlock_node (rn);
- bgp_unlock_node (top);
- return;
- }
- #endif /* AGGREGATE_NEXTHOP_CHECK */
- if (ri->sub_type != BGP_ROUTE_AGGREGATE)
- {
- if (aggregate->summary_only)
- {
- ri->suppress++;
- SET_FLAG (ri->flags, BGP_INFO_ATTR_CHANGED);
- match++;
- }
- aggregate->count++;
- if (aggregate->as_set)
- {
- if (origin < ri->attr->origin)
- origin = ri->attr->origin;
- if (aspath)
- {
- asmerge = aspath_aggregate (aspath, ri->attr->aspath);
- aspath_free (aspath);
- aspath = asmerge;
- }
- else
- aspath = aspath_dup (ri->attr->aspath);
- if (ri->attr->community)
- {
- if (community)
- {
- commerge = community_merge (community,
- ri->attr->community);
- community = community_uniq_sort (commerge);
- community_free (commerge);
- }
- else
- community = community_dup (ri->attr->community);
- }
- }
- }
- }
- if (match)
- bgp_process (bgp, rn, afi, safi);
- }
- bgp_unlock_node (top);
- if (rinew)
- {
- aggregate->count++;
-
- if (aggregate->summary_only)
- rinew->suppress++;
- if (aggregate->as_set)
- {
- if (origin < rinew->attr->origin)
- origin = rinew->attr->origin;
- if (aspath)
- {
- asmerge = aspath_aggregate (aspath, rinew->attr->aspath);
- aspath_free (aspath);
- aspath = asmerge;
- }
- else
- aspath = aspath_dup (rinew->attr->aspath);
- if (rinew->attr->community)
- {
- if (community)
- {
- commerge = community_merge (community,
- rinew->attr->community);
- community = community_uniq_sort (commerge);
- community_free (commerge);
- }
- else
- community = community_dup (rinew->attr->community);
- }
- }
- }
- if (aggregate->count > 0)
- {
- rn = bgp_node_get (table, p);
- new = bgp_info_new ();
- new->type = ZEBRA_ROUTE_BGP;
- new->sub_type = BGP_ROUTE_AGGREGATE;
- new->peer = bgp->peer_self;
- SET_FLAG (new->flags, BGP_INFO_VALID);
- new->attr = bgp_attr_aggregate_intern (bgp, origin, aspath, community, aggregate->as_set);
- new->uptime = time (NULL);
- bgp_info_add (rn, new);
- bgp_process (bgp, rn, afi, safi);
- }
- else
- {
- if (aspath)
- aspath_free (aspath);
- if (community)
- community_free (community);
- }
- }
- void bgp_aggregate_delete (struct bgp *, struct prefix *, afi_t, safi_t,
- struct bgp_aggregate *);
- void
- bgp_aggregate_increment (struct bgp *bgp, struct prefix *p,
- struct bgp_info *ri, afi_t afi, safi_t safi)
- {
- struct bgp_node *child;
- struct bgp_node *rn;
- struct bgp_aggregate *aggregate;
- /* MPLS-VPN aggregation is not yet supported. */
- if (safi == SAFI_MPLS_VPN)
- return;
- if (p->prefixlen == 0)
- return;
- if (BGP_INFO_HOLDDOWN (ri))
- return;
- child = bgp_node_get (bgp->aggregate[afi][safi], p);
- /* Aggregate address configuration check. */
- for (rn = child; rn; rn = rn->parent)
- if ((aggregate = rn->info) != NULL && rn->p.prefixlen < p->prefixlen)
- {
- bgp_aggregate_delete (bgp, &rn->p, afi, safi, aggregate);
- bgp_aggregate_route (bgp, &rn->p, ri, afi, safi, NULL, aggregate);
- }
- bgp_unlock_node (child);
- }
- void
- bgp_aggregate_decrement (struct bgp *bgp, struct prefix *p,
- struct bgp_info *del, afi_t afi, safi_t safi)
- {
- struct bgp_node *child;
- struct bgp_node *rn;
- struct bgp_aggregate *aggregate;
- /* MPLS-VPN aggregation is not yet supported. */
- if (safi == SAFI_MPLS_VPN)
- return;
- if (p->prefixlen == 0)
- return;
- child = bgp_node_get (bgp->aggregate[afi][safi], p);
- /* Aggregate address configuration check. */
- for (rn = child; rn; rn = rn->parent)
- if ((aggregate = rn->info) != NULL && rn->p.prefixlen < p->prefixlen)
- {
- bgp_aggregate_delete (bgp, &rn->p, afi, safi, aggregate);
- bgp_aggregate_route (bgp, &rn->p, NULL, afi, safi, del, aggregate);
- }
- bgp_unlock_node (child);
- }
- void
- bgp_aggregate_add (struct bgp *bgp, struct prefix *p, afi_t afi, safi_t safi,
- struct bgp_aggregate *aggregate)
- {
- struct bgp_table *table;
- struct bgp_node *top;
- struct bgp_node *rn;
- struct bgp_info *new;
- struct bgp_info *ri;
- unsigned long match;
- u_char origin = BGP_ORIGIN_IGP;
- struct aspath *aspath = NULL;
- struct aspath *asmerge = NULL;
- struct community *community = NULL;
- struct community *commerge = NULL;
- table = bgp->rib[afi][safi];
- /* Sanity check. */
- if (afi == AFI_IP && p->prefixlen == IPV4_MAX_BITLEN)
- return;
- if (afi == AFI_IP6 && p->prefixlen == IPV6_MAX_BITLEN)
- return;
-
- /* If routes exists below this node, generate aggregate routes. */
- top = bgp_node_get (table, p);
- for (rn = bgp_node_get (table, p); rn; rn = bgp_route_next_until (rn, top))
- if (rn->p.prefixlen > p->prefixlen)
- {
- match = 0;
- for (ri = rn->info; ri; ri = ri->next)
- {
- if (BGP_INFO_HOLDDOWN (ri))
- continue;
- if (ri->sub_type != BGP_ROUTE_AGGREGATE)
- {
- /* summary-only aggregate route suppress aggregated
- route announcement. */
- if (aggregate->summary_only)
- {
- ri->suppress++;