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