Line data Source code
1 : /*
2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3 : * Copyright Contributors to the OpenSDN project
4 : */
5 : #include "bgp/routing-instance/rtarget_group_mgr.h"
6 :
7 : #include <boost/foreach.hpp>
8 :
9 : #include <utility>
10 :
11 : #include "base/map_util.h"
12 : #include "base/set_util.h"
13 : #include "base/task_annotations.h"
14 : #include "base/task_trigger.h"
15 : #include "bgp/bgp_config.h"
16 : #include "bgp/bgp_peer.h"
17 : #include "bgp/bgp_ribout.h"
18 : #include "bgp/bgp_server.h"
19 : #include "bgp/bgp_table.h"
20 : #include "bgp/routing-instance/routing_instance.h"
21 : #include "bgp/rtarget/rtarget_route.h"
22 :
23 : using std::pair;
24 :
25 499765 : void VpnRouteState::AddRouteTarget(RTargetGroupMgr *mgr, int part_id,
26 : BgpRoute *rt, RTargetList::const_iterator it) {
27 499765 : pair<RTargetList::iterator, bool> result;
28 499760 : result = list_.insert(*it);
29 499915 : assert(result.second);
30 499915 : RtGroup *rtgroup = mgr->LocateRtGroup(*it);
31 499962 : rtgroup->AddDepRoute(part_id, rt);
32 499945 : }
33 :
34 499670 : void VpnRouteState::DeleteRouteTarget(RTargetGroupMgr *mgr, int part_id,
35 : BgpRoute *rt, RTargetList::const_iterator it) {
36 499670 : RtGroup *rtgroup = mgr->GetRtGroup(*it);
37 499959 : rtgroup->RemoveDepRoute(part_id, rt);
38 499697 : mgr->RemoveRtGroup(*it);
39 499955 : list_.erase(it);
40 499929 : }
41 :
42 27076 : void RTargetState::AddInterestedPeer(RTargetGroupMgr *mgr, RtGroup *rtgroup,
43 : RTargetRoute *rt, RtGroup::InterestedPeerList::const_iterator it) {
44 27076 : pair<RtGroup::InterestedPeerList::iterator, bool> result;
45 27076 : result = list_.insert(*it);
46 27076 : assert(result.second);
47 27076 : rtgroup->AddInterestedPeer(it->first, rt);
48 27076 : mgr->NotifyRtGroupUnlocked(rtgroup->rt());
49 27076 : }
50 :
51 27076 : void RTargetState::DeleteInterestedPeer(RTargetGroupMgr *mgr, RtGroup *rtgroup,
52 : RTargetRoute *rt, RtGroup::InterestedPeerList::iterator it) {
53 27076 : rtgroup->RemoveInterestedPeer(it->first, rt);
54 27076 : mgr->NotifyRtGroupUnlocked(rtgroup->rt());
55 27076 : list_.erase(it);
56 27076 : }
57 :
58 9743 : RTargetGroupMgr::RTargetGroupMgr(BgpServer *server) : server_(server),
59 19486 : rtarget_route_trigger_(new TaskTrigger(
60 : boost::bind(&RTargetGroupMgr::ProcessRTargetRouteList, this),
61 19486 : TaskScheduler::GetInstance()->GetTaskId("bgp::RTFilter"), 0)),
62 19486 : remove_rtgroup_trigger_(new TaskTrigger(
63 : boost::bind(&RTargetGroupMgr::ProcessRtGroupList, this),
64 19486 : TaskScheduler::GetInstance()->GetTaskId("bgp::RTFilter"), 0)),
65 9743 : rtarget_trigger_lists_(DB::PartitionCount()),
66 29229 : master_instance_delete_ref_(this, NULL) {
67 48190 : for (int i = 0; i < DB::PartitionCount(); i++) {
68 115341 : rtarget_dep_triggers_.push_back(boost::shared_ptr<TaskTrigger>(new
69 : TaskTrigger(boost::bind(&RTargetGroupMgr::ProcessRouteTargetList,
70 : this, i),
71 76894 : TaskScheduler::GetInstance()->GetTaskId("db::DBTable"), i)));
72 : }
73 9743 : }
74 :
75 102664 : void RTargetGroupMgr::RTargetPeerSync(BgpTable *table, RTargetRoute *rt,
76 : DBTableBase::ListenerId id, RTargetState *dbstate,
77 : const RtGroup::InterestedPeerList *future) {
78 102664 : CHECK_CONCURRENCY("bgp::RTFilter");
79 :
80 102664 : RouteTarget rtarget = rt->GetPrefix().rtarget();
81 102664 : RtGroup *rtgroup = LocateRtGroup(rtarget);
82 102664 : assert(rtgroup);
83 :
84 102664 : map_synchronize(dbstate->GetMutableList(), future,
85 : boost::bind(&RTargetState::AddInterestedPeer, dbstate, this, rtgroup,
86 : rt, _1),
87 : boost::bind(&RTargetState::DeleteInterestedPeer, dbstate, this, rtgroup,
88 : rt, _1));
89 :
90 102664 : if (dbstate->GetList()->empty()) {
91 64575 : rt->ClearState(table, id);
92 64575 : delete dbstate;
93 64575 : RemoveRtGroup(rtarget);
94 : }
95 102664 : }
96 :
97 102664 : void RTargetGroupMgr::BuildRTargetDistributionGraph(BgpTable *table,
98 : RTargetRoute *rt, DBTableBase::ListenerId id) {
99 102664 : CHECK_CONCURRENCY("bgp::RTFilter");
100 :
101 : RTargetState *dbstate =
102 102664 : static_cast<RTargetState *>(rt->GetState(table, id));
103 :
104 102664 : RtGroup::InterestedPeerList peer_list;
105 :
106 179235 : if (rt->IsDeleted() || !rt->BestPath() ||
107 76571 : !rt->BestPath()->IsFeasible()) {
108 26093 : RTargetPeerSync(table, rt, id, dbstate, &peer_list);
109 26093 : return;
110 : }
111 :
112 76571 : const BgpPath *best_ebgp_path = NULL;
113 222610 : for (Route::PathList::iterator it = rt->GetPathList().begin();
114 445220 : it != rt->GetPathList().end(); it++) {
115 146039 : BgpPath *path = static_cast<BgpPath *>(it.operator->());
116 146039 : if (!path->IsFeasible())
117 0 : break;
118 146039 : if (!path->GetPeer() || path->GetPeer()->IsXmppPeer())
119 106691 : continue;
120 :
121 39416 : const BgpPeer *peer = static_cast<const BgpPeer *>(path->GetPeer());
122 39416 : if (peer->PeerType() == BgpProto::EBGP) {
123 17282 : if (!best_ebgp_path) {
124 17110 : best_ebgp_path = path;
125 172 : } else if (!best_ebgp_path->PathSameNeighborAs(*path)) {
126 68 : continue;
127 : }
128 : }
129 :
130 : std::pair<RtGroup::InterestedPeerList::iterator, bool> ret =
131 39348 : peer_list.insert(std::pair<const BgpPeer *,
132 78696 : RtGroup::RTargetRouteList>(peer, RtGroup::RTargetRouteList()));
133 39348 : assert(ret.second);
134 39348 : ret.first->second.insert(rt);
135 : }
136 :
137 76571 : RTargetPeerSync(table, rt, id, dbstate, &peer_list);
138 102664 : }
139 :
140 164503 : bool RTargetGroupMgr::ProcessRouteTargetList(int part_id) {
141 164503 : CHECK_CONCURRENCY("db::DBTable");
142 :
143 760313 : BOOST_FOREACH(const RouteTarget &rtarget, rtarget_trigger_lists_[part_id]) {
144 297414 : RtGroup *rtgroup = GetRtGroup(rtarget);
145 299555 : if (!rtgroup)
146 28332 : continue;
147 271223 : rtgroup->NotifyDepRoutes(part_id);
148 : }
149 :
150 164592 : rtarget_trigger_lists_[part_id].clear();
151 164617 : return true;
152 : }
153 :
154 186532 : void RTargetGroupMgr::AddRouteTargetToLists(const RouteTarget &rtarget) {
155 915800 : for (int idx = 0; idx < DB::PartitionCount(); ++idx) {
156 729268 : rtarget_trigger_lists_[idx].insert(rtarget);
157 729268 : rtarget_dep_triggers_[idx]->Set();
158 : }
159 186532 : }
160 :
161 8 : void RTargetGroupMgr::DisableRouteTargetProcessing() {
162 40 : for (int idx = 0; idx < DB::PartitionCount(); ++idx) {
163 32 : rtarget_dep_triggers_[idx]->set_disable();
164 : }
165 8 : }
166 :
167 8 : void RTargetGroupMgr::EnableRouteTargetProcessing() {
168 40 : for (int idx = 0; idx < DB::PartitionCount(); ++idx) {
169 32 : rtarget_dep_triggers_[idx]->set_enable();
170 : }
171 8 : }
172 :
173 20 : bool RTargetGroupMgr::IsRouteTargetOnList(const RouteTarget &rtarget) const {
174 56 : for (int idx = 0; idx < DB::PartitionCount(); ++idx) {
175 47 : if (rtarget_trigger_lists_[idx].find(rtarget) !=
176 94 : rtarget_trigger_lists_[idx].end()) {
177 11 : return true;
178 : }
179 : }
180 9 : return false;
181 : }
182 :
183 41594 : bool RTargetGroupMgr::ProcessRTargetRouteList() {
184 41594 : CHECK_CONCURRENCY("bgp::RTFilter");
185 :
186 41594 : RoutingInstanceMgr *mgr = server()->routing_instance_mgr();
187 41594 : RoutingInstance *master = mgr->GetDefaultRoutingInstance();
188 41594 : BgpTable *table = master->GetTable(Address::RTARGET);
189 :
190 : // Get the Listener id
191 41594 : DBTableBase::ListenerId id = GetListenerId(table);
192 :
193 41594 : for (RTargetRouteTriggerList::iterator it = rtarget_route_list_.begin();
194 144258 : it != rtarget_route_list_.end(); it++) {
195 102664 : BuildRTargetDistributionGraph(table, *it, id);
196 : }
197 :
198 41594 : rtarget_route_list_.clear();
199 41594 : return true;
200 : }
201 :
202 8 : void RTargetGroupMgr::DisableRTargetRouteProcessing() {
203 8 : rtarget_route_trigger_->set_disable();
204 8 : }
205 :
206 8 : void RTargetGroupMgr::EnableRTargetRouteProcessing() {
207 8 : rtarget_route_trigger_->set_enable();
208 8 : }
209 :
210 19 : bool RTargetGroupMgr::IsRTargetRouteOnList(RTargetRoute *rt) const {
211 19 : return rtarget_route_list_.find(rt) != rtarget_route_list_.end();
212 : }
213 :
214 6510 : void RTargetGroupMgr::Initialize() {
215 6510 : assert(table_state_.empty());
216 6510 : RoutingInstanceMgr *mgr = server()->routing_instance_mgr();
217 6510 : RoutingInstance *master = mgr->GetDefaultRoutingInstance();
218 6510 : assert(master);
219 :
220 6510 : master_instance_delete_ref_.Reset(master->deleter());
221 :
222 6510 : RoutingInstance::RouteTableList const table_list = master->GetTables();
223 : DBTableBase::ListenerId id;
224 6510 : RtGroupMgrTableState *ts = NULL;
225 6510 : for (RoutingInstance::RouteTableList::const_iterator it =
226 71610 : table_list.begin(); it != table_list.end(); ++it) {
227 58590 : if (!it->second->IsVpnTable()) continue;
228 :
229 32550 : BgpTable *vpntable = it->second;
230 32550 : id = vpntable->Register(
231 : boost::bind(&RTargetGroupMgr::VpnRouteNotify, this, _1, _2),
232 : "RTargetGroupMgr");
233 32550 : ts = new RtGroupMgrTableState(vpntable, id);
234 32550 : table_state_.insert(std::make_pair(vpntable, ts));
235 : }
236 :
237 6510 : BgpTable *rttable = master->GetTable(Address::RTARGET);
238 6510 : id = rttable->Register(
239 : boost::bind(&RTargetGroupMgr::RTargetRouteNotify, this, _1, _2),
240 : "RTargetGroupMgr");
241 6510 : ts = new RtGroupMgrTableState(rttable, id);
242 6510 : table_state_.insert(std::make_pair(rttable, ts));
243 6510 : }
244 :
245 6510 : void RTargetGroupMgr::ManagedDelete() {
246 6510 : if (rtgroup_map_.empty()) remove_rtgroup_trigger_->Set();
247 6510 : }
248 :
249 : void
250 617406 : RTargetGroupMgr::RTargetDepSync(DBTablePartBase *root, BgpRoute *rt,
251 : DBTableBase::ListenerId id,
252 : VpnRouteState *dbstate,
253 : const VpnRouteState::RTargetList *future) {
254 617406 : CHECK_CONCURRENCY("db::DBTable");
255 :
256 617302 : BgpTable *table = static_cast<BgpTable *>(root->parent());
257 617287 : if (!dbstate) {
258 184768 : dbstate = new VpnRouteState();
259 184772 : rt->SetState(table, id, dbstate);
260 : }
261 :
262 617296 : int part_id = root->index();
263 617269 : set_synchronize(dbstate->GetMutableList(), future,
264 : boost::bind(
265 : &VpnRouteState::AddRouteTarget, dbstate, this, part_id, rt, _1),
266 : boost::bind(
267 : &VpnRouteState::DeleteRouteTarget, dbstate, this, part_id, rt, _1));
268 :
269 617359 : if (dbstate->GetList()->empty()) {
270 184786 : rt->ClearState(root->parent(), id);
271 184785 : delete dbstate;
272 : }
273 617349 : }
274 :
275 777687 : DBTableBase::ListenerId RTargetGroupMgr::GetListenerId(BgpTable *table) {
276 777687 : RtGroupMgrTableStateList::iterator loc = table_state_.find(table);
277 777521 : assert(loc != table_state_.end());
278 777494 : RtGroupMgrTableState *ts = loc->second;
279 777487 : DBTableBase::ListenerId id = ts->GetListenerId();
280 777486 : assert(id != DBTableBase::kInvalidId);
281 777486 : return id;
282 : }
283 :
284 617457 : bool RTargetGroupMgr::VpnRouteNotify(DBTablePartBase *root,
285 : DBEntryBase *entry) {
286 617457 : CHECK_CONCURRENCY("db::DBTable");
287 :
288 617367 : BgpTable *table = static_cast<BgpTable *>(root->parent());
289 617359 : BgpRoute *rt = static_cast<BgpRoute *>(entry);
290 : // Get the Listener id
291 617359 : DBTableBase::ListenerId id = GetListenerId(table);
292 :
293 : // Get the dbstate
294 : VpnRouteState *dbstate =
295 617163 : static_cast<VpnRouteState *>(rt->GetState(table, id));
296 :
297 617747 : VpnRouteState::RTargetList list;
298 :
299 1050243 : if (entry->IsDeleted() || !rt->BestPath() ||
300 432653 : !rt->BestPath()->IsFeasible()) {
301 184857 : if (!dbstate)
302 119 : return true;
303 184738 : RTargetDepSync(root, rt, id, dbstate, &list);
304 184766 : return true;
305 : }
306 :
307 432622 : const BgpPath *path = rt->BestPath();
308 432581 : const BgpAttr *attr = path->GetAttr();
309 432565 : const ExtCommunity *ext_community = attr->ext_community();
310 :
311 432545 : if (ext_community) {
312 : // Gather all Route Target
313 7878928 : BOOST_FOREACH(const ExtCommunity::ExtCommunityValue &comm,
314 : ext_community->communities()) {
315 3722011 : if (ExtCommunity::is_route_target(comm)) {
316 3004237 : list.insert(RouteTarget(comm));
317 : }
318 : }
319 : }
320 :
321 432662 : RTargetDepSync(root, rt, id, dbstate, &list);
322 432588 : return true;
323 617473 : }
324 :
325 118759 : bool RTargetGroupMgr::RTargetRouteNotify(DBTablePartBase *root,
326 : DBEntryBase *entry) {
327 118759 : CHECK_CONCURRENCY("db::DBTable");
328 :
329 118759 : BgpTable *table = static_cast<BgpTable *>(root->parent());
330 118759 : RTargetRoute *rt = static_cast<RTargetRoute *>(entry);
331 : // Get the Listener id
332 118759 : DBTableBase::ListenerId id = GetListenerId(table);
333 :
334 : // Get the dbstate
335 : RTargetState *dbstate =
336 118759 : static_cast<RTargetState *>(rt->GetState(table, id));
337 :
338 118759 : if (!dbstate) {
339 78640 : if (rt->IsDeleted()) return true;
340 64575 : dbstate = new RTargetState();
341 64575 : rt->SetState(table, id, dbstate);
342 : }
343 104694 : if (rtarget_route_list_.empty())
344 41594 : rtarget_route_trigger_->Set();
345 104694 : rtarget_route_list_.insert(rt);
346 104694 : return true;
347 : }
348 :
349 18648 : RTargetGroupMgr::~RTargetGroupMgr() {
350 9743 : assert(rtgroup_map_.empty());
351 18648 : }
352 :
353 : // Search a RtGroup
354 6478625 : RtGroup *RTargetGroupMgr::GetRtGroup(const RouteTarget &rt) {
355 6478625 : std::scoped_lock lock(mutex_);
356 6482708 : RtGroupMap::iterator loc = rtgroup_map_.find(rt);
357 6482069 : if (loc != rtgroup_map_.end()) {
358 6129635 : return loc->second;
359 : }
360 352336 : return NULL;
361 6481868 : }
362 :
363 : // Search a RtGroup
364 4430953 : RtGroup *RTargetGroupMgr::GetRtGroup(const ExtCommunity::ExtCommunityValue
365 : &community) {
366 4430953 : RouteTarget rt(community);
367 8863226 : return GetRtGroup(rt);
368 : }
369 :
370 1531015 : RtGroup *RTargetGroupMgr::LocateRtGroup(const RouteTarget &rt) {
371 1531015 : std::scoped_lock lock(mutex_);
372 1531277 : RtGroupMap::iterator loc = rtgroup_map_.find(rt);
373 1531249 : RtGroup *group = (loc != rtgroup_map_.end()) ? loc->second : NULL;
374 1531246 : if (group == NULL) {
375 108909 : group = new RtGroup(rt);
376 108909 : rtgroup_map_.insert(rt, group);
377 : }
378 1531273 : return group;
379 1531246 : }
380 :
381 186532 : void RTargetGroupMgr::NotifyRtGroupUnlocked(const RouteTarget &rt) {
382 186532 : CHECK_CONCURRENCY("bgp::RTFilter", "bgp::Config", "bgp::ConfigHelper");
383 :
384 186532 : AddRouteTargetToLists(rt);
385 186532 : if (!rt.IsNull())
386 186516 : return;
387 :
388 16 : for (RtGroupMgrTableStateList::iterator it = table_state_.begin();
389 112 : it != table_state_.end(); ++it) {
390 96 : BgpTable *table = it->first;
391 96 : if (!table->IsVpnTable())
392 16 : continue;
393 80 : table->NotifyAllEntries();
394 : }
395 : }
396 :
397 132380 : void RTargetGroupMgr::NotifyRtGroup(const RouteTarget &rt) {
398 132380 : CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
399 132380 : std::scoped_lock lock(mutex_);
400 132380 : NotifyRtGroupUnlocked(rt);
401 132380 : }
402 :
403 994439 : void RTargetGroupMgr::RemoveRtGroup(const RouteTarget &rt) {
404 994439 : std::scoped_lock lock(mutex_);
405 994493 : RtGroupMap::iterator loc = rtgroup_map_.find(rt);
406 994468 : RtGroup *rtgroup = (loc != rtgroup_map_.end()) ? loc->second : NULL;
407 994453 : assert(rtgroup);
408 :
409 994453 : rtgroup_remove_list_.insert(rtgroup);
410 994509 : remove_rtgroup_trigger_->Set();
411 994505 : }
412 :
413 321889 : void RTargetGroupMgr::GetRibOutInterestedPeers(RibOut *ribout,
414 : const ExtCommunity *ext_community,
415 : const RibPeerSet &peerset, RibPeerSet *new_peerset) {
416 321889 : RtGroupInterestedPeerSet peer_set;
417 321918 : RtGroup *null_rtgroup = GetRtGroup(RouteTarget::null_rtarget);
418 322196 : if (null_rtgroup) peer_set = null_rtgroup->GetInterestedPeers();
419 6162176 : BOOST_FOREACH(const ExtCommunity::ExtCommunityValue &comm,
420 : ext_community->communities()) {
421 2919870 : if (ExtCommunity::is_route_target(comm)) {
422 2257872 : RtGroup *rtgroup = GetRtGroup(comm);
423 2258203 : if (!rtgroup) continue;
424 2258203 : peer_set |= rtgroup->GetInterestedPeers();
425 : }
426 : }
427 322188 : RibOut::PeerIterator iter(ribout, peerset);
428 648041 : while (iter.HasNext()) {
429 325865 : int current_index = iter.index();
430 325864 : IPeerUpdate *peer = iter.Next();
431 325839 : BgpPeer *tmp = dynamic_cast<BgpPeer *>(peer);
432 325839 : assert(tmp);
433 325839 : if (tmp->IsFamilyNegotiated(Address::RTARGET)) {
434 317567 : if (!peer_set.test(tmp->GetIndex())) {
435 23077 : new_peerset->reset(current_index);
436 : }
437 : }
438 : }
439 322140 : }
440 :
441 10794 : void RTargetGroupMgr::UnregisterTables() {
442 10794 : CHECK_CONCURRENCY("bgp::RTFilter");
443 :
444 10794 : if (rtgroup_map_.empty()) {
445 10794 : RoutingInstanceMgr *mgr = server()->routing_instance_mgr();
446 10794 : RoutingInstance *master = mgr->GetDefaultRoutingInstance();
447 10794 : if (master && master->deleted()) {
448 7963 : for (RtGroupMgrTableStateList::iterator it =
449 54986 : table_state_.begin(), itnext; it != table_state_.end();
450 39060 : it = itnext) {
451 39060 : itnext = it;
452 39060 : itnext++;
453 39060 : RtGroupMgrTableState *ts = it->second;
454 39060 : DBTableBase::ListenerId id = ts->GetListenerId();
455 39060 : BgpTable *bgptable = it->first;
456 39060 : bgptable->Unregister(id);
457 39060 : table_state_.erase(it);
458 39060 : delete ts;
459 : }
460 7963 : master_instance_delete_ref_.Reset(NULL);
461 : }
462 : }
463 10794 : }
464 :
465 140853 : bool RTargetGroupMgr::ProcessRtGroupList() {
466 140853 : CHECK_CONCURRENCY("bgp::RTFilter");
467 789893 : BOOST_FOREACH(RtGroup *rtgroup, rtgroup_remove_list_) {
468 324520 : if (!rtgroup->MayDelete())
469 215611 : continue;
470 108909 : RouteTarget rt = rtgroup->rt();
471 108909 : rtgroup_map_.erase(rt);
472 : }
473 140853 : rtgroup_remove_list_.clear();
474 :
475 140853 : if (rtgroup_map_.empty()) UnregisterTables();
476 :
477 140853 : return true;
478 : }
479 :
480 3 : void RTargetGroupMgr::DisableRtGroupProcessing() {
481 3 : remove_rtgroup_trigger_->set_disable();
482 3 : }
483 :
484 3 : void RTargetGroupMgr::EnableRtGroupProcessing() {
485 3 : remove_rtgroup_trigger_->set_enable();
486 3 : }
487 :
488 12 : bool RTargetGroupMgr::IsRtGroupOnList(RtGroup *rtgroup) const {
489 12 : return rtgroup_remove_list_.find(rtgroup) != rtgroup_remove_list_.end();
490 : }
491 :
492 39060 : RtGroupMgrTableState::RtGroupMgrTableState(BgpTable *table,
493 39060 : DBTableBase::ListenerId id)
494 39060 : : id_(id), table_delete_ref_(this, table->deleter()) {
495 39060 : assert(table->deleter() != NULL);
496 39060 : }
497 :
498 39060 : RtGroupMgrTableState::~RtGroupMgrTableState() {
499 39060 : }
500 :
501 34500 : void RtGroupMgrTableState::ManagedDelete() {
502 34500 : }
|