OpenSDN source code
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
rtarget_group_mgr.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3  */
5 
6 #include <boost/foreach.hpp>
7 
8 #include <utility>
9 
10 #include "base/map_util.h"
11 #include "base/set_util.h"
12 #include "base/task_annotations.h"
13 #include "base/task_trigger.h"
14 #include "bgp/bgp_config.h"
15 #include "bgp/bgp_peer.h"
16 #include "bgp/bgp_ribout.h"
17 #include "bgp/bgp_server.h"
18 #include "bgp/bgp_table.h"
21 
22 using std::pair;
23 
25  BgpRoute *rt, RTargetList::const_iterator it) {
26  pair<RTargetList::iterator, bool> result;
27  result = list_.insert(*it);
28  assert(result.second);
29  RtGroup *rtgroup = mgr->LocateRtGroup(*it);
30  rtgroup->AddDepRoute(part_id, rt);
31 }
32 
34  BgpRoute *rt, RTargetList::const_iterator it) {
35  RtGroup *rtgroup = mgr->GetRtGroup(*it);
36  rtgroup->RemoveDepRoute(part_id, rt);
37  mgr->RemoveRtGroup(*it);
38  list_.erase(it);
39 }
40 
42  RTargetRoute *rt, RtGroup::InterestedPeerList::const_iterator it) {
43  pair<RtGroup::InterestedPeerList::iterator, bool> result;
44  result = list_.insert(*it);
45  assert(result.second);
46  rtgroup->AddInterestedPeer(it->first, rt);
47  mgr->NotifyRtGroupUnlocked(rtgroup->rt());
48 }
49 
51  RTargetRoute *rt, RtGroup::InterestedPeerList::iterator it) {
52  rtgroup->RemoveInterestedPeer(it->first, rt);
53  mgr->NotifyRtGroupUnlocked(rtgroup->rt());
54  list_.erase(it);
55 }
56 
57 RTargetGroupMgr::RTargetGroupMgr(BgpServer *server) : server_(server),
58  rtarget_route_trigger_(new TaskTrigger(
59  boost::bind(&RTargetGroupMgr::ProcessRTargetRouteList, this),
60  TaskScheduler::GetInstance()->GetTaskId("bgp::RTFilter"), 0)),
61  remove_rtgroup_trigger_(new TaskTrigger(
62  boost::bind(&RTargetGroupMgr::ProcessRtGroupList, this),
63  TaskScheduler::GetInstance()->GetTaskId("bgp::RTFilter"), 0)),
64  rtarget_trigger_lists_(DB::PartitionCount()),
65  master_instance_delete_ref_(this, NULL) {
66  for (int i = 0; i < DB::PartitionCount(); i++) {
67  rtarget_dep_triggers_.push_back(boost::shared_ptr<TaskTrigger>(new
69  this, i),
70  TaskScheduler::GetInstance()->GetTaskId("db::DBTable"), i)));
71  }
72 }
73 
76  const RtGroup::InterestedPeerList *future) {
77  CHECK_CONCURRENCY("bgp::RTFilter");
78 
79  RouteTarget rtarget = rt->GetPrefix().rtarget();
80  RtGroup *rtgroup = LocateRtGroup(rtarget);
81  assert(rtgroup);
82 
83  map_synchronize(dbstate->GetMutableList(), future,
84  boost::bind(&RTargetState::AddInterestedPeer, dbstate, this, rtgroup,
85  rt, _1),
86  boost::bind(&RTargetState::DeleteInterestedPeer, dbstate, this, rtgroup,
87  rt, _1));
88 
89  if (dbstate->GetList()->empty()) {
90  rt->ClearState(table, id);
91  delete dbstate;
92  RemoveRtGroup(rtarget);
93  }
94 }
95 
98  CHECK_CONCURRENCY("bgp::RTFilter");
99 
100  RTargetState *dbstate =
101  static_cast<RTargetState *>(rt->GetState(table, id));
102 
103  RtGroup::InterestedPeerList peer_list;
104 
105  if (rt->IsDeleted() || !rt->BestPath() ||
106  !rt->BestPath()->IsFeasible()) {
107  RTargetPeerSync(table, rt, id, dbstate, &peer_list);
108  return;
109  }
110 
111  const BgpPath *best_ebgp_path = NULL;
112  for (Route::PathList::iterator it = rt->GetPathList().begin();
113  it != rt->GetPathList().end(); it++) {
114  BgpPath *path = static_cast<BgpPath *>(it.operator->());
115  if (!path->IsFeasible())
116  break;
117  if (!path->GetPeer() || path->GetPeer()->IsXmppPeer())
118  continue;
119 
120  const BgpPeer *peer = static_cast<const BgpPeer *>(path->GetPeer());
121  if (peer->PeerType() == BgpProto::EBGP) {
122  if (!best_ebgp_path) {
123  best_ebgp_path = path;
124  } else if (!best_ebgp_path->PathSameNeighborAs(*path)) {
125  continue;
126  }
127  }
128 
129  std::pair<RtGroup::InterestedPeerList::iterator, bool> ret =
130  peer_list.insert(std::pair<const BgpPeer *,
132  assert(ret.second);
133  ret.first->second.insert(rt);
134  }
135 
136  RTargetPeerSync(table, rt, id, dbstate, &peer_list);
137 }
138 
140  CHECK_CONCURRENCY("db::DBTable");
141 
142  BOOST_FOREACH(const RouteTarget &rtarget, rtarget_trigger_lists_[part_id]) {
143  RtGroup *rtgroup = GetRtGroup(rtarget);
144  if (!rtgroup)
145  continue;
146  rtgroup->NotifyDepRoutes(part_id);
147  }
148 
149  rtarget_trigger_lists_[part_id].clear();
150  return true;
151 }
152 
154  for (int idx = 0; idx < DB::PartitionCount(); ++idx) {
155  rtarget_trigger_lists_[idx].insert(rtarget);
156  rtarget_dep_triggers_[idx]->Set();
157  }
158 }
159 
161  for (int idx = 0; idx < DB::PartitionCount(); ++idx) {
162  rtarget_dep_triggers_[idx]->set_disable();
163  }
164 }
165 
167  for (int idx = 0; idx < DB::PartitionCount(); ++idx) {
168  rtarget_dep_triggers_[idx]->set_enable();
169  }
170 }
171 
173  for (int idx = 0; idx < DB::PartitionCount(); ++idx) {
174  if (rtarget_trigger_lists_[idx].find(rtarget) !=
175  rtarget_trigger_lists_[idx].end()) {
176  return true;
177  }
178  }
179  return false;
180 }
181 
183  CHECK_CONCURRENCY("bgp::RTFilter");
184 
187  BgpTable *table = master->GetTable(Address::RTARGET);
188 
189  // Get the Listener id
191 
192  for (RTargetRouteTriggerList::iterator it = rtarget_route_list_.begin();
193  it != rtarget_route_list_.end(); it++) {
194  BuildRTargetDistributionGraph(table, *it, id);
195  }
196 
197  rtarget_route_list_.clear();
198  return true;
199 }
200 
202  rtarget_route_trigger_->set_disable();
203 }
204 
206  rtarget_route_trigger_->set_enable();
207 }
208 
210  return rtarget_route_list_.find(rt) != rtarget_route_list_.end();
211 }
212 
214  assert(table_state_.empty());
216  RoutingInstance *master = mgr->GetDefaultRoutingInstance();
217  assert(master);
218 
220 
221  RoutingInstance::RouteTableList const table_list = master->GetTables();
223  RtGroupMgrTableState *ts = NULL;
224  for (RoutingInstance::RouteTableList::const_iterator it =
225  table_list.begin(); it != table_list.end(); ++it) {
226  if (!it->second->IsVpnTable()) continue;
227 
228  BgpTable *vpntable = it->second;
229  id = vpntable->Register(
230  boost::bind(&RTargetGroupMgr::VpnRouteNotify, this, _1, _2),
231  "RTargetGroupMgr");
232  ts = new RtGroupMgrTableState(vpntable, id);
233  table_state_.insert(std::make_pair(vpntable, ts));
234  }
235 
236  BgpTable *rttable = master->GetTable(Address::RTARGET);
237  id = rttable->Register(
238  boost::bind(&RTargetGroupMgr::RTargetRouteNotify, this, _1, _2),
239  "RTargetGroupMgr");
240  ts = new RtGroupMgrTableState(rttable, id);
241  table_state_.insert(std::make_pair(rttable, ts));
242 }
243 
245  if (rtgroup_map_.empty()) remove_rtgroup_trigger_->Set();
246 }
247 
248 void
251  VpnRouteState *dbstate,
252  const VpnRouteState::RTargetList *future) {
253  CHECK_CONCURRENCY("db::DBTable");
254 
255  BgpTable *table = static_cast<BgpTable *>(root->parent());
256  if (!dbstate) {
257  dbstate = new VpnRouteState();
258  rt->SetState(table, id, dbstate);
259  }
260 
261  int part_id = root->index();
262  set_synchronize(dbstate->GetMutableList(), future,
263  boost::bind(
264  &VpnRouteState::AddRouteTarget, dbstate, this, part_id, rt, _1),
265  boost::bind(
266  &VpnRouteState::DeleteRouteTarget, dbstate, this, part_id, rt, _1));
267 
268  if (dbstate->GetList()->empty()) {
269  rt->ClearState(root->parent(), id);
270  delete dbstate;
271  }
272 }
273 
275  RtGroupMgrTableStateList::iterator loc = table_state_.find(table);
276  assert(loc != table_state_.end());
277  RtGroupMgrTableState *ts = loc->second;
279  assert(id != DBTableBase::kInvalidId);
280  return id;
281 }
282 
284  DBEntryBase *entry) {
285  CHECK_CONCURRENCY("db::DBTable");
286 
287  BgpTable *table = static_cast<BgpTable *>(root->parent());
288  BgpRoute *rt = static_cast<BgpRoute *>(entry);
289  // Get the Listener id
291 
292  // Get the dbstate
293  VpnRouteState *dbstate =
294  static_cast<VpnRouteState *>(rt->GetState(table, id));
295 
297 
298  if (entry->IsDeleted() || !rt->BestPath() ||
299  !rt->BestPath()->IsFeasible()) {
300  if (!dbstate)
301  return true;
302  RTargetDepSync(root, rt, id, dbstate, &list);
303  return true;
304  }
305 
306  const BgpPath *path = rt->BestPath();
307  const BgpAttr *attr = path->GetAttr();
308  const ExtCommunity *ext_community = attr->ext_community();
309 
310  if (ext_community) {
311  // Gather all Route Target
312  BOOST_FOREACH(const ExtCommunity::ExtCommunityValue &comm,
313  ext_community->communities()) {
314  if (ExtCommunity::is_route_target(comm)) {
315  list.insert(RouteTarget(comm));
316  }
317  }
318  }
319 
320  RTargetDepSync(root, rt, id, dbstate, &list);
321  return true;
322 }
323 
325  DBEntryBase *entry) {
326  CHECK_CONCURRENCY("db::DBTable");
327 
328  BgpTable *table = static_cast<BgpTable *>(root->parent());
329  RTargetRoute *rt = static_cast<RTargetRoute *>(entry);
330  // Get the Listener id
332 
333  // Get the dbstate
334  RTargetState *dbstate =
335  static_cast<RTargetState *>(rt->GetState(table, id));
336 
337  if (!dbstate) {
338  if (rt->IsDeleted()) return true;
339  dbstate = new RTargetState();
340  rt->SetState(table, id, dbstate);
341  }
342  if (rtarget_route_list_.empty())
343  rtarget_route_trigger_->Set();
344  rtarget_route_list_.insert(rt);
345  return true;
346 }
347 
349  assert(rtgroup_map_.empty());
350 }
351 
352 // Search a RtGroup
354  tbb::mutex::scoped_lock lock(mutex_);
355  RtGroupMap::iterator loc = rtgroup_map_.find(rt);
356  if (loc != rtgroup_map_.end()) {
357  return loc->second;
358  }
359  return NULL;
360 }
361 
362 // Search a RtGroup
364  &community) {
365  RouteTarget rt(community);
366  return GetRtGroup(rt);
367 }
368 
370  tbb::mutex::scoped_lock lock(mutex_);
371  RtGroupMap::iterator loc = rtgroup_map_.find(rt);
372  RtGroup *group = (loc != rtgroup_map_.end()) ? loc->second : NULL;
373  if (group == NULL) {
374  group = new RtGroup(rt);
375  rtgroup_map_.insert(rt, group);
376  }
377  return group;
378 }
379 
381  CHECK_CONCURRENCY("bgp::RTFilter", "bgp::Config", "bgp::ConfigHelper");
382 
384  if (!rt.IsNull())
385  return;
386 
387  for (RtGroupMgrTableStateList::iterator it = table_state_.begin();
388  it != table_state_.end(); ++it) {
389  BgpTable *table = it->first;
390  if (!table->IsVpnTable())
391  continue;
392  table->NotifyAllEntries();
393  }
394 }
395 
397  CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
398  tbb::mutex::scoped_lock lock(mutex_);
400 }
401 
403  tbb::mutex::scoped_lock lock(mutex_);
404  RtGroupMap::iterator loc = rtgroup_map_.find(rt);
405  RtGroup *rtgroup = (loc != rtgroup_map_.end()) ? loc->second : NULL;
406  assert(rtgroup);
407 
408  rtgroup_remove_list_.insert(rtgroup);
410 }
411 
413  const ExtCommunity *ext_community,
414  const RibPeerSet &peerset, RibPeerSet *new_peerset) {
415  RtGroupInterestedPeerSet peer_set;
417  if (null_rtgroup) peer_set = null_rtgroup->GetInterestedPeers();
418  BOOST_FOREACH(const ExtCommunity::ExtCommunityValue &comm,
419  ext_community->communities()) {
420  if (ExtCommunity::is_route_target(comm)) {
421  RtGroup *rtgroup = GetRtGroup(comm);
422  if (!rtgroup) continue;
423  peer_set |= rtgroup->GetInterestedPeers();
424  }
425  }
426  RibOut::PeerIterator iter(ribout, peerset);
427  while (iter.HasNext()) {
428  int current_index = iter.index();
429  IPeerUpdate *peer = iter.Next();
430  BgpPeer *tmp = dynamic_cast<BgpPeer *>(peer);
431  assert(tmp);
433  if (!peer_set.test(tmp->GetIndex())) {
434  new_peerset->reset(current_index);
435  }
436  }
437  }
438 }
439 
441  CHECK_CONCURRENCY("bgp::RTFilter");
442 
443  if (rtgroup_map_.empty()) {
446  if (master && master->deleted()) {
447  for (RtGroupMgrTableStateList::iterator it =
448  table_state_.begin(), itnext; it != table_state_.end();
449  it = itnext) {
450  itnext = it;
451  itnext++;
452  RtGroupMgrTableState *ts = it->second;
454  BgpTable *bgptable = it->first;
455  bgptable->Unregister(id);
456  table_state_.erase(it);
457  delete ts;
458  }
460  }
461  }
462 }
463 
465  CHECK_CONCURRENCY("bgp::RTFilter");
466  BOOST_FOREACH(RtGroup *rtgroup, rtgroup_remove_list_) {
467  if (!rtgroup->MayDelete())
468  continue;
469  RouteTarget rt = rtgroup->rt();
470  rtgroup_map_.erase(rt);
471  }
472  rtgroup_remove_list_.clear();
473 
474  if (rtgroup_map_.empty()) UnregisterTables();
475 
476  return true;
477 }
478 
480  remove_rtgroup_trigger_->set_disable();
481 }
482 
484  remove_rtgroup_trigger_->set_enable();
485 }
486 
488  return rtgroup_remove_list_.find(rtgroup) != rtgroup_remove_list_.end();
489 }
490 
493  : id_(id), table_delete_ref_(this, table->deleter()) {
494  assert(table->deleter() != NULL);
495 }
496 
498 }
499 
501 }
RtGroupMgrTableStateList table_state_
std::map< const BgpPeer *, RTargetRouteList > InterestedPeerList
Definition: rtarget_group.h:68
std::set< RTargetRoute * > RTargetRouteList
Definition: rtarget_group.h:67
int index() const
Definition: bgp_ribout.h:276
bool IsRouteTargetOnList(const RouteTarget &rtarget) const
boost::array< uint8_t, 8 > ExtCommunityValue
Definition: community.h:152
void RemoveDepRoute(int part_id, BgpRoute *rt)
BgpTable * GetTable(Address::Family fmly)
void DisableRTargetRouteProcessing()
bool IsNull() const
RTargetList list_
const BgpPath * BestPath() const
Definition: bgp_route.cc:46
const RtGroup::InterestedPeerList * GetList() const
The TaskScheduler keeps track of what tasks are currently schedulable. When a task is enqueued it is ...
Definition: task.h:178
void NotifyRtGroup(const RouteTarget &rt)
void AddInterestedPeer(RTargetGroupMgr *mgr, RtGroup *rtgroup, RTargetRoute *rt, RtGroup::InterestedPeerList::const_iterator it)
DBState * GetState(DBTableBase *tbl_base, ListenerId listener) const
Definition: db_entry.cc:37
bool test(size_t pos) const
Definition: bitset.cc:146
virtual bool IsXmppPeer() const =0
bool set_synchronize(const SetType *set1, const SetType *set2, AddFunctor add_fn, DelFunctor del_fn)
Definition: set_util.h:21
RouteTarget rtarget() const
virtual ~RTargetGroupMgr()
void RTargetPeerSync(BgpTable *table, RTargetRoute *rt, DBTableBase::ListenerId id, RTargetState *dbstate, const RtGroup::InterestedPeerList *future)
BgpServer * server()
BitSet & reset(size_t pos)
Definition: bitset.cc:136
virtual bool IsVpnTable() const
Definition: bgp_table.h:110
bool IsDeleted() const
Definition: db_entry.h:49
void SetState(DBTableBase *tbl_base, ListenerId listener, DBState *state)
Definition: db_entry.cc:22
bool ProcessRouteTargetList(int part_id)
int ListenerId
Definition: db_table.h:62
std::vector< RouteTargetTriggerList > rtarget_trigger_lists_
RTargetRouteTriggerList rtarget_route_list_
RoutingInstanceMgr * routing_instance_mgr()
Definition: bgp_server.h:102
DBTableBase * parent()
void AddRouteTargetToLists(const RouteTarget &rtarget)
RoutingInstance * GetDefaultRoutingInstance()
RtGroupRemoveList rtgroup_remove_list_
virtual BgpProto::BgpPeerType PeerType() const
Definition: bgp_peer.h:208
void NotifyAllEntries()
Definition: db_table.cc:596
bool HasNext() const
Definition: bgp_ribout.h:268
const RTargetPrefix & GetPrefix() const
Definition: rtarget_route.h:27
void AddDepRoute(int part_id, BgpRoute *rt)
void Unregister(ListenerId listener)
Definition: db_table.cc:186
const RTargetList * GetList() const
const RtGroupInterestedPeerSet & GetInterestedPeers() const
RouteTableList & GetTables()
ListenerId Register(ChangeCallback callback, const std::string &name="unspecified")
Definition: db_table.cc:181
Definition: db.h:24
void DisableRouteTargetProcessing()
LifetimeRef< RTargetGroupMgr > master_instance_delete_ref_
bool IsFeasible() const
Definition: bgp_path.h:92
static RouteTarget null_rtarget
DBTableBase::ListenerId GetListenerId() const
RtGroup * LocateRtGroup(const RouteTarget &rt)
const ExtCommunityList & communities() const
Definition: community.h:180
static TaskScheduler * GetInstance()
Definition: task.cc:547
void Reset(LifetimeActor *actor)
Definition: lifetime.h:82
void RemoveRtGroup(const RouteTarget &rt)
void EnableRouteTargetProcessing()
void NotifyRtGroupUnlocked(const RouteTarget &rt)
#define CHECK_CONCURRENCY(...)
RtGroupMgrTableState(BgpTable *table, DBTableBase::ListenerId id)
boost::scoped_ptr< TaskTrigger > remove_rtgroup_trigger_
boost::scoped_ptr< TaskTrigger > rtarget_route_trigger_
bool IsRTargetRouteOnList(RTargetRoute *rt) const
IPeer * GetPeer()
Definition: bgp_path.h:76
bool MayDelete() const
void ClearState(DBTableBase *tbl_base, ListenerId listener)
Definition: db_entry.cc:73
LifetimeActor * deleter()
RTargetGroupMgr(BgpServer *server)
std::map< std::string, BgpTable * > RouteTableList
void DeleteRouteTarget(RTargetGroupMgr *mgr, int part_id, BgpRoute *rt, RTargetList::const_iterator it)
RTargetList * GetMutableList()
bool RTargetRouteNotify(DBTablePartBase *root, DBEntryBase *entry)
RtGroup * GetRtGroup(const RouteTarget &rt)
RtGroupMap rtgroup_map_
void BuildRTargetDistributionGraph(BgpTable *table, RTargetRoute *rt, DBTableBase::ListenerId id)
const ExtCommunity * ext_community() const
Definition: bgp_attr.h:915
RtGroup::InterestedPeerList list_
void DeleteInterestedPeer(RTargetGroupMgr *mgr, RtGroup *rtgroup, RTargetRoute *rt, RtGroup::InterestedPeerList::iterator it)
static bool is_route_target(const ExtCommunityValue &val)
Definition: community.h:265
const BgpAttr * GetAttr() const
Definition: bgp_path.h:87
static const int kInvalidId
Definition: db_table.h:64
void NotifyDepRoutes(int part_id)
RtGroup::InterestedPeerList * GetMutableList()
LifetimeActor * deleter()
Definition: bgp_table.cc:1108
void AddInterestedPeer(const BgpPeer *peer, RTargetRoute *rt)
DBTableBase::ListenerId GetListenerId(BgpTable *table)
void EnableRTargetRouteProcessing()
static int PartitionCount()
Definition: db.cc:32
std::vector< boost::shared_ptr< TaskTrigger > > rtarget_dep_triggers_
bool IsFamilyNegotiated(Address::Family family)
Definition: bgp_peer.cc:1174
void AddRouteTarget(RTargetGroupMgr *mgr, int part_id, BgpRoute *rt, RTargetList::const_iterator it)
bool IsRtGroupOnList(RtGroup *rtgroup) const
const RouteTarget & rt()
bool deleted() const
void RTargetDepSync(DBTablePartBase *root, BgpRoute *rt, DBTableBase::ListenerId id, VpnRouteState *dbstate, const VpnRouteState::RTargetList *future)
bool VpnRouteNotify(DBTablePartBase *root, DBEntryBase *entry)
int GetIndex() const
Definition: bgp_peer.h:205
virtual void GetRibOutInterestedPeers(RibOut *ribout, const ExtCommunity *ext_community, const RibPeerSet &peerset, RibPeerSet *new_peerset)
std::set< RouteTarget > RTargetList
void map_synchronize(MapType *map1, const MapType *map2, AddFunctor add_fn, DelFunctor del_fn)
Definition: map_util.h:102
IPeerUpdate * Next()
Definition: bgp_ribout.h:271
bool PathSameNeighborAs(const BgpPath &rhs) const
Definition: bgp_path.cc:159
int index() const
const PathList & GetPathList() const
Definition: route.h:46
void RemoveInterestedPeer(const BgpPeer *peer, RTargetRoute *rt)