Line data Source code
1 : /*
2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3 : */
4 :
5 : #include <cmn/agent_cmn.h>
6 : #include <oper/vrf.h>
7 : #include <oper/route_common.h>
8 : #include <oper/peer.h>
9 : #include <oper/agent_route_walker.h>
10 : #include <oper/mirror_table.h>
11 :
12 : #include <controller/controller_route_walker.h>
13 : #include <controller/controller_peer.h>
14 : #include <controller/controller_vrf_export.h>
15 : #include <controller/controller_export.h>
16 : #include <controller/controller_init.h>
17 :
18 484 : Peer::Peer(Type type, const std::string &name, bool export_to_controller) :
19 484 : type_(type), name_(name), export_to_controller_(export_to_controller) {
20 484 : refcount_ = 0;
21 484 : sequence_number_ = 0;
22 484 : }
23 :
24 532 : Peer::~Peer() {
25 532 : }
26 :
27 758 : bool Peer::DeleteOnZeroRefcount() const {
28 758 : return false;
29 : }
30 :
31 55366 : void intrusive_ptr_add_ref(const Peer *p) {
32 55366 : p->refcount_++;
33 : // validate that reference is not taken while delete is in progress
34 55366 : assert(!p->IsDeleted());
35 55366 : }
36 :
37 55366 : void intrusive_ptr_release(const Peer *p) {
38 110732 : if (p->refcount_.fetch_sub(1) == 1 && p->DeleteOnZeroRefcount()) {
39 142 : delete p;
40 : }
41 55366 : }
42 :
43 142 : DynamicPeer::DynamicPeer(Agent *agent, Type type, const std::string &name,
44 142 : bool export_to_controller) :
45 142 : Peer(type, name, export_to_controller) {
46 284 : delete_timeout_timer_ = TimerManager::CreateTimer(
47 142 : *(agent->event_manager())->io_service(),
48 : "Dynamic Peer Delete Timer",
49 : agent->task_scheduler()->\
50 : GetTaskId("db::DBTable"), 0);
51 142 : deleted_ = false;
52 142 : skip_add_change_ = false;
53 142 : }
54 :
55 142 : DynamicPeer::~DynamicPeer() {
56 : // Dynamic Peer should be marked deleted and will free
57 : // automatically once all the references go away
58 142 : assert(deleted_);
59 142 : assert(refcount() == 0);
60 142 : TimerManager::DeleteTimer(delete_timeout_timer_);
61 142 : }
62 :
63 142 : void DynamicPeer::ProcessDelete(DynamicPeer *p) {
64 142 : p->StopRouteExports();
65 :
66 142 : if (p->deleted_.exchange(true)) {
67 0 : return;
68 : }
69 :
70 142 : if (p->refcount() != 0) {
71 : // still pending references are there start delete timeout timer
72 142 : p->delete_timeout_timer_->Start(kDeleteTimeout,
73 : boost::bind(&DynamicPeer::DeleteTimeout,
74 : p));
75 142 : return;
76 : }
77 :
78 : // no pending references delete the peer inline and return
79 0 : delete p;
80 : }
81 :
82 0 : bool DynamicPeer::DeleteTimeout() {
83 0 : assert(0);
84 : return false;
85 : }
86 :
87 142 : bool DynamicPeer::DeleteOnZeroRefcount() const {
88 142 : if (!deleted_) {
89 0 : return false;
90 : }
91 :
92 : // last reference has gone, cancel the timer and delete peer
93 142 : delete_timeout_timer_->Cancel();
94 :
95 142 : return true;
96 : }
97 :
98 1099 : const Ip4Address *Peer::NexthopIp(Agent *agent, const AgentPath *path) const {
99 1099 : return agent->router_ip_ptr();
100 : }
101 :
102 142 : BgpPeer::BgpPeer(AgentXmppChannel *channel, const Ip4Address &server_ip,
103 : const std::string &name, DBTableBase::ListenerId id,
104 142 : Peer::Type bgp_peer_type) :
105 : DynamicPeer(channel->agent(), bgp_peer_type, name, false),
106 284 : channel_(channel), server_ip_(server_ip), id_(id),
107 142 : delete_stale_walker_(NULL), route_walker_cb_(NULL),
108 284 : delete_stale_walker_cb_(NULL) {
109 142 : AllocPeerNotifyWalker();
110 142 : AllocDeleteStaleWalker();
111 142 : AllocDeletePeerWalker();
112 142 : setup_time_ = UTCTimestampUsec();
113 142 : }
114 :
115 284 : BgpPeer::~BgpPeer() {
116 142 : const Agent *agent = route_walker()->agent();
117 : // TODO verify if this unregister can be done in walkdone callback
118 : // for delpeer
119 142 : if ((id_ != -1) && agent->vrf_table()) {
120 142 : agent->vrf_table()->Unregister(id_);
121 : }
122 142 : ReleaseDeleteStaleWalker();
123 142 : ReleaseDeletePeerWalker();
124 142 : ReleasePeerNotifyWalker();
125 284 : }
126 :
127 : // Route notify walker routines
128 286 : void BgpPeer::AllocPeerNotifyWalker() {
129 286 : if (!route_walker()) {
130 286 : Agent *agent = channel_->agent();
131 572 : route_walker_ = new ControllerRouteWalker(server_ip_.to_string(),
132 286 : this);
133 : agent->oper_db()->agent_route_walk_manager()->
134 286 : RegisterWalker(static_cast<AgentRouteWalker *>
135 : (route_walker_.get()));
136 : }
137 286 : }
138 :
139 286 : void BgpPeer::ReleasePeerNotifyWalker() {
140 286 : if (!route_walker()) {
141 0 : return;
142 : }
143 :
144 286 : Agent *agent = Agent::GetInstance();
145 286 : agent->oper_db()->agent_route_walk_manager()->ReleaseWalker(route_walker());
146 286 : route_walker_.reset();
147 : }
148 :
149 0 : void BgpPeer::PeerNotifyRoutes(WalkDoneCb cb) {
150 0 : route_walker_cb_ = cb;
151 0 : route_walker()->Start(ControllerRouteWalker::NOTIFYALL, true,
152 0 : route_walker_cb_);
153 0 : }
154 :
155 144 : void BgpPeer::StopPeerNotifyRoutes() {
156 : //No implementation of stop, to stop a walk release walker. Re-allocate for
157 : //further use.
158 144 : ReleasePeerNotifyWalker();
159 144 : AllocPeerNotifyWalker();
160 144 : }
161 :
162 0 : void BgpPeer::PeerNotifyMulticastRoutes(bool associate) {
163 0 : route_walker()->Start(ControllerRouteWalker::NOTIFYMULTICAST, associate,
164 : NULL);
165 0 : }
166 :
167 : // Delete stale walker routines
168 286 : void BgpPeer::AllocDeleteStaleWalker() {
169 286 : if (!delete_stale_walker()) {
170 286 : Agent *agent = channel_->agent();
171 572 : delete_stale_walker_ = new ControllerRouteWalker(server_ip_.to_string(),
172 286 : this);
173 : agent->oper_db()->agent_route_walk_manager()->
174 286 : RegisterWalker(static_cast<AgentRouteWalker *>
175 : (delete_stale_walker_.get()));
176 : }
177 286 : }
178 :
179 428 : void BgpPeer::ReleaseDeleteStaleWalker() {
180 428 : if (!delete_stale_walker()) {
181 142 : return;
182 : }
183 :
184 286 : Agent *agent = Agent::GetInstance();
185 : agent->oper_db()->agent_route_walk_manager()->
186 286 : ReleaseWalker(delete_stale_walker());
187 286 : delete_stale_walker_.reset();
188 : }
189 :
190 : // Delete stale walker routines
191 142 : void BgpPeer::AllocDeletePeerWalker() {
192 142 : if (!delete_peer_walker()) {
193 142 : Agent *agent = channel_->agent();
194 284 : delete_peer_walker_ = new ControllerRouteWalker(server_ip_.to_string(),
195 142 : this);
196 : agent->oper_db()->agent_route_walk_manager()->
197 142 : RegisterWalker(static_cast<AgentRouteWalker *>
198 : (delete_peer_walker_.get()));
199 : }
200 142 : }
201 :
202 142 : void BgpPeer::ReleaseDeletePeerWalker() {
203 142 : if (!delete_peer_walker()) {
204 0 : return;
205 : }
206 :
207 142 : Agent *agent = Agent::GetInstance();
208 : agent->oper_db()->agent_route_walk_manager()->
209 142 : ReleaseWalker(delete_peer_walker());
210 142 : delete_peer_walker_.reset();
211 : }
212 :
213 142 : void BgpPeer::DelPeerRoutes(WalkDoneCb walk_done_cb,
214 : uint64_t sequence_number) {
215 : //Since peer is getting deleted no need of seperate walk to delete stale or
216 : //non stale paths.
217 142 : ReleaseDeleteStaleWalker();
218 142 : delete_peer_walker_cb_ = walk_done_cb;
219 142 : delete_peer_walker()->set_sequence_number(sequence_number);
220 284 : delete_peer_walker()->Start(ControllerRouteWalker::DELPEER, false,
221 142 : delete_peer_walker_cb_);
222 142 : }
223 :
224 282 : void BgpPeer::DeleteStale() {
225 : //If peer is marked for deletion skip. Deletion should take care of removing
226 : //routes.
227 282 : if (SkipAddChangeRequest())
228 142 : return;
229 :
230 140 : delete_stale_walker()->set_sequence_number(sequence_number());
231 280 : delete_stale_walker()->Start(ControllerRouteWalker::DELSTALE, false,
232 140 : delete_stale_walker_cb_);
233 : }
234 :
235 144 : void BgpPeer::StopDeleteStale() {
236 : //No implementation of stop, to stop a walk release walker. Re-allocate for
237 : //further use.
238 144 : ReleaseDeleteStaleWalker();
239 144 : AllocDeleteStaleWalker();
240 144 : }
241 :
242 1168 : ControllerRouteWalker *BgpPeer::route_walker() const {
243 1168 : return static_cast<ControllerRouteWalker *>(route_walker_.get());
244 : }
245 :
246 1280 : ControllerRouteWalker *BgpPeer::delete_stale_walker() const {
247 1280 : return static_cast<ControllerRouteWalker *>(delete_stale_walker_.get());
248 : }
249 :
250 710 : ControllerRouteWalker *BgpPeer::delete_peer_walker() const {
251 710 : return static_cast<ControllerRouteWalker *>(delete_peer_walker_.get());
252 : }
253 : /*
254 : * Get the VRF state and unregister from all route table using
255 : * rt_export listener id. This will be called for active and non active bgp
256 : * peers. In case of active bgp peers send unsubscribe to control node(request
257 : * came via vrf delete).
258 : */
259 5312 : void BgpPeer::DeleteVrfState(DBTablePartBase *partition,
260 : DBEntryBase *entry) {
261 5312 : VrfEntry *vrf = static_cast<VrfEntry *>(entry);
262 :
263 5312 : DBTableBase::ListenerId id = GetVrfExportListenerId();
264 : VrfExport::State *vrf_state = static_cast<VrfExport::State *>
265 5312 : (GetVrfExportState(partition, entry));
266 :
267 5312 : if (vrf_state == NULL)
268 5144 : return;
269 :
270 1176 : for (uint8_t table_type = (Agent::INVALID + 1);
271 1176 : table_type < Agent::ROUTE_TABLE_MAX; table_type++) {
272 1008 : if (vrf_state->rt_export_[table_type])
273 1008 : vrf_state->rt_export_[table_type]->Unregister();
274 : }
275 :
276 168 : if (vrf_state->exported_ == true) {
277 : // Check if the notification is for active bgp peer or not.
278 : // Send unsubscribe only for active bgp peer.
279 : // If skip_add_change is set for this dynamic peer, then dont export.
280 168 : if (SkipAddChangeRequest() == false) {
281 168 : AgentXmppChannel::ControllerSendSubscribe(GetAgentXmppChannel(),
282 : vrf,
283 : false);
284 : }
285 : }
286 :
287 168 : vrf->ClearState(partition->parent(), id);
288 168 : delete vrf_state;
289 :
290 168 : return;
291 : }
292 :
293 : // For given peer return the dbstate for given VRF and partition
294 6944 : DBState *BgpPeer::GetVrfExportState(DBTablePartBase *partition,
295 : DBEntryBase *entry) {
296 6944 : DBTableBase::ListenerId id = GetVrfExportListenerId();
297 6944 : VrfEntry *vrf = static_cast<VrfEntry *>(entry);
298 6944 : return (static_cast<VrfExport::State *>(vrf->GetState(partition->parent(),
299 6944 : id)));
300 : }
301 :
302 : // For given route return the dbstate for given partiton
303 678 : DBState *BgpPeer::GetRouteExportState(DBTablePartBase *partition,
304 : DBEntryBase *entry) {
305 678 : AgentRoute *route = static_cast<AgentRoute *>(entry);
306 678 : VrfEntry *vrf = route->vrf();
307 :
308 678 : DBTablePartBase *vrf_partition = agent()->vrf_table()->
309 678 : GetTablePartition(vrf);
310 :
311 : VrfExport::State *vs = static_cast<VrfExport::State *>
312 678 : (GetVrfExportState(vrf_partition, vrf));
313 :
314 678 : if (vs == NULL)
315 0 : return NULL;
316 :
317 678 : Agent::RouteTableType table_type = route->GetTableType();
318 678 : RouteExport::State *state = NULL;
319 678 : if (vs->rt_export_[table_type]) {
320 678 : state = static_cast<RouteExport::State *>(route->GetState(partition->
321 : parent(),
322 678 : vs->rt_export_[table_type]->GetListenerId()));
323 : }
324 678 : return state;
325 : }
326 :
327 3439 : Agent *BgpPeer::agent() const {
328 3439 : return channel_->agent();
329 : }
330 :
331 5251 : AgentXmppChannel *BgpPeer::GetAgentXmppChannel() const {
332 5251 : return channel_;
333 : }
334 :
335 0 : uint64_t BgpPeer::ChannelSequenceNumber() const {
336 0 : return GetAgentXmppChannel()->sequence_number();
337 : }
338 :
339 0 : void BgpPeer::set_route_walker_cb(WalkDoneCb cb) {
340 0 : route_walker_cb_ = cb;
341 0 : }
342 :
343 0 : void BgpPeer::set_delete_stale_walker_cb(WalkDoneCb cb) {
344 0 : delete_stale_walker_cb_ = cb;
345 0 : }
346 0 : void BgpPeer::set_delete_peer_walker_cb(WalkDoneCb cb) {
347 0 : delete_peer_walker_cb_ = cb;
348 0 : }
|