📄 bgpd.c
字号:
/* BGP-4, BGP-4+ daemon program Copyright (C) 1996, 97, 98, 99, 2000 Kunihiro IshiguroThis file is part of GNU Zebra.GNU Zebra is free software; you can redistribute it and/or modify itunder the terms of the GNU General Public License as published by theFree Software Foundation; either version 2, or (at your option) anylater version.GNU Zebra is distributed in the hope that it will be useful, butWITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNUGeneral Public License for more details.You should have received a copy of the GNU General Public Licensealong with GNU Zebra; see the file COPYING. If not, write to the FreeSoftware Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA02111-1307, USA. */#include <zebra.h>#include "prefix.h"#include "thread.h"#include "buffer.h"#include "stream.h"#include "command.h"#include "sockunion.h"#include "network.h"#include "memory.h"#include "filter.h"#include "routemap.h"#include "str.h"#include "log.h"#include "plist.h"#include "linklist.h"#include "bgpd/bgpd.h"#include "bgpd/bgp_table.h"#include "bgpd/bgp_aspath.h"#include "bgpd/bgp_route.h"#include "bgpd/bgp_dump.h"#include "bgpd/bgp_debug.h"#include "bgpd/bgp_community.h"#include "bgpd/bgp_attr.h"#include "bgpd/bgp_regex.h"#include "bgpd/bgp_clist.h"#include "bgpd/bgp_fsm.h"#include "bgpd/bgp_packet.h"#include "bgpd/bgp_zebra.h"#include "bgpd/bgp_open.h"#include "bgpd/bgp_filter.h"#include "bgpd/bgp_nexthop.h"#include "bgpd/bgp_damp.h"#include "bgpd/bgp_mplsvpn.h"#include "bgpd/bgp_advertise.h"#include "bgpd/bgp_network.h"#include "bgpd/bgp_vty.h"#ifdef HAVE_SNMP#include "bgpd/bgp_snmp.h"#endif /* HAVE_SNMP *//* BGP process wide configuration. */static struct bgp_master bgp_master;/* BGP process wide configuration pointer to export. */struct bgp_master *bm;/* BGP community-list. */struct community_list_handler *bgp_clist;/* BGP global flag manipulation. */intbgp_option_set (int flag){ switch (flag) { case BGP_OPT_NO_FIB: case BGP_OPT_MULTIPLE_INSTANCE: case BGP_OPT_CONFIG_CISCO: SET_FLAG (bm->options, flag); break; default: return BGP_ERR_INVALID_FLAG; break; } return 0;}intbgp_option_unset (int flag){ switch (flag) { case BGP_OPT_MULTIPLE_INSTANCE: if (listcount (bm->bgp) > 1) return BGP_ERR_MULTIPLE_INSTANCE_USED; /* Fall through. */ case BGP_OPT_NO_FIB: case BGP_OPT_CONFIG_CISCO: UNSET_FLAG (bm->options, flag); break; default: return BGP_ERR_INVALID_FLAG; break; } return 0;}intbgp_option_check (int flag){ return CHECK_FLAG (bm->options, flag);}/* BGP flag manipulation. */intbgp_flag_set (struct bgp *bgp, int flag){ SET_FLAG (bgp->flags, flag); return 0;}intbgp_flag_unset (struct bgp *bgp, int flag){ UNSET_FLAG (bgp->flags, flag); return 0;}intbgp_flag_check (struct bgp *bgp, int flag){ return CHECK_FLAG (bgp->flags, flag);}/* Internal function to set BGP structure configureation flag. */static voidbgp_config_set (struct bgp *bgp, int config){ SET_FLAG (bgp->config, config);}static voidbgp_config_unset (struct bgp *bgp, int config){ UNSET_FLAG (bgp->config, config);}static intbgp_config_check (struct bgp *bgp, int config){ return CHECK_FLAG (bgp->config, config);}/* Set BGP router identifier. */intbgp_router_id_set (struct bgp *bgp, struct in_addr *id){ struct peer *peer; struct listnode *nn; if (bgp_config_check (bgp, BGP_CONFIG_ROUTER_ID) && IPV4_ADDR_SAME (&bgp->router_id, id)) return 0; IPV4_ADDR_COPY (&bgp->router_id, id); bgp_config_set (bgp, BGP_CONFIG_ROUTER_ID); /* Set all peer's local identifier with this value. */ LIST_LOOP (bgp->peer, peer, nn) { IPV4_ADDR_COPY (&peer->local_id, id); if (peer->status == Established) { peer->last_reset = PEER_DOWN_RID_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } } return 0;}/* Unset BGP router identifier. */intbgp_router_id_unset (struct bgp *bgp){ struct peer *peer; struct listnode *nn; if (! bgp_config_check (bgp, BGP_CONFIG_ROUTER_ID)) return 0; bgp->router_id.s_addr = 0; bgp_config_unset (bgp, BGP_CONFIG_ROUTER_ID); /* Clear peer router id configuration. */ LIST_LOOP (bgp->peer, peer, nn) { peer->local_id.s_addr = 0; } /* Set router-id from interface's address. */ bgp_if_update_all (); /* Reset all BGP sessions to use new router-id. */ LIST_LOOP (bgp->peer, peer, nn) { if (peer->status == Established) { peer->last_reset = PEER_DOWN_RID_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } } return 0;}/* BGP's cluster-id control. */intbgp_cluster_id_set (struct bgp *bgp, struct in_addr *cluster_id){ struct peer *peer; struct listnode *nn; if (bgp_config_check (bgp, BGP_CONFIG_CLUSTER_ID) && IPV4_ADDR_SAME (&bgp->cluster_id, cluster_id)) return 0; IPV4_ADDR_COPY (&bgp->cluster_id, cluster_id); bgp_config_set (bgp, BGP_CONFIG_CLUSTER_ID); /* Clear all IBGP peer. */ LIST_LOOP (bgp->peer, peer, nn) { if (peer_sort (peer) != BGP_PEER_IBGP) continue; if (peer->status == Established) { peer->last_reset = PEER_DOWN_CLID_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } } return 0;}intbgp_cluster_id_unset (struct bgp *bgp){ struct peer *peer; struct listnode *nn; if (! bgp_config_check (bgp, BGP_CONFIG_CLUSTER_ID)) return 0; bgp->cluster_id.s_addr = 0; bgp_config_unset (bgp, BGP_CONFIG_CLUSTER_ID); /* Clear all IBGP peer. */ LIST_LOOP (bgp->peer, peer, nn) { if (peer_sort (peer) != BGP_PEER_IBGP) continue; if (peer->status == Established) { peer->last_reset = PEER_DOWN_CLID_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } } return 0;}/* BGP timer configuration. */intbgp_timers_set (struct bgp *bgp, u_int32_t keepalive, u_int32_t holdtime){ bgp->default_keepalive = (keepalive < holdtime / 3 ? keepalive : holdtime / 3); bgp->default_holdtime = holdtime; return 0;}intbgp_timers_unset (struct bgp *bgp){ bgp->default_keepalive = BGP_DEFAULT_KEEPALIVE; bgp->default_holdtime = BGP_DEFAULT_HOLDTIME; return 0;}/* BGP confederation configuration. */intbgp_confederation_id_set (struct bgp *bgp, as_t as){ struct peer *peer; struct listnode *nn; int already_confed; if (as == 0) return BGP_ERR_INVALID_AS; /* Remember - were we doing confederation before? */ already_confed = bgp_config_check (bgp, BGP_CONFIG_CONFEDERATION); bgp->confed_id = as; bgp_config_set (bgp, BGP_CONFIG_CONFEDERATION); /* If we were doing confederation already, this is just an external AS change. Just Reset EBGP sessions, not CONFED sessions. If we were not doing confederation before, reset all EBGP sessions. */ LIST_LOOP (bgp->peer, peer, nn) { /* We're looking for peers who's AS is not local or part of our confederation. */ if (already_confed) { if (peer_sort (peer) == BGP_PEER_EBGP) { peer->local_as = as; if (peer->status == Established) { peer->last_reset = PEER_DOWN_CONFED_ID_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else BGP_EVENT_ADD (peer, BGP_Stop); } } else { /* Not doign confederation before, so reset every non-local session */ if (peer_sort (peer) != BGP_PEER_IBGP) { /* Reset the local_as to be our EBGP one */ if (peer_sort (peer) == BGP_PEER_EBGP) peer->local_as = as; if (peer->status == Established) { peer->last_reset = PEER_DOWN_CONFED_ID_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else BGP_EVENT_ADD (peer, BGP_Stop); } } } return 0;}intbgp_confederation_id_unset (struct bgp *bgp){ struct peer *peer; struct listnode *nn; bgp->confed_id = 0; bgp_config_unset (bgp, BGP_CONFIG_CONFEDERATION); LIST_LOOP (bgp->peer, peer, nn) { /* We're looking for peers who's AS is not local */ if (peer_sort (peer) != BGP_PEER_IBGP) { peer->local_as = bgp->as; if (peer->status == Established) { peer->last_reset = PEER_DOWN_CONFED_ID_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else BGP_EVENT_ADD (peer, BGP_Stop); } } return 0;}/* Is an AS part of the confed or not? */intbgp_confederation_peers_check (struct bgp *bgp, as_t as){ int i; if (! bgp) return 0; for (i = 0; i < bgp->confed_peers_cnt; i++) if (bgp->confed_peers[i] == as) return 1; return 0;}/* Add an AS to the confederation set. */intbgp_confederation_peers_add (struct bgp *bgp, as_t as){ struct peer *peer; struct listnode *nn; if (! bgp) return BGP_ERR_INVALID_BGP; if (bgp->as == as) return BGP_ERR_INVALID_AS; if (bgp_confederation_peers_check (bgp, as)) return -1; if (bgp->confed_peers) bgp->confed_peers = XREALLOC (MTYPE_BGP_CONFED_LIST, bgp->confed_peers, (bgp->confed_peers_cnt + 1) * sizeof (as_t)); else bgp->confed_peers = XMALLOC (MTYPE_BGP_CONFED_LIST, (bgp->confed_peers_cnt + 1) * sizeof (as_t)); bgp->confed_peers[bgp->confed_peers_cnt] = as; bgp->confed_peers_cnt++; if (bgp_config_check (bgp, BGP_CONFIG_CONFEDERATION)) { LIST_LOOP (bgp->peer, peer, nn) { if (peer->as == as) { peer->local_as = bgp->as; if (peer->status == Established) { peer->last_reset = PEER_DOWN_CONFED_PEER_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else BGP_EVENT_ADD (peer, BGP_Stop); } } } return 0;}/* Delete an AS from the confederation set. */intbgp_confederation_peers_remove (struct bgp *bgp, as_t as){ int i; int j; struct peer *peer; struct listnode *nn; if (! bgp) return -1; if (! bgp_confederation_peers_check (bgp, as)) return -1; 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]; bgp->confed_peers_cnt--; if (bgp->confed_peers_cnt == 0) { if (bgp->confed_peers) 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)); /* Now reset any peer who's remote AS has just been removed from the CONFED */ if (bgp_config_check (bgp, BGP_CONFIG_CONFEDERATION)) { LIST_LOOP (bgp->peer, peer, nn) { if (peer->as == as) { peer->local_as = bgp->confed_id; if (peer->status == Established) { peer->last_reset = PEER_DOWN_CONFED_PEER_CHANGE; bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else BGP_EVENT_ADD (peer, BGP_Stop); } } } return 0;}/* Local preference configuration. */intbgp_default_local_preference_set (struct bgp *bgp, u_int32_t local_pref){ if (! bgp) return -1; bgp_config_set (bgp, BGP_CONFIG_DEFAULT_LOCAL_PREF); bgp->default_local_pref = local_pref; return 0;}intbgp_default_local_preference_unset (struct bgp *bgp){ if (! bgp) return -1; bgp_config_unset (bgp, BGP_CONFIG_DEFAULT_LOCAL_PREF); bgp->default_local_pref = BGP_DEFAULT_LOCAL_PREF; return 0;}/* Peer comparison function for sorting. */static intpeer_cmp (struct peer *p1, struct peer *p2){ return sockunion_cmp (&p1->su, &p2->su);}intpeer_af_flag_check (struct peer *peer, afi_t afi, safi_t safi, u_int32_t flag){ return CHECK_FLAG (peer->af_flags[afi][safi], flag);}/* Reset all address family specific configuration. */static void
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -