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 33 : Peer::Peer(Type type, const std::string &name, bool export_to_controller) :
19 33 : type_(type), name_(name), export_to_controller_(export_to_controller) {
20 33 : refcount_ = 0;
21 33 : sequence_number_ = 0;
22 33 : }
23 :
24 45 : Peer::~Peer() {
25 45 : }
26 :
27 71 : bool Peer::DeleteOnZeroRefcount() const {
28 71 : return false;
29 : }
30 :
31 1224 : void intrusive_ptr_add_ref(const Peer *p) {
32 1224 : p->refcount_++;
33 : // validate that reference is not taken while delete is in progress
34 1224 : assert(!p->IsDeleted());
35 1224 : }
36 :
37 1224 : void intrusive_ptr_release(const Peer *p) {
38 2448 : if (p->refcount_.fetch_sub(1) == 1 && p->DeleteOnZeroRefcount()) {
39 2 : delete p;
40 : }
41 1224 : }
42 :
43 2 : DynamicPeer::DynamicPeer(Agent *agent, Type type, const std::string &name,
44 2 : bool export_to_controller) :
45 2 : Peer(type, name, export_to_controller) {
46 4 : delete_timeout_timer_ = TimerManager::CreateTimer(
47 2 : *(agent->event_manager())->io_service(),
48 : "Dynamic Peer Delete Timer",
49 : agent->task_scheduler()->\
50 : GetTaskId("db::DBTable"), 0);
51 2 : deleted_ = false;
52 2 : skip_add_change_ = false;
53 2 : }
54 :
55 2 : DynamicPeer::~DynamicPeer() {
56 : // Dynamic Peer should be marked deleted and will free
57 : // automatically once all the references go away
58 2 : assert(deleted_);
59 2 : assert(refcount() == 0);
60 2 : TimerManager::DeleteTimer(delete_timeout_timer_);
61 2 : }
62 :
63 2 : void DynamicPeer::ProcessDelete(DynamicPeer *p) {
64 2 : p->StopRouteExports();
65 :
66 2 : if (p->deleted_.exchange(true)) {
67 0 : return;
68 : }
69 :
70 2 : if (p->refcount() != 0) {
71 : // still pending references are there start delete timeout timer
72 2 : p->delete_timeout_timer_->Start(kDeleteTimeout,
73 : boost::bind(&DynamicPeer::DeleteTimeout,
74 : p));
75 2 : 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 2 : bool DynamicPeer::DeleteOnZeroRefcount() const {
88 2 : if (!deleted_) {
89 0 : return false;
90 : }
91 :
92 : // last reference has gone, cancel the timer and delete peer
93 2 : delete_timeout_timer_->Cancel();
94 :
95 2 : return true;
96 : }
97 :
98 72 : const Ip4Address *Peer::NexthopIp(Agent *agent, const AgentPath *path) const {
99 72 : return agent->router_ip_ptr();
100 : }
101 :
102 2 : BgpPeer::BgpPeer(AgentXmppChannel *channel, const Ip4Address &server_ip,
103 : const std::string &name, DBTableBase::ListenerId id,
104 2 : Peer::Type bgp_peer_type) :
105 : DynamicPeer(channel->agent(), bgp_peer_type, name, false),
106 4 : channel_(channel), server_ip_(server_ip), id_(id),
107 2 : delete_stale_walker_(NULL), route_walker_cb_(NULL),
108 4 : delete_stale_walker_cb_(NULL) {
109 2 : AllocPeerNotifyWalker();
110 2 : AllocDeleteStaleWalker();
111 2 : AllocDeletePeerWalker();
112 2 : setup_time_ = UTCTimestampUsec();
113 2 : }
114 :
115 4 : BgpPeer::~BgpPeer() {
116 2 : const Agent *agent = route_walker()->agent();
117 : // TODO verify if this unregister can be done in walkdone callback
118 : // for delpeer
119 2 : if ((id_ != -1) && agent->vrf_table()) {
120 2 : agent->vrf_table()->Unregister(id_);
121 : }
122 2 : ReleaseDeleteStaleWalker();
123 2 : ReleaseDeletePeerWalker();
124 2 : ReleasePeerNotifyWalker();
125 4 : }
126 :
127 : // Route notify walker routines
128 4 : void BgpPeer::AllocPeerNotifyWalker() {
129 4 : if (!route_walker()) {
130 4 : Agent *agent = channel_->agent();
131 8 : route_walker_ = new ControllerRouteWalker(server_ip_.to_string(),
132 4 : this);
133 : agent->oper_db()->agent_route_walk_manager()->
134 4 : RegisterWalker(static_cast<AgentRouteWalker *>
135 : (route_walker_.get()));
136 : }
137 4 : }
138 :
139 4 : void BgpPeer::ReleasePeerNotifyWalker() {
140 4 : if (!route_walker()) {
141 0 : return;
142 : }
143 :
144 4 : Agent *agent = Agent::GetInstance();
145 4 : agent->oper_db()->agent_route_walk_manager()->ReleaseWalker(route_walker());
146 4 : 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 2 : void BgpPeer::StopPeerNotifyRoutes() {
156 : //No implementation of stop, to stop a walk release walker. Re-allocate for
157 : //further use.
158 2 : ReleasePeerNotifyWalker();
159 2 : AllocPeerNotifyWalker();
160 2 : }
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 4 : void BgpPeer::AllocDeleteStaleWalker() {
169 4 : if (!delete_stale_walker()) {
170 4 : Agent *agent = channel_->agent();
171 8 : delete_stale_walker_ = new ControllerRouteWalker(server_ip_.to_string(),
172 4 : this);
173 : agent->oper_db()->agent_route_walk_manager()->
174 4 : RegisterWalker(static_cast<AgentRouteWalker *>
175 : (delete_stale_walker_.get()));
176 : }
177 4 : }
178 :
179 6 : void BgpPeer::ReleaseDeleteStaleWalker() {
180 6 : if (!delete_stale_walker()) {
181 2 : return;
182 : }
183 :
184 4 : Agent *agent = Agent::GetInstance();
185 : agent->oper_db()->agent_route_walk_manager()->
186 4 : ReleaseWalker(delete_stale_walker());
187 4 : delete_stale_walker_.reset();
188 : }
189 :
190 : // Delete stale walker routines
191 2 : void BgpPeer::AllocDeletePeerWalker() {
192 2 : if (!delete_peer_walker()) {
193 2 : Agent *agent = channel_->agent();
194 4 : delete_peer_walker_ = new ControllerRouteWalker(server_ip_.to_string(),
195 2 : this);
196 : agent->oper_db()->agent_route_walk_manager()->
197 2 : RegisterWalker(static_cast<AgentRouteWalker *>
198 : (delete_peer_walker_.get()));
199 : }
200 2 : }
201 :
202 2 : void BgpPeer::ReleaseDeletePeerWalker() {
203 2 : if (!delete_peer_walker()) {
204 0 : return;
205 : }
206 :
207 2 : Agent *agent = Agent::GetInstance();
208 : agent->oper_db()->agent_route_walk_manager()->
209 2 : ReleaseWalker(delete_peer_walker());
210 2 : delete_peer_walker_.reset();
211 : }
212 :
213 2 : 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 2 : ReleaseDeleteStaleWalker();
218 2 : delete_peer_walker_cb_ = walk_done_cb;
219 2 : delete_peer_walker()->set_sequence_number(sequence_number);
220 4 : delete_peer_walker()->Start(ControllerRouteWalker::DELPEER, false,
221 2 : delete_peer_walker_cb_);
222 2 : }
223 :
224 3 : void BgpPeer::DeleteStale() {
225 : //If peer is marked for deletion skip. Deletion should take care of removing
226 : //routes.
227 3 : if (SkipAddChangeRequest())
228 2 : return;
229 :
230 1 : delete_stale_walker()->set_sequence_number(sequence_number());
231 2 : delete_stale_walker()->Start(ControllerRouteWalker::DELSTALE, false,
232 1 : delete_stale_walker_cb_);
233 : }
234 :
235 2 : void BgpPeer::StopDeleteStale() {
236 : //No implementation of stop, to stop a walk release walker. Re-allocate for
237 : //further use.
238 2 : ReleaseDeleteStaleWalker();
239 2 : AllocDeleteStaleWalker();
240 2 : }
241 :
242 20 : ControllerRouteWalker *BgpPeer::route_walker() const {
243 20 : return static_cast<ControllerRouteWalker *>(route_walker_.get());
244 : }
245 :
246 16 : ControllerRouteWalker *BgpPeer::delete_stale_walker() const {
247 16 : return static_cast<ControllerRouteWalker *>(delete_stale_walker_.get());
248 : }
249 :
250 10 : ControllerRouteWalker *BgpPeer::delete_peer_walker() const {
251 10 : 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 224 : void BgpPeer::DeleteVrfState(DBTablePartBase *partition,
260 : DBEntryBase *entry) {
261 224 : VrfEntry *vrf = static_cast<VrfEntry *>(entry);
262 :
263 224 : DBTableBase::ListenerId id = GetVrfExportListenerId();
264 : VrfExport::State *vrf_state = static_cast<VrfExport::State *>
265 224 : (GetVrfExportState(partition, entry));
266 :
267 224 : if (vrf_state == NULL)
268 218 : return;
269 :
270 42 : for (uint8_t table_type = (Agent::INVALID + 1);
271 42 : table_type < Agent::ROUTE_TABLE_MAX; table_type++) {
272 36 : if (vrf_state->rt_export_[table_type])
273 36 : vrf_state->rt_export_[table_type]->Unregister();
274 : }
275 :
276 6 : 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 6 : if (SkipAddChangeRequest() == false) {
281 6 : AgentXmppChannel::ControllerSendSubscribe(GetAgentXmppChannel(),
282 : vrf,
283 : false);
284 : }
285 : }
286 :
287 6 : vrf->ClearState(partition->parent(), id);
288 6 : delete vrf_state;
289 :
290 6 : return;
291 : }
292 :
293 : // For given peer return the dbstate for given VRF and partition
294 275 : DBState *BgpPeer::GetVrfExportState(DBTablePartBase *partition,
295 : DBEntryBase *entry) {
296 275 : DBTableBase::ListenerId id = GetVrfExportListenerId();
297 275 : VrfEntry *vrf = static_cast<VrfEntry *>(entry);
298 275 : return (static_cast<VrfExport::State *>(vrf->GetState(partition->parent(),
299 275 : id)));
300 : }
301 :
302 : // For given route return the dbstate for given partiton
303 24 : DBState *BgpPeer::GetRouteExportState(DBTablePartBase *partition,
304 : DBEntryBase *entry) {
305 24 : AgentRoute *route = static_cast<AgentRoute *>(entry);
306 24 : VrfEntry *vrf = route->vrf();
307 :
308 24 : DBTablePartBase *vrf_partition = agent()->vrf_table()->
309 24 : GetTablePartition(vrf);
310 :
311 : VrfExport::State *vs = static_cast<VrfExport::State *>
312 24 : (GetVrfExportState(vrf_partition, vrf));
313 :
314 24 : if (vs == NULL)
315 0 : return NULL;
316 :
317 24 : Agent::RouteTableType table_type = route->GetTableType();
318 24 : RouteExport::State *state = NULL;
319 24 : if (vs->rt_export_[table_type]) {
320 24 : state = static_cast<RouteExport::State *>(route->GetState(partition->
321 : parent(),
322 24 : vs->rt_export_[table_type]->GetListenerId()));
323 : }
324 24 : return state;
325 : }
326 :
327 35 : Agent *BgpPeer::agent() const {
328 35 : return channel_->agent();
329 : }
330 :
331 50 : AgentXmppChannel *BgpPeer::GetAgentXmppChannel() const {
332 50 : 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 : }
|