/
controller_route_walker.cc
292 lines (255 loc) · 11 KB
/
controller_route_walker.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
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
/*
* Copyright (c) 2014 Juniper Networks, Inc. All rights reserved.
*/
#include <boost/shared_ptr.hpp>
#include <sandesh/sandesh.h>
#include <sandesh/sandesh_types.h>
#include <sandesh/sandesh_trace.h>
#include <cmn/agent_cmn.h>
#include <oper/route_common.h>
#include <oper/agent_route_walker.h>
#include <oper/peer.h>
#include <oper/vrf.h>
#include <oper/mirror_table.h>
#include <oper/agent_sandesh.h>
#include "controller/controller_route_walker.h"
#include "controller/controller_init.h"
#include "controller/controller_types.h"
#include "controller/controller_vrf_export.h"
#include "controller/controller_export.h"
ControllerRouteWalker::ControllerRouteWalker(Agent *agent, Peer *peer) :
AgentRouteWalker(agent, AgentRouteWalker::ALL), peer_(peer),
associate_(false), type_(NOTIFYALL) {
}
// Takes action based on context of walk. These walks are not parallel.
// At a time peer can be only in one state.
bool ControllerRouteWalker::VrfWalkNotify(DBTablePartBase *partition,
DBEntryBase *entry) {
VrfEntry *vrf = static_cast<VrfEntry *>(entry);
// Notification from deleted VRF should have taken care of all operations
// w.r.t. peer, see VrfExport::Notify
// Exception is DelPeer walk. Reason being that this walk will start when
// peer goes down in agent xmpp channel. When it happens bgp peer in channel
// is reset. Any add/delete notification on said VRF checks if xmpp channel
// is active which internally checks for bgp peer. In current case it will
// be NULL and will in-turn ignore notification for delete. State will
// not be deleted for that peer in vrf. To delete state, delpeer walk will
// have to traverse deleted VRF as well.
if (vrf->IsDeleted() && (type_ != DELPEER))
return true;
switch (type_) {
case NOTIFYALL:
return VrfNotifyAll(partition, entry);
case NOTIFYMULTICAST:
return VrfNotifyMulticast(partition, entry);
case DELPEER:
return VrfDelPeer(partition, entry);
case STALE:
return VrfNotifyStale(partition, entry);
default:
return false;
}
return false;
}
/*
* Notification for vrf entry - Creates states (VRF and route) and
* send subscription to control node
* This will be called for active bgp peer only.
*/
bool ControllerRouteWalker::VrfNotifyAll(DBTablePartBase *partition,
DBEntryBase *entry) {
VrfEntry *vrf = static_cast<VrfEntry *>(entry);
if (peer_->GetType() == Peer::BGP_PEER) {
BgpPeer *bgp_peer = static_cast<BgpPeer *>(peer_);
DBTableBase::ListenerId id = bgp_peer->GetVrfExportListenerId();
VrfExport::State *state =
static_cast<VrfExport::State *>(vrf->GetState(partition->parent(),
id));
if (state) {
/* state for __default__ instance will not be created if the
* xmpp channel is up the first time as export code registers to
* vrf-table after entry for __default__ instance is created */
state->force_chg_ = true;
}
//Pass this object pointer so that VrfExport::Notify can start the route
//walk if required on this VRF. Also it adds state if none is found.
VrfExport::Notify(agent(), bgp_peer->GetBgpXmppPeer(),
partition, entry);
CONTROLLER_TRACE(Walker, "Vrf Notify all", vrf->GetName(),
bgp_peer->GetName());
return true;
}
return false;
}
/*
* Delete peer notifications for VRF.
*/
bool ControllerRouteWalker::VrfDelPeer(DBTablePartBase *partition,
DBEntryBase *entry) {
VrfEntry *vrf = static_cast<VrfEntry *>(entry);
if (peer_->GetType() == Peer::BGP_PEER) {
// Register Callback for deletion of VRF state on completion of route
// walks
RouteWalkDoneForVrfCallback(boost::bind(
&ControllerRouteWalker::RouteWalkDoneForVrf,
this, _1));
StartRouteWalk(vrf);
CONTROLLER_TRACE(Walker, "Vrf DelPeer", vrf->GetName(),
peer_->GetName());
return true;
}
return false;
}
bool ControllerRouteWalker::VrfNotifyMulticast(DBTablePartBase *partition,
DBEntryBase *entry) {
VrfEntry *vrf = static_cast<VrfEntry *>(entry);
CONTROLLER_TRACE(Walker, "Vrf Multicast", vrf->GetName(), peer_->GetName());
return VrfNotifyInternal(partition, entry);
}
bool ControllerRouteWalker::VrfNotifyStale(DBTablePartBase *partition,
DBEntryBase *entry) {
VrfEntry *vrf = static_cast<VrfEntry *>(entry);
CONTROLLER_TRACE(Walker, "Vrf Stale", vrf->GetName(), peer_->GetName());
return VrfNotifyInternal(partition, entry);
}
//Common routeine if basic vrf and peer check is required for the walk
bool ControllerRouteWalker::VrfNotifyInternal(DBTablePartBase *partition,
DBEntryBase *entry) {
VrfEntry *vrf = static_cast<VrfEntry *>(entry);
if (peer_->GetType() == Peer::BGP_PEER) {
BgpPeer *bgp_peer = static_cast<BgpPeer *>(peer_);
DBTableBase::ListenerId id = bgp_peer->GetVrfExportListenerId();
VrfExport::State *state =
static_cast<VrfExport::State *>(vrf->GetState(partition->parent(),
id));
//TODO check if state is not added for default vrf
if (state && (vrf->GetName().compare(agent()->fabric_vrf_name()) != 0)) {
StartRouteWalk(vrf);
}
return true;
}
return false;
}
// Takes action based on context of walk. These walks are not parallel.
// At a time peer can be only in one state.
bool ControllerRouteWalker::RouteWalkNotify(DBTablePartBase *partition,
DBEntryBase *entry) {
switch (type_) {
case NOTIFYALL:
return RouteNotifyAll(partition, entry);
case NOTIFYMULTICAST:
return RouteNotifyMulticast(partition, entry);
case DELPEER:
return RouteDelPeer(partition, entry);
case STALE:
return RouteStaleMarker(partition, entry);
default:
return false;
}
return false;
}
bool ControllerRouteWalker::RouteNotifyInternal(DBTablePartBase *partition,
DBEntryBase *entry) {
AgentRoute *route = static_cast<AgentRoute *>(entry);
if ((type_ == NOTIFYMULTICAST) && !route->is_multicast())
return true;
BgpPeer *bgp_peer = static_cast<BgpPeer *>(peer_);
Agent::RouteTableType table_type = route->GetTableType();
//Get the route state
RouteExport::State *route_state = static_cast<RouteExport::State *>
(bgp_peer->GetRouteExportState(partition, entry));
if (route_state) {
// Forcibly send the notification to peer.
route_state->force_chg_ = true;
}
VrfEntry *vrf = route->vrf();
DBTablePartBase *vrf_partition = agent()->vrf_table()->
GetTablePartition(vrf);
VrfExport::State *vs = static_cast<VrfExport::State *>
(bgp_peer->GetVrfExportState(vrf_partition, vrf));
vs->rt_export_[table_type]->
Notify(agent(), bgp_peer->GetBgpXmppPeer(), associate_, table_type,
partition, entry);
return true;
}
bool ControllerRouteWalker::RouteNotifyAll(DBTablePartBase *partition,
DBEntryBase *entry) {
AgentRoute *route = static_cast<AgentRoute *>(entry);
CONTROLLER_TRACE(Walker, "Route NotifyAll", route->ToString(),
peer_->GetName());
return RouteNotifyInternal(partition, entry);
}
bool ControllerRouteWalker::RouteNotifyMulticast(DBTablePartBase *partition,
DBEntryBase *entry) {
AgentRoute *route = static_cast<AgentRoute *>(entry);
CONTROLLER_TRACE(Walker, "Route Multicast Notify", route->ToString(),
peer_->GetName());
return RouteNotifyInternal(partition, entry);
}
// Deletes the peer and corresponding state in route
bool ControllerRouteWalker::RouteDelPeer(DBTablePartBase *partition,
DBEntryBase *entry) {
AgentRoute *route = static_cast<AgentRoute *>(entry);
BgpPeer *bgp_peer = static_cast<BgpPeer *>(peer_);
if (!route)
return true;
CONTROLLER_TRACE(Walker, "Route Delpeer", route->ToString(),
peer_->GetName());
VrfEntry *vrf = route->vrf();
DBTablePartBase *vrf_partition = agent()->vrf_table()->
GetTablePartition(vrf);
VrfExport::State *vrf_state = static_cast<VrfExport::State *>
(bgp_peer->GetVrfExportState(vrf_partition, vrf));
RouteExport::State *state = static_cast<RouteExport::State *>
(bgp_peer->GetRouteExportState(partition, entry));
if (vrf_state && state && vrf_state->rt_export_[route->GetTableType()]) {
route->ClearState(partition->parent(), vrf_state->rt_export_[route->
GetTableType()]->GetListenerId());
delete state;
CONTROLLER_TRACE(Walker, "DelPeer route walk, delete state",
route->ToString(), peer_->GetName());
}
AgentRouteKey *key = (static_cast<AgentRouteKey *>(route->
GetDBRequestKey().get()))->Clone();
key->set_peer(peer_);
route->DeletePathUsingKeyData(key, NULL, true);
delete key;
return true;
}
bool ControllerRouteWalker::RouteStaleMarker(DBTablePartBase *partition,
DBEntryBase *entry) {
AgentRoute *route = static_cast<AgentRoute *>(entry);
if (route) {
route->vrf()->GetRouteTable(route->GetTableType())->
StalePathFromPeer(partition, route, peer_);
}
CONTROLLER_TRACE(Walker, "Route Stale", route->ToString(),
peer_->GetName());
return true;
}
// Called when for a VRF all route table walks are complete.
// Deletes the VRF state of that peer.
void ControllerRouteWalker::RouteWalkDoneForVrf(VrfEntry *vrf) {
// Currently used only for delete peer handling
// Deletes the state and release the listener id
if (type_ != DELPEER)
return;
CONTROLLER_TRACE(Walker, "Route Walk done", vrf->GetName(),
peer_->GetName());
BgpPeer *bgp_peer = static_cast<BgpPeer *>(peer_);
DBEntryBase *entry = static_cast<DBEntryBase *>(vrf);
DBTablePartBase *partition = agent()->vrf_table()->GetTablePartition(vrf);
bgp_peer->DeleteVrfState(partition, entry);
}
// walk_done_cb - Called back when all walk i.e. VRF and route are done.
void ControllerRouteWalker::Start(Type type, bool associate,
AgentRouteWalker::WalkDone walk_done_cb) {
associate_ = associate;
type_ = type;
WalkDoneCallback(walk_done_cb);
StartVrfWalk();
}
void ControllerRouteWalker::Cancel() {
CONTROLLER_TRACE(Walker, "Cancel Vrf Walk", "", peer_->GetName());
CancelVrfWalk();
}