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