Line data Source code
1 : /*
2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3 : */
4 :
5 : #ifndef SRC_BGP_COMMUNITY_H_
6 : #define SRC_BGP_COMMUNITY_H_
7 :
8 : #include <boost/array.hpp>
9 : #include <boost/intrusive_ptr.hpp>
10 : #include <boost/system/error_code.hpp>
11 :
12 : #include <atomic>
13 : #include <set>
14 : #include <string>
15 : #include <vector>
16 :
17 : #include "base/parse_object.h"
18 : #include "base/util.h"
19 : #include "bgp/bgp_attr_base.h"
20 : #include "bgp/bgp_common.h"
21 : #include "bgp/extended-community/types.h"
22 : #include "bgp/large-community/types.h"
23 :
24 : class BgpAttr;
25 : class CommunityDB;
26 : class ExtCommunityDB;
27 : class LargeCommunityDB;
28 : class BgpServer;
29 :
30 : struct CommunitySpec : public BgpAttribute {
31 : static const int kSize = -1;
32 : static const uint8_t kFlags = Optional | Transitive;
33 62109 : CommunitySpec() : BgpAttribute(Communities, kFlags) { }
34 6664 : explicit CommunitySpec(const BgpAttribute &rhs) : BgpAttribute(rhs) { }
35 : std::vector<uint32_t> communities;
36 2009 : virtual int CompareTo(const BgpAttribute &rhs_attr) const {
37 2009 : int ret = BgpAttribute::CompareTo(rhs_attr);
38 2009 : if (ret != 0) return ret;
39 2009 : KEY_COMPARE(communities,
40 : static_cast<const CommunitySpec &>(rhs_attr).communities);
41 2009 : return 0;
42 : }
43 : virtual void ToCanonical(BgpAttr *attr);
44 : virtual std::string ToString() const;
45 : virtual size_t EncodeLength() const;
46 : };
47 :
48 : class Community {
49 : public:
50 : typedef std::vector<uint32_t> CommunityList;
51 22390 : explicit Community(CommunityDB *comm_db)
52 22390 : : comm_db_(comm_db) {
53 22390 : refcount_ = 0;
54 22390 : }
55 985 : explicit Community(const Community &rhs)
56 985 : : comm_db_(rhs.comm_db_), communities_(rhs.communities_) {
57 985 : refcount_ = 0;
58 985 : }
59 : explicit Community(CommunityDB *comm_db, const CommunitySpec spec);
60 56950 : virtual ~Community() { }
61 : virtual void Remove();
62 :
63 : int CompareTo(const Community &rhs) const;
64 : bool ContainsValue(uint32_t value) const;
65 : void BuildStringList(std::vector<std::string> *list) const;
66 :
67 39334 : const std::vector<uint32_t> &communities() const { return communities_; }
68 :
69 0 : friend std::size_t hash_value(Community const &comm) {
70 0 : size_t hash = 0;
71 0 : boost::hash_range(hash, comm.communities_.begin(),
72 : comm.communities_.end());
73 0 : return hash;
74 : }
75 :
76 : private:
77 : friend int intrusive_ptr_add_ref(const Community *ccomm);
78 : friend int intrusive_ptr_del_ref(const Community *ccomm);
79 : friend void intrusive_ptr_release(const Community *ccomm);
80 : friend class CommunityDB;
81 : friend class BgpAttrTest;
82 :
83 : void Append(uint32_t value);
84 : void Append(const std::vector<uint32_t> &communities);
85 : void Set(const std::vector<uint32_t> &communities);
86 : void Remove(const std::vector<uint32_t> &communities);
87 :
88 : mutable std::atomic<int> refcount_;
89 : CommunityDB *comm_db_;
90 : std::vector<uint32_t> communities_;
91 : };
92 :
93 373098 : inline int intrusive_ptr_add_ref(const Community *ccomm) {
94 746196 : return ccomm->refcount_.fetch_add(1);
95 : }
96 :
97 107826 : inline int intrusive_ptr_del_ref(const Community *ccomm) {
98 215652 : return ccomm->refcount_.fetch_sub(1);
99 : }
100 :
101 265295 : inline void intrusive_ptr_release(const Community *ccomm) {
102 265295 : int prev = ccomm->refcount_.fetch_sub(1);
103 265295 : if (prev == 1) {
104 2348 : Community *comm = const_cast<Community *>(ccomm);
105 2348 : comm->Remove();
106 2348 : assert(comm->refcount_ == 0);
107 2348 : delete comm;
108 : }
109 265295 : }
110 :
111 : typedef boost::intrusive_ptr<const Community> CommunityPtr;
112 :
113 : struct CommunityCompare {
114 216856 : bool operator()(const Community *lhs, const Community *rhs) const {
115 216856 : return lhs->CompareTo(*rhs) < 0;
116 : }
117 : };
118 :
119 : class CommunityDB : public BgpPathAttributeDB<Community, CommunityPtr,
120 : CommunitySpec, CommunityCompare,
121 : CommunityDB> {
122 : public:
123 : explicit CommunityDB(BgpServer *server);
124 19484 : virtual ~CommunityDB() { }
125 :
126 : CommunityPtr AppendAndLocate(const Community *src, uint32_t value);
127 : CommunityPtr AppendAndLocate(const Community *src,
128 : const std::vector<uint32_t> &value);
129 : CommunityPtr SetAndLocate(const Community *src,
130 : const std::vector<uint32_t> &value);
131 : CommunityPtr RemoveAndLocate(const Community *src,
132 : const std::vector<uint32_t> &value);
133 : CommunityPtr RemoveAndLocate(const Community *src, uint32_t value);
134 :
135 : private:
136 : };
137 :
138 : class ExtCommunitySpec : public BgpAttribute {
139 : public:
140 : static const int kSize = -1;
141 : static const uint8_t kFlags = Optional | Transitive;
142 235438 : ExtCommunitySpec() : BgpAttribute(ExtendedCommunities, kFlags) { }
143 92280 : explicit ExtCommunitySpec(const BgpAttribute &rhs) : BgpAttribute(rhs) { }
144 : virtual size_t EncodeLength() const;
145 : std::vector<uint64_t> communities;
146 : void AddTunnelEncaps(std::vector<std::string> encaps);
147 : virtual int CompareTo(const BgpAttribute &rhs_attr) const;
148 : virtual void ToCanonical(BgpAttr *attr);
149 : virtual std::string ToString() const;
150 : };
151 :
152 : class ExtCommunity {
153 : public:
154 : typedef boost::array<uint8_t, 8> ExtCommunityValue;
155 : typedef std::vector<ExtCommunityValue> ExtCommunityList;
156 :
157 147034 : explicit ExtCommunity(ExtCommunityDB *extcomm_db)
158 147034 : : extcomm_db_(extcomm_db) {
159 147034 : refcount_ = 0;
160 147036 : }
161 541185 : explicit ExtCommunity(const ExtCommunity &rhs)
162 541185 : : extcomm_db_(rhs.extcomm_db_),
163 541185 : communities_(rhs.communities_) {
164 541109 : refcount_ = 0;
165 541259 : }
166 :
167 : explicit ExtCommunity(ExtCommunityDB *extcomm_db,
168 : const ExtCommunitySpec spec);
169 1749870 : virtual ~ExtCommunity() { }
170 : virtual void Remove();
171 : int CompareTo(const ExtCommunity &rhs) const;
172 :
173 : bool ContainsRTarget(const ExtCommunityValue &val) const;
174 : bool ContainsOriginVn(as_t asn, uint32_t vn_index) const;
175 : bool ContainsOriginVn(const ExtCommunityValue &val) const;
176 : bool ContainsOriginVn4(const ExtCommunityValue &val) const;
177 : bool ContainsVrfRouteImport(const ExtCommunityValue &val) const;
178 : bool ContainsSourceAs(const ExtCommunityValue &val) const;
179 : uint32_t GetSubClusterId() const;
180 :
181 : // Return vector of communities
182 84375412 : const ExtCommunityList &communities() const {
183 84375412 : return communities_;
184 : }
185 :
186 : std::vector<std::string> GetTunnelEncap() const;
187 : std::vector<int> GetTagList(as2_t asn = 0) const;
188 : std::vector<int> GetTag4List(as_t asn = 0) const;
189 : bool ContainsTunnelEncapVxlan() const;
190 : int GetOriginVnIndex() const;
191 : static ExtCommunityList ExtCommunityFromString(const std::string &comm);
192 : static ExtCommunityValue FromHexString(const std::string &comm,
193 : boost::system::error_code *errorp);
194 :
195 9330880 : static bool is_origin_vn(const ExtCommunityValue &val) {
196 : //
197 : // Origin VN extended community
198 : // 2 Octet AS specific extended community
199 : //
200 9330880 : return ((val[0] == BgpExtendedCommunityType::Experimental ||
201 10145923 : val[0] == BgpExtendedCommunityType::Experimental4ByteAs) &&
202 10145689 : (val[1] == BgpExtendedCommunityExperimentalSubType::OriginVn));
203 : }
204 :
205 432 : static bool is_default_gateway(const ExtCommunityValue &val) {
206 : //
207 : // Default Gateway extended community
208 : //
209 552 : return (val[0] == BgpExtendedCommunityType::Opaque) &&
210 552 : (val[1] == BgpExtendedCommunityOpaqueSubType::DefaultGateway);
211 : }
212 :
213 432 : static bool is_es_import(const ExtCommunityValue &val) {
214 : //
215 : // ES Import extended community
216 : //
217 434 : return (val[0] == BgpExtendedCommunityType::Evpn) &&
218 434 : (val[1] == BgpExtendedCommunityEvpnSubType::EsImport);
219 : }
220 :
221 542 : static bool is_esi_label(const ExtCommunityValue &val) {
222 : //
223 : // ESI Label extended community
224 : //
225 599 : return (val[0] == BgpExtendedCommunityType::Evpn) &&
226 599 : (val[1] == BgpExtendedCommunityEvpnSubType::EsiMplsLabel);
227 : }
228 :
229 33598500 : static bool is_mac_mobility(const ExtCommunityValue &val) {
230 : //
231 : // MAC Mobility extended community
232 : //
233 33962586 : return (val[0] == BgpExtendedCommunityType::Evpn) &&
234 33962553 : (val[1] == BgpExtendedCommunityEvpnSubType::MacMobility);
235 : }
236 :
237 432 : static bool is_local_sequence_number(const ExtCommunityValue &val) {
238 432 : return (val[0] == BgpExtendedCommunityType::ExperimentalNonTransitive &&
239 432 : val[1] == BgpExtendedCommunityExperimentalNonTransitiveSubType::LocalSequenceNumber);
240 : }
241 :
242 12745738 : static bool is_etree(const ExtCommunityValue &val) {
243 : //
244 : // ETree extended community
245 : //
246 12869540 : return (val[0] == BgpExtendedCommunityType::Evpn) &&
247 12869570 : (val[1] == BgpExtendedCommunityEvpnSubType::ETree);
248 : }
249 :
250 26684 : static bool is_multicast_flags(const ExtCommunityValue &val) {
251 : //
252 : // Multicast Flags extended community
253 : //
254 28625 : return (val[0] == BgpExtendedCommunityType::Evpn) &&
255 28625 : (val[1] == BgpExtendedCommunityEvpnSubType::MulticastFlags);
256 : }
257 :
258 :
259 2736397 : static bool is_router_mac(const ExtCommunityValue &val) {
260 : //
261 : // Router MAC extended community
262 : //
263 2747257 : return (val[0] == BgpExtendedCommunityType::Evpn) &&
264 2747248 : (val[1] == BgpExtendedCommunityEvpnSubType::RouterMac);
265 : }
266 :
267 10085770 : static bool is_route_target(const ExtCommunityValue &val) {
268 : //
269 : // Route target extended community
270 : // 1. 2 Octet AS specific extended community Route Target
271 : // 2. IPv4 Address specific extended community Route Target
272 : // 3. 4 Octet AS specific extended community Route Target
273 : //
274 10085770 : return ((val[0] == BgpExtendedCommunityType::TwoOctetAS ||
275 2411905 : (val[0] == BgpExtendedCommunityType::FourOctetAS) ||
276 20494287 : (val[0] == BgpExtendedCommunityType::IPv4Address)) &&
277 18082392 : (val[1] == BgpExtendedCommunitySubType::RouteTarget));
278 : }
279 :
280 8252 : static uint32_t get_rtarget_val(const ExtCommunityValue &val) {
281 : //
282 : // Get non user-configured RT value from Route Target extended
283 : // community for
284 : // 1. 2 Octet AS specific extended community Route Target
285 : // 2. 4 Octet AS specific extended community Route Target
286 : //
287 8252 : if (is_route_target(val)) {
288 : uint8_t data[8];
289 : uint32_t rt;
290 8252 : std::copy(val.begin(), val.end(), &data[0]);
291 8252 : if (data[0] == BgpExtendedCommunityType::TwoOctetAS) {
292 8249 : rt = get_value(data + 4, 4);
293 8249 : if (rt >= BGP_RTGT_MIN_ID_AS2 && rt <= BGP_RTGT_MAX_ID_AS2) {
294 4 : return (rt);
295 : }
296 3 : } else if (data[0] == BgpExtendedCommunityType::FourOctetAS) {
297 3 : rt = get_value(data + 6, 2);
298 3 : if (rt >= BGP_RTGT_MIN_ID_AS4 && rt <= BGP_RTGT_MAX_ID_AS4) {
299 2 : return (rt);
300 : }
301 : }
302 : }
303 8248 : return (0);
304 : }
305 :
306 3101892 : static bool is_security_group(const ExtCommunityValue &val) {
307 : //
308 : // SG ID extended community
309 : // 2 Octet AS specific extended community
310 : //
311 3586147 : return (val[0] == BgpExtendedCommunityType::Experimental) &&
312 3586097 : (val[1] == BgpExtendedCommunityExperimentalSubType::SgId);
313 : }
314 :
315 2651307 : static bool is_security_group4(const ExtCommunityValue &val) {
316 : //
317 : // SG ID extended community
318 : // 2 Octet AS specific extended community
319 : //
320 2847915 : return (val[0] == BgpExtendedCommunityType::Experimental4ByteAs) &&
321 2847914 : (val[1] == BgpExtendedCommunityExperimentalSubType::SgId);
322 : }
323 :
324 27199 : static bool is_site_of_origin(const ExtCommunityValue &val) {
325 : //
326 : // Site of Origin / Route Origin extended community
327 : // 1. 2 Octet AS specific extended community
328 : // 2. IPv4 Address specific extended community
329 : // 3. 4 Octet AS specific extended community Route Target
330 : //
331 27199 : return ((val[0] == BgpExtendedCommunityType::TwoOctetAS ||
332 24845 : (val[0] == BgpExtendedCommunityType::FourOctetAS) ||
333 54398 : (val[0] == BgpExtendedCommunityType::IPv4Address)) &&
334 29553 : (val[1] == BgpExtendedCommunitySubType::RouteOrigin));
335 : }
336 :
337 3500 : static bool is_source_as(const ExtCommunityValue &val) {
338 : //
339 : // Source AS extended community
340 : // 1. 2 Octet AS specific extended community
341 : // 2. 4 Octet AS specific extended community
342 : //
343 3500 : return ((val[0] == BgpExtendedCommunityType::TwoOctetAS ||
344 4102 : (val[0] == BgpExtendedCommunityType::FourOctetAS)) &&
345 4102 : (val[1] == BgpExtendedCommunitySubType::SourceAS));
346 : }
347 :
348 2479255 : static bool is_sub_cluster(const ExtCommunityValue &val) {
349 : //
350 : // Sub Cluster extended community
351 : // 1. Experimental AS specific extended community
352 : // 2. Experimental4Byte AS specific extended community
353 : //
354 2479255 : return (((val[0] == BgpExtendedCommunityType::Experimental) ||
355 2695515 : (val[0] == BgpExtendedCommunityType::Experimental4ByteAs)) &&
356 2695522 : (val[1] == BgpExtendedCommunitySubType::SubCluster));
357 : }
358 :
359 2126 : static bool is_vrf_route_import(const ExtCommunityValue &val) {
360 : //
361 : // VRF Route Import extended community
362 : // IPv4 Address specific extended community
363 : //
364 2426 : return ((val[0] == BgpExtendedCommunityType::IPv4Address) &&
365 2426 : (val[1] == BgpExtendedCommunitySubType::VrfRouteImport));
366 : }
367 :
368 4684416 : static bool is_tunnel_encap(const ExtCommunityValue &val) {
369 : // Tunnel encap extended community
370 5344095 : return (val[0] == BgpExtendedCommunityType::Opaque) &&
371 5344028 : (val[1] == BgpExtendedCommunityOpaqueSubType::TunnelEncap);
372 : }
373 :
374 2484360 : static bool is_load_balance(const ExtCommunityValue &val) {
375 : // Load Balance extended community
376 2932798 : return (val[0] == BgpExtendedCommunityType::Opaque) &&
377 2932789 : (val[1] == BgpExtendedCommunityOpaqueSubType::LoadBalance);
378 : }
379 :
380 6 : static bool is_tag(const ExtCommunityValue &val) {
381 : // Tag extended community
382 9 : return (val[0] == BgpExtendedCommunityType::Experimental) &&
383 9 : (val[1] == BgpExtendedCommunityExperimentalSubType::Tag);
384 : }
385 :
386 0 : static bool is_tag4(const ExtCommunityValue &val) {
387 : // Tag extended community
388 0 : return (val[0] == BgpExtendedCommunityType::Experimental4ByteAs) &&
389 0 : (val[1] == BgpExtendedCommunityExperimentalSubType::Tag);
390 : }
391 :
392 0 : friend std::size_t hash_value(ExtCommunity const &comm) {
393 0 : size_t hash = 0;
394 0 : for (ExtCommunityList::const_iterator iter = comm.communities_.begin();
395 0 : iter != comm.communities_.end(); iter++) {
396 0 : boost::hash_range(hash, iter->begin(), iter->end());
397 : }
398 0 : return hash;
399 : }
400 :
401 : static std::string ToString(const ExtCommunityValue &val);
402 : static std::string ToHexString(const ExtCommunityValue &val);
403 :
404 : private:
405 : friend int intrusive_ptr_add_ref(const ExtCommunity *cextcomm);
406 : friend int intrusive_ptr_del_ref(const ExtCommunity *cextcomm);
407 : friend void intrusive_ptr_release(const ExtCommunity *cextcomm);
408 : friend class ExtCommunityDB;
409 : friend class BgpAttrTest;
410 :
411 : void Append(const ExtCommunityValue &value);
412 : void Append(const ExtCommunityList &list);
413 : void Remove(const ExtCommunityList &list);
414 : void RemoveMFlags();
415 : void RemoveRTarget();
416 : void RemoveSGID();
417 : void RemoveTag();
418 : void RemoveSiteOfOrigin();
419 : void RemoveSourceAS();
420 : void RemoveVrfRouteImport();
421 : void RemoveOriginVn();
422 : void RemoveTunnelEncapsulation();
423 : void RemoveLoadBalance();
424 : void RemoveSubCluster();
425 : void Set(const ExtCommunityList &list);
426 :
427 : mutable std::atomic<int> refcount_;
428 : ExtCommunityDB *extcomm_db_;
429 : ExtCommunityList communities_;
430 : };
431 :
432 10866111 : inline int intrusive_ptr_add_ref(const ExtCommunity *cextcomm) {
433 21732222 : return cextcomm->refcount_.fetch_add(1);
434 : }
435 :
436 1154427 : inline int intrusive_ptr_del_ref(const ExtCommunity *cextcomm) {
437 2308854 : return cextcomm->refcount_.fetch_sub(1);
438 : }
439 :
440 9713333 : inline void intrusive_ptr_release(const ExtCommunity *cextcomm) {
441 9713333 : int prev = cextcomm->refcount_.fetch_sub(1);
442 9713333 : if (prev == 1) {
443 185254 : ExtCommunity *extcomm = const_cast<ExtCommunity *>(cextcomm);
444 185254 : extcomm->Remove();
445 185254 : assert(extcomm->refcount_ == 0);
446 185254 : delete extcomm;
447 : }
448 9713333 : }
449 :
450 : typedef boost::intrusive_ptr<const ExtCommunity> ExtCommunityPtr;
451 :
452 : struct ExtCommunityCompare {
453 4878746 : bool operator()(const ExtCommunity *lhs, const ExtCommunity *rhs) const {
454 4878746 : return lhs->CompareTo(*rhs) < 0;
455 : }
456 : };
457 :
458 : class ExtCommunityDB : public BgpPathAttributeDB<ExtCommunity, ExtCommunityPtr,
459 : ExtCommunitySpec,
460 : ExtCommunityCompare,
461 : ExtCommunityDB> {
462 : public:
463 : explicit ExtCommunityDB(BgpServer *server);
464 :
465 : ExtCommunityPtr AppendAndLocate(const ExtCommunity *src,
466 : const ExtCommunity::ExtCommunityList &list);
467 : ExtCommunityPtr AppendAndLocate(const ExtCommunity *src,
468 : const ExtCommunity::ExtCommunityValue &value);
469 : ExtCommunityPtr RemoveAndLocate(const ExtCommunity *src,
470 : const ExtCommunity::ExtCommunityList &list);
471 :
472 : ExtCommunityPtr ReplaceMFlagsAndLocate(const ExtCommunity *src,
473 : const ExtCommunity::ExtCommunityList &export_list);
474 : ExtCommunityPtr ReplaceRTargetAndLocate(const ExtCommunity *src,
475 : const ExtCommunity::ExtCommunityList &export_list);
476 : ExtCommunityPtr ReplaceSGIDListAndLocate(const ExtCommunity *src,
477 : const ExtCommunity::ExtCommunityList &sgid_list);
478 : ExtCommunityPtr ReplaceTagListAndLocate(const ExtCommunity *src,
479 : const ExtCommunity::ExtCommunityList &tag_list);
480 : ExtCommunityPtr RemoveSiteOfOriginAndLocate(const ExtCommunity *src);
481 : ExtCommunityPtr ReplaceSiteOfOriginAndLocate(const ExtCommunity *src,
482 : const ExtCommunity::ExtCommunityValue &soo);
483 : ExtCommunityPtr RemoveVrfRouteImportAndLocate(const ExtCommunity *src);
484 : ExtCommunityPtr ReplaceVrfRouteImportAndLocate(const ExtCommunity *src,
485 : const ExtCommunity::ExtCommunityValue &vit);
486 : ExtCommunityPtr RemoveSourceASAndLocate(const ExtCommunity *src);
487 : ExtCommunityPtr ReplaceSourceASAndLocate(const ExtCommunity *src,
488 : const ExtCommunity::ExtCommunityValue &sas);
489 : ExtCommunityPtr RemoveOriginVnAndLocate(const ExtCommunity *src);
490 : ExtCommunityPtr ReplaceOriginVnAndLocate(const ExtCommunity *src,
491 : const ExtCommunity::ExtCommunityValue &origin_vn);
492 : ExtCommunityPtr ReplaceTunnelEncapsulationAndLocate(
493 : const ExtCommunity *src,
494 : const ExtCommunity::ExtCommunityList &tunnel_encaps);
495 : ExtCommunityPtr ReplaceLoadBalanceAndLocate(const ExtCommunity *src,
496 : const ExtCommunity::ExtCommunityValue &lb);
497 : ExtCommunityPtr ReplaceSubClusterAndLocate(const ExtCommunity *src,
498 : const ExtCommunity::ExtCommunityValue &sc);
499 : ExtCommunityPtr SetAndLocate(const ExtCommunity *src,
500 : const ExtCommunity::ExtCommunityList &list);
501 :
502 : private:
503 : };
504 :
505 : /// @brief This class encapsulates the wire-format representation of a BGP
506 : /// Large Community attribute and provides encoding, comparison, and
507 : /// canonicalization functions for Large Community attributes.
508 : class LargeCommunitySpec : public BgpAttribute {
509 : public:
510 : /// Indicates variable size of BGP attribute in encoded form (used
511 : /// internally by encoding functions). -1 means the total size depends on
512 : /// how many communities are present.
513 : static const int kSize = -1;
514 :
515 : /// Flags indicating whether the attribute is Optional and Transitive per BGP
516 : /// standards.
517 : static const uint8_t kFlags = Optional | Transitive;
518 :
519 : /// @brief Constructs a new instance using the attribute type and
520 : /// flags.
521 534435 : LargeCommunitySpec() : BgpAttribute(LargeCommunities, kFlags) { }
522 :
523 : /// @brief Constructs from an existing BgpAttribute.
524 6 : explicit LargeCommunitySpec(const BgpAttribute &rhs) :
525 6 : BgpAttribute(rhs) { }
526 :
527 : /// @brief Constructs an instance from an Extened Community specification
528 : /// by distributing its bits inside a new Large Community spec.
529 : static LargeCommunitySpec FromTag(const ExtCommunitySpec &ex_spec);
530 :
531 : /// @brief Removes extended communities corresponding to tags
532 : /// from the given ExtCommunitySpec.
533 : static ExtCommunitySpec RemoveTags(const ExtCommunitySpec& ex_spec);
534 :
535 : /// @brief Compute the encoded length of the attribute.
536 : virtual size_t EncodeLength() const;
537 :
538 : /// @brief Vector of community values. Each Large Community value consists
539 : /// of three 4-byte fields (12 bytes total).
540 : std::vector<uint32_t> communities;
541 :
542 : /// @brief Compare the attribute with another BgpAttribute.
543 : virtual int CompareTo(const BgpAttribute &rhs_attr) const;
544 :
545 : /// @brief Convert the attribute to its canonical form.
546 : virtual void ToCanonical(BgpAttr *attr);
547 :
548 : /// @brief Generate a human-readable string representation.
549 : virtual std::string ToString() const;
550 : };
551 :
552 : /// @brief This class represents an array of BGP Large Community values.
553 : /// A LargeCommunity consists of one or more 12-byte tuples. This class
554 : /// provides manipulation (append, remove, set), comparison, hashing, and
555 : /// conversion to/from human-readable formats.
556 : class LargeCommunity {
557 : public:
558 : /// A single Large Community value.
559 : typedef boost::array<uint8_t, 12> LargeCommunityValue;
560 :
561 : /// A list (vector) of LargeCommunityValue items.
562 : typedef std::vector<LargeCommunityValue> LargeCommunityList;
563 :
564 : /// @brief Constructs an instance of the class and links to the
565 : /// given LargeCommunityDB instance.
566 18862 : explicit LargeCommunity(LargeCommunityDB *largecomm_db)
567 18862 : : largecomm_db_(largecomm_db) {
568 18862 : refcount_ = 0;
569 18862 : }
570 :
571 : /// @brief Copy constructor.
572 0 : explicit LargeCommunity(const LargeCommunity &rhs)
573 0 : : largecomm_db_(rhs.largecomm_db_),
574 0 : communities_(rhs.communities_) {
575 0 : refcount_ = 0;
576 0 : }
577 :
578 : /// @brief Constructs an instance of the class using the given
579 : /// LargeCommunitySpec and links to the given LargeCommunityDB
580 : /// instance.
581 : explicit LargeCommunity(LargeCommunityDB *largecomm_db,
582 : const LargeCommunitySpec spec);
583 :
584 : /// @brief Destroys an instance.
585 404373 : virtual ~LargeCommunity() { }
586 :
587 : /// @brief Remove this community.
588 : virtual void Remove();
589 :
590 : /// @brief Compare this LargeCommunity to another.
591 : int CompareTo(const LargeCommunity &rhs) const;
592 :
593 : /// @brief Get the list of Large Community values.
594 100439 : const LargeCommunityList &communities() const {
595 100439 : return communities_;
596 : }
597 :
598 : /// @brief Get the list of tags with the specified ASN.
599 : std::vector<uint64_t> GetTagList(as_t asn = 0) const;
600 :
601 : /// @brief Parse a string into a list of LargeCommunity values.
602 : static LargeCommunityList LargeCommunityFromString(
603 : const std::string &comm);
604 :
605 : /// @brief Convert a hexadecimal string to a LargeCommunityValue.
606 : static LargeCommunityValue FromHexString(const std::string &comm,
607 : boost::system::error_code *errorp);
608 :
609 : /// @brief Compute the hash value for a LargeCommunity object.
610 0 : friend std::size_t hash_value(LargeCommunity const &comm) {
611 0 : size_t hash = 0;
612 0 : for (LargeCommunityList::const_iterator iter =
613 0 : comm.communities_.begin();
614 0 : iter != comm.communities_.end(); iter++) {
615 0 : boost::hash_range(hash, iter->begin(), iter->end());
616 : }
617 0 : return hash;
618 : }
619 :
620 : /// @brief Check if the LargeCommunity value is tag.
621 160 : static bool is_tag(const LargeCommunityValue &val) {
622 160 : return (val[4] == BgpLargeCommunityType::TagLC);
623 : }
624 :
625 : /// @brief Convert a LargeCommunityValue to a human-readable string.
626 : static std::string ToString(const LargeCommunityValue &val);
627 :
628 : /// @brief Convert a LargeCommunityValue to a hexadecimal string.
629 : static std::string ToHexString(const LargeCommunityValue &val);
630 :
631 : private:
632 : /// @brief Increment reference count atomically.
633 : friend int intrusive_ptr_add_ref(const LargeCommunity *clargecomm);
634 : /// @brief Decrement reference count of an clargecomm.
635 : friend int intrusive_ptr_del_ref(const LargeCommunity *clargecomm);
636 : /// @brief Release a LargeCommunity instance when the reference count
637 : /// reaches zero.
638 : friend void intrusive_ptr_release(const LargeCommunity *clargecomm);
639 : /// @brief Enables the access to private members for LargeCommunityDB.
640 : friend class LargeCommunityDB;
641 : /// @brief Enables the access to private members for BgpAttrTest.
642 : friend class BgpAttrTest;
643 :
644 : /// Append a single LargeCommunity value.
645 : void Append(const LargeCommunityValue &value);
646 : /// Append a list of LargeCommunity values.
647 : void Append(const LargeCommunityList &list);
648 : /// Remove specific LargeCommunity values.
649 : void Remove(const LargeCommunityList &list);
650 : /// Remove all the tags.
651 : void RemoveTag();
652 : /// Replace all existing values with the provided list.
653 : void Set(const LargeCommunityList &list);
654 :
655 : /// @brief A reference counter, needed for memory management.
656 : mutable std::atomic<int> refcount_;
657 : /// @brief A pointer to the managing LargeCommunityDB.
658 : LargeCommunityDB *largecomm_db_;
659 : /// @brief A list of LargeCommunity storing BGP Large Community values.
660 : LargeCommunityList communities_;
661 : };
662 :
663 : /// @brief Increment reference count atomically.
664 2940843 : inline int intrusive_ptr_add_ref(const LargeCommunity *clargecomm) {
665 5881686 : return clargecomm->refcount_.fetch_add(1);
666 : }
667 :
668 : /// @brief Decrement reference count of given large community.
669 205222 : inline int intrusive_ptr_del_ref(const LargeCommunity *clargecomm) {
670 410444 : return clargecomm->refcount_.fetch_sub(1);
671 : }
672 :
673 : /// @brief Release a LargeCommunity instance when the reference count reaches
674 : /// zero.
675 2735168 : inline void intrusive_ptr_release(const LargeCommunity *clargecomm) {
676 2735168 : int prev = clargecomm->refcount_.fetch_sub(1);
677 2735168 : if (prev == 1) {
678 6124 : LargeCommunity *largecomm = const_cast<LargeCommunity *>(clargecomm);
679 6124 : largecomm->Remove();
680 6124 : assert(largecomm->refcount_ == 0);
681 6124 : delete largecomm;
682 : }
683 2735168 : }
684 :
685 : /// @brief Defines a type for automatic storage of a LargeCommunity instance.
686 : typedef boost::intrusive_ptr<const LargeCommunity> LargeCommunityPtr;
687 :
688 : /// @brief A structure to compare order LargeCommunity objects.
689 : struct LargeCommunityCompare {
690 410721 : bool operator()(const LargeCommunity *lhs, const LargeCommunity *rhs) const {
691 410721 : return lhs->CompareTo(*rhs) < 0;
692 : }
693 : };
694 :
695 : /// @brief This class represents a database for managing LargeCommunity
696 : /// objects. It is used to store, deduplicate, and retrieve canonical
697 : /// instances of LargeCommunity.
698 : class LargeCommunityDB : public BgpPathAttributeDB<LargeCommunity,
699 : LargeCommunityPtr,
700 : LargeCommunitySpec,
701 : LargeCommunityCompare,
702 : LargeCommunityDB> {
703 : public:
704 : /// @brief Constructs an instance of the class and links to the
705 : /// given BgpServer instance.
706 : explicit LargeCommunityDB(BgpServer *server);
707 :
708 : /// @brief Append a list of LargeCommunity values to an existing attribute.
709 : LargeCommunityPtr AppendAndLocate(
710 : const LargeCommunity *src,
711 : const LargeCommunity::LargeCommunityList &list);
712 :
713 : /// @brief Append a single LargeCommunity value to an existing attribute.
714 : LargeCommunityPtr AppendAndLocate(
715 : const LargeCommunity *src,
716 : const LargeCommunity::LargeCommunityValue &value);
717 :
718 : /// @brief Remove a list of LargeCommunity values from an existing
719 : /// attribute.
720 : LargeCommunityPtr RemoveAndLocate(
721 : const LargeCommunity *src,
722 : const LargeCommunity::LargeCommunityList &list);
723 :
724 : /// @brief Replace all tags in a LargeCommunity with a new tag list.
725 : LargeCommunityPtr ReplaceTagListAndLocate(
726 : const LargeCommunity *src,
727 : const LargeCommunity::LargeCommunityList &tag_list);
728 :
729 : /// @brief Replace all values in a LargeCommunity with a new list.
730 : LargeCommunityPtr SetAndLocate(
731 : const LargeCommunity *src,
732 : const LargeCommunity::LargeCommunityList &list);
733 :
734 : private:
735 : };
736 :
737 : #endif // SRC_BGP_COMMUNITY_H_
|