Line data Source code
1 : /*
2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3 : */
4 :
5 : #include "bgp/bgp_table.h"
6 :
7 : #include <boost/foreach.hpp>
8 :
9 : #include "sandesh/sandesh_trace.h"
10 : #include "base/task_annotations.h"
11 : #include "bgp/bgp_log.h"
12 : #include "bgp/bgp_membership.h"
13 : #include "bgp/bgp_peer.h"
14 : #include "bgp/bgp_peer_types.h"
15 : #include "bgp/bgp_ribout.h"
16 : #include "bgp/bgp_ribout_updates.h"
17 : #include "bgp/bgp_route.h"
18 : #include "bgp/bgp_server.h"
19 : #include "bgp/bgp_update.h"
20 : #include "bgp/inet/inet_table.h"
21 : #include "bgp/routing-instance/iroute_aggregator.h"
22 : #include "bgp/routing-instance/path_resolver.h"
23 : #include "bgp/routing-instance/routing_instance.h"
24 : #include "bgp/routing-instance/rtarget_group_mgr.h"
25 : #include "bgp/tunnel_encap/tunnel_encap.h"
26 : #include "net/community_type.h"
27 :
28 : using std::make_pair;
29 : using std::string;
30 :
31 : class BgpTable::DeleteActor : public LifetimeActor {
32 : public:
33 288592 : explicit DeleteActor(BgpTable *table)
34 288592 : : LifetimeActor(table->rtinstance_->server()->lifetime_manager()),
35 288592 : table_(table) {
36 288592 : }
37 577184 : virtual ~DeleteActor() {
38 577184 : }
39 294942 : virtual bool MayDelete() const {
40 294942 : return table_->MayDelete();
41 : }
42 :
43 288592 : virtual void Shutdown() {
44 288592 : table_->Shutdown();
45 288592 : }
46 :
47 : // Make sure that all notifications have been processed and all db
48 : // state have been cleared for all partitions, before we inform the
49 : // parent instance that this table deletion process is complete.
50 288592 : virtual void Destroy() {
51 288592 : table_->rtinstance_->DestroyDBTable(table_);
52 288592 : }
53 :
54 : private:
55 : BgpTable *table_;
56 : };
57 :
58 296922 : BgpTable::BgpTable(DB *db, const string &name)
59 : : RouteTable(db, name),
60 296885 : rtinstance_(NULL),
61 296885 : path_resolver_(NULL),
62 296922 : instance_delete_ref_(this, NULL) {
63 296897 : primary_path_count_ = 0;
64 296970 : secondary_path_count_ = 0;
65 296968 : infeasible_path_count_ = 0;
66 296948 : stale_path_count_ = 0;
67 296967 : llgr_stale_path_count_ = 0;
68 296967 : }
69 :
70 : //
71 : // Remove the table from the instance dependents before attempting to
72 : // destroy the DeleteActor which can have its Delete() method be called
73 : // via the reference.
74 : //
75 296975 : BgpTable::~BgpTable() {
76 296975 : assert(path_resolver_ == NULL),
77 296975 : instance_delete_ref_.Reset(NULL);
78 296975 : }
79 :
80 288591 : void BgpTable::set_routing_instance(RoutingInstance *rtinstance) {
81 288591 : rtinstance_ = rtinstance;
82 288591 : assert(rtinstance);
83 288591 : deleter_.reset(new DeleteActor(this));
84 288587 : instance_delete_ref_.Reset(rtinstance->deleter());
85 288589 : }
86 :
87 3037010 : BgpServer *BgpTable::server() {
88 3037010 : return rtinstance_->server();
89 : }
90 :
91 1770384 : const BgpServer *BgpTable::server() const {
92 1770384 : return rtinstance_->server();
93 : }
94 :
95 : //
96 : // Find the RibOut for the given RibExportPolicy.
97 : //
98 60 : RibOut *BgpTable::RibOutFind(const RibExportPolicy &policy) {
99 60 : RibOutMap::iterator loc = ribout_map_.find(policy);
100 60 : return (loc != ribout_map_.end()) ? loc->second : NULL;
101 : }
102 :
103 : //
104 : // Find or create the RibOut associated with the given RibExportPolicy.
105 : // If a new RibOut is created, an entry for the pair gets added to the
106 : // RibOutMap.
107 : //
108 82957 : RibOut *BgpTable::RibOutLocate(BgpUpdateSender *sender,
109 : const RibExportPolicy &policy) {
110 82957 : RibOutMap::iterator loc = ribout_map_.find(policy);
111 82957 : if (loc == ribout_map_.end()) {
112 34964 : RibOut *ribout = new RibOut(this, sender, policy);
113 34964 : ribout_map_.insert(make_pair(policy, ribout));
114 34964 : return ribout;
115 : }
116 47993 : return loc->second;
117 : }
118 :
119 : //
120 : // Delete the entry corresponding to the given RibExportPolicy from the
121 : // RibOutMap. Also deletes the RibOut itself.
122 : //
123 34932 : void BgpTable::RibOutDelete(const RibExportPolicy &policy) {
124 34932 : RibOutMap::iterator loc = ribout_map_.find(policy);
125 34932 : assert(loc != ribout_map_.end());
126 34932 : delete loc->second;
127 34932 : ribout_map_.erase(loc);
128 34932 : }
129 :
130 : // If both as2 and as4 aggregators are present then we need to choose one
131 248053 : void BgpTable::CheckAggregatorAttr(BgpAttr *attr) const {
132 248053 : if (attr->aggregator_as_num() && attr->aggregator_as4_num()) {
133 32 : if (attr->aggregator_as_num() != AS_TRANS) {
134 : // If as2 aggregator is not as_trans then we ignore as4 aggregator
135 : // and ignore as4_path also
136 16 : attr->set_as4_path(NULL);
137 16 : attr->set_as4_aggregator(0, attr->aggregator_adderess());
138 : } else {
139 : // If as2 aggregator is as_trans then we use as4 aggregator
140 16 : attr->set_aggregator(attr->aggregator_as4_num(),
141 16 : attr->aggregator_adderess());
142 16 : attr->set_as4_aggregator(0, attr->aggregator_adderess());
143 : }
144 : }
145 248060 : }
146 :
147 203518 : void BgpTable::PrependLocalAs(const RibOut *ribout, BgpAttr *clone,
148 : const IPeer* peer) const {
149 203518 : CheckAggregatorAttr(clone);
150 203519 : as_t local_as = ribout->local_as() ?:
151 466 : clone->attr_db()->server()->local_autonomous_system();
152 203519 : if (!server()->enable_4byte_as())
153 203203 : return PrependAsToAsPath2Byte(clone, (as2_t)local_as);
154 313 : if (ribout->as4_supported()) {
155 121 : if (clone->aspath_4byte())
156 48 : PrependAsToAsPath4Byte(clone, local_as);
157 : else
158 73 : CreateAsPath4Byte(clone, local_as);
159 : } else {
160 192 : if (!clone->as_path())
161 44 : CreateAsPath2Byte(clone);
162 192 : PrependAsToAsPath2Byte(clone, local_as);
163 : }
164 : }
165 :
166 82 : void BgpTable::RemovePrivateAs(const RibOut *ribout, BgpAttr *attr) const {
167 82 : bool all = ribout->remove_private_all();
168 82 : bool replace = ribout->remove_private_replace();
169 82 : bool peer_loop_check = ribout->remove_private_peer_loop_check();
170 :
171 82 : const AsPathSpec &spec = attr->as_path()->path();
172 82 : as_t peer_asn = peer_loop_check ? ribout->peer_as() : 0;
173 82 : as_t replace_asn = 0;
174 82 : if (replace) {
175 56 : if (ribout->peer_type() == BgpProto::EBGP) {
176 32 : replace_asn = server()->local_autonomous_system();
177 : } else {
178 24 : replace_asn = spec.AsLeftMostPublic();
179 : }
180 : }
181 82 : if (replace_asn > AS2_MAX) {
182 8 : if (!attr->as4_path())
183 8 : CreateAs4Path(attr);
184 8 : const As4PathSpec &spec = attr->as4_path()->path();
185 8 : As4PathSpec *new_spec = spec.RemovePrivate(all, replace_asn, peer_asn);
186 8 : attr->set_as4_path(new_spec);
187 8 : delete new_spec;
188 8 : replace_asn = AS_TRANS;
189 : }
190 82 : if (peer_asn > AS2_MAX)
191 8 : peer_asn = AS_TRANS;
192 :
193 82 : AsPathSpec *new_spec = spec.RemovePrivate(all, replace_asn, peer_asn);
194 82 : attr->set_as_path(new_spec);
195 82 : delete new_spec;
196 82 : }
197 :
198 24 : void BgpTable::RemovePrivate4ByteAs(const RibOut *ribout, BgpAttr *attr) const {
199 24 : bool all = ribout->remove_private_all();
200 24 : bool replace = ribout->remove_private_replace();
201 24 : bool peer_loop_check = ribout->remove_private_peer_loop_check();
202 :
203 24 : const AsPath4ByteSpec &spec = attr->aspath_4byte()->path();
204 24 : as_t peer_asn = peer_loop_check ? ribout->peer_as() : 0;
205 24 : as_t replace_asn = 0;
206 24 : if (replace) {
207 16 : if (ribout->peer_type() == BgpProto::EBGP) {
208 16 : replace_asn = server()->local_autonomous_system();
209 : } else {
210 0 : replace_asn = spec.AsLeftMostPublic();
211 : }
212 : }
213 :
214 24 : AsPath4ByteSpec *new_spec = spec.RemovePrivate(all, replace_asn, peer_asn);
215 24 : attr->set_aspath_4byte(new_spec);
216 24 : delete new_spec;
217 24 : }
218 :
219 8 : void BgpTable::RemovePrivateAs4(const RibOut *ribout, BgpAttr *attr) const {
220 8 : bool all = ribout->remove_private_all();
221 8 : bool replace = ribout->remove_private_replace();
222 8 : bool peer_loop_check = ribout->remove_private_peer_loop_check();
223 :
224 8 : const As4PathSpec &spec = attr->as4_path()->path();
225 8 : as_t peer_asn = peer_loop_check ? ribout->peer_as() : 0;
226 8 : as_t replace_asn = 0;
227 8 : if (replace) {
228 8 : if (ribout->peer_type() == BgpProto::EBGP) {
229 8 : replace_asn = server()->local_autonomous_system();
230 : } else {
231 0 : replace_asn = spec.AsLeftMostPublic();
232 : }
233 : }
234 :
235 8 : As4PathSpec *new_spec = spec.RemovePrivate(all, replace_asn, peer_asn);
236 8 : attr->set_as4_path(new_spec);
237 8 : delete new_spec;
238 8 : }
239 :
240 : //
241 : // Process Remove Private information.
242 : //
243 247913 : void BgpTable::ProcessRemovePrivate(const RibOut *ribout, BgpAttr *attr) const {
244 247913 : if (!ribout->IsEncodingBgp())
245 0 : return;
246 248063 : if (!ribout->remove_private_enabled())
247 247949 : return;
248 :
249 112 : if (attr->as_path())
250 82 : RemovePrivateAs(ribout, attr);
251 110 : if (attr->aspath_4byte())
252 24 : RemovePrivate4ByteAs(ribout, attr);
253 110 : if (attr->as4_path())
254 8 : RemovePrivateAs4(ribout, attr);
255 : }
256 :
257 : //
258 : // Process Remove Private information.
259 : //
260 203521 : void BgpTable::ProcessAsOverride(const RibOut *ribout, BgpAttr *attr) const {
261 203521 : if (ribout->as_override() && !attr->IsAsPathEmpty()) {
262 52 : as_t replace_as = ribout->local_as() ?:
263 52 : attr->attr_db()->server()->local_autonomous_system();
264 52 : if (attr->as_path()) {
265 44 : const AsPathSpec &as_path = attr->as_path()->path();
266 : // If peer_as is > 0xffff, it can't be in as_path
267 44 : if (ribout->peer_as() <= AS2_MAX) {
268 44 : if (replace_as > AS2_MAX) {
269 : // if replace_as > 0xffff, as4_path should be created if
270 : // not already there by copying data from as_path
271 12 : if (!attr->as4_path()) {
272 12 : CreateAs4Path(attr);
273 : }
274 12 : replace_as = AS_TRANS;
275 : }
276 44 : AsPathSpec *as_path_ptr = as_path.Replace(
277 44 : ribout->peer_as(), replace_as);
278 44 : attr->set_as_path(as_path_ptr);
279 44 : delete as_path_ptr;
280 : }
281 44 : if (attr->as4_path()) {
282 12 : As4PathSpec *as_path_ptr = attr->as4_path()->path().Replace(
283 : ribout->peer_as(), replace_as);
284 12 : attr->set_as4_path(as_path_ptr);
285 12 : delete as_path_ptr;
286 : }
287 : }
288 52 : if (attr->aspath_4byte()) {
289 8 : const AsPath4ByteSpec &as_path = attr->aspath_4byte()->path();
290 : AsPath4ByteSpec *as_path_ptr =
291 8 : as_path.Replace(ribout->peer_as(), replace_as);
292 8 : attr->set_aspath_4byte(as_path_ptr);
293 8 : delete as_path_ptr;
294 : }
295 : }
296 203521 : }
297 :
298 : //
299 : // Process Long Lived Graceful Restart state information.
300 : //
301 : // For LLGR_STALE paths, if the peer supports LLGR then attach LLGR_STALE
302 : // community. Otherwise, strip LLGR_STALE community, reduce LOCAL_PREF and
303 : // attach NO_EXPORT community instead.
304 : //
305 248073 : void BgpTable::ProcessLlgrState(const RibOut *ribout, const BgpPath *path,
306 : BgpAttr *attr, bool llgr_stale_comm) {
307 248073 : if (!server() || !server()->comm_db())
308 0 : return;
309 :
310 : // Skip LLGR specific attributes manipulation for rtarget routes.
311 248071 : if (family() == Address::RTARGET)
312 54432 : return;
313 :
314 : // If the path is not marked as llgr_stale or if it does not have the
315 : // LLGR_STALE community, then no action is necessary.
316 193638 : if (!path->IsLlgrStale() && !llgr_stale_comm)
317 187584 : return;
318 :
319 : // If peers support LLGR, then attach LLGR_STALE community and return.
320 6054 : if (ribout->llgr()) {
321 6041 : if (!llgr_stale_comm) {
322 : CommunityPtr comm = server()->comm_db()->AppendAndLocate(
323 6033 : attr->community(), CommunityType::LlgrStale);
324 6033 : attr->set_community(comm);
325 6033 : }
326 6041 : return;
327 : }
328 :
329 : // Peers do not understand LLGR. Bring down local preference instead to
330 : // make the advertised path less preferred.
331 12 : attr->set_local_pref(0);
332 :
333 : // Remove LLGR_STALE community as the peers do not support LLGR.
334 12 : if (llgr_stale_comm) {
335 : CommunityPtr comm = server()->comm_db()->RemoveAndLocate(
336 8 : attr->community(), CommunityType::LlgrStale);
337 8 : attr->set_community(comm);
338 8 : }
339 :
340 : // Attach NO_EXPORT community as well to make sure that this path does not
341 : // exits local AS, unless it is already present.
342 20 : if (!attr->community() ||
343 8 : !attr->community()->ContainsValue(CommunityType::NoExport)) {
344 : CommunityPtr comm = server()->comm_db()->AppendAndLocate(
345 12 : attr->community(), CommunityType::NoExport);
346 12 : attr->set_community(comm);
347 12 : }
348 : }
349 :
350 248072 : void BgpTable::ProcessDefaultTunnelEncapsulation(const RibOut *ribout,
351 : ExtCommunityDB *extcomm_db, BgpAttr *attr) const {
352 248072 : if (!ribout->ExportPolicy().default_tunnel_encap_list.empty()) {
353 8 : ExtCommunity::ExtCommunityList encap_list;
354 30 : BOOST_FOREACH(const string &encap_string,
355 : ribout->ExportPolicy().default_tunnel_encap_list) {
356 11 : TunnelEncap tunnel_encap(encap_string);
357 11 : encap_list.push_back(tunnel_encap.GetExtCommunity());
358 : }
359 8 : ExtCommunityPtr ext_community = attr->ext_community();
360 : ext_community =
361 16 : extcomm_db->ReplaceTunnelEncapsulationAndLocate(
362 8 : ext_community.get(), encap_list);
363 8 : attr->set_ext_community(ext_community);
364 8 : }
365 248073 : }
366 :
367 203395 : void BgpTable::PrependAsToAsPath2Byte(BgpAttr *attr, as2_t asn) const {
368 203395 : if (attr->as_path()) {
369 72281 : const AsPathSpec &as_path = attr->as_path()->path();
370 72281 : AsPathSpec *as_path_ptr = as_path.Add(asn);
371 72277 : attr->set_as_path(as_path_ptr);
372 72283 : delete as_path_ptr;
373 : } else {
374 131113 : AsPathSpec as_path;
375 131117 : AsPathSpec *as_path_ptr = as_path.Add(asn);
376 131081 : attr->set_as_path(as_path_ptr);
377 131129 : delete as_path_ptr;
378 131129 : }
379 203411 : }
380 :
381 192 : void BgpTable::PrependAsToAsPath2Byte(BgpAttr *attr, as_t asn) const {
382 192 : if (asn <= AS2_MAX) {
383 108 : if (attr->as_path() && attr->as4_path()) {
384 23 : PrependAsToAs4Path(attr, asn);
385 : }
386 108 : return PrependAsToAsPath2Byte(attr, static_cast<as2_t>(asn & AS2_MAX));
387 : }
388 84 : if (attr->as_path() && !attr->as4_path()) {
389 46 : CreateAs4Path(attr);
390 46 : assert(attr->as_path()->path().path_segments.size() ==
391 : attr->as4_path()->path().path_segments.size());
392 : }
393 84 : as2_t as_trans = AS_TRANS;
394 84 : PrependAsToAsPath2Byte(attr, as_trans);
395 84 : PrependAsToAs4Path(attr, asn);
396 : }
397 :
398 48 : void BgpTable::PrependAsToAsPath4Byte(BgpAttr *clone, as_t asn) const {
399 48 : if (clone->aspath_4byte()) {
400 48 : const AsPath4ByteSpec &as4_path = clone->aspath_4byte()->path();
401 48 : AsPath4ByteSpec *as4_path_ptr = as4_path.Add(asn);
402 48 : clone->set_aspath_4byte(as4_path_ptr);
403 48 : delete as4_path_ptr;
404 : } else {
405 0 : AsPath4ByteSpec as_path;
406 0 : AsPath4ByteSpec *as_path_ptr = as_path.Add(asn);
407 0 : clone->set_aspath_4byte(as_path_ptr);
408 0 : delete as_path_ptr;
409 0 : }
410 48 : }
411 :
412 107 : void BgpTable::PrependAsToAs4Path(BgpAttr* attr, as_t asn) const {
413 107 : if (attr->as4_path()) {
414 107 : const As4PathSpec &as4_path = attr->as4_path()->path();
415 107 : As4PathSpec *as4_path_ptr = as4_path.Add(asn);
416 107 : attr->set_as4_path(as4_path_ptr);
417 107 : delete as4_path_ptr;
418 : } else {
419 0 : As4PathSpec as_path;
420 0 : As4PathSpec *as_path_ptr = as_path.Add(asn);
421 0 : attr->set_as4_path(as_path_ptr);
422 0 : delete as_path_ptr;
423 0 : }
424 107 : }
425 :
426 : // Create as4_path by copying data from as_path
427 66 : void BgpTable::CreateAs4Path(BgpAttr *attr) const {
428 66 : if (!attr->as_path()) {
429 0 : return;
430 : }
431 :
432 66 : std::unique_ptr<As4PathSpec> new_as_path(new As4PathSpec);
433 66 : const AsPathSpec &as_path = attr->as_path()->path();
434 107 : for (size_t i = 0; i < as_path.path_segments.size(); i++) {
435 41 : As4PathSpec::PathSegment *ps4 = new As4PathSpec::PathSegment;
436 41 : AsPathSpec::PathSegment *ps = as_path.path_segments[i];
437 41 : ps4->path_segment_type = ps->path_segment_type;
438 108 : for (size_t j = 0; j < ps->path_segment.size(); j++) {
439 67 : as_t as = ps->path_segment[j];
440 67 : ps4->path_segment.push_back(as);
441 : }
442 41 : new_as_path->path_segments.push_back(ps4);
443 : }
444 66 : attr->set_as4_path(new_as_path.get());
445 66 : }
446 :
447 : // Check if aspath_4byte has any asn > 0xFFFF
448 60 : bool BgpTable::Has4ByteAsn(BgpAttr *attr) const {
449 60 : if (!attr->aspath_4byte())
450 13 : return false;
451 47 : const AsPath4ByteSpec &as_path4 = attr->aspath_4byte()->path();
452 67 : for (size_t i = 0; i < as_path4.path_segments.size(); ++i) {
453 47 : AsPath4ByteSpec::PathSegment *ps4 = as_path4.path_segments[i];
454 67 : for (size_t j = 0; j < ps4->path_segment.size(); ++j) {
455 47 : if (ps4->path_segment[j] > AS2_MAX)
456 27 : return true;
457 : }
458 : }
459 20 : return false;
460 : }
461 :
462 : // Create as_path (and as4_path) from as_path4byte
463 60 : void BgpTable::CreateAsPath2Byte(BgpAttr *attr) const {
464 60 : std::unique_ptr<AsPathSpec> new_as_path(new AsPathSpec);
465 60 : As4PathSpec *new_as4_path = NULL;
466 60 : bool has_4byte_asn = Has4ByteAsn(attr);
467 60 : if (has_4byte_asn)
468 27 : new_as4_path = new As4PathSpec;
469 60 : if (attr->aspath_4byte()) {
470 47 : const AsPath4ByteSpec &as_path4 = attr->aspath_4byte()->path();
471 110 : for (size_t i = 0; i < as_path4.path_segments.size(); i++) {
472 63 : AsPathSpec::PathSegment *ps = new AsPathSpec::PathSegment;
473 63 : As4PathSpec::PathSegment *as4_ps = NULL;
474 63 : AsPath4ByteSpec::PathSegment *ps4 = as_path4.path_segments[i];
475 63 : ps->path_segment_type = ps4->path_segment_type;
476 63 : if (has_4byte_asn) {
477 43 : as4_ps = new As4PathSpec::PathSegment;
478 43 : as4_ps->path_segment_type = ps4->path_segment_type;
479 : }
480 164 : for (size_t j = 0; j < ps4->path_segment.size(); ++j) {
481 101 : as_t as4 = ps4->path_segment[j];
482 101 : if (as4 > AS2_MAX) {
483 57 : as2_t as_trans = AS_TRANS;
484 57 : ps->path_segment.push_back(as_trans);
485 : } else {
486 44 : ps->path_segment.push_back(static_cast<as2_t>(
487 : as4 & AS2_MAX));
488 : }
489 101 : if (has_4byte_asn)
490 81 : as4_ps->path_segment.push_back(as4);
491 : }
492 63 : new_as_path->path_segments.push_back(ps);
493 63 : if (has_4byte_asn)
494 43 : new_as4_path->path_segments.push_back(as4_ps);
495 : }
496 47 : attr->set_aspath_4byte(NULL);
497 : }
498 60 : attr->set_as_path(new_as_path.get());
499 60 : if (has_4byte_asn) {
500 27 : attr->set_as4_path(new_as4_path);
501 27 : delete new_as4_path;
502 : }
503 60 : }
504 :
505 : // Create aspath_4byte by merging as_path and as4_path
506 77 : void BgpTable::CreateAsPath4Byte(BgpAttr *attr, as_t local_as) const {
507 77 : int as2_count = attr->as_path_count();
508 77 : int as4_count = attr->as4_path_count();
509 77 : if (as2_count < as4_count) {
510 8 : as4_count = 0;
511 8 : attr->set_as4_path(NULL);
512 : }
513 77 : AsPath4ByteSpec::PathSegment *ps4 = NULL;
514 77 : bool part_segment = false;
515 77 : std::unique_ptr <AsPath4ByteSpec> aspath_4byte(new AsPath4ByteSpec);
516 77 : if (attr->as_path()) {
517 32 : const AsPathSpec &as_path = attr->as_path()->path();
518 32 : int new_as_count = 0;
519 86 : for (size_t i = 0; i < as_path.path_segments.size() &&
520 32 : new_as_count < (as2_count - as4_count) ; ++i) {
521 30 : ps4 = new AsPath4ByteSpec::PathSegment;
522 30 : AsPathSpec::PathSegment *ps = as_path.path_segments[i];
523 30 : ps4->path_segment_type = ps->path_segment_type;
524 30 : if (ps->path_segment_type == AsPathSpec::PathSegment::AS_SET) {
525 0 : new_as_count++;
526 0 : for (size_t j = 0; j < ps->path_segment.size(); ++j) {
527 0 : as2_t as = ps->path_segment[j];
528 0 : ps4->path_segment.push_back(as);
529 : }
530 : } else {
531 130 : for (size_t j = 0; j < ps->path_segment.size() &&
532 54 : new_as_count < (as2_count - as4_count); ++j) {
533 46 : new_as_count++;
534 46 : as2_t as = ps->path_segment[j];
535 46 : ps4->path_segment.push_back(as);
536 : }
537 30 : if (new_as_count == (as2_count - as4_count)) {
538 30 : if (attr->as4_path()) {
539 8 : part_segment = true;
540 8 : break;
541 : }
542 : }
543 : }
544 22 : aspath_4byte->path_segments.push_back(ps4);
545 : }
546 32 : if (attr->as4_path()) {
547 10 : const As4PathSpec &as4_path = attr->as4_path()->path();
548 20 : for (size_t i = 0; i < as4_path.path_segments.size(); ++i) {
549 10 : if (!part_segment) {
550 2 : ps4 = new AsPath4ByteSpec::PathSegment;
551 : }
552 10 : part_segment = false;
553 10 : As4PathSpec::PathSegment *ps = as4_path.path_segments[i];
554 10 : ps4->path_segment_type = ps->path_segment_type;
555 10 : if (ps->path_segment_type == As4PathSpec::PathSegment::AS_SET) {
556 0 : new_as_count++;
557 0 : for (size_t j = 0; j < ps->path_segment.size(); ++j) {
558 0 : as2_t as = ps->path_segment[j];
559 0 : ps4->path_segment.push_back(as);
560 : }
561 : } else {
562 40 : for (size_t j = 0; j < ps->path_segment.size(); ++j) {
563 30 : as_t as = ps->path_segment[j];
564 30 : ps4->path_segment.push_back(as);
565 : }
566 : }
567 10 : aspath_4byte->path_segments.push_back(ps4);
568 : }
569 10 : attr->set_as4_path(NULL);
570 : }
571 32 : attr->set_as_path(NULL);
572 : }
573 77 : if (local_as) {
574 73 : std::unique_ptr<AsPath4ByteSpec> as_path_spec(aspath_4byte->Add(local_as));
575 73 : attr->set_aspath_4byte(as_path_spec.get());
576 73 : } else {
577 4 : attr->set_aspath_4byte(aspath_4byte.get());
578 : }
579 77 : }
580 :
581 896785 : UpdateInfo *BgpTable::GetUpdateInfo(RibOut *ribout, BgpRoute *route,
582 : const RibPeerSet &peerset) {
583 896785 : const BgpPath *path = route->BestPath();
584 :
585 : // Ignore if there is no best-path.
586 896811 : if (!path)
587 16 : return NULL;
588 :
589 : // Don't advertise infeasible paths.
590 896795 : if (!path->IsFeasible())
591 3158 : return NULL;
592 :
593 : // Check whether the route is contributing route
594 893622 : if (IsRouteAggregationSupported() && IsContributingRoute(route))
595 7 : return NULL;
596 :
597 : // Needs to be outside the if block so it's not destroyed prematurely.
598 893585 : BgpAttrPtr attr_ptr;
599 893585 : const BgpAttr *attr = path->GetAttr();
600 :
601 893592 : RibPeerSet new_peerset = peerset;
602 :
603 : // LocalPref, Med and AsPath manipulation is needed only if the RibOut
604 : // has BGP encoding. Similarly, well-known communities do not apply if
605 : // the encoding is not BGP.
606 893498 : if (ribout->IsEncodingBgp()) {
607 : // Handle well-known communities.
608 448148 : if (attr->community() != NULL &&
609 7199 : attr->community()->communities().size()) {
610 21448 : BOOST_FOREACH(uint32_t value, attr->community()->communities()) {
611 7224 : if (value == CommunityType::NoAdvertise)
612 99 : return NULL;
613 :
614 11864 : if ((ribout->peer_type() == BgpProto::EBGP) &&
615 4696 : ((value == CommunityType::NoExport) ||
616 : (value == CommunityType::NoExportSubconfed))) {
617 43 : return NULL;
618 : }
619 : }
620 : }
621 :
622 440846 : const IPeer *peer = path->GetPeer();
623 440840 : BgpAttr *clone = NULL;
624 447938 : bool llgr_stale_comm = attr->community() &&
625 7099 : attr->community()->ContainsValue(CommunityType::LlgrStale);
626 440840 : if (ribout->peer_type() == BgpProto::IBGP) {
627 : // Split horizon check.
628 86746 : if (peer && peer->CheckSplitHorizon(server()->cluster_id(),
629 : ribout->cluster_id()))
630 37307 : return NULL;
631 :
632 : // Handle route-target filtering.
633 49444 : if (IsVpnTable() && attr->ext_community() != NULL) {
634 23616 : server()->rtarget_group_mgr()->GetRibOutInterestedPeers(
635 : ribout, attr->ext_community(), peerset, &new_peerset);
636 23616 : if (new_peerset.empty())
637 4905 : return NULL;
638 : }
639 :
640 44539 : if (server()->cluster_id()) {
641 : // Check if there is a loop in cluster_list
642 8 : if (attr->cluster_list() && attr->cluster_list()->cluster_list()
643 0 : .ClusterListLoop(server()->cluster_id())) {
644 0 : return NULL;
645 : }
646 : }
647 :
648 44538 : if (server()->cluster_id() && (family() != Address::RTARGET)) {
649 : // route reflector should not reflect the route back to the peer
650 : // from which it received that route, for non rtarget routes
651 : // This is done by checking peer_router_id of all the feasible
652 : // paths of this route
653 8 : RibPeerSet route_peerset;
654 16 : for (Route::PathList::iterator it= route->GetPathList().begin();
655 32 : it != route->GetPathList().end(); it++) {
656 8 : BgpPath *ipath = static_cast<BgpPath *>(it.operator->());
657 8 : if (ipath->IsFeasible() && ipath->GetPeer()) {
658 8 : const IPeer *ipeer = ipath->GetPeer();
659 8 : const BgpPeer *bgp_peer = dynamic_cast<
660 8 : const BgpPeer *>(ipeer);
661 8 : if (bgp_peer)
662 2 : route_peerset.set(bgp_peer->GetIndex());
663 : }
664 : }
665 8 : RibOut::PeerIterator iter(ribout, new_peerset);
666 30 : while (iter.HasNext()) {
667 22 : int current_index = iter.index();
668 22 : IPeerUpdate *peer = iter.Next();
669 22 : const BgpPeer *bgp_peer = dynamic_cast<
670 22 : const BgpPeer *>(peer);
671 22 : if (bgp_peer && route_peerset.test(bgp_peer->GetIndex()))
672 2 : new_peerset.reset(current_index);
673 : }
674 8 : if (new_peerset.empty())
675 0 : return NULL;
676 8 : }
677 :
678 44538 : clone = new BgpAttr(*attr);
679 :
680 : // Retain LocalPref value if set, else set default to 100.
681 44540 : if (clone->local_pref() == 0)
682 0 : clone->set_local_pref(100);
683 :
684 : // Check aggregator attributes to identify which ones to be used
685 44540 : CheckAggregatorAttr(clone);
686 :
687 : // Should not normally be needed for iBGP, but there could be
688 : // complex configurations where this is useful.
689 44539 : ProcessRemovePrivate(ribout, clone);
690 :
691 : // Add Originator_Id if acting as route reflector and cluster_id
692 : // is not present
693 44539 : if (server()->cluster_id()) {
694 8 : if (clone->originator_id().is_unspecified()) {
695 8 : if (peer && (peer->bgp_identifier() != 0)) {
696 2 : clone->set_originator_id(Ip4Address(
697 2 : peer->bgp_identifier()));
698 : } else {
699 6 : clone->set_originator_id(Ip4Address(
700 : server()->bgp_identifier()));
701 : }
702 : }
703 8 : if (attr->cluster_list()) {
704 : const ClusterListSpec &cluster =
705 0 : clone->cluster_list()->cluster_list();
706 : ClusterListSpec *cl_ptr = new ClusterListSpec(
707 0 : server()->cluster_id(), &cluster);
708 0 : clone->set_cluster_list(cl_ptr);
709 0 : delete cl_ptr;
710 : } else {
711 : ClusterListSpec *cl_ptr = new ClusterListSpec(
712 8 : server()->cluster_id(), NULL);
713 8 : clone->set_cluster_list(cl_ptr);
714 8 : delete cl_ptr;
715 : }
716 : }
717 : // If the route is locally originated i.e. there's no AsPath,
718 : // then generate a Nil AsPath i.e. one with 0 length. No need
719 : // to modify the AsPath if it already exists since this is an
720 : // iBGP RibOut.
721 44539 : if (ribout->as4_supported() && !clone->aspath_4byte()) {
722 53 : if (attr->as_path()) {
723 4 : CreateAsPath4Byte(clone, 0);
724 : } else {
725 49 : AsPath4ByteSpec as_path;
726 49 : clone->set_aspath_4byte(&as_path);
727 49 : }
728 : }
729 44539 : if (!ribout->as4_supported() && !clone->as_path()) {
730 40778 : if (attr->aspath_4byte()) {
731 16 : CreateAsPath2Byte(clone);
732 : } else {
733 40762 : AsPathSpec as_path;
734 40761 : clone->set_as_path(&as_path);
735 40762 : }
736 : }
737 354089 : } else if (ribout->peer_type() == BgpProto::EBGP) {
738 : // Don't advertise routes from non-master instances if there's
739 : // no nexthop. The ribout has to be for bgpaas-clients because
740 : // that's the only case with bgp peers in non-master instance.
741 356572 : if (!rtinstance_->IsMasterRoutingInstance() &&
742 2485 : ribout->nexthop().is_unspecified()) {
743 0 : return NULL;
744 : }
745 :
746 : // Handle route-target filtering.
747 354083 : if (IsVpnTable() && attr->ext_community() != NULL) {
748 296776 : server()->rtarget_group_mgr()->GetRibOutInterestedPeers(
749 : ribout, attr->ext_community(), peerset, &new_peerset);
750 296972 : if (new_peerset.empty())
751 13370 : return NULL;
752 : }
753 :
754 : // Sender side AS path loop check and split horizon within RibOut.
755 340899 : if (!ribout->as_override()) {
756 340844 : if (attr->IsAsPathLoop(ribout->peer_as()))
757 137386 : return NULL;
758 : } else {
759 60 : if (peer && peer->PeerType() == BgpProto::EBGP) {
760 40 : ribout->GetSubsetPeerSet(&new_peerset, peer);
761 40 : if (new_peerset.empty())
762 0 : return NULL;
763 : }
764 : }
765 :
766 203500 : clone = new BgpAttr(*attr);
767 :
768 : // Remove non-transitive attributes.
769 : // Note that med is handled further down.
770 203531 : clone->set_originator_id(Ip4Address());
771 203531 : clone->set_cluster_list(NULL);
772 :
773 : // Update nexthop.
774 203527 : if (!ribout->nexthop().is_unspecified())
775 1610 : clone->set_nexthop(ribout->nexthop());
776 :
777 : // Reset LocalPref.
778 203524 : if (clone->local_pref())
779 203523 : clone->set_local_pref(0);
780 :
781 : // Reset Med if the path did not originate from an xmpp peer.
782 : // The AS path is NULL if the originating xmpp peer is locally
783 : // connected. It's non-NULL but empty if the originating xmpp
784 : // peer is connected to another bgp speaker in the iBGP mesh.
785 203522 : if (clone->med() && !clone->IsAsPathEmpty())
786 366 : clone->set_med(0);
787 :
788 : // Override the peer AS with local AS in AsPath.
789 203523 : ProcessAsOverride(ribout, clone);
790 :
791 : // Remove private processing must happen before local AS prepend.
792 203521 : ProcessRemovePrivate(ribout, clone);
793 :
794 : // Prepend the local AS to AsPath.
795 203521 : PrependLocalAs(ribout, clone, peer);
796 : }
797 :
798 248073 : assert(clone);
799 :
800 : // Update with the Default tunnel Encapsulation ordered List if
801 : // configured on the peer.
802 : // Note that all peers with the same list share the same Ribout, this is
803 : // ensured by making the Default Encapsulation List part of the Rib
804 : // Export policy.Note that, if there is Default Tunnel Encapsulation
805 : // configuration any tunnel encapsulation present is removed.
806 248073 : ProcessDefaultTunnelEncapsulation(ribout, server()->extcomm_db(),
807 : clone);
808 :
809 248073 : ProcessLlgrState(ribout, path, clone, llgr_stale_comm);
810 :
811 : // Locate the new BgpAttrPtr.
812 248068 : attr_ptr = clone->attr_db()->Locate(clone);
813 248073 : attr = attr_ptr.get();
814 : }
815 :
816 700617 : UpdateInfo *uinfo = new UpdateInfo;
817 700749 : uinfo->target = new_peerset;
818 700716 : uinfo->roattr = RibOutAttr(route, attr, ribout->IsEncodingXmpp());
819 700979 : return uinfo;
820 894046 : }
821 :
822 : // Bgp Path selection..
823 : // Based Attribute weight
824 1808639 : bool BgpTable::PathSelection(const Path &path1, const Path &path2) {
825 1808639 : const BgpPath &l_path = dynamic_cast<const BgpPath &> (path1);
826 1808642 : const BgpPath &r_path = dynamic_cast<const BgpPath &> (path2);
827 :
828 : // Check the weight of Path
829 1808642 : bool res = l_path.PathCompare(r_path, false) < 0;
830 :
831 1808634 : return res;
832 : }
833 :
834 65 : bool BgpTable::DeletePath(DBTablePartBase *root, BgpRoute *rt, BgpPath *path) {
835 130 : return InputCommon(root, rt, path, path->GetPeer(), NULL,
836 130 : DBRequest::DB_ENTRY_DELETE, NULL, path->GetPathId(), 0, 0, 0);
837 : }
838 :
839 539163 : bool BgpTable::InputCommon(DBTablePartBase *root, BgpRoute *rt, BgpPath *path,
840 : const IPeer *peer, DBRequest *req,
841 : DBRequest::DBOperation oper, BgpAttrPtr attrs,
842 : uint32_t path_id, uint32_t flags, uint32_t label,
843 : uint32_t l3_label) {
844 539163 : bool notify_rt = false;
845 :
846 539163 : switch (oper) {
847 288226 : case DBRequest::DB_ENTRY_ADD_CHANGE: {
848 288226 : assert(rt);
849 :
850 : // The entry may currently be marked as deleted.
851 288226 : rt->ClearDelete();
852 288223 : if (peer)
853 244179 : peer->UpdateCloseRouteStats(family(), path, flags);
854 :
855 : // Check whether peer already has a path.
856 288221 : if (path != NULL) {
857 57556 : if ((path->GetAttr() != attrs.get()) ||
858 22724 : (path->GetFlags() != flags) ||
859 59915 : (path->GetLabel() != label) ||
860 2241 : (path->GetL3Label() != l3_label)) {
861 : // Update Attributes and notify (if needed)
862 34954 : if (path->NeedsResolution())
863 1362 : path_resolver_->StopPathResolution(root->index(), path);
864 34954 : rt->DeletePath(path);
865 : } else {
866 : // Ignore duplicate update.
867 2237 : break;
868 : }
869 : }
870 :
871 : BgpPath *new_path;
872 571977 : new_path = new BgpPath(
873 285995 : peer, path_id, BgpPath::BGP_XMPP, attrs, flags, label, l3_label);
874 :
875 : // Start path resolution for the new path if
876 : // (1) Path flag has ResolveNextHop set in which case the path will
877 : // be resolved in the overlay routing table (or)
878 : // (2) Fast convergence knob is enabled in which case the path will
879 : // be marked for resolution in the underlay (default) routing table
880 : // (3) Path resolution in this case is needed only for routes
881 : // in the VRF routing tables and for INET, INET6 and EVPN
882 : // address families.
883 285995 : bool fc_family = false;
884 518748 : if (family() == Address::INET || family() == Address::INET6 ||
885 232758 : family() == Address::EVPN) {
886 99605 : fc_family = true;
887 : }
888 285983 : bool fc_enabled = (server()->IsNextHopCheckEnabled() &&
889 285965 : !rtinstance_->IsMasterRoutingInstance() && fc_family);
890 285965 : if (new_path->NeedsResolution() || fc_enabled) {
891 2910 : if (peer && !(peer->IsXmppPeer()) ) {
892 2786 : rt->add_peer_sources(peer->ToString());
893 : }
894 2910 : Address::Family family = new_path->GetAttr()->nexthop_family();
895 : BgpTable *table;
896 2910 : if (new_path->NeedsResolution()) {
897 2804 : table = rtinstance_->GetTable(family);
898 : } else {
899 : // Fast convergence knob is enabled.
900 : // Update path flag to indicate need for resolution.
901 106 : new_path->SetResolveNextHop();
902 :
903 : // Get the default table.
904 106 : RoutingInstanceMgr *mgr = server()->routing_instance_mgr();
905 106 : assert(mgr);
906 106 : RoutingInstance *master_ri = mgr->GetDefaultRoutingInstance();
907 106 : assert(master_ri);
908 106 : table = master_ri->GetTable(family);
909 : }
910 2910 : path_resolver_->StartPathResolution(rt, new_path, table);
911 : }
912 :
913 285962 : rt->InsertPath(new_path);
914 285987 : notify_rt = true;
915 285987 : break;
916 : }
917 :
918 250938 : case DBRequest::DB_ENTRY_DELETE: {
919 250938 : if (rt && !rt->IsDeleted()) {
920 250922 : if (peer && !(peer->IsXmppPeer()) ) {
921 154094 : rt->del_peer_sources(peer->ToString());
922 : }
923 273249 : BGP_LOG_ROUTE(this, const_cast<IPeer *>(peer), rt,
924 : "Delete BGP path");
925 :
926 : // Remove the Path from the route
927 250930 : if (path->NeedsResolution())
928 1548 : path_resolver_->StopPathResolution(root->index(), path);
929 250927 : rt->DeletePath(path);
930 250992 : notify_rt = true;
931 : }
932 251003 : break;
933 : }
934 :
935 0 : default: {
936 0 : assert(false);
937 : break;
938 : }
939 : }
940 539227 : return notify_rt;
941 : }
942 :
943 466268 : void BgpTable::Input(DBTablePartition *root, DBClient *client,
944 : DBRequest *req) {
945 466268 : const IPeer *peer = (static_cast<RequestKey *>(req->key.get()))->GetPeer();
946 466161 : RequestData *data = static_cast<RequestData *>(req->data.get());
947 :
948 466101 : if (req->oper == DBRequest::DB_ENTRY_ADD_CHANGE && peer) {
949 : // Skip if this peer is down.
950 239415 : if (!peer->IsReady())
951 21943 : return;
952 :
953 : // For xmpp peers, verify that agent is subscribed to the table and
954 : // the route add is from the same incarnation of table subscription.
955 229480 : if (peer->IsXmppPeer() && peer->IsRegistrationRequired()) {
956 59318 : BgpMembershipManager *mgr = rtinstance_->server()->membership_mgr();
957 59318 : int instance_id = -1;
958 59318 : uint64_t subscription_gen_id = 0;
959 : bool is_registered =
960 59318 : mgr->GetRegistrationInfo(const_cast<IPeer *>(peer), this,
961 : &instance_id, &subscription_gen_id);
962 86342 : if ((!is_registered && (family() != Address::RTARGET)) ||
963 27024 : (is_registered &&
964 27024 : (subscription_gen_id != data->subscription_gen_id()))) {
965 3 : return;
966 : }
967 : }
968 : }
969 :
970 : // Create route if it's not already present in case of add/change.
971 456163 : BgpRoute *rt = TableFind(root, req->key.get());
972 456109 : if (!rt) {
973 223737 : if ((req->oper == DBRequest::DB_ENTRY_DELETE) ||
974 213087 : (req->oper == DBRequest::DB_ENTRY_NOTIFY))
975 11025 : return;
976 :
977 212712 : rt = static_cast<BgpRoute *>(Add(req));
978 212674 : static_cast<DBTablePartition *>(root)->Add(rt);
979 230511 : BGP_LOG_ROUTE(this, const_cast<IPeer *>(peer), rt,
980 : "Insert new BGP path");
981 : }
982 :
983 445150 : if (req->oper == DBRequest::DB_ENTRY_NOTIFY) {
984 419 : root->Notify(rt);
985 419 : return;
986 : }
987 :
988 444731 : uint32_t path_id = 0;
989 444731 : uint32_t flags = 0;
990 444731 : uint32_t label = 0;
991 444731 : uint32_t l3_label = 0;
992 444731 : BgpPath *path = rt->FindPath(peer);
993 444807 : BgpAttrPtr attr = data ? data->attrs() : NULL;
994 444838 : if (req->oper == DBRequest::DB_ENTRY_ADD_CHANGE) {
995 273529 : assert(data);
996 273529 : const RequestData::NextHop &nexthop = data->nexthop();
997 273526 : if (nexthop.address_.is_v4())
998 268951 : path_id = nexthop.address_.to_v4().to_ulong();
999 273508 : flags = nexthop.flags_;
1000 273508 : label = nexthop.label_;
1001 273508 : l3_label = nexthop.l3_label_;
1002 :
1003 273508 : attr = GetAttributes(rt, attr, peer);
1004 : } else {
1005 171309 : if (!path)
1006 551 : return;
1007 170758 : path_id = path->GetPathId();
1008 : }
1009 :
1010 444269 : bool notify_rt = InputCommon(root, rt, path, peer, req, req->oper,
1011 : attr, path_id, flags, label, l3_label);
1012 444311 : InputCommonPostProcess(root, rt, notify_rt);
1013 444773 : }
1014 :
1015 935706 : void BgpTable::InputCommonPostProcess(DBTablePartBase *root,
1016 : BgpRoute *rt, bool notify_rt) {
1017 935706 : if (!notify_rt)
1018 399233 : return;
1019 :
1020 536473 : if (rt->front() == NULL)
1021 213102 : root->Delete(rt);
1022 : else
1023 323326 : root->Notify(rt);
1024 : }
1025 :
1026 294942 : bool BgpTable::MayDelete() const {
1027 294942 : CHECK_CONCURRENCY("bgp::Config");
1028 :
1029 : // Bail if the table has listeners.
1030 294942 : if (HasListeners()) {
1031 6336 : BGP_LOG_TABLE(this, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_ALL,
1032 : "Paused table deletion due to pending listeners");
1033 6336 : return false;
1034 : }
1035 :
1036 : // Bail if the table has walkers.
1037 288606 : if (HasWalkers()) {
1038 0 : BGP_LOG_TABLE(this, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_ALL,
1039 : "Paused table deletion due to pending walkers");
1040 0 : return false;
1041 : }
1042 :
1043 : // Bail if the table is not empty.
1044 288606 : size_t size = Size();
1045 288606 : if (size > 0) {
1046 14 : BGP_LOG_TABLE(this, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_ALL,
1047 : "Paused table deletion due to " << size <<
1048 : " pending routes");
1049 14 : return false;
1050 : }
1051 :
1052 : // Check the base class at the end so that we add custom checks
1053 : // before this if needed and to get more informative log message.
1054 288592 : if (!DBTableBase::MayDelete())
1055 0 : return false;
1056 :
1057 288592 : return true;
1058 : }
1059 :
1060 288592 : void BgpTable::Shutdown() {
1061 288592 : CHECK_CONCURRENCY("bgp::PeerMembership", "bgp::Config");
1062 288592 : }
1063 :
1064 288592 : void BgpTable::ManagedDelete() {
1065 288592 : BGP_LOG_TABLE(this, SandeshLevel::SYS_INFO, BGP_LOG_FLAG_ALL,
1066 : "Received request for table deletion");
1067 288592 : deleter_->Delete();
1068 288592 : }
1069 :
1070 : //
1071 : // Retry deletion of the table if it is pending.
1072 : //
1073 575791 : void BgpTable::RetryDelete() {
1074 575791 : if (!deleter()->IsDeleted())
1075 256834 : return;
1076 318952 : deleter()->RetryDelete();
1077 : }
1078 :
1079 0 : PathResolver *BgpTable::CreatePathResolver() {
1080 0 : return NULL;
1081 : }
1082 :
1083 172723 : void BgpTable::LocatePathResolver() {
1084 172723 : if (path_resolver_)
1085 1102 : return;
1086 171621 : assert(!deleter()->IsDeleted());
1087 171627 : path_resolver_ = CreatePathResolver();
1088 : }
1089 :
1090 171632 : void BgpTable::DestroyPathResolver() {
1091 171632 : if (!path_resolver_)
1092 0 : return;
1093 171632 : delete path_resolver_;
1094 171632 : path_resolver_ = NULL;
1095 : }
1096 :
1097 14097 : size_t BgpTable::GetPendingRiboutsCount(size_t *markers) const {
1098 14097 : CHECK_CONCURRENCY("bgp::ShowCommand", "bgp::Config");
1099 14097 : size_t count = 0;
1100 14097 : *markers = 0;
1101 :
1102 18737 : BOOST_FOREACH(const RibOutMap::value_type &value, ribout_map_) {
1103 2320 : const RibOut *ribout = value.second;
1104 10331 : for (int idx = 0; idx < DB::PartitionCount(); ++idx) {
1105 8011 : const RibOutUpdates *updates = ribout->updates(idx);
1106 24033 : for (int qid = RibOutUpdates::QFIRST; qid < RibOutUpdates::QCOUNT;
1107 : ++qid) {
1108 16022 : count += updates->queue_size(qid);
1109 16022 : *markers += updates->queue_marker_count(qid);
1110 : }
1111 : }
1112 : }
1113 :
1114 14097 : return count;
1115 : }
1116 :
1117 2075948 : LifetimeActor *BgpTable::deleter() {
1118 2075948 : return deleter_.get();
1119 : }
1120 :
1121 292158 : const LifetimeActor *BgpTable::deleter() const {
1122 292158 : return deleter_.get();
1123 : }
1124 :
1125 1930456 : void BgpTable::UpdatePathCount(const BgpPath *path, int count) {
1126 1930456 : if (dynamic_cast<const BgpSecondaryPath *>(path)) {
1127 1157686 : secondary_path_count_ += count;
1128 : } else {
1129 772770 : primary_path_count_ += count;
1130 : }
1131 :
1132 1931561 : if (!path->IsFeasible()) {
1133 8666 : infeasible_path_count_ += count;
1134 : }
1135 :
1136 1931466 : if (path->IsStale()) {
1137 90512 : stale_path_count_ += count;
1138 : }
1139 :
1140 1931403 : if (path->IsLlgrStale()) {
1141 20119 : llgr_stale_path_count_ += count;
1142 : }
1143 1931271 : }
1144 :
1145 : // Check whether the route is aggregate route
1146 0 : bool BgpTable::IsAggregateRoute(const BgpRoute *route) const {
1147 0 : return routing_instance()->IsAggregateRoute(this, route);
1148 : }
1149 :
1150 : // Check whether the route is contributing route to aggregate route
1151 920515 : bool BgpTable::IsContributingRoute(const BgpRoute *route) const {
1152 920515 : return routing_instance()->IsContributingRoute(this, route);
1153 : }
1154 :
1155 18 : void BgpTable::FillRibOutStatisticsInfo(
1156 : vector<ShowRibOutStatistics> *sros_list) const {
1157 22 : BOOST_FOREACH(const RibOutMap::value_type &value, ribout_map_) {
1158 2 : const RibOut *ribout = value.second;
1159 2 : ribout->FillStatisticsInfo(sros_list);
1160 : }
1161 18 : }
|