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 768 : explicit DeleteActor(BgpTable *table)
34 768 : : LifetimeActor(table->rtinstance_->server()->lifetime_manager()),
35 768 : table_(table) {
36 768 : }
37 1536 : virtual ~DeleteActor() {
38 1536 : }
39 778 : virtual bool MayDelete() const {
40 778 : return table_->MayDelete();
41 : }
42 :
43 768 : virtual void Shutdown() {
44 768 : table_->Shutdown();
45 768 : }
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 768 : virtual void Destroy() {
51 768 : table_->rtinstance_->DestroyDBTable(table_);
52 768 : }
53 :
54 : private:
55 : BgpTable *table_;
56 : };
57 :
58 766 : BgpTable::BgpTable(DB *db, const string &name)
59 : : RouteTable(db, name),
60 767 : rtinstance_(NULL),
61 767 : path_resolver_(NULL),
62 766 : instance_delete_ref_(this, NULL) {
63 767 : primary_path_count_ = 0;
64 768 : secondary_path_count_ = 0;
65 768 : infeasible_path_count_ = 0;
66 768 : stale_path_count_ = 0;
67 768 : llgr_stale_path_count_ = 0;
68 768 : }
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 768 : BgpTable::~BgpTable() {
76 768 : assert(path_resolver_ == NULL),
77 768 : instance_delete_ref_.Reset(NULL);
78 768 : }
79 :
80 768 : void BgpTable::set_routing_instance(RoutingInstance *rtinstance) {
81 768 : rtinstance_ = rtinstance;
82 768 : assert(rtinstance);
83 768 : deleter_.reset(new DeleteActor(this));
84 767 : instance_delete_ref_.Reset(rtinstance->deleter());
85 767 : }
86 :
87 4242 : BgpServer *BgpTable::server() {
88 4242 : return rtinstance_->server();
89 : }
90 :
91 90 : const BgpServer *BgpTable::server() const {
92 90 : return rtinstance_->server();
93 : }
94 :
95 : //
96 : // Find the RibOut for the given RibExportPolicy.
97 : //
98 0 : RibOut *BgpTable::RibOutFind(const RibExportPolicy &policy) {
99 0 : RibOutMap::iterator loc = ribout_map_.find(policy);
100 0 : 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 144 : RibOut *BgpTable::RibOutLocate(BgpUpdateSender *sender,
109 : const RibExportPolicy &policy) {
110 144 : RibOutMap::iterator loc = ribout_map_.find(policy);
111 144 : if (loc == ribout_map_.end()) {
112 144 : RibOut *ribout = new RibOut(this, sender, policy);
113 144 : ribout_map_.insert(make_pair(policy, ribout));
114 144 : return ribout;
115 : }
116 0 : 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 144 : void BgpTable::RibOutDelete(const RibExportPolicy &policy) {
124 144 : RibOutMap::iterator loc = ribout_map_.find(policy);
125 144 : assert(loc != ribout_map_.end());
126 144 : delete loc->second;
127 144 : ribout_map_.erase(loc);
128 144 : }
129 :
130 : // If both as2 and as4 aggregators are present then we need to choose one
131 250 : void BgpTable::CheckAggregatorAttr(BgpAttr *attr) const {
132 250 : if (attr->aggregator_as_num() && attr->aggregator_as4_num()) {
133 0 : 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 0 : attr->set_as4_path(NULL);
137 0 : attr->set_as4_aggregator(0, attr->aggregator_adderess());
138 : } else {
139 : // If as2 aggregator is as_trans then we use as4 aggregator
140 0 : attr->set_aggregator(attr->aggregator_as4_num(),
141 0 : attr->aggregator_adderess());
142 0 : attr->set_as4_aggregator(0, attr->aggregator_adderess());
143 : }
144 : }
145 250 : }
146 :
147 90 : void BgpTable::PrependLocalAs(const RibOut *ribout, BgpAttr *clone,
148 : const IPeer* peer) const {
149 90 : CheckAggregatorAttr(clone);
150 90 : as_t local_as = ribout->local_as() ?:
151 0 : clone->attr_db()->server()->local_autonomous_system();
152 90 : if (!server()->enable_4byte_as())
153 45 : return PrependAsToAsPath2Byte(clone, (as2_t)local_as);
154 45 : if (ribout->as4_supported()) {
155 45 : if (clone->aspath_4byte())
156 0 : PrependAsToAsPath4Byte(clone, local_as);
157 : else
158 45 : CreateAsPath4Byte(clone, local_as);
159 : } else {
160 0 : if (!clone->as_path())
161 0 : CreateAsPath2Byte(clone);
162 0 : PrependAsToAsPath2Byte(clone, local_as);
163 : }
164 : }
165 :
166 0 : void BgpTable::RemovePrivateAs(const RibOut *ribout, BgpAttr *attr) const {
167 0 : bool all = ribout->remove_private_all();
168 0 : bool replace = ribout->remove_private_replace();
169 0 : bool peer_loop_check = ribout->remove_private_peer_loop_check();
170 :
171 0 : const AsPathSpec &spec = attr->as_path()->path();
172 0 : as_t peer_asn = peer_loop_check ? ribout->peer_as() : 0;
173 0 : as_t replace_asn = 0;
174 0 : if (replace) {
175 0 : if (ribout->peer_type() == BgpProto::EBGP) {
176 0 : replace_asn = server()->local_autonomous_system();
177 : } else {
178 0 : replace_asn = spec.AsLeftMostPublic();
179 : }
180 : }
181 0 : if (replace_asn > AS2_MAX) {
182 0 : if (!attr->as4_path())
183 0 : CreateAs4Path(attr);
184 0 : const As4PathSpec &spec = attr->as4_path()->path();
185 0 : As4PathSpec *new_spec = spec.RemovePrivate(all, replace_asn, peer_asn);
186 0 : attr->set_as4_path(new_spec);
187 0 : delete new_spec;
188 0 : replace_asn = AS_TRANS;
189 : }
190 0 : if (peer_asn > AS2_MAX)
191 0 : peer_asn = AS_TRANS;
192 :
193 0 : AsPathSpec *new_spec = spec.RemovePrivate(all, replace_asn, peer_asn);
194 0 : attr->set_as_path(new_spec);
195 0 : delete new_spec;
196 0 : }
197 :
198 0 : void BgpTable::RemovePrivate4ByteAs(const RibOut *ribout, BgpAttr *attr) const {
199 0 : bool all = ribout->remove_private_all();
200 0 : bool replace = ribout->remove_private_replace();
201 0 : bool peer_loop_check = ribout->remove_private_peer_loop_check();
202 :
203 0 : const AsPath4ByteSpec &spec = attr->aspath_4byte()->path();
204 0 : as_t peer_asn = peer_loop_check ? ribout->peer_as() : 0;
205 0 : as_t replace_asn = 0;
206 0 : if (replace) {
207 0 : if (ribout->peer_type() == BgpProto::EBGP) {
208 0 : replace_asn = server()->local_autonomous_system();
209 : } else {
210 0 : replace_asn = spec.AsLeftMostPublic();
211 : }
212 : }
213 :
214 0 : AsPath4ByteSpec *new_spec = spec.RemovePrivate(all, replace_asn, peer_asn);
215 0 : attr->set_aspath_4byte(new_spec);
216 0 : delete new_spec;
217 0 : }
218 :
219 0 : void BgpTable::RemovePrivateAs4(const RibOut *ribout, BgpAttr *attr) const {
220 0 : bool all = ribout->remove_private_all();
221 0 : bool replace = ribout->remove_private_replace();
222 0 : bool peer_loop_check = ribout->remove_private_peer_loop_check();
223 :
224 0 : const As4PathSpec &spec = attr->as4_path()->path();
225 0 : as_t peer_asn = peer_loop_check ? ribout->peer_as() : 0;
226 0 : as_t replace_asn = 0;
227 0 : if (replace) {
228 0 : if (ribout->peer_type() == BgpProto::EBGP) {
229 0 : replace_asn = server()->local_autonomous_system();
230 : } else {
231 0 : replace_asn = spec.AsLeftMostPublic();
232 : }
233 : }
234 :
235 0 : As4PathSpec *new_spec = spec.RemovePrivate(all, replace_asn, peer_asn);
236 0 : attr->set_as4_path(new_spec);
237 0 : delete new_spec;
238 0 : }
239 :
240 : //
241 : // Process Remove Private information.
242 : //
243 250 : void BgpTable::ProcessRemovePrivate(const RibOut *ribout, BgpAttr *attr) const {
244 250 : if (!ribout->IsEncodingBgp())
245 0 : return;
246 250 : if (!ribout->remove_private_enabled())
247 250 : return;
248 :
249 0 : if (attr->as_path())
250 0 : RemovePrivateAs(ribout, attr);
251 0 : if (attr->aspath_4byte())
252 0 : RemovePrivate4ByteAs(ribout, attr);
253 0 : if (attr->as4_path())
254 0 : RemovePrivateAs4(ribout, attr);
255 : }
256 :
257 : //
258 : // Process Remove Private information.
259 : //
260 90 : void BgpTable::ProcessAsOverride(const RibOut *ribout, BgpAttr *attr) const {
261 90 : if (ribout->as_override() && !attr->IsAsPathEmpty()) {
262 0 : as_t replace_as = ribout->local_as() ?:
263 0 : attr->attr_db()->server()->local_autonomous_system();
264 0 : if (attr->as_path()) {
265 0 : const AsPathSpec &as_path = attr->as_path()->path();
266 : // If peer_as is > 0xffff, it can't be in as_path
267 0 : if (ribout->peer_as() <= AS2_MAX) {
268 0 : 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 0 : if (!attr->as4_path()) {
272 0 : CreateAs4Path(attr);
273 : }
274 0 : replace_as = AS_TRANS;
275 : }
276 0 : AsPathSpec *as_path_ptr = as_path.Replace(
277 0 : ribout->peer_as(), replace_as);
278 0 : attr->set_as_path(as_path_ptr);
279 0 : delete as_path_ptr;
280 : }
281 0 : if (attr->as4_path()) {
282 0 : As4PathSpec *as_path_ptr = attr->as4_path()->path().Replace(
283 : ribout->peer_as(), replace_as);
284 0 : attr->set_as4_path(as_path_ptr);
285 0 : delete as_path_ptr;
286 : }
287 : }
288 0 : if (attr->aspath_4byte()) {
289 0 : const AsPath4ByteSpec &as_path = attr->aspath_4byte()->path();
290 : AsPath4ByteSpec *as_path_ptr =
291 0 : as_path.Replace(ribout->peer_as(), replace_as);
292 0 : attr->set_aspath_4byte(as_path_ptr);
293 0 : delete as_path_ptr;
294 : }
295 : }
296 90 : }
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 250 : void BgpTable::ProcessLlgrState(const RibOut *ribout, const BgpPath *path,
306 : BgpAttr *attr, bool llgr_stale_comm) {
307 250 : if (!server() || !server()->comm_db())
308 0 : return;
309 :
310 : // Skip LLGR specific attributes manipulation for rtarget routes.
311 250 : if (family() == Address::RTARGET)
312 0 : 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 250 : if (!path->IsLlgrStale() && !llgr_stale_comm)
317 250 : return;
318 :
319 : // If peers support LLGR, then attach LLGR_STALE community and return.
320 0 : if (ribout->llgr()) {
321 0 : if (!llgr_stale_comm) {
322 : CommunityPtr comm = server()->comm_db()->AppendAndLocate(
323 0 : attr->community(), CommunityType::LlgrStale);
324 0 : attr->set_community(comm);
325 0 : }
326 0 : return;
327 : }
328 :
329 : // Peers do not understand LLGR. Bring down local preference instead to
330 : // make the advertised path less preferred.
331 0 : attr->set_local_pref(0);
332 :
333 : // Remove LLGR_STALE community as the peers do not support LLGR.
334 0 : if (llgr_stale_comm) {
335 : CommunityPtr comm = server()->comm_db()->RemoveAndLocate(
336 0 : attr->community(), CommunityType::LlgrStale);
337 0 : attr->set_community(comm);
338 0 : }
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 0 : if (!attr->community() ||
343 0 : !attr->community()->ContainsValue(CommunityType::NoExport)) {
344 : CommunityPtr comm = server()->comm_db()->AppendAndLocate(
345 0 : attr->community(), CommunityType::NoExport);
346 0 : attr->set_community(comm);
347 0 : }
348 : }
349 :
350 250 : void BgpTable::ProcessDefaultTunnelEncapsulation(const RibOut *ribout,
351 : ExtCommunityDB *extcomm_db, BgpAttr *attr) const {
352 250 : if (!ribout->ExportPolicy().default_tunnel_encap_list.empty()) {
353 0 : ExtCommunity::ExtCommunityList encap_list;
354 0 : BOOST_FOREACH(const string &encap_string,
355 : ribout->ExportPolicy().default_tunnel_encap_list) {
356 0 : TunnelEncap tunnel_encap(encap_string);
357 0 : encap_list.push_back(tunnel_encap.GetExtCommunity());
358 : }
359 0 : ExtCommunityPtr ext_community = attr->ext_community();
360 : ext_community =
361 0 : extcomm_db->ReplaceTunnelEncapsulationAndLocate(
362 0 : ext_community.get(), encap_list);
363 0 : attr->set_ext_community(ext_community);
364 0 : }
365 250 : }
366 :
367 45 : void BgpTable::PrependAsToAsPath2Byte(BgpAttr *attr, as2_t asn) const {
368 45 : if (attr->as_path()) {
369 0 : const AsPathSpec &as_path = attr->as_path()->path();
370 0 : AsPathSpec *as_path_ptr = as_path.Add(asn);
371 0 : attr->set_as_path(as_path_ptr);
372 0 : delete as_path_ptr;
373 : } else {
374 45 : AsPathSpec as_path;
375 45 : AsPathSpec *as_path_ptr = as_path.Add(asn);
376 45 : attr->set_as_path(as_path_ptr);
377 45 : delete as_path_ptr;
378 45 : }
379 45 : }
380 :
381 0 : void BgpTable::PrependAsToAsPath2Byte(BgpAttr *attr, as_t asn) const {
382 0 : if (asn <= AS2_MAX) {
383 0 : if (attr->as_path() && attr->as4_path()) {
384 0 : PrependAsToAs4Path(attr, asn);
385 : }
386 0 : return PrependAsToAsPath2Byte(attr, static_cast<as2_t>(asn & AS2_MAX));
387 : }
388 0 : if (attr->as_path() && !attr->as4_path()) {
389 0 : CreateAs4Path(attr);
390 0 : assert(attr->as_path()->path().path_segments.size() ==
391 : attr->as4_path()->path().path_segments.size());
392 : }
393 0 : as2_t as_trans = AS_TRANS;
394 0 : PrependAsToAsPath2Byte(attr, as_trans);
395 0 : PrependAsToAs4Path(attr, asn);
396 : }
397 :
398 0 : void BgpTable::PrependAsToAsPath4Byte(BgpAttr *clone, as_t asn) const {
399 0 : if (clone->aspath_4byte()) {
400 0 : const AsPath4ByteSpec &as4_path = clone->aspath_4byte()->path();
401 0 : AsPath4ByteSpec *as4_path_ptr = as4_path.Add(asn);
402 0 : clone->set_aspath_4byte(as4_path_ptr);
403 0 : 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 0 : }
411 :
412 0 : void BgpTable::PrependAsToAs4Path(BgpAttr* attr, as_t asn) const {
413 0 : if (attr->as4_path()) {
414 0 : const As4PathSpec &as4_path = attr->as4_path()->path();
415 0 : As4PathSpec *as4_path_ptr = as4_path.Add(asn);
416 0 : attr->set_as4_path(as4_path_ptr);
417 0 : 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 0 : }
425 :
426 : // Create as4_path by copying data from as_path
427 0 : void BgpTable::CreateAs4Path(BgpAttr *attr) const {
428 0 : if (!attr->as_path()) {
429 0 : return;
430 : }
431 :
432 0 : std::unique_ptr<As4PathSpec> new_as_path(new As4PathSpec);
433 0 : const AsPathSpec &as_path = attr->as_path()->path();
434 0 : for (size_t i = 0; i < as_path.path_segments.size(); i++) {
435 0 : As4PathSpec::PathSegment *ps4 = new As4PathSpec::PathSegment;
436 0 : AsPathSpec::PathSegment *ps = as_path.path_segments[i];
437 0 : ps4->path_segment_type = ps->path_segment_type;
438 0 : for (size_t j = 0; j < ps->path_segment.size(); j++) {
439 0 : as_t as = ps->path_segment[j];
440 0 : ps4->path_segment.push_back(as);
441 : }
442 0 : new_as_path->path_segments.push_back(ps4);
443 : }
444 0 : attr->set_as4_path(new_as_path.get());
445 0 : }
446 :
447 : // Check if aspath_4byte has any asn > 0xFFFF
448 8 : bool BgpTable::Has4ByteAsn(BgpAttr *attr) const {
449 8 : if (!attr->aspath_4byte())
450 0 : return false;
451 8 : const AsPath4ByteSpec &as_path4 = attr->aspath_4byte()->path();
452 16 : for (size_t i = 0; i < as_path4.path_segments.size(); ++i) {
453 8 : AsPath4ByteSpec::PathSegment *ps4 = as_path4.path_segments[i];
454 16 : for (size_t j = 0; j < ps4->path_segment.size(); ++j) {
455 8 : if (ps4->path_segment[j] > AS2_MAX)
456 0 : return true;
457 : }
458 : }
459 8 : return false;
460 : }
461 :
462 : // Create as_path (and as4_path) from as_path4byte
463 8 : void BgpTable::CreateAsPath2Byte(BgpAttr *attr) const {
464 8 : std::unique_ptr<AsPathSpec> new_as_path(new AsPathSpec);
465 8 : As4PathSpec *new_as4_path = NULL;
466 8 : bool has_4byte_asn = Has4ByteAsn(attr);
467 8 : if (has_4byte_asn)
468 0 : new_as4_path = new As4PathSpec;
469 8 : if (attr->aspath_4byte()) {
470 8 : const AsPath4ByteSpec &as_path4 = attr->aspath_4byte()->path();
471 16 : for (size_t i = 0; i < as_path4.path_segments.size(); i++) {
472 8 : AsPathSpec::PathSegment *ps = new AsPathSpec::PathSegment;
473 8 : As4PathSpec::PathSegment *as4_ps = NULL;
474 8 : AsPath4ByteSpec::PathSegment *ps4 = as_path4.path_segments[i];
475 8 : ps->path_segment_type = ps4->path_segment_type;
476 8 : if (has_4byte_asn) {
477 0 : as4_ps = new As4PathSpec::PathSegment;
478 0 : as4_ps->path_segment_type = ps4->path_segment_type;
479 : }
480 16 : for (size_t j = 0; j < ps4->path_segment.size(); ++j) {
481 8 : as_t as4 = ps4->path_segment[j];
482 8 : if (as4 > AS2_MAX) {
483 0 : as2_t as_trans = AS_TRANS;
484 0 : ps->path_segment.push_back(as_trans);
485 : } else {
486 8 : ps->path_segment.push_back(static_cast<as2_t>(
487 : as4 & AS2_MAX));
488 : }
489 8 : if (has_4byte_asn)
490 0 : as4_ps->path_segment.push_back(as4);
491 : }
492 8 : new_as_path->path_segments.push_back(ps);
493 8 : if (has_4byte_asn)
494 0 : new_as4_path->path_segments.push_back(as4_ps);
495 : }
496 8 : attr->set_aspath_4byte(NULL);
497 : }
498 8 : attr->set_as_path(new_as_path.get());
499 8 : if (has_4byte_asn) {
500 0 : attr->set_as4_path(new_as4_path);
501 0 : delete new_as4_path;
502 : }
503 8 : }
504 :
505 : // Create aspath_4byte by merging as_path and as4_path
506 45 : void BgpTable::CreateAsPath4Byte(BgpAttr *attr, as_t local_as) const {
507 45 : int as2_count = attr->as_path_count();
508 45 : int as4_count = attr->as4_path_count();
509 45 : if (as2_count < as4_count) {
510 0 : as4_count = 0;
511 0 : attr->set_as4_path(NULL);
512 : }
513 45 : AsPath4ByteSpec::PathSegment *ps4 = NULL;
514 45 : bool part_segment = false;
515 45 : std::unique_ptr <AsPath4ByteSpec> aspath_4byte(new AsPath4ByteSpec);
516 45 : if (attr->as_path()) {
517 0 : const AsPathSpec &as_path = attr->as_path()->path();
518 0 : int new_as_count = 0;
519 0 : for (size_t i = 0; i < as_path.path_segments.size() &&
520 0 : new_as_count < (as2_count - as4_count) ; ++i) {
521 0 : ps4 = new AsPath4ByteSpec::PathSegment;
522 0 : AsPathSpec::PathSegment *ps = as_path.path_segments[i];
523 0 : ps4->path_segment_type = ps->path_segment_type;
524 0 : 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 0 : for (size_t j = 0; j < ps->path_segment.size() &&
532 0 : new_as_count < (as2_count - as4_count); ++j) {
533 0 : new_as_count++;
534 0 : as2_t as = ps->path_segment[j];
535 0 : ps4->path_segment.push_back(as);
536 : }
537 0 : if (new_as_count == (as2_count - as4_count)) {
538 0 : if (attr->as4_path()) {
539 0 : part_segment = true;
540 0 : break;
541 : }
542 : }
543 : }
544 0 : aspath_4byte->path_segments.push_back(ps4);
545 : }
546 0 : if (attr->as4_path()) {
547 0 : const As4PathSpec &as4_path = attr->as4_path()->path();
548 0 : for (size_t i = 0; i < as4_path.path_segments.size(); ++i) {
549 0 : if (!part_segment) {
550 0 : ps4 = new AsPath4ByteSpec::PathSegment;
551 : }
552 0 : part_segment = false;
553 0 : As4PathSpec::PathSegment *ps = as4_path.path_segments[i];
554 0 : ps4->path_segment_type = ps->path_segment_type;
555 0 : 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 0 : for (size_t j = 0; j < ps->path_segment.size(); ++j) {
563 0 : as_t as = ps->path_segment[j];
564 0 : ps4->path_segment.push_back(as);
565 : }
566 : }
567 0 : aspath_4byte->path_segments.push_back(ps4);
568 : }
569 0 : attr->set_as4_path(NULL);
570 : }
571 0 : attr->set_as_path(NULL);
572 : }
573 45 : if (local_as) {
574 45 : std::unique_ptr<AsPath4ByteSpec> as_path_spec(aspath_4byte->Add(local_as));
575 45 : attr->set_aspath_4byte(as_path_spec.get());
576 45 : } else {
577 0 : attr->set_aspath_4byte(aspath_4byte.get());
578 : }
579 45 : }
580 :
581 492 : UpdateInfo *BgpTable::GetUpdateInfo(RibOut *ribout, BgpRoute *route,
582 : const RibPeerSet &peerset) {
583 492 : const BgpPath *path = route->BestPath();
584 :
585 : // Ignore if there is no best-path.
586 492 : if (!path)
587 0 : return NULL;
588 :
589 : // Don't advertise infeasible paths.
590 492 : if (!path->IsFeasible())
591 4 : return NULL;
592 :
593 : // Check whether the route is contributing route
594 488 : if (IsRouteAggregationSupported() && IsContributingRoute(route))
595 0 : return NULL;
596 :
597 : // Needs to be outside the if block so it's not destroyed prematurely.
598 488 : BgpAttrPtr attr_ptr;
599 488 : const BgpAttr *attr = path->GetAttr();
600 :
601 488 : 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 488 : if (ribout->IsEncodingBgp()) {
607 : // Handle well-known communities.
608 544 : if (attr->community() != NULL &&
609 56 : attr->community()->communities().size()) {
610 104 : BOOST_FOREACH(uint32_t value, attr->community()->communities()) {
611 56 : if (value == CommunityType::NoAdvertise)
612 32 : return NULL;
613 :
614 36 : if ((ribout->peer_type() == BgpProto::EBGP) &&
615 4 : ((value == CommunityType::NoExport) ||
616 : (value == CommunityType::NoExportSubconfed))) {
617 8 : return NULL;
618 : }
619 : }
620 : }
621 :
622 456 : const IPeer *peer = path->GetPeer();
623 456 : BgpAttr *clone = NULL;
624 480 : bool llgr_stale_comm = attr->community() &&
625 24 : attr->community()->ContainsValue(CommunityType::LlgrStale);
626 456 : if (ribout->peer_type() == BgpProto::IBGP) {
627 : // Split horizon check.
628 265 : if (peer && peer->CheckSplitHorizon(server()->cluster_id(),
629 : ribout->cluster_id()))
630 105 : return NULL;
631 :
632 : // Handle route-target filtering.
633 160 : if (IsVpnTable() && attr->ext_community() != NULL) {
634 104 : server()->rtarget_group_mgr()->GetRibOutInterestedPeers(
635 : ribout, attr->ext_community(), peerset, &new_peerset);
636 104 : if (new_peerset.empty())
637 0 : return NULL;
638 : }
639 :
640 160 : if (server()->cluster_id()) {
641 : // Check if there is a loop in cluster_list
642 0 : if (attr->cluster_list() && attr->cluster_list()->cluster_list()
643 0 : .ClusterListLoop(server()->cluster_id())) {
644 0 : return NULL;
645 : }
646 : }
647 :
648 160 : 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 0 : RibPeerSet route_peerset;
654 0 : for (Route::PathList::iterator it= route->GetPathList().begin();
655 0 : it != route->GetPathList().end(); it++) {
656 0 : BgpPath *ipath = static_cast<BgpPath *>(it.operator->());
657 0 : if (ipath->IsFeasible() && ipath->GetPeer()) {
658 0 : const IPeer *ipeer = ipath->GetPeer();
659 0 : const BgpPeer *bgp_peer = dynamic_cast<
660 0 : const BgpPeer *>(ipeer);
661 0 : if (bgp_peer)
662 0 : route_peerset.set(bgp_peer->GetIndex());
663 : }
664 : }
665 0 : RibOut::PeerIterator iter(ribout, new_peerset);
666 0 : while (iter.HasNext()) {
667 0 : int current_index = iter.index();
668 0 : IPeerUpdate *peer = iter.Next();
669 0 : const BgpPeer *bgp_peer = dynamic_cast<
670 0 : const BgpPeer *>(peer);
671 0 : if (bgp_peer && route_peerset.test(bgp_peer->GetIndex()))
672 0 : new_peerset.reset(current_index);
673 : }
674 0 : if (new_peerset.empty())
675 0 : return NULL;
676 0 : }
677 :
678 160 : clone = new BgpAttr(*attr);
679 :
680 : // Retain LocalPref value if set, else set default to 100.
681 160 : 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 160 : CheckAggregatorAttr(clone);
686 :
687 : // Should not normally be needed for iBGP, but there could be
688 : // complex configurations where this is useful.
689 160 : ProcessRemovePrivate(ribout, clone);
690 :
691 : // Add Originator_Id if acting as route reflector and cluster_id
692 : // is not present
693 160 : if (server()->cluster_id()) {
694 0 : if (clone->originator_id().is_unspecified()) {
695 0 : if (peer && (peer->bgp_identifier() != 0)) {
696 0 : clone->set_originator_id(Ip4Address(
697 0 : peer->bgp_identifier()));
698 : } else {
699 0 : clone->set_originator_id(Ip4Address(
700 : server()->bgp_identifier()));
701 : }
702 : }
703 0 : 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 0 : server()->cluster_id(), NULL);
713 0 : clone->set_cluster_list(cl_ptr);
714 0 : 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 160 : if (ribout->as4_supported() && !clone->aspath_4byte()) {
722 49 : if (attr->as_path()) {
723 0 : CreateAsPath4Byte(clone, 0);
724 : } else {
725 49 : AsPath4ByteSpec as_path;
726 49 : clone->set_aspath_4byte(&as_path);
727 49 : }
728 : }
729 160 : if (!ribout->as4_supported() && !clone->as_path()) {
730 97 : if (attr->aspath_4byte()) {
731 8 : CreateAsPath2Byte(clone);
732 : } else {
733 89 : AsPathSpec as_path;
734 89 : clone->set_as_path(&as_path);
735 89 : }
736 : }
737 191 : } 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 191 : if (!rtinstance_->IsMasterRoutingInstance() &&
742 0 : ribout->nexthop().is_unspecified()) {
743 0 : return NULL;
744 : }
745 :
746 : // Handle route-target filtering.
747 191 : if (IsVpnTable() && attr->ext_community() != NULL) {
748 191 : server()->rtarget_group_mgr()->GetRibOutInterestedPeers(
749 : ribout, attr->ext_community(), peerset, &new_peerset);
750 191 : if (new_peerset.empty())
751 0 : return NULL;
752 : }
753 :
754 : // Sender side AS path loop check and split horizon within RibOut.
755 191 : if (!ribout->as_override()) {
756 191 : if (attr->IsAsPathLoop(ribout->peer_as()))
757 101 : return NULL;
758 : } else {
759 0 : if (peer && peer->PeerType() == BgpProto::EBGP) {
760 0 : ribout->GetSubsetPeerSet(&new_peerset, peer);
761 0 : if (new_peerset.empty())
762 0 : return NULL;
763 : }
764 : }
765 :
766 90 : clone = new BgpAttr(*attr);
767 :
768 : // Remove non-transitive attributes.
769 : // Note that med is handled further down.
770 90 : clone->set_originator_id(Ip4Address());
771 90 : clone->set_cluster_list(NULL);
772 :
773 : // Update nexthop.
774 90 : if (!ribout->nexthop().is_unspecified())
775 0 : clone->set_nexthop(ribout->nexthop());
776 :
777 : // Reset LocalPref.
778 90 : if (clone->local_pref())
779 90 : 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 90 : if (clone->med() && !clone->IsAsPathEmpty())
786 0 : clone->set_med(0);
787 :
788 : // Override the peer AS with local AS in AsPath.
789 90 : ProcessAsOverride(ribout, clone);
790 :
791 : // Remove private processing must happen before local AS prepend.
792 90 : ProcessRemovePrivate(ribout, clone);
793 :
794 : // Prepend the local AS to AsPath.
795 90 : PrependLocalAs(ribout, clone, peer);
796 : }
797 :
798 250 : 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 250 : ProcessDefaultTunnelEncapsulation(ribout, server()->extcomm_db(),
807 : clone);
808 :
809 250 : ProcessLlgrState(ribout, path, clone, llgr_stale_comm);
810 :
811 : // Locate the new BgpAttrPtr.
812 250 : attr_ptr = clone->attr_db()->Locate(clone);
813 250 : attr = attr_ptr.get();
814 : }
815 :
816 250 : UpdateInfo *uinfo = new UpdateInfo;
817 250 : uinfo->target = new_peerset;
818 250 : uinfo->roattr = RibOutAttr(route, attr, ribout->IsEncodingXmpp());
819 250 : return uinfo;
820 488 : }
821 :
822 : // Bgp Path selection..
823 : // Based Attribute weight
824 0 : bool BgpTable::PathSelection(const Path &path1, const Path &path2) {
825 0 : const BgpPath &l_path = dynamic_cast<const BgpPath &> (path1);
826 0 : const BgpPath &r_path = dynamic_cast<const BgpPath &> (path2);
827 :
828 : // Check the weight of Path
829 0 : bool res = l_path.PathCompare(r_path, false) < 0;
830 :
831 0 : return res;
832 : }
833 :
834 0 : bool BgpTable::DeletePath(DBTablePartBase *root, BgpRoute *rt, BgpPath *path) {
835 0 : return InputCommon(root, rt, path, path->GetPeer(), NULL,
836 0 : DBRequest::DB_ENTRY_DELETE, NULL, path->GetPathId(), 0, 0, 0);
837 : }
838 :
839 344 : 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 344 : bool notify_rt = false;
845 :
846 344 : switch (oper) {
847 184 : case DBRequest::DB_ENTRY_ADD_CHANGE: {
848 184 : assert(rt);
849 :
850 : // The entry may currently be marked as deleted.
851 184 : rt->ClearDelete();
852 184 : if (peer)
853 184 : peer->UpdateCloseRouteStats(family(), path, flags);
854 :
855 : // Check whether peer already has a path.
856 184 : if (path != NULL) {
857 24 : if ((path->GetAttr() != attrs.get()) ||
858 0 : (path->GetFlags() != flags) ||
859 24 : (path->GetLabel() != label) ||
860 0 : (path->GetL3Label() != l3_label)) {
861 : // Update Attributes and notify (if needed)
862 24 : if (path->NeedsResolution())
863 0 : path_resolver_->StopPathResolution(root->index(), path);
864 24 : rt->DeletePath(path);
865 : } else {
866 : // Ignore duplicate update.
867 0 : break;
868 : }
869 : }
870 :
871 : BgpPath *new_path;
872 368 : new_path = new BgpPath(
873 184 : 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 184 : bool fc_family = false;
884 316 : if (family() == Address::INET || family() == Address::INET6 ||
885 132 : family() == Address::EVPN) {
886 52 : fc_family = true;
887 : }
888 184 : bool fc_enabled = (server()->IsNextHopCheckEnabled() &&
889 184 : !rtinstance_->IsMasterRoutingInstance() && fc_family);
890 184 : if (new_path->NeedsResolution() || fc_enabled) {
891 0 : if (peer && !(peer->IsXmppPeer()) ) {
892 0 : rt->add_peer_sources(peer->ToString());
893 : }
894 0 : Address::Family family = new_path->GetAttr()->nexthop_family();
895 : BgpTable *table;
896 0 : if (new_path->NeedsResolution()) {
897 0 : table = rtinstance_->GetTable(family);
898 : } else {
899 : // Fast convergence knob is enabled.
900 : // Update path flag to indicate need for resolution.
901 0 : new_path->SetResolveNextHop();
902 :
903 : // Get the default table.
904 0 : RoutingInstanceMgr *mgr = server()->routing_instance_mgr();
905 0 : assert(mgr);
906 0 : RoutingInstance *master_ri = mgr->GetDefaultRoutingInstance();
907 0 : assert(master_ri);
908 0 : table = master_ri->GetTable(family);
909 : }
910 0 : path_resolver_->StartPathResolution(rt, new_path, table);
911 : }
912 :
913 184 : rt->InsertPath(new_path);
914 184 : notify_rt = true;
915 184 : break;
916 : }
917 :
918 160 : case DBRequest::DB_ENTRY_DELETE: {
919 160 : if (rt && !rt->IsDeleted()) {
920 160 : if (peer && !(peer->IsXmppPeer()) ) {
921 160 : rt->del_peer_sources(peer->ToString());
922 : }
923 160 : BGP_LOG_ROUTE(this, const_cast<IPeer *>(peer), rt,
924 : "Delete BGP path");
925 :
926 : // Remove the Path from the route
927 160 : if (path->NeedsResolution())
928 0 : path_resolver_->StopPathResolution(root->index(), path);
929 160 : rt->DeletePath(path);
930 160 : notify_rt = true;
931 : }
932 160 : break;
933 : }
934 :
935 0 : default: {
936 0 : assert(false);
937 : break;
938 : }
939 : }
940 344 : return notify_rt;
941 : }
942 :
943 261 : void BgpTable::Input(DBTablePartition *root, DBClient *client,
944 : DBRequest *req) {
945 261 : const IPeer *peer = (static_cast<RequestKey *>(req->key.get()))->GetPeer();
946 261 : RequestData *data = static_cast<RequestData *>(req->data.get());
947 :
948 261 : if (req->oper == DBRequest::DB_ENTRY_ADD_CHANGE && peer) {
949 : // Skip if this peer is down.
950 184 : if (!peer->IsReady())
951 0 : 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 184 : if (peer->IsXmppPeer() && peer->IsRegistrationRequired()) {
956 0 : BgpMembershipManager *mgr = rtinstance_->server()->membership_mgr();
957 0 : int instance_id = -1;
958 0 : uint64_t subscription_gen_id = 0;
959 : bool is_registered =
960 0 : mgr->GetRegistrationInfo(const_cast<IPeer *>(peer), this,
961 : &instance_id, &subscription_gen_id);
962 0 : if ((!is_registered && (family() != Address::RTARGET)) ||
963 0 : (is_registered &&
964 0 : (subscription_gen_id != data->subscription_gen_id()))) {
965 0 : return;
966 : }
967 : }
968 : }
969 :
970 : // Create route if it's not already present in case of add/change.
971 261 : BgpRoute *rt = TableFind(root, req->key.get());
972 261 : if (!rt) {
973 160 : if ((req->oper == DBRequest::DB_ENTRY_DELETE) ||
974 160 : (req->oper == DBRequest::DB_ENTRY_NOTIFY))
975 0 : return;
976 :
977 160 : rt = static_cast<BgpRoute *>(Add(req));
978 160 : static_cast<DBTablePartition *>(root)->Add(rt);
979 160 : BGP_LOG_ROUTE(this, const_cast<IPeer *>(peer), rt,
980 : "Insert new BGP path");
981 : }
982 :
983 261 : if (req->oper == DBRequest::DB_ENTRY_NOTIFY) {
984 0 : root->Notify(rt);
985 0 : return;
986 : }
987 :
988 261 : uint32_t path_id = 0;
989 261 : uint32_t flags = 0;
990 261 : uint32_t label = 0;
991 261 : uint32_t l3_label = 0;
992 261 : BgpPath *path = rt->FindPath(peer);
993 261 : BgpAttrPtr attr = data ? data->attrs() : NULL;
994 261 : if (req->oper == DBRequest::DB_ENTRY_ADD_CHANGE) {
995 184 : assert(data);
996 184 : const RequestData::NextHop &nexthop = data->nexthop();
997 184 : if (nexthop.address_.is_v4())
998 184 : path_id = nexthop.address_.to_v4().to_ulong();
999 184 : flags = nexthop.flags_;
1000 184 : label = nexthop.label_;
1001 184 : l3_label = nexthop.l3_label_;
1002 :
1003 184 : attr = GetAttributes(rt, attr, peer);
1004 : } else {
1005 77 : if (!path)
1006 0 : return;
1007 77 : path_id = path->GetPathId();
1008 : }
1009 :
1010 261 : bool notify_rt = InputCommon(root, rt, path, peer, req, req->oper,
1011 : attr, path_id, flags, label, l3_label);
1012 261 : InputCommonPostProcess(root, rt, notify_rt);
1013 261 : }
1014 :
1015 392 : void BgpTable::InputCommonPostProcess(DBTablePartBase *root,
1016 : BgpRoute *rt, bool notify_rt) {
1017 392 : if (!notify_rt)
1018 48 : return;
1019 :
1020 344 : if (rt->front() == NULL)
1021 160 : root->Delete(rt);
1022 : else
1023 184 : root->Notify(rt);
1024 : }
1025 :
1026 778 : bool BgpTable::MayDelete() const {
1027 778 : CHECK_CONCURRENCY("bgp::Config");
1028 :
1029 : // Bail if the table has listeners.
1030 778 : if (HasListeners()) {
1031 10 : BGP_LOG_TABLE(this, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_ALL,
1032 : "Paused table deletion due to pending listeners");
1033 10 : return false;
1034 : }
1035 :
1036 : // Bail if the table has walkers.
1037 768 : 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 768 : size_t size = Size();
1045 768 : if (size > 0) {
1046 0 : BGP_LOG_TABLE(this, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_ALL,
1047 : "Paused table deletion due to " << size <<
1048 : " pending routes");
1049 0 : 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 768 : if (!DBTableBase::MayDelete())
1055 0 : return false;
1056 :
1057 768 : return true;
1058 : }
1059 :
1060 768 : void BgpTable::Shutdown() {
1061 768 : CHECK_CONCURRENCY("bgp::PeerMembership", "bgp::Config");
1062 768 : }
1063 :
1064 768 : void BgpTable::ManagedDelete() {
1065 768 : BGP_LOG_TABLE(this, SandeshLevel::SYS_INFO, BGP_LOG_FLAG_ALL,
1066 : "Received request for table deletion");
1067 768 : deleter_->Delete();
1068 768 : }
1069 :
1070 : //
1071 : // Retry deletion of the table if it is pending.
1072 : //
1073 1428 : void BgpTable::RetryDelete() {
1074 1428 : if (!deleter()->IsDeleted())
1075 352 : return;
1076 1076 : deleter()->RetryDelete();
1077 : }
1078 :
1079 0 : PathResolver *BgpTable::CreatePathResolver() {
1080 0 : return NULL;
1081 : }
1082 :
1083 384 : void BgpTable::LocatePathResolver() {
1084 384 : if (path_resolver_)
1085 0 : return;
1086 384 : assert(!deleter()->IsDeleted());
1087 384 : path_resolver_ = CreatePathResolver();
1088 : }
1089 :
1090 384 : void BgpTable::DestroyPathResolver() {
1091 384 : if (!path_resolver_)
1092 0 : return;
1093 384 : delete path_resolver_;
1094 384 : path_resolver_ = NULL;
1095 : }
1096 :
1097 0 : size_t BgpTable::GetPendingRiboutsCount(size_t *markers) const {
1098 0 : CHECK_CONCURRENCY("bgp::ShowCommand", "bgp::Config");
1099 0 : size_t count = 0;
1100 0 : *markers = 0;
1101 :
1102 0 : BOOST_FOREACH(const RibOutMap::value_type &value, ribout_map_) {
1103 0 : const RibOut *ribout = value.second;
1104 0 : for (int idx = 0; idx < DB::PartitionCount(); ++idx) {
1105 0 : const RibOutUpdates *updates = ribout->updates(idx);
1106 0 : for (int qid = RibOutUpdates::QFIRST; qid < RibOutUpdates::QCOUNT;
1107 : ++qid) {
1108 0 : count += updates->queue_size(qid);
1109 0 : *markers += updates->queue_marker_count(qid);
1110 : }
1111 : }
1112 : }
1113 :
1114 0 : return count;
1115 : }
1116 :
1117 5560 : LifetimeActor *BgpTable::deleter() {
1118 5560 : return deleter_.get();
1119 : }
1120 :
1121 392 : const LifetimeActor *BgpTable::deleter() const {
1122 392 : return deleter_.get();
1123 : }
1124 :
1125 1192 : void BgpTable::UpdatePathCount(const BgpPath *path, int count) {
1126 1192 : if (dynamic_cast<const BgpSecondaryPath *>(path)) {
1127 568 : secondary_path_count_ += count;
1128 : } else {
1129 624 : primary_path_count_ += count;
1130 : }
1131 :
1132 1192 : if (!path->IsFeasible()) {
1133 8 : infeasible_path_count_ += count;
1134 : }
1135 :
1136 1192 : if (path->IsStale()) {
1137 0 : stale_path_count_ += count;
1138 : }
1139 :
1140 1192 : if (path->IsLlgrStale()) {
1141 0 : llgr_stale_path_count_ += count;
1142 : }
1143 1192 : }
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 168 : bool BgpTable::IsContributingRoute(const BgpRoute *route) const {
1152 168 : return routing_instance()->IsContributingRoute(this, route);
1153 : }
1154 :
1155 0 : void BgpTable::FillRibOutStatisticsInfo(
1156 : vector<ShowRibOutStatistics> *sros_list) const {
1157 0 : BOOST_FOREACH(const RibOutMap::value_type &value, ribout_map_) {
1158 0 : const RibOut *ribout = value.second;
1159 0 : ribout->FillStatisticsInfo(sros_list);
1160 : }
1161 0 : }
|