LCOV - code coverage report
Current view: top level - bgp - bgp_attr_base.h (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 53 55 96.4 %
Date: 2026-06-08 02:02:55 Functions: 101 101 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
       3             :  */
       4             : 
       5             : #ifndef SRC_BGP_BGP_ATTR_BASE_H_
       6             : #define SRC_BGP_BGP_ATTR_BASE_H_
       7             : 
       8             : #include <boost/functional/hash.hpp>
       9             : #include <boost/scoped_array.hpp>
      10             : 
      11             : #include <set>
      12             : #include <string>
      13             : #include <utility>
      14             : #include <vector>
      15             : #include <mutex>
      16             : 
      17             : #include "base/parse_object.h"
      18             : #include "base/task.h"
      19             : 
      20             : class BgpAttr;
      21             : 
      22             : class BgpAttribute : public ParseObject {
      23             : public:
      24             :     enum Flag {
      25             :         Optional = 1 << 7,
      26             :         Transitive = 1 << 6,
      27             :         Partial = 1 << 5,
      28             :         ExtendedLength = 1 << 4
      29             :     };
      30             :     enum Code {
      31             :         Reserved = 0,
      32             :         Origin = 1,
      33             :         AsPath = 2,
      34             :         NextHop = 3,
      35             :         MultiExitDisc = 4,
      36             :         LocalPref = 5,
      37             :         AtomicAggregate = 6,
      38             :         Aggregator = 7,
      39             :         Communities = 8,
      40             :         OriginatorId = 9,
      41             :         ClusterList = 10,
      42             :         MPReachNlri = 14,
      43             :         MPUnreachNlri = 15,
      44             :         ExtendedCommunities = 16,
      45             :         As4Path = 17,
      46             :         As4Aggregator = 18,
      47             :         PmsiTunnel = 22,
      48             :         LargeCommunities = 32,
      49             :         McastEdgeDiscovery = 241,
      50             :         McastEdgeForwarding = 242,
      51             :         OriginVnPath = 243,
      52             :     };
      53             :     enum Subcode {
      54             :         OList = 1,
      55             :         LabelBlock = 2,
      56             :         SourceRd = 3,
      57             :         Esi = 4,
      58             :         Params = 5,
      59             :         LeafOList = 6,
      60             :         SubProtocol = 7
      61             :     };
      62             : 
      63      630715 :     BgpAttribute() : code(0), subcode(0), flags(0) { }
      64     2603082 :     BgpAttribute(uint8_t code, uint8_t flags)
      65     2603082 :         : code(code), subcode(0), flags(flags) { }
      66      121886 :     BgpAttribute(uint8_t code, uint8_t subcode, uint8_t flags)
      67      121886 :         : code(code), subcode(subcode), flags(flags) { }
      68             :     static const uint8_t FLAG_MASK = Optional|Transitive;
      69             :     uint8_t code;
      70             :     uint8_t subcode;
      71             :     uint8_t flags;
      72             :     /*
      73             :      * Variable length attributes should return the size of the attribute
      74             :      * for encoding purposes in order to set the ExtendedLength flag.
      75             :      */
      76             :     virtual size_t EncodeLength() const;
      77             :     /*
      78             :      * Helper method to compute flags used when encoding attributes.
      79             :      */
      80             :     uint8_t GetEncodeFlags() const;
      81             : 
      82             :     virtual std::string ToString() const;
      83             :     virtual int CompareTo(const BgpAttribute &rhs) const;
      84           1 :     virtual void ToCanonical(BgpAttr *attr) { }
      85             : };
      86             : 
      87             : //
      88             : // Canonical structure used to exchange a single NLRI prefix between the
      89             : // common parser and the address family specific BGP code.
      90             : //
      91             : // ReadLabel and WriteLabel need a label offset because the label is at
      92             : // different locations in different NLRI.
      93             : //
      94             : // The prefix length is in bits.
      95             : // The type is relevant only for NLRI that have multiple route types e.g.
      96             : // erm-vpn and e-vpn.
      97             : //
      98             : struct BgpProtoPrefix : public ParseObject {
      99             :     static const size_t kLabelSize;
     100             : 
     101             :     BgpProtoPrefix();
     102             : 
     103             :     uint32_t ReadLabel(size_t label_offset, bool is_vni = false) const;
     104             :     void WriteLabel(size_t label_offset, uint32_t label, bool is_vni = false);
     105             : 
     106             :     std::vector<uint8_t> prefix;
     107             :     int prefixlen;
     108             :     uint8_t type;
     109             : };
     110             : 
     111             : //
     112             : // Base class to manage BGP Path Attributes database. This class provides
     113             : // thread safe access to the data base.
     114             : //
     115             : // Lock contention can be tuned by varying the hash table size passed to the
     116             : // constructor.
     117             : //
     118             : // Attribute contents must be hashable via hash_value() and hashed using
     119             : // boost::hash_combine() to partition the attribute database.
     120             : //
     121             : template <class Type, class TypePtr, class TypeSpec, typename TypeCompare,
     122             :           class TypeDB>
     123             : class BgpPathAttributeDB {
     124             : public:
     125      126646 :     explicit BgpPathAttributeDB(int hash_size = GetHashSize())
     126      126646 :         : hash_size_(hash_size),
     127      253292 :           set_(new Set[hash_size]),
     128      253292 :           mutex_(new std::mutex[hash_size]) {
     129      126646 :     }
     130             : 
     131       10752 :     size_t Size() {
     132       10752 :         size_t size = 0;
     133             : 
     134       21532 :         for (size_t i = 0; i < hash_size_; i++) {
     135       10751 :             std::scoped_lock lock(mutex_[i]);
     136       10787 :             size += set_[i].size();
     137             :         }
     138       10781 :         return size;
     139             :     }
     140             : 
     141      662482 :     void Delete(Type *attr) {
     142      662482 :         size_t hash = HashCompute(attr);
     143             : 
     144      662479 :         std::scoped_lock lock(mutex_[hash]);
     145      662485 :         assert(set_[hash].erase(attr));
     146      662449 :     }
     147             : 
     148             :     // Locate passed in attribute in the data base based on the attr ptr.
     149     3774470 :     TypePtr Locate(Type *attr) {
     150     3774470 :         return LocateInternal(attr);
     151             :     }
     152             : 
     153             :     // Locate passed in attribute in the data base, based on the attr spec.
     154     1156534 :     TypePtr Locate(const TypeSpec &spec) {
     155     1156534 :         Type *attr = new Type(static_cast<TypeDB *>(this), spec);
     156     1156589 :         return LocateInternal(attr);
     157             :     }
     158             : 
     159             : private:
     160     5593296 :     const size_t HashCompute(Type *attr) const {
     161     5593296 :         if (hash_size_ <= 1) return 0;
     162             : 
     163           7 :         size_t hash = 0;
     164           7 :         boost::hash_combine(hash, *attr);
     165           0 :         return hash % hash_size_;
     166             :     }
     167             : 
     168      126646 :     static size_t GetHashSize() {
     169      126646 :         char *str = getenv("BGP_PATH_ATTRIBUTE_DB_HASH_SIZE");
     170             : 
     171             :         // Use just one bucket for now.
     172      126646 :         if (!str) return 1;
     173           0 :         return strtoul(str, NULL, 0);
     174             :     }
     175             : 
     176             :     // This template safely retrieves an attribute entry from its data base.
     177             :     // If the entry is not found, it is inserted into the database.
     178             :     //
     179             :     // If the entry is already present, then passed in entry is freed and
     180             :     // existing entry is returned.
     181     4930937 :     TypePtr LocateInternal(Type *attr) {
     182             :         // Hash attribute contents to to avoid potential mutex contention.
     183     4930937 :         size_t hash = HashCompute(attr);
     184     8392170 :         while (true) {
     185             :             // Grab mutex to keep db access thread safe.
     186     6659720 :             std::scoped_lock lock(mutex_[hash]);
     187     6663276 :             std::pair<typename Set::iterator, bool> ret;
     188             : 
     189             :             // Try to insert the passed entry into the database.
     190     6663145 :             ret = set_[hash].insert(attr);
     191             : 
     192             :             // Take a reference to prevent this entry from getting deleted.
     193             :             // Counter is automatically incremented, hence we get thread safety
     194             :             // here.
     195     6663219 :             int prev = intrusive_ptr_add_ref(*ret.first);
     196             : 
     197             :             // Check if passed in entry did get into the data base.
     198     6662936 :             if (ret.second) {
     199             :                 // Take intrusive pointer, thereby incrementing the refcount.
     200      662484 :                 TypePtr ptr = TypePtr(*ret.first);
     201             : 
     202             :                 // Release redundant refcount taken above to protect this entry
     203             :                 // from getting deleted, as we have now bumped up refcount above
     204      662475 :                 intrusive_ptr_del_ref(*ret.first);
     205      662485 :                 return ptr;
     206      662483 :             }
     207             : 
     208             :             // Make sure that this entry, though in the database is not
     209             :             // undergoing deletion. This can happen because attribute intrusive
     210             :             // pointer is released without taking the mutex.
     211             :             //
     212             :             // If the previous refcount is 0, it implies that this entry is
     213             :             // about to get deleted (after we release the mutex). In such
     214             :             // cases, we retry inserting the passed attribute pointer into the
     215             :             // data base.
     216     6000452 :             if (prev > 0) {
     217             :                 // Free passed in attribute, as it is already in the database.
     218     4269036 :                 delete attr;
     219             : 
     220             :                 // Take intrusive pointer, thereby incrementing the refcount.
     221     4269197 :                 TypePtr ptr = TypePtr(*ret.first);
     222             : 
     223             :                 // Release redundant refcount taken above to protect this entry
     224             :                 // from getting deleted, as we have now bumped up refcount above
     225     4269411 :                 intrusive_ptr_del_ref(*ret.first);
     226     4269506 :                 return ptr;
     227     4269415 :             }
     228             : 
     229             :             // Decrement the counter bumped up above as we can't use this entry
     230             :             // which is about to be deleted. Instead, retry inserting the passed
     231             :             // entry again, into the database.
     232     1731416 :             intrusive_ptr_del_ref(*ret.first);
     233             :         }
     234             : 
     235             :         assert(false);
     236             :         return NULL;
     237             :     }
     238             : 
     239             :     typedef std::set<Type *, TypeCompare> Set;
     240             :     size_t hash_size_;
     241             :     boost::scoped_array<Set> set_;
     242             :     boost::scoped_array<std::mutex> mutex_;
     243             : };
     244             : 
     245             : #endif  // SRC_BGP_BGP_ATTR_BASE_H_

Generated by: LCOV version 1.14