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