OpenSDN source code
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
controller_route_walker.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved.
3  */
4 
5 #include <boost/shared_ptr.hpp>
6 
7 #include <sandesh/sandesh_trace.h>
8 
9 #include <cmn/agent_cmn.h>
10 #include <oper/route_common.h>
12 #include <oper/peer.h>
13 #include <oper/vrf.h>
14 #include <oper/mirror_table.h>
15 #include <oper/agent_sandesh.h>
16 
19 #include "controller/controller_types.h"
23 
25  Peer *peer) :
26  AgentRouteWalker(name, dynamic_cast<BgpPeer *>(peer)->agent()),
27  peer_(peer), associate_(false), type_(NOTIFYALL), sequence_number_(0) {
28 }
29 
30 // Takes action based on context of walk. These walks are not parallel.
31 // At a time peer can be only in one state.
33  DBEntryBase *entry) {
34  VrfEntry *vrf = static_cast<VrfEntry *>(entry);
35  // Notification from deleted VRF should have taken care of all operations
36  // w.r.t. peer, see VrfExport::Notify
37  // Exception is DelPeer walk. Reason being that this walk will start when
38  // peer goes down in agent xmpp channel. When it happens bgp peer in channel
39  // is reset. Any add/delete notification on said VRF checks if xmpp channel
40  // is active which internally checks for bgp peer. In current case it will
41  // be NULL and will in-turn ignore notification for delete. State will
42  // not be deleted for that peer in vrf. To delete state, delpeer walk will
43  // have to traverse deleted VRF as well.
44  if (vrf->IsDeleted() && (type_ != DELPEER))
45  return true;
46 
47  switch (type_) {
48  case NOTIFYALL:
49  return VrfNotifyAll(partition, entry);
50  case NOTIFYMULTICAST:
51  return VrfNotifyMulticast(partition, entry);
52  case DELPEER:
53  return VrfDelPeer(partition, entry);
54  case DELSTALE:
55  return VrfDelStale(partition, entry);
56  default:
57  return false;
58  }
59  return false;
60 }
61 
62 /*
63  * Notification for vrf entry - Creates states (VRF and route) and
64  * send subscription to control node
65  * This will be called for active bgp peer only.
66  */
68  DBEntryBase *entry) {
69  VrfEntry *vrf = static_cast<VrfEntry *>(entry);
70  if (peer_->GetType() == Peer::BGP_PEER) {
71  BgpPeer *bgp_peer = static_cast<BgpPeer *>(peer_);
72 
74  VrfExport::State *state =
75  static_cast<VrfExport::State *>(vrf->GetState(partition->parent(),
76  id));
77  if (state) {
78  /* state for __default__ instance will not be created if the
79  * xmpp channel is up the first time as export code registers to
80  * vrf-table after entry for __default__ instance is created */
81  state->force_chg_ = true;
82  }
83 
84  //Pass this object pointer so that VrfExport::Notify can start the route
85  //walk if required on this VRF. Also it adds state if none is found.
87  partition, entry);
88  CONTROLLER_ROUTE_WALKER_TRACE(Walker, "Vrf Notify all", vrf->GetName(),
89  bgp_peer->GetName());
90  return true;
91  }
92  return false;
93 }
94 
95 /*
96  * Delete peer notifications for VRF.
97  */
99  DBEntryBase *entry) {
100  VrfEntry *vrf = static_cast<VrfEntry *>(entry);
101  if (peer_->GetType() == Peer::BGP_PEER) {
102  BgpPeer *bgp_peer = static_cast<BgpPeer *>(peer_);
103  VrfExport::State *state = static_cast<VrfExport::State *>
104  (bgp_peer->GetVrfExportState(partition, vrf));
105  // State can be NULL, when vrf delete has happened before peer goes down
106  // and VRF is not deleted before delpeer walker reaches the entry.
107  // Controller Notify would have deleted state before delpeer was invoked.
108  if (!state)
109  return true;
110  // skip starting walk on route tables if all the the route tables
111  // are already delete, this also safe-gaurds that StartRouteWalk
112  // will not be the first reference on the deleted VRF which will
113  // end up taking reference and setting refcount state on deleted
114  // VRF which can cause Bug - 1495824
115  if (vrf->AllRouteTableDeleted()) return true;
116  // Register Callback for deletion of VRF state on completion of route
117  // walks
119  RouteWalkDoneForVrfCallback(boost::bind(
121  this, _1));
122  }
124  return true;
125  }
126  return false;
127 }
128 
129 /*
130  * Delete stale notifications for VRF.
131  */
133  DBEntryBase *entry) {
134  VrfEntry *vrf = static_cast<VrfEntry *>(entry);
135  if (peer_->GetType() == Peer::BGP_PEER) {
136  // skip starting walk on route tables if all the the route tables
137  // are already delete, this also safe-gaurds that StartRouteWalk
138  // will not be the first reference on the deleted VRF which will
139  // end up taking reference and setting refcount state on deleted
140  // VRF which can cause Bug - 1495824
141  if (vrf->AllRouteTableDeleted()) return true;
142  // Register Callback for deletion of VRF state on completion of route
143  // walks
145  RouteWalkDoneForVrfCallback(boost::bind(
147  this, _1));
148  }
150  return true;
151  }
152  return false;
153 }
154 
156  DBEntryBase *entry) {
157  VrfEntry *vrf = static_cast<VrfEntry *>(entry);
158  CONTROLLER_ROUTE_WALKER_TRACE(Walker, "Vrf Multicast", vrf->GetName(),
159  peer_->GetName());
160  return VrfNotifyInternal(partition, entry);
161 }
162 
163 //Common routeine if basic vrf and peer check is required for the walk
165  DBEntryBase *entry) {
166  VrfEntry *vrf = static_cast<VrfEntry *>(entry);
167  if (peer_->GetType() == Peer::BGP_PEER) {
168  BgpPeer *bgp_peer = static_cast<BgpPeer *>(peer_);
169  if (IgnoreNotify()) {
170  return false;
171  }
172 
174  VrfExport::State *state =
175  static_cast<VrfExport::State *>(vrf->GetState(partition->parent(),
176  id));
177  if (state) {
179 
180  if (Agent::GetInstance()->mulitcast_builder() ==
181  bgp_peer->GetAgentXmppChannel()) {
182  state->mcast_exported_ = associate_;
183  }
184  }
185 
186  return true;
187  }
188  return false;
189 }
190 
191 // Takes action based on context of walk. These walks are not parallel.
192 // At a time peer can be only in one state.
194  DBEntryBase *entry) {
195  switch (type_) {
196  case NOTIFYALL:
197  return RouteNotifyAll(partition, entry);
198  case NOTIFYMULTICAST:
199  return RouteNotifyMulticast(partition, entry);
200  case DELPEER:
201  return RouteDelPeer(partition, entry);
202  case DELSTALE:
203  return RouteDelStale(partition, entry);
204  default:
205  return false;
206  }
207  return false;
208 }
209 
211  DBEntryBase *entry) {
212  AgentRoute *route = static_cast<AgentRoute *>(entry);
213 
214  if ((type_ == NOTIFYMULTICAST) && !route->is_multicast())
215  return true;
216 
217  BgpPeer *bgp_peer = static_cast<BgpPeer *>(peer_);
218  if (IgnoreNotify()) {
219  return false;
220  }
221 
222  Agent::RouteTableType table_type = route->GetTableType();
223 
224  //Get the route state
225  RouteExport::State *route_state = static_cast<RouteExport::State *>
226  (bgp_peer->GetRouteExportState(partition, entry));
227  if (route_state) {
228  // Forcibly send the notification to peer.
229  route_state->force_chg_ = true;
230  }
231 
232  VrfEntry *vrf = route->vrf();
233  DBTablePartBase *vrf_partition = agent()->vrf_table()->
234  GetTablePartition(vrf);
235  VrfExport::State *vs = static_cast<VrfExport::State *>
236  (bgp_peer->GetVrfExportState(vrf_partition, vrf));
237 
238  if (vs) {
239  vs->rt_export_[table_type]->
240  Notify(agent(), bgp_peer->GetAgentXmppChannel(), associate_,
241  table_type, partition, entry);
242  }
243  return true;
244 }
245 
247  DBEntryBase *entry) {
248  AgentRoute *route = static_cast<AgentRoute *>(entry);
249  CONTROLLER_ROUTE_WALKER_TRACE(Walker, "Route NotifyAll", route->ToString(),
250  peer_->GetName());
251  return RouteNotifyInternal(partition, entry);
252 }
253 
255  DBEntryBase *entry) {
256  AgentRoute *route = static_cast<AgentRoute *>(entry);
257  CONTROLLER_ROUTE_WALKER_TRACE(Walker, "Route Multicast Notify", route->ToString(),
258  peer_->GetName());
259  return RouteNotifyInternal(partition, entry);
260 }
261 
263  DBEntryBase *entry) {
264  AgentRoute *route = static_cast<AgentRoute *>(entry);
265  if (!route)
266  return true;
267 
268  //Enqueue path delete.
269  AgentRouteKey *key = (static_cast<AgentRouteKey *>(route->
270  GetDBRequestKey().get()))->Clone();
271  key->set_peer(peer_);
273  req.key.reset(key);
274  req.data.reset(new StalePathData(sequence_number_));
275  AgentRouteTable *table = static_cast<AgentRouteTable *>(route->get_table());
276  table->Process(req);
277  return true;
278 }
279 
280 // Deletes the peer and corresponding state in route
282  DBEntryBase *entry) {
283  AgentRoute *route = static_cast<AgentRoute *>(entry);
284  BgpPeer *bgp_peer = static_cast<BgpPeer *>(peer_);
285 
286  if (!route)
287  return true;
288 
289  CONTROLLER_ROUTE_WALKER_TRACE(Walker, "Route Delpeer", route->ToString(),
290  peer_->GetName());
291 
292  VrfEntry *vrf = route->vrf();
293  DBTablePartBase *vrf_partition = agent()->vrf_table()->
294  GetTablePartition(vrf);
295  VrfExport::State *vrf_state = static_cast<VrfExport::State *>
296  (bgp_peer->GetVrfExportState(vrf_partition, vrf));
297  RouteExport::State *state = static_cast<RouteExport::State *>
298  (bgp_peer->GetRouteExportState(partition, entry));
299  if (vrf_state && state && vrf_state->rt_export_[route->GetTableType()]) {
300  route->ClearState(partition->parent(), vrf_state->rt_export_[route->
301  GetTableType()]->GetListenerId());
302  delete state;
303  CONTROLLER_ROUTE_WALKER_TRACE(Walker, "DelPeer route walk, delete state",
304  route->ToString(), peer_->GetName());
305  }
306 
307  //Enqueue path delete.
308  AgentRouteKey *key = (static_cast<AgentRouteKey *>(route->
309  GetDBRequestKey().get()))->Clone();
310  key->set_peer(peer_);
312  req.key.reset(key);
313  req.data.reset();
314  AgentRouteTable *table = static_cast<AgentRouteTable *>(route->get_table());
315  table->Process(req);
316  return true;
317 }
318 
319 // Called when for a VRF all route table walks are complete.
320 // Deletes the VRF state of that peer.
322  // Currently used only for delete peer handling
323  // Deletes the state and release the listener id
324  if (type_ != DELPEER)
325  return;
326 
327  CONTROLLER_ROUTE_WALKER_TRACE(Walker, "Route Walk done", vrf->GetName(),
328  peer_->GetName());
329  BgpPeer *bgp_peer = static_cast<BgpPeer *>(peer_);
330  DBEntryBase *entry = static_cast<DBEntryBase *>(vrf);
331  DBTablePartBase *partition = agent()->vrf_table()->GetTablePartition(vrf);
332  bgp_peer->DeleteVrfState(partition, entry);
333 }
334 
335 // walk_done_cb - Called back when all walk i.e. VRF and route are done.
337  AgentRouteWalker::WalkDone walk_done_cb) {
338  associate_ = associate;
339  type_ = type;
340  WalkDoneCallback(walk_done_cb);
341 
342  StartVrfWalk();
343 }
344 
346  Type type) {
347  associate_ = associate;
348  type_ = type;
350 }
351 
353  return ((type_ == DELSTALE) || (type_ == DELPEER));
354 }
355 
357  BgpPeer *bgp_peer = static_cast<BgpPeer *>(peer_);
358  return bgp_peer->SkipAddChangeRequest();
359 }
const std::string & GetName() const
Definition: peer.h:86
bool VrfNotifyAll(DBTablePartBase *partition, DBEntryBase *e)
static Agent * GetInstance()
Definition: agent.h:436
Agent * agent() const
void WalkDoneCallback(WalkDone cb)
Definition: vrf.h:86
virtual bool SkipAddChangeRequest() const
Definition: peer.h:131
void StartRouteWalk(VrfEntry *vrf, bool associate, Type type)
DBState * GetState(DBTableBase *tbl_base, ListenerId listener) const
Definition: db_entry.cc:37
DBTableBase * get_table() const
Definition: db_entry.cc:119
Agent supports multiple route tables - Inet-unicast (IPv4/IPv6), Inet-multicast, bridge, EVPN (Type2/Type5). This base class contains common code for all types of route tables.
Definition: agent_route.h:109
bool IsDeleted() const
Definition: db_entry.h:49
bool RouteNotifyInternal(DBTablePartBase *partition, DBEntryBase *e)
int ListenerId
Definition: db_table.h:62
bool is_multicast() const
Definition: agent_route.h:274
std::unique_ptr< DBRequestData > data
Definition: db_table.h:49
DBTableBase * parent()
virtual bool VrfWalkNotify(DBTablePartBase *partition, DBEntryBase *e)
const string & GetName() const
Definition: vrf.h:100
DBState * GetRouteExportState(DBTablePartBase *partition, DBEntryBase *e)
Definition: peer.cc:303
bool RouteNotifyMulticast(DBTablePartBase *partition, DBEntryBase *e)
Base class for all Route entries in agent.
Definition: agent_route.h:224
DBTableBase::ListenerId GetListenerId() const
bool RouteNotifyAll(DBTablePartBase *partition, DBEntryBase *e)
const Type GetType() const
Definition: peer.h:87
virtual Agent::RouteTableType GetTableType() const =0
uint8_t type
Definition: load_balance.h:109
std::unique_ptr< DBRequestKey > key
Definition: db_table.h:48
DBTableBase::ListenerId GetVrfExportListenerId()
Definition: peer.h:171
void StartRouteWalk(VrfEntry *vrf)
AgentXmppChannel * GetAgentXmppChannel() const
Definition: peer.cc:331
void RouteWalkDoneForVrfCallback(RouteWalkDoneCb cb)
DBState * GetVrfExportState(DBTablePartBase *partition, DBEntryBase *e)
Definition: peer.cc:294
ControllerRouteWalker(const std::string &name, Peer *peer)
Definition: peer.h:44
void ClearState(DBTableBase *tbl_base, ListenerId listener)
Definition: db_entry.cc:73
void Start(Type type, bool associate, AgentRouteWalker::WalkDone walk_done_cb)
virtual bool RouteWalkNotify(DBTablePartBase *partition, DBEntryBase *e)
VrfTable * vrf_table() const
Definition: agent.h:485
virtual DBTablePartBase * GetTablePartition(const DBRequestKey *key)
Definition: db_table.cc:436
virtual AgentRouteKey * Clone() const =0
void RouteWalkDoneForVrf(VrfEntry *vrf)
virtual std::string ToString() const =0
bool VrfDelStale(DBTablePartBase *partition, DBEntryBase *e)
bool RouteDelStale(DBTablePartBase *partition, DBEntryBase *e)
VrfEntry * vrf() const
Definition: agent_route.h:275
void Process(DBRequest &req)
Definition: agent_route.cc:186
RouteExport * rt_export_[Agent::ROUTE_TABLE_MAX]
bool VrfNotifyInternal(DBTablePartBase *partition, DBEntryBase *e)
bool VrfNotifyMulticast(DBTablePartBase *partition, DBEntryBase *e)
RouteTableType
Definition: agent.h:415
static void Notify(const Agent *agent, AgentXmppChannel *, DBTablePartBase *partition, DBEntryBase *e)
#define CONTROLLER_ROUTE_WALKER_TRACE(obj,...)
boost::function< void()> WalkDone
bool AllRouteTableDeleted() const
Definition: vrf.cc:268
bool RouteDelPeer(DBTablePartBase *partition, DBEntryBase *e)
void set_peer(const Peer *peer)
Definition: agent_route.h:48
bool VrfDelPeer(DBTablePartBase *partition, DBEntryBase *e)