Line data Source code
1 : /*
2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3 : */
4 :
5 : #include "bgp/routing-instance/peer_manager.h"
6 :
7 : #include "base/task_annotations.h"
8 : #include "base/address_util.h"
9 : #include "bgp/bgp_factory.h"
10 : #include "bgp/bgp_log.h"
11 : #include "bgp/bgp_peer.h"
12 : #include "bgp/bgp_peer_types.h"
13 : #include "bgp/bgp_server.h"
14 : #include "bgp/routing-instance/routing_instance.h"
15 : #include "bgp/routing-instance/routing_instance_log.h"
16 :
17 : struct BgpSandeshContext;
18 :
19 : using std::make_pair;
20 : using std::string;
21 : using std::vector;
22 :
23 : //
24 : // Find or create a BgpPeer for the given BgpNeighborConfig.
25 : // Return NULL if the peer already exists and is being deleted. The BgpPeer
26 : // will eventually get created in this case via PeerResurrect.
27 : //
28 80 : BgpPeer *PeerManager::PeerLocate(BgpServer *server,
29 : const BgpNeighborConfig *config) {
30 80 : BgpPeerKey key(config);
31 :
32 80 : BgpPeerNameMap::iterator loc = peers_by_name_.find(config->name());
33 80 : if (loc != peers_by_name_.end()) {
34 0 : if (loc->second->IsDeleted())
35 0 : return NULL;
36 0 : RemovePeerByKey(loc->second->peer_key(), loc->second);
37 0 : InsertPeerByKey(key, loc->second);
38 0 : return loc->second;
39 : }
40 :
41 : BgpPeer *peer =
42 80 : BgpStaticObjectFactory::Create<BgpPeer>(server, instance(), config);
43 80 : peer->Initialize();
44 80 : InsertPeerByKey(key, peer);
45 80 : InsertPeerByName(config->name(), peer);
46 80 : RoutingInstanceInfo info = instance_->GetDataCollection("Add");
47 80 : info.set_peer(peer->ToString());
48 80 : ROUTING_INSTANCE_COLLECTOR_INFO(info);
49 :
50 80 : BGP_LOG_PEER(Config, peer, SandeshLevel::SYS_INFO, BGP_LOG_FLAG_ALL,
51 : BGP_PEER_DIR_NA, "Created peer");
52 80 : RTINSTANCE_LOG_PEER(Create, instance_, peer,
53 : SandeshLevel::SYS_DEBUG, RTINSTANCE_LOG_FLAG_ALL);
54 80 : return peer;
55 80 : }
56 :
57 : //
58 : // Resurrect the BgpPeer with given name if we have configuration for it.
59 : // Also insert it into the BgpServer's EndpointPeerList - in case it is
60 : // a BGPaaS peer. This needs to happen here since we would not have been
61 : // able to do it from BgpServer::ConfigUpdater::ProcessNeighborConfig since
62 : // old incarnation of the BgpPeer still existed at that point.
63 : //
64 80 : void PeerManager::PeerResurrect(string name) {
65 80 : CHECK_CONCURRENCY("bgp::Config");
66 :
67 80 : if (instance_->deleted())
68 80 : return;
69 :
70 : const BgpConfigManager *config_manager =
71 0 : instance_->manager()->server()->config_manager();
72 : const BgpNeighborConfig *config =
73 0 : config_manager->FindNeighbor(instance_->name(), name);
74 0 : if (!config)
75 0 : return;
76 :
77 0 : BgpPeer *peer = PeerLocate(server(), config);
78 0 : assert(peer);
79 0 : server()->InsertPeer(peer->endpoint(), peer);
80 : }
81 :
82 : //
83 : // Delete the BgpPeer corresponding to the given BgpNeighborConfig.
84 : //
85 0 : BgpPeer *PeerManager::TriggerPeerDeletion(const BgpNeighborConfig *config) {
86 0 : CHECK_CONCURRENCY("bgp::Config");
87 :
88 0 : BgpPeerNameMap::iterator loc = peers_by_name_.find(config->name());
89 0 : if (loc == peers_by_name_.end())
90 0 : return NULL;
91 :
92 0 : BgpPeer *peer = loc->second;
93 0 : peer->ManagedDelete();
94 :
95 0 : RoutingInstanceInfo info = instance_->GetDataCollection("Delete");
96 0 : info.set_peer(peer->ToString());
97 0 : ROUTING_INSTANCE_COLLECTOR_INFO(info);
98 :
99 0 : RTINSTANCE_LOG_PEER(Delete, instance_, peer,
100 : SandeshLevel::SYS_DEBUG, RTINSTANCE_LOG_FLAG_ALL);
101 :
102 : // Configuration is deleted by the config manager (parser)
103 : // Do not hold reference to it any more
104 0 : peer->ClearConfig();
105 0 : return peer;
106 0 : }
107 :
108 : //
109 : // Concurrency: Called from bgp config task
110 : //
111 : // Complete the deletion process of a peer. Remove it from BgpPeerKeyMap and
112 : // BgpPeerNameMap.
113 : //
114 80 : void PeerManager::DestroyIPeer(IPeer *ipeer) {
115 80 : CHECK_CONCURRENCY("bgp::Config");
116 :
117 80 : BgpPeer *peer = static_cast<BgpPeer *>(ipeer);
118 80 : string peer_name = peer->peer_name();
119 80 : BGP_LOG_PEER(Config, peer, SandeshLevel::SYS_INFO, BGP_LOG_FLAG_ALL,
120 : BGP_PEER_DIR_NA, "Destroyed peer");
121 80 : RTINSTANCE_LOG_PEER(Destroy, instance_, peer,
122 : SandeshLevel::SYS_DEBUG, RTINSTANCE_LOG_FLAG_ALL);
123 80 : RemovePeerByKey(peer->peer_key(), peer);
124 80 : RemovePeerByName(peer->peer_name(), peer);
125 80 : delete peer;
126 :
127 80 : PeerResurrect(peer_name);
128 80 : }
129 :
130 : //
131 : // Insert the BgpPeer info the BgpPeerKeyMap.
132 : //
133 80 : void PeerManager::InsertPeerByKey(const BgpPeerKey key, BgpPeer *peer) {
134 80 : peers_by_key_.insert(make_pair(key, peer));
135 80 : }
136 :
137 : //
138 : // Remove the BgpPeer from the BgpPeerKeyMap. There may be more than
139 : // one BgpPeer with the same key, so we need to find the right one.
140 : //
141 80 : void PeerManager::RemovePeerByKey(const BgpPeerKey key, BgpPeer *peer) {
142 80 : for (BgpPeerKeyMap::iterator loc = peers_by_key_.find(key);
143 80 : loc != peers_by_key_.end() && loc->first == key; ++loc) {
144 80 : if (loc->second == peer) {
145 80 : peers_by_key_.erase(loc);
146 80 : return;
147 : }
148 : }
149 0 : assert(false);
150 : }
151 :
152 : //
153 : // Insert the BgpPeer info the BgpPeerNameMap.
154 : //
155 80 : void PeerManager::InsertPeerByName(const string name, BgpPeer *peer) {
156 80 : peers_by_name_.insert(make_pair(name, peer));
157 80 : }
158 :
159 : //
160 : // Remove the BgpPeer from the BgpPeerNameMap.
161 : //
162 80 : void PeerManager::RemovePeerByName(const string name, BgpPeer *peer) {
163 80 : BgpPeerNameMap::iterator loc = peers_by_name_.find(name);
164 80 : assert(loc != peers_by_name_.end() && loc->second == peer);
165 80 : peers_by_name_.erase(loc);
166 80 : }
167 :
168 0 : BgpPeer *PeerManager::PeerFind(string ip_address) const {
169 0 : if (ip_address.empty())
170 0 : return NULL;
171 :
172 0 : boost::system::error_code ec;
173 0 : boost::asio::ip::tcp::endpoint endpoint;
174 0 : endpoint.address(AddressFromString(ip_address, &ec));
175 0 : if (ec)
176 0 : return NULL;
177 :
178 0 : return PeerLookup(endpoint);
179 : }
180 :
181 64 : BgpPeer *PeerManager::PeerLookup(string name) const {
182 64 : BgpPeerNameMap::const_iterator loc = peers_by_name_.find(name);
183 64 : return (loc != peers_by_name_.end() ? loc->second : NULL);
184 : }
185 :
186 0 : size_t PeerManager::GetNeighborCount(string up_or_down) {
187 0 : size_t count = 0;
188 0 : BgpPeerNameMap::iterator iter;
189 :
190 0 : for (iter = peers_by_name_.begin(); iter != peers_by_name_.end(); iter++) {
191 0 : BgpPeer *peer = iter->second;
192 0 : if (boost::iequals(up_or_down, "up") && !peer->IsReady())
193 0 : continue;
194 0 : if (boost::iequals(up_or_down, "down") && peer->IsReady())
195 0 : continue;
196 0 : count += 1;
197 : }
198 :
199 0 : return count;
200 : }
201 :
202 0 : void PeerManager::ClearAllPeers() {
203 0 : BgpPeerNameMap::iterator iter;
204 :
205 0 : for (iter = peers_by_name_.begin(); iter != peers_by_name_.end(); iter++) {
206 0 : BgpPeer *peer = iter->second;
207 0 : peer->Clear(BgpProto::Notification::OtherConfigChange);
208 : }
209 0 : }
210 :
211 0 : void PeerManager::ClearAllInternalPeers() {
212 0 : BgpPeerNameMap::iterator iter;
213 :
214 0 : for (iter = peers_by_name_.begin(); iter != peers_by_name_.end(); iter++) {
215 0 : BgpPeer *peer = iter->second;
216 0 : if (peer->PeerType() == BgpProto::IBGP)
217 0 : peer->Clear(BgpProto::Notification::OtherConfigChange);
218 : }
219 0 : }
220 :
221 : //
222 : // Concurrency: Called from state machine thread
223 : //
224 32 : BgpPeer *PeerManager::PeerLookup(TcpSession::Endpoint remote_endpoint) const {
225 32 : BgpPeer *peer = NULL;
226 32 : BgpPeerKey peer_key;
227 :
228 : // Bail if the instance is undergoing deletion.
229 32 : if (instance_->deleted())
230 0 : return NULL;
231 :
232 32 : peer_key.endpoint.address(remote_endpoint.address());
233 :
234 : // Do a partial match, as we do not know the peer's port yet.
235 32 : BgpPeerKeyMap::const_iterator loc = peers_by_key_.lower_bound(peer_key);
236 32 : while (loc != peers_by_key_.end()) {
237 : // Check if the address does indeed match as we are doing a partial
238 : // match here
239 32 : if (loc->second->peer_key().endpoint.address() !=
240 64 : peer_key.endpoint.address()) {
241 0 : break;
242 : }
243 :
244 : // This peer certainly matches with the IP address. If we do not find
245 : // an exact match with the peer-id, then just use this.
246 32 : peer = loc->second;
247 32 : break;
248 : }
249 :
250 32 : return peer;
251 : }
252 :
253 0 : const BgpPeer *PeerManager::NextPeer(const BgpPeerKey &peer_key) const {
254 : // Do a partial match
255 0 : BgpPeerKeyMap::const_iterator loc = peers_by_key_.upper_bound(peer_key);
256 0 : if (loc != peers_by_key_.end()) {
257 0 : return loc->second;
258 : }
259 :
260 0 : return NULL;
261 : }
262 :
263 0 : const string &PeerManager::name() const {
264 0 : return instance_->name();
265 : }
266 :
267 32 : BgpServer *PeerManager::server() const {
268 32 : return instance_->server();
269 : }
|