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

Generated by: LCOV version 1.14