Line data Source code
1 : /*
2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3 : */
4 : #include "bgp/routing-instance/rtarget_group_mgr.h"
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"
19 : #include "bgp/routing-instance/routing_instance.h"
20 : #include "bgp/rtarget/rtarget_route.h"
21 :
22 : using std::pair;
23 :
24 499622 : void VpnRouteState::AddRouteTarget(RTargetGroupMgr *mgr, int part_id,
25 : BgpRoute *rt, RTargetList::const_iterator it) {
26 499622 : pair<RTargetList::iterator, bool> result;
27 499622 : result = list_.insert(*it);
28 499691 : assert(result.second);
29 499691 : RtGroup *rtgroup = mgr->LocateRtGroup(*it);
30 499675 : rtgroup->AddDepRoute(part_id, rt);
31 499713 : }
32 :
33 499461 : void VpnRouteState::DeleteRouteTarget(RTargetGroupMgr *mgr, int part_id,
34 : BgpRoute *rt, RTargetList::const_iterator it) {
35 499461 : RtGroup *rtgroup = mgr->GetRtGroup(*it);
36 499712 : rtgroup->RemoveDepRoute(part_id, rt);
37 499692 : mgr->RemoveRtGroup(*it);
38 499708 : list_.erase(it);
39 499692 : }
40 :
41 27162 : void RTargetState::AddInterestedPeer(RTargetGroupMgr *mgr, RtGroup *rtgroup,
42 : RTargetRoute *rt, RtGroup::InterestedPeerList::const_iterator it) {
43 27162 : pair<RtGroup::InterestedPeerList::iterator, bool> result;
44 27162 : result = list_.insert(*it);
45 27162 : assert(result.second);
46 27162 : rtgroup->AddInterestedPeer(it->first, rt);
47 27162 : mgr->NotifyRtGroupUnlocked(rtgroup->rt());
48 27162 : }
49 :
50 27162 : void RTargetState::DeleteInterestedPeer(RTargetGroupMgr *mgr, RtGroup *rtgroup,
51 : RTargetRoute *rt, RtGroup::InterestedPeerList::iterator it) {
52 27162 : rtgroup->RemoveInterestedPeer(it->first, rt);
53 27162 : mgr->NotifyRtGroupUnlocked(rtgroup->rt());
54 27162 : list_.erase(it);
55 27162 : }
56 :
57 9742 : RTargetGroupMgr::RTargetGroupMgr(BgpServer *server) : server_(server),
58 19484 : rtarget_route_trigger_(new TaskTrigger(
59 : boost::bind(&RTargetGroupMgr::ProcessRTargetRouteList, this),
60 19484 : TaskScheduler::GetInstance()->GetTaskId("bgp::RTFilter"), 0)),
61 19484 : remove_rtgroup_trigger_(new TaskTrigger(
62 : boost::bind(&RTargetGroupMgr::ProcessRtGroupList, this),
63 19484 : TaskScheduler::GetInstance()->GetTaskId("bgp::RTFilter"), 0)),
64 9742 : rtarget_trigger_lists_(DB::PartitionCount()),
65 29226 : master_instance_delete_ref_(this, NULL) {
66 48185 : for (int i = 0; i < DB::PartitionCount(); i++) {
67 115329 : rtarget_dep_triggers_.push_back(boost::shared_ptr<TaskTrigger>(new
68 : TaskTrigger(boost::bind(&RTargetGroupMgr::ProcessRouteTargetList,
69 : this, i),
70 76886 : TaskScheduler::GetInstance()->GetTaskId("db::DBTable"), i)));
71 : }
72 9742 : }
73 :
74 103148 : void RTargetGroupMgr::RTargetPeerSync(BgpTable *table, RTargetRoute *rt,
75 : DBTableBase::ListenerId id, RTargetState *dbstate,
76 : const RtGroup::InterestedPeerList *future) {
77 103148 : CHECK_CONCURRENCY("bgp::RTFilter");
78 :
79 103148 : RouteTarget rtarget = rt->GetPrefix().rtarget();
80 103148 : RtGroup *rtgroup = LocateRtGroup(rtarget);
81 103148 : assert(rtgroup);
82 :
83 103148 : 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 103148 : if (dbstate->GetList()->empty()) {
90 64624 : rt->ClearState(table, id);
91 64624 : delete dbstate;
92 64624 : RemoveRtGroup(rtarget);
93 : }
94 103148 : }
95 :
96 103148 : void RTargetGroupMgr::BuildRTargetDistributionGraph(BgpTable *table,
97 : RTargetRoute *rt, DBTableBase::ListenerId id) {
98 103148 : CHECK_CONCURRENCY("bgp::RTFilter");
99 :
100 : RTargetState *dbstate =
101 103148 : static_cast<RTargetState *>(rt->GetState(table, id));
102 :
103 103148 : RtGroup::InterestedPeerList peer_list;
104 :
105 180235 : if (rt->IsDeleted() || !rt->BestPath() ||
106 77087 : !rt->BestPath()->IsFeasible()) {
107 26061 : RTargetPeerSync(table, rt, id, dbstate, &peer_list);
108 26061 : return;
109 : }
110 :
111 77087 : const BgpPath *best_ebgp_path = NULL;
112 223821 : for (Route::PathList::iterator it = rt->GetPathList().begin();
113 447642 : it != rt->GetPathList().end(); it++) {
114 146734 : BgpPath *path = static_cast<BgpPath *>(it.operator->());
115 146734 : if (!path->IsFeasible())
116 0 : break;
117 146734 : if (!path->GetPeer() || path->GetPeer()->IsXmppPeer())
118 106941 : continue;
119 :
120 39869 : const BgpPeer *peer = static_cast<const BgpPeer *>(path->GetPeer());
121 39869 : if (peer->PeerType() == BgpProto::EBGP) {
122 17273 : if (!best_ebgp_path) {
123 17093 : best_ebgp_path = path;
124 180 : } else if (!best_ebgp_path->PathSameNeighborAs(*path)) {
125 76 : continue;
126 : }
127 : }
128 :
129 : std::pair<RtGroup::InterestedPeerList::iterator, bool> ret =
130 39793 : peer_list.insert(std::pair<const BgpPeer *,
131 79586 : RtGroup::RTargetRouteList>(peer, RtGroup::RTargetRouteList()));
132 39793 : assert(ret.second);
133 39793 : ret.first->second.insert(rt);
134 : }
135 :
136 77087 : RTargetPeerSync(table, rt, id, dbstate, &peer_list);
137 103148 : }
138 :
139 163498 : bool RTargetGroupMgr::ProcessRouteTargetList(int part_id) {
140 163498 : CHECK_CONCURRENCY("db::DBTable");
141 :
142 759058 : BOOST_FOREACH(const RouteTarget &rtarget, rtarget_trigger_lists_[part_id]) {
143 297308 : RtGroup *rtgroup = GetRtGroup(rtarget);
144 299263 : if (!rtgroup)
145 26911 : continue;
146 272352 : rtgroup->NotifyDepRoutes(part_id);
147 : }
148 :
149 163646 : rtarget_trigger_lists_[part_id].clear();
150 163656 : return true;
151 : }
152 :
153 186714 : void RTargetGroupMgr::AddRouteTargetToLists(const RouteTarget &rtarget) {
154 916728 : for (int idx = 0; idx < DB::PartitionCount(); ++idx) {
155 730014 : rtarget_trigger_lists_[idx].insert(rtarget);
156 730014 : rtarget_dep_triggers_[idx]->Set();
157 : }
158 186714 : }
159 :
160 8 : void RTargetGroupMgr::DisableRouteTargetProcessing() {
161 40 : for (int idx = 0; idx < DB::PartitionCount(); ++idx) {
162 32 : rtarget_dep_triggers_[idx]->set_disable();
163 : }
164 8 : }
165 :
166 8 : void RTargetGroupMgr::EnableRouteTargetProcessing() {
167 40 : for (int idx = 0; idx < DB::PartitionCount(); ++idx) {
168 32 : rtarget_dep_triggers_[idx]->set_enable();
169 : }
170 8 : }
171 :
172 20 : bool RTargetGroupMgr::IsRouteTargetOnList(const RouteTarget &rtarget) const {
173 56 : for (int idx = 0; idx < DB::PartitionCount(); ++idx) {
174 47 : if (rtarget_trigger_lists_[idx].find(rtarget) !=
175 94 : rtarget_trigger_lists_[idx].end()) {
176 11 : return true;
177 : }
178 : }
179 9 : return false;
180 : }
181 :
182 41566 : bool RTargetGroupMgr::ProcessRTargetRouteList() {
183 41566 : CHECK_CONCURRENCY("bgp::RTFilter");
184 :
185 41566 : RoutingInstanceMgr *mgr = server()->routing_instance_mgr();
186 41566 : RoutingInstance *master = mgr->GetDefaultRoutingInstance();
187 41566 : BgpTable *table = master->GetTable(Address::RTARGET);
188 :
189 : // Get the Listener id
190 41566 : DBTableBase::ListenerId id = GetListenerId(table);
191 :
192 41566 : for (RTargetRouteTriggerList::iterator it = rtarget_route_list_.begin();
193 144714 : it != rtarget_route_list_.end(); it++) {
194 103148 : BuildRTargetDistributionGraph(table, *it, id);
195 : }
196 :
197 41566 : rtarget_route_list_.clear();
198 41566 : return true;
199 : }
200 :
201 8 : void RTargetGroupMgr::DisableRTargetRouteProcessing() {
202 8 : rtarget_route_trigger_->set_disable();
203 8 : }
204 :
205 8 : void RTargetGroupMgr::EnableRTargetRouteProcessing() {
206 8 : rtarget_route_trigger_->set_enable();
207 8 : }
208 :
209 19 : bool RTargetGroupMgr::IsRTargetRouteOnList(RTargetRoute *rt) const {
210 19 : return rtarget_route_list_.find(rt) != rtarget_route_list_.end();
211 : }
212 :
213 6509 : void RTargetGroupMgr::Initialize() {
214 6509 : assert(table_state_.empty());
215 6509 : RoutingInstanceMgr *mgr = server()->routing_instance_mgr();
216 6509 : RoutingInstance *master = mgr->GetDefaultRoutingInstance();
217 6509 : assert(master);
218 :
219 6509 : master_instance_delete_ref_.Reset(master->deleter());
220 :
221 6509 : RoutingInstance::RouteTableList const table_list = master->GetTables();
222 : DBTableBase::ListenerId id;
223 6509 : RtGroupMgrTableState *ts = NULL;
224 6509 : for (RoutingInstance::RouteTableList::const_iterator it =
225 71599 : table_list.begin(); it != table_list.end(); ++it) {
226 58581 : if (!it->second->IsVpnTable()) continue;
227 :
228 32545 : BgpTable *vpntable = it->second;
229 32545 : id = vpntable->Register(
230 : boost::bind(&RTargetGroupMgr::VpnRouteNotify, this, _1, _2),
231 : "RTargetGroupMgr");
232 32545 : ts = new RtGroupMgrTableState(vpntable, id);
233 32545 : table_state_.insert(std::make_pair(vpntable, ts));
234 : }
235 :
236 6509 : BgpTable *rttable = master->GetTable(Address::RTARGET);
237 6509 : id = rttable->Register(
238 : boost::bind(&RTargetGroupMgr::RTargetRouteNotify, this, _1, _2),
239 : "RTargetGroupMgr");
240 6509 : ts = new RtGroupMgrTableState(rttable, id);
241 6509 : table_state_.insert(std::make_pair(rttable, ts));
242 6509 : }
243 :
244 6509 : void RTargetGroupMgr::ManagedDelete() {
245 6509 : if (rtgroup_map_.empty()) remove_rtgroup_trigger_->Set();
246 6509 : }
247 :
248 : void
249 601874 : RTargetGroupMgr::RTargetDepSync(DBTablePartBase *root, BgpRoute *rt,
250 : DBTableBase::ListenerId id,
251 : VpnRouteState *dbstate,
252 : const VpnRouteState::RTargetList *future) {
253 601874 : CHECK_CONCURRENCY("db::DBTable");
254 :
255 601690 : BgpTable *table = static_cast<BgpTable *>(root->parent());
256 601690 : if (!dbstate) {
257 184805 : dbstate = new VpnRouteState();
258 184805 : rt->SetState(table, id, dbstate);
259 : }
260 :
261 601701 : int part_id = root->index();
262 601697 : 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 601786 : if (dbstate->GetList()->empty()) {
269 184819 : rt->ClearState(root->parent(), id);
270 184823 : delete dbstate;
271 : }
272 601775 : }
273 :
274 762501 : DBTableBase::ListenerId RTargetGroupMgr::GetListenerId(BgpTable *table) {
275 762501 : RtGroupMgrTableStateList::iterator loc = table_state_.find(table);
276 762420 : assert(loc != table_state_.end());
277 762408 : RtGroupMgrTableState *ts = loc->second;
278 762404 : DBTableBase::ListenerId id = ts->GetListenerId();
279 762403 : assert(id != DBTableBase::kInvalidId);
280 762403 : return id;
281 : }
282 :
283 601820 : bool RTargetGroupMgr::VpnRouteNotify(DBTablePartBase *root,
284 : DBEntryBase *entry) {
285 601820 : CHECK_CONCURRENCY("db::DBTable");
286 :
287 601799 : BgpTable *table = static_cast<BgpTable *>(root->parent());
288 601795 : BgpRoute *rt = static_cast<BgpRoute *>(entry);
289 : // Get the Listener id
290 601795 : DBTableBase::ListenerId id = GetListenerId(table);
291 :
292 : // Get the dbstate
293 : VpnRouteState *dbstate =
294 601692 : static_cast<VpnRouteState *>(rt->GetState(table, id));
295 :
296 602095 : VpnRouteState::RTargetList list;
297 :
298 1019016 : if (entry->IsDeleted() || !rt->BestPath() ||
299 417019 : !rt->BestPath()->IsFeasible()) {
300 184898 : if (!dbstate)
301 122 : return true;
302 184776 : RTargetDepSync(root, rt, id, dbstate, &list);
303 184800 : return true;
304 : }
305 :
306 417008 : const BgpPath *path = rt->BestPath();
307 417004 : const BgpAttr *attr = path->GetAttr();
308 416989 : const ExtCommunity *ext_community = attr->ext_community();
309 :
310 416896 : if (ext_community) {
311 : // Gather all Route Target
312 7745493 : BOOST_FOREACH(const ExtCommunity::ExtCommunityValue &comm,
313 : ext_community->communities()) {
314 3663342 : if (ExtCommunity::is_route_target(comm)) {
315 2974582 : list.insert(RouteTarget(comm));
316 : }
317 : }
318 : }
319 :
320 417031 : RTargetDepSync(root, rt, id, dbstate, &list);
321 416978 : return true;
322 601900 : }
323 :
324 119164 : bool RTargetGroupMgr::RTargetRouteNotify(DBTablePartBase *root,
325 : DBEntryBase *entry) {
326 119164 : CHECK_CONCURRENCY("db::DBTable");
327 :
328 119164 : BgpTable *table = static_cast<BgpTable *>(root->parent());
329 119164 : RTargetRoute *rt = static_cast<RTargetRoute *>(entry);
330 : // Get the Listener id
331 119164 : DBTableBase::ListenerId id = GetListenerId(table);
332 :
333 : // Get the dbstate
334 : RTargetState *dbstate =
335 119164 : static_cast<RTargetState *>(rt->GetState(table, id));
336 :
337 119164 : if (!dbstate) {
338 78831 : if (rt->IsDeleted()) return true;
339 64624 : dbstate = new RTargetState();
340 64624 : rt->SetState(table, id, dbstate);
341 : }
342 104957 : if (rtarget_route_list_.empty())
343 41566 : rtarget_route_trigger_->Set();
344 104957 : rtarget_route_list_.insert(rt);
345 104957 : return true;
346 : }
347 :
348 18646 : RTargetGroupMgr::~RTargetGroupMgr() {
349 9742 : assert(rtgroup_map_.empty());
350 18646 : }
351 :
352 : // Search a RtGroup
353 6466079 : RtGroup *RTargetGroupMgr::GetRtGroup(const RouteTarget &rt) {
354 6466079 : std::scoped_lock lock(mutex_);
355 6469718 : RtGroupMap::iterator loc = rtgroup_map_.find(rt);
356 6469184 : if (loc != rtgroup_map_.end()) {
357 6124486 : return loc->second;
358 : }
359 344617 : return NULL;
360 6469089 : }
361 :
362 : // Search a RtGroup
363 4424982 : RtGroup *RTargetGroupMgr::GetRtGroup(const ExtCommunity::ExtCommunityValue
364 : &community) {
365 4424982 : RouteTarget rt(community);
366 8851560 : return GetRtGroup(rt);
367 : }
368 :
369 1530816 : RtGroup *RTargetGroupMgr::LocateRtGroup(const RouteTarget &rt) {
370 1530816 : std::scoped_lock lock(mutex_);
371 1531405 : RtGroupMap::iterator loc = rtgroup_map_.find(rt);
372 1531383 : RtGroup *group = (loc != rtgroup_map_.end()) ? loc->second : NULL;
373 1531385 : if (group == NULL) {
374 108821 : group = new RtGroup(rt);
375 108822 : rtgroup_map_.insert(rt, group);
376 : }
377 1531402 : return group;
378 1531386 : }
379 :
380 186714 : void RTargetGroupMgr::NotifyRtGroupUnlocked(const RouteTarget &rt) {
381 186714 : CHECK_CONCURRENCY("bgp::RTFilter", "bgp::Config", "bgp::ConfigHelper");
382 :
383 186714 : AddRouteTargetToLists(rt);
384 186714 : if (!rt.IsNull())
385 186698 : return;
386 :
387 16 : for (RtGroupMgrTableStateList::iterator it = table_state_.begin();
388 112 : it != table_state_.end(); ++it) {
389 96 : BgpTable *table = it->first;
390 96 : if (!table->IsVpnTable())
391 16 : continue;
392 80 : table->NotifyAllEntries();
393 : }
394 : }
395 :
396 132390 : void RTargetGroupMgr::NotifyRtGroup(const RouteTarget &rt) {
397 132390 : CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
398 132390 : std::scoped_lock lock(mutex_);
399 132390 : NotifyRtGroupUnlocked(rt);
400 132390 : }
401 :
402 994196 : void RTargetGroupMgr::RemoveRtGroup(const RouteTarget &rt) {
403 994196 : std::scoped_lock lock(mutex_);
404 994229 : RtGroupMap::iterator loc = rtgroup_map_.find(rt);
405 994194 : RtGroup *rtgroup = (loc != rtgroup_map_.end()) ? loc->second : NULL;
406 994189 : assert(rtgroup);
407 :
408 994189 : rtgroup_remove_list_.insert(rtgroup);
409 994229 : remove_rtgroup_trigger_->Set();
410 994240 : }
411 :
412 315601 : void RTargetGroupMgr::GetRibOutInterestedPeers(RibOut *ribout,
413 : const ExtCommunity *ext_community,
414 : const RibPeerSet &peerset, RibPeerSet *new_peerset) {
415 315601 : RtGroupInterestedPeerSet peer_set;
416 315613 : RtGroup *null_rtgroup = GetRtGroup(RouteTarget::null_rtarget);
417 315820 : if (null_rtgroup) peer_set = null_rtgroup->GetInterestedPeers();
418 6077833 : BOOST_FOREACH(const ExtCommunity::ExtCommunityValue &comm,
419 : ext_community->communities()) {
420 2880921 : if (ExtCommunity::is_route_target(comm)) {
421 2232471 : RtGroup *rtgroup = GetRtGroup(comm);
422 2232730 : if (!rtgroup) continue;
423 2232730 : peer_set |= rtgroup->GetInterestedPeers();
424 : }
425 : }
426 315814 : RibOut::PeerIterator iter(ribout, peerset);
427 635277 : while (iter.HasNext()) {
428 319480 : int current_index = iter.index();
429 319480 : IPeerUpdate *peer = iter.Next();
430 319469 : BgpPeer *tmp = dynamic_cast<BgpPeer *>(peer);
431 319469 : assert(tmp);
432 319469 : if (tmp->IsFamilyNegotiated(Address::RTARGET)) {
433 311260 : if (!peer_set.test(tmp->GetIndex())) {
434 20114 : new_peerset->reset(current_index);
435 : }
436 : }
437 : }
438 315768 : }
439 :
440 10773 : void RTargetGroupMgr::UnregisterTables() {
441 10773 : CHECK_CONCURRENCY("bgp::RTFilter");
442 :
443 10773 : if (rtgroup_map_.empty()) {
444 10773 : RoutingInstanceMgr *mgr = server()->routing_instance_mgr();
445 10773 : RoutingInstance *master = mgr->GetDefaultRoutingInstance();
446 10773 : if (master && master->deleted()) {
447 7962 : for (RtGroupMgrTableStateList::iterator it =
448 54978 : table_state_.begin(), itnext; it != table_state_.end();
449 39054 : it = itnext) {
450 39054 : itnext = it;
451 39054 : itnext++;
452 39054 : RtGroupMgrTableState *ts = it->second;
453 39054 : DBTableBase::ListenerId id = ts->GetListenerId();
454 39054 : BgpTable *bgptable = it->first;
455 39054 : bgptable->Unregister(id);
456 39054 : table_state_.erase(it);
457 39054 : delete ts;
458 : }
459 7962 : master_instance_delete_ref_.Reset(NULL);
460 : }
461 : }
462 10773 : }
463 :
464 140027 : bool RTargetGroupMgr::ProcessRtGroupList() {
465 140027 : CHECK_CONCURRENCY("bgp::RTFilter");
466 785391 : BOOST_FOREACH(RtGroup *rtgroup, rtgroup_remove_list_) {
467 322682 : if (!rtgroup->MayDelete())
468 213860 : continue;
469 108822 : RouteTarget rt = rtgroup->rt();
470 108822 : rtgroup_map_.erase(rt);
471 : }
472 140027 : rtgroup_remove_list_.clear();
473 :
474 140027 : if (rtgroup_map_.empty()) UnregisterTables();
475 :
476 140027 : return true;
477 : }
478 :
479 3 : void RTargetGroupMgr::DisableRtGroupProcessing() {
480 3 : remove_rtgroup_trigger_->set_disable();
481 3 : }
482 :
483 3 : void RTargetGroupMgr::EnableRtGroupProcessing() {
484 3 : remove_rtgroup_trigger_->set_enable();
485 3 : }
486 :
487 12 : bool RTargetGroupMgr::IsRtGroupOnList(RtGroup *rtgroup) const {
488 12 : return rtgroup_remove_list_.find(rtgroup) != rtgroup_remove_list_.end();
489 : }
490 :
491 39054 : RtGroupMgrTableState::RtGroupMgrTableState(BgpTable *table,
492 39054 : DBTableBase::ListenerId id)
493 39054 : : id_(id), table_delete_ref_(this, table->deleter()) {
494 39054 : assert(table->deleter() != NULL);
495 39054 : }
496 :
497 39054 : RtGroupMgrTableState::~RtGroupMgrTableState() {
498 39054 : }
499 :
500 34500 : void RtGroupMgrTableState::ManagedDelete() {
501 34500 : }
|