LCOV - code coverage report
Current view: top level - bgp - bgp_config.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 150 391 38.4 %
Date: 2026-09-28 02:13:17 Functions: 22 57 38.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved.
       3             :  */
       4             : #include "bgp/bgp_config.h"
       5             : 
       6             : #include <boost/foreach.hpp>
       7             : 
       8             : #include <sstream>
       9             : 
      10             : #include "base/string_util.h"
      11             : #include "base/time_util.h"
      12             : 
      13             : using std::copy;
      14             : using std::endl;
      15             : using std::ostringstream;
      16             : using std::ostream_iterator;
      17             : using std::sort;
      18             : using std::string;
      19             : using std::swap;
      20             : using std::vector;
      21             : 
      22             : const char *BgpConfigManager::kMasterNetwork =
      23             :         "default-domain:default-project:ip-fabric";
      24             : const char *BgpConfigManager::kMasterInstance =
      25             :         "default-domain:default-project:ip-fabric:__default__";
      26             : const char *BgpConfigManager::kFabricInstance =
      27             :         "default-domain:default-project:ip-fabric:ip-fabric";
      28             : const int BgpConfigManager::kDefaultPort = 179;
      29             : const uint32_t BgpConfigManager::kDefaultAutonomousSystem = 64512;
      30             : 
      31           0 : static int CompareTo(const AuthenticationKey &lhs,
      32             :                      const AuthenticationKey &rhs) {
      33           0 :     KEY_COMPARE(lhs.id, rhs.id);
      34           0 :     KEY_COMPARE(lhs.value, rhs.value);
      35           0 :     KEY_COMPARE(lhs.start_time, rhs.start_time);
      36           0 :     return 0;
      37             : }
      38             : 
      39           0 : bool AuthenticationKey::operator<(const AuthenticationKey &rhs) const {
      40           0 :     int cmp = CompareTo(*this, rhs);
      41           0 :     return cmp < 0;
      42             : }
      43             : 
      44           0 : bool AuthenticationKey::operator==(const AuthenticationKey &rhs) const {
      45           0 :     int cmp = CompareTo(*this, rhs);
      46           0 :     return cmp == 0;
      47             : }
      48             : 
      49        9002 : AuthenticationData::AuthenticationData() : key_type_(NIL) {
      50        9002 : }
      51             : 
      52           0 : AuthenticationData::AuthenticationData(KeyType type,
      53           0 :         const AuthenticationKeyChain &chain) :
      54           0 :     key_type_(type), key_chain_(chain) {
      55           0 : }
      56             : 
      57        3616 : bool AuthenticationData::operator<(const AuthenticationData &rhs) const {
      58        3616 :     BOOL_KEY_COMPARE(key_type_, rhs.key_type());
      59        3616 :     BOOL_KEY_COMPARE(key_chain_, rhs.key_chain());
      60        3616 :     return false;
      61             : }
      62             : 
      63        1618 : bool AuthenticationData::operator==(const AuthenticationData &rhs) const {
      64        3236 :     if ((key_chain_.size() != rhs.key_chain().size()) ||
      65        1618 :         (key_type_ != rhs.key_type())) {
      66           0 :         return false;
      67             :     }
      68             : 
      69        1618 :     for (size_t ocnt = 0; ocnt < rhs.key_chain().size(); ++ocnt) {
      70           0 :         bool found = false;
      71           0 :         for (size_t icnt = 0; icnt < key_chain_.size(); ++icnt) {
      72           0 :             if (key_chain_[icnt] == rhs.key_chain()[ocnt]) {
      73           0 :                 found = true;
      74           0 :                 break;
      75             :             }
      76             :         }
      77           0 :         if (!found) {
      78           0 :             return false;
      79             :         }
      80             :     }
      81        1618 :     return true;
      82             : }
      83             : 
      84        5588 : AuthenticationData &AuthenticationData::operator=(
      85             :         const AuthenticationData &rhs) {
      86        5588 :     set_key_type(rhs.key_type());
      87        5588 :     set_key_chain(rhs.key_chain());
      88        5588 :     return *this;
      89             : }
      90             : 
      91           0 : void AuthenticationData::AddKeyToKeyChain(const AuthenticationKey &key) {
      92           0 :     key_chain_.push_back(key);
      93           0 : }
      94             : 
      95           0 : const AuthenticationKey *AuthenticationData::Find(int key_id) const {
      96             :     const AuthenticationKey *item;
      97           0 :     for (size_t i = 0; i < key_chain_.size(); ++i) {
      98           0 :         item = &key_chain_[i];
      99           0 :         if (item->id == key_id) {
     100           0 :             return item;
     101             :         }
     102             :     }
     103           0 :     return NULL;
     104             : }
     105             : 
     106        2794 : bool AuthenticationData::Empty() const {
     107        2794 :     return key_chain_.empty();
     108             : }
     109             : 
     110           0 : void AuthenticationData::Clear() {
     111           0 :     key_chain_.clear();
     112           0 : }
     113             : 
     114           0 : string AuthenticationData::KeyTypeToString() const {
     115           0 :     switch (key_type_) {
     116           0 :         case MD5:
     117           0 :             return "MD5";
     118           0 :         default:
     119           0 :             return "NIL";
     120             :     }
     121             : }
     122             : 
     123           0 : string AuthenticationData::KeyTypeToString(KeyType key_type) {
     124           0 :     switch (key_type) {
     125           0 :         case MD5:
     126           0 :             return "MD5";
     127           0 :         default:
     128           0 :             return "NIL";
     129             :     }
     130             : }
     131             : 
     132           0 : vector<string> AuthenticationData::KeysToString() const {
     133           0 :     AuthenticationKeyChain::const_iterator iter;
     134           0 :     vector<string> auth_keys;
     135           0 :     for (iter = key_chain_.begin(); iter != key_chain_.end(); ++iter) {
     136           0 :         AuthenticationKey key = *iter;
     137           0 :         auth_keys.push_back(integerToString(key.id));
     138           0 :     }
     139           0 :     return auth_keys;
     140           0 : }
     141             : 
     142             : // NOTE: This prints the actual key too. Use with care.
     143           0 : vector<string> AuthenticationData::KeysToStringDetail() const {
     144           0 :     AuthenticationKeyChain::const_iterator iter;
     145           0 :     vector<string> auth_keys;
     146           0 :     for (iter = key_chain_.begin(); iter != key_chain_.end(); ++iter) {
     147           0 :         AuthenticationKey key = *iter;
     148           0 :         auth_keys.push_back(integerToString(key.id) + ":" + key.value);
     149           0 :     }
     150           0 :     return auth_keys;
     151           0 : }
     152             : 
     153        2794 : BgpNeighborConfig::OriginOverrideConfig::OriginOverrideConfig()
     154        2794 :         : origin_override(false), origin("IGP") {
     155        2794 : }
     156             : 
     157        4060 : bool BgpNeighborConfig::OriginOverrideConfig::operator<(
     158             :                 const OriginOverrideConfig &rhs) const {
     159        4060 :     if (origin_override == rhs.origin_override) {
     160        4060 :         if (origin_override) {
     161             :             // chek origin value only if override is set
     162           0 :             return origin < rhs.origin;
     163             :         }
     164        4060 :         return false;
     165             :     }
     166             : 
     167           0 :     return origin_override < rhs.origin_override;
     168             : }
     169             : 
     170           0 : bool BgpFamilyAttributesConfig::operator==(
     171             :         const BgpFamilyAttributesConfig &rhs) const {
     172           0 :     if (family != rhs.family)
     173           0 :         return false;
     174           0 :     if (loop_count != rhs.loop_count)
     175           0 :         return false;
     176           0 :     if (prefix_limit != rhs.prefix_limit)
     177           0 :         return false;
     178           0 :     if (idle_timeout != rhs.idle_timeout)
     179           0 :         return false;
     180           0 :     if (default_tunnel_encap_list != rhs.default_tunnel_encap_list)
     181           0 :         return false;
     182           0 :     return true;
     183             : }
     184             : 
     185        2794 : BgpNeighborConfig::BgpNeighborConfig()
     186        2794 :         : type_(UNSPECIFIED),
     187        2794 :           admin_down_(false),
     188        2794 :           passive_(false),
     189        2794 :           as_override_(false),
     190        2794 :           cluster_id_(0),
     191        2794 :           peer_as_(0),
     192        2794 :           identifier_(0),
     193        2794 :           port_(BgpConfigManager::kDefaultPort),
     194        2794 :           source_port_(0),
     195        2794 :           hold_time_(0),
     196        2794 :           loop_count_(0),
     197        2794 :           local_as_(0),
     198        2794 :           local_identifier_(0),
     199        2794 :           last_change_at_(UTCTimestampUsec()) {
     200        2794 : }
     201             : 
     202           0 : void BgpNeighborConfig::CopyValues(const BgpNeighborConfig &rhs) {
     203           0 :     instance_name_ = rhs.instance_name_;
     204           0 :     group_name_ = rhs.group_name_;
     205           0 :     type_ = rhs.type_;
     206           0 :     admin_down_ = rhs.admin_down_;
     207           0 :     passive_ = rhs.passive_;
     208           0 :     as_override_ = rhs.as_override_;
     209           0 :     private_as_action_  = rhs.private_as_action_;
     210           0 :     cluster_id_ = rhs.cluster_id_;
     211           0 :     peer_as_ = rhs.peer_as_;
     212           0 :     identifier_ = rhs.identifier_;
     213           0 :     address_ = rhs.address_;
     214           0 :     inet_gateway_address_ = rhs.inet_gateway_address_;
     215           0 :     inet6_gateway_address_ = rhs.inet6_gateway_address_;
     216           0 :     port_ = rhs.port_;
     217           0 :     source_port_ = rhs.source_port_;
     218           0 :     hold_time_ = rhs.hold_time_;
     219           0 :     loop_count_ = rhs.loop_count_;
     220           0 :     local_as_ = rhs.local_as_;
     221           0 :     local_identifier_ = rhs.local_identifier_;
     222           0 :     auth_data_ = rhs.auth_data_;
     223           0 :     family_attributes_list_ = rhs.family_attributes_list_;
     224           0 :     origin_override_ = rhs.origin_override_;
     225           0 : }
     226             : 
     227        2174 : int BgpNeighborConfig::CompareTo(const BgpNeighborConfig &rhs) const {
     228        2174 :     KEY_COMPARE(name_, rhs.name_);
     229        2174 :     KEY_COMPARE(uuid_, rhs.uuid_);
     230        2174 :     KEY_COMPARE(instance_name_, rhs.instance_name_);
     231        2174 :     KEY_COMPARE(type_, rhs.type_);
     232        2174 :     KEY_COMPARE(admin_down_, rhs.admin_down_);
     233        2054 :     KEY_COMPARE(passive_, rhs.passive_);
     234        2030 :     KEY_COMPARE(as_override_, rhs.as_override_);
     235        2030 :     KEY_COMPARE(origin_override_, rhs.origin_override_);
     236        2030 :     KEY_COMPARE(private_as_action_, rhs.private_as_action_);
     237        2030 :     KEY_COMPARE(cluster_id_, rhs.cluster_id_);
     238        2030 :     KEY_COMPARE(peer_as_, rhs.peer_as_);
     239        1958 :     KEY_COMPARE(identifier_, rhs.identifier_);
     240        1940 :     KEY_COMPARE(address_, rhs.address_);
     241        1940 :     KEY_COMPARE(inet_gateway_address_, rhs.inet_gateway_address_);
     242        1940 :     KEY_COMPARE(inet6_gateway_address_, rhs.inet6_gateway_address_);
     243        1940 :     KEY_COMPARE(port_, rhs.port_);
     244        1940 :     KEY_COMPARE(source_port_, rhs.source_port_);
     245        1940 :     KEY_COMPARE(hold_time_, rhs.hold_time_);
     246        1832 :     KEY_COMPARE(loop_count_, rhs.loop_count_);
     247        1832 :     KEY_COMPARE(local_as_, rhs.local_as_);
     248        1808 :     KEY_COMPARE(local_identifier_, rhs.local_identifier_);
     249        1808 :     KEY_COMPARE(auth_data_, rhs.auth_data_);
     250        1808 :     return STLSortedCompare(
     251             :         family_attributes_list_.begin(), family_attributes_list_.end(),
     252             :         rhs.family_attributes_list_.begin(), rhs.family_attributes_list_.end(),
     253        1808 :         BgpFamilyAttributesConfigCompare());
     254             : }
     255             : 
     256        2794 : void BgpNeighborConfig::SetOriginOverride(bool origin_override,
     257             :                                           std::string origin) {
     258        2794 :     origin_override_.origin_override = origin_override;
     259        2794 :     origin_override_.origin = origin;
     260        2794 : }
     261             : 
     262           0 : const IpAddress &BgpNeighborConfig::gateway_address(
     263             :     Address::Family family) const {
     264           0 :     assert(family == Address::INET || family == Address::INET6);
     265           0 :     if (family == Address::INET) {
     266           0 :         return inet_gateway_address_;
     267             :     } else {
     268           0 :         return inet6_gateway_address_;
     269             :     }
     270             : }
     271             : 
     272           0 : void BgpNeighborConfig::set_gateway_address(Address::Family family,
     273             :     const IpAddress &address) {
     274           0 :     assert(family == Address::INET || family == Address::INET6);
     275           0 :     if (family == Address::INET) {
     276           0 :         inet_gateway_address_ = address;
     277             :     } else {
     278           0 :         inet6_gateway_address_ = address;
     279             :     }
     280           0 : }
     281             : 
     282             : BgpNeighborConfig::AddressFamilyList
     283        1618 : BgpNeighborConfig::GetAddressFamilies() const {
     284        1618 :     BgpNeighborConfig::AddressFamilyList family_list;
     285        3608 :     for (const auto& family_config : family_attributes_list_) {
     286        1990 :         family_list.push_back(family_config.family);
     287             :     }
     288        1618 :     sort(family_list.begin(), family_list.end());
     289        1618 :     return family_list;
     290           0 : }
     291             : 
     292           0 : string BgpNeighborConfig::AuthKeyTypeToString() const {
     293           0 :     return auth_data_.KeyTypeToString();
     294             : }
     295             : 
     296             : // Return the key's id concatenated with its type.
     297           0 : vector<string> BgpNeighborConfig::AuthKeysToString() const {
     298           0 :     return auth_data_.KeysToString();
     299             : }
     300             : 
     301             : 
     302           0 : bool StaticRouteConfig::operator<(const StaticRouteConfig &rhs) const {
     303           0 :     BOOL_KEY_COMPARE(address, rhs.address);
     304           0 :     BOOL_KEY_COMPARE(prefix_length, rhs.prefix_length);
     305           0 :     BOOL_KEY_COMPARE(nexthop, rhs.nexthop);
     306           0 :     return false;
     307             : }
     308             : 
     309         378 : BgpProtocolConfig::BgpProtocolConfig(const string &instance_name)
     310         378 :     : instance_name_(instance_name),
     311         378 :       admin_down_(false),
     312         378 :       cluster_id_(0),
     313         378 :       autonomous_system_(0),
     314         378 :       local_autonomous_system_(0),
     315         378 :       identifier_(0),
     316         378 :       port_(0),
     317         378 :       hold_time_(0),
     318         378 :       last_change_at_(UTCTimestampUsec()) {
     319         378 : }
     320             : 
     321           0 : int BgpProtocolConfig::CompareTo(const BgpProtocolConfig &rhs) const {
     322           0 :     KEY_COMPARE(instance_name_, rhs.instance_name_);
     323           0 :     KEY_COMPARE(admin_down_, rhs.admin_down_);
     324           0 :     KEY_COMPARE(autonomous_system_, rhs.autonomous_system_);
     325           0 :     KEY_COMPARE(identifier_, rhs.identifier_);
     326           0 :     KEY_COMPARE(port_, rhs.port_);
     327           0 :     KEY_COMPARE(hold_time_, rhs.hold_time_);
     328           0 :     return 0;
     329             : }
     330             : 
     331         378 : BgpInstanceConfig::BgpInstanceConfig(const string &name)
     332         378 :     : name_(name),
     333         378 :       has_pnf_(false),
     334         378 :       virtual_network_index_(0),
     335         378 :       virtual_network_allow_transit_(false),
     336         378 :       virtual_network_pbb_evpn_enable_(false),
     337         378 :       index_(-1),
     338         378 :       vxlan_id_(0),
     339         378 :       last_change_at_(UTCTimestampUsec()) {
     340         378 : }
     341             : 
     342         378 : BgpInstanceConfig::~BgpInstanceConfig() {
     343         378 : }
     344             : 
     345         238 : void BgpInstanceConfig::Clear() {
     346         238 :     import_list_.clear();
     347         238 :     export_list_.clear();
     348         238 :     has_pnf_ = false;
     349         238 :     virtual_network_.clear();
     350         238 :     virtual_network_index_ = 0;
     351         238 :     virtual_network_allow_transit_ = false;
     352         238 :     virtual_network_pbb_evpn_enable_ = false;
     353         238 :     vxlan_id_ = 0;
     354         238 :     inet_static_routes_.clear();
     355         238 :     inet6_static_routes_.clear();
     356         238 :     service_chain_list_.clear();
     357         238 : }
     358             : 
     359           0 : const BgpInstanceConfig::StaticRouteList &BgpInstanceConfig::static_routes(
     360             :     Address::Family family) const {
     361           0 :     assert(family == Address::INET || family == Address::INET6);
     362           0 :     if (family == Address::INET) {
     363           0 :         return inet_static_routes_;
     364             :     } else {
     365           0 :         return inet6_static_routes_;
     366             :     }
     367             : }
     368             : 
     369           0 : void BgpInstanceConfig::swap_static_routes(Address::Family family,
     370             :     StaticRouteList *list) {
     371           0 :     assert(family == Address::INET || family == Address::INET6);
     372           0 :     if (family == Address::INET) {
     373           0 :         swap(inet_static_routes_, *list);
     374             :     } else {
     375           0 :         swap(inet6_static_routes_, *list);
     376             :     }
     377           0 : }
     378             : 
     379           0 : const ServiceChainConfig *BgpInstanceConfig::service_chain_info(
     380             :     SCAddress::Family family) const {
     381           0 :     for (ServiceChainList::const_iterator it = service_chain_list_.begin();
     382           0 :          it != service_chain_list_.end(); ++it) {
     383           0 :         if (it->family == family)
     384           0 :             return it.operator->();
     385             :     }
     386           0 :     return NULL;
     387             : }
     388             : 
     389             : const BgpInstanceConfig::AggregateRouteList &
     390           0 : BgpInstanceConfig::aggregate_routes(Address::Family family) const {
     391           0 :     assert(family == Address::INET || family == Address::INET6);
     392           0 :     if (family == Address::INET) {
     393           0 :         return inet_aggregate_routes_;
     394             :     } else {
     395           0 :         return inet6_aggregate_routes_;
     396             :     }
     397             : }
     398             : 
     399         476 : void BgpInstanceConfig::swap_aggregate_routes(Address::Family family,
     400             :                                               AggregateRouteList *list) {
     401         476 :     assert(family == Address::INET || family == Address::INET6);
     402         476 :     if (family == Address::INET) {
     403         238 :         swap(inet_aggregate_routes_, *list);
     404             :     } else {
     405         238 :         swap(inet6_aggregate_routes_, *list);
     406             :     }
     407         476 : }
     408             : 
     409           0 : BgpRoutingPolicyConfig::BgpRoutingPolicyConfig(const string &name)
     410           0 :         : name_(name),
     411           0 :           last_change_at_(UTCTimestampUsec()) {
     412           0 : }
     413             : 
     414           0 : BgpRoutingPolicyConfig::~BgpRoutingPolicyConfig() {
     415           0 : }
     416             : 
     417           0 : void BgpRoutingPolicyConfig::Clear() {
     418           0 :     terms_.clear();
     419           0 : }
     420             : 
     421           0 : string RoutingPolicyMatchConfig::ToString() const {
     422           0 :     ostringstream oss;
     423           0 :     oss << "from {" << endl;
     424           0 :     if (!protocols_match.empty()) {
     425           0 :         oss << "    protocol [ ";
     426           0 :         for (const auto &protocol : protocols_match) {
     427           0 :             oss << protocol << ",";
     428             :         }
     429           0 :         oss.seekp(-1, oss.cur);
     430           0 :         oss << " ]";
     431             :     }
     432           0 :     if (!community_match.empty()) {
     433           0 :         if (community_match_all) {
     434           0 :             oss << "    community (all) [ ";
     435             :         } else {
     436           0 :             oss << "    community (any) [ ";
     437             :         }
     438           0 :         for (const auto &community : community_match) {
     439           0 :             oss << community << ",";
     440             :         }
     441           0 :         oss.seekp(-1, oss.cur);
     442           0 :         oss << " ]";
     443             :     }
     444           0 :     if (!prefixes_to_match.empty()) {
     445           0 :         for (const auto &match : prefixes_to_match) {
     446           0 :             oss << "    prefix " << match.prefix_to_match << " "
     447           0 :                 << match.prefix_match_type << endl;
     448             :         }
     449             :     }
     450           0 :     oss << "}" << endl;
     451           0 :     return oss.str();
     452           0 : }
     453             : 
     454           0 : static void PutAsnList(ostringstream *oss, const AsnList &list) {
     455           0 :     copy(list.begin(), list.end(), ostream_iterator<uint16_t>(*oss, ","));
     456           0 :     oss->seekp(-1, oss->cur);
     457           0 : }
     458             : 
     459           0 : static void PutCommunityList(ostringstream *oss, const CommunityList &list) {
     460           0 :     copy(list.begin(), list.end(), ostream_iterator<string>(*oss, ","));
     461           0 :     oss->seekp(-1, oss->cur);
     462           0 : }
     463             : 
     464           0 : string RoutingPolicyActionConfig::ToString() const {
     465           0 :     ostringstream oss;
     466           0 :     oss << "then {" << endl;
     467           0 :     if (!update.aspath_expand.empty()) {
     468           0 :         oss << "    as-path expand [ ";
     469           0 :         PutAsnList(&oss, update.aspath_expand);
     470           0 :         oss << " ]" << endl;
     471             :     }
     472           0 :     if (!update.community_set.empty()) {
     473           0 :         oss << "    community set [ ";
     474           0 :         PutCommunityList(&oss, update.community_set);
     475           0 :         oss << " ]" << endl;
     476             :     }
     477           0 :     if (!update.community_add.empty()) {
     478           0 :         oss << "    community add [ ";
     479           0 :         PutCommunityList(&oss, update.community_add);
     480           0 :         oss << " ]" << endl;
     481             :     }
     482           0 :     if (!update.community_remove.empty()) {
     483           0 :         oss << "    community remove [ ";
     484           0 :         PutCommunityList(&oss, update.community_remove);
     485           0 :         oss << " ]" << endl;
     486             :     }
     487           0 :     if (update.local_pref) {
     488           0 :         oss << "    local-preference " << update.local_pref << endl;
     489             :     }
     490           0 :     if (update.med) {
     491           0 :         oss << "    med " << update.med << endl;
     492             :     }
     493             : 
     494           0 :     if (action == ACCEPT) {
     495           0 :         oss << "    accept" << endl;
     496           0 :     } else if (action == REJECT) {
     497           0 :         oss << "    reject" << endl;
     498           0 :     } else if (action == NEXT_TERM) {
     499           0 :         oss << "    next-term" << endl;
     500             :     }
     501           0 :     oss << "}" << endl;
     502           0 :     return oss.str();
     503           0 : }
     504             : 
     505         378 : BgpConfigManager::BgpConfigManager(BgpServer *server)
     506         378 :         : server_(server) {
     507         378 : }
     508             : 
     509         378 : BgpConfigManager::~BgpConfigManager() {
     510         378 : }
     511             : 
     512             : template<>
     513         876 : void BgpConfigManager::Notify<BgpInstanceConfig>(
     514             :         const BgpInstanceConfig *config, EventType event) {
     515         876 :     config->set_last_change_at(UTCTimestampUsec());
     516        1752 :     for (auto obs : obs_) {
     517         876 :         if (obs.instance) {
     518         876 :             (obs.instance)(config, event);
     519             :         }
     520         876 :     }
     521         876 : }
     522             : 
     523             : template<>
     524           0 : void BgpConfigManager::Notify<BgpRoutingPolicyConfig>(
     525             :         const BgpRoutingPolicyConfig *config, EventType event) {
     526           0 :     config->set_last_change_at(UTCTimestampUsec());
     527           0 :     for (auto obs : obs_) {
     528           0 :         if (obs.policy) {
     529           0 :             (obs.policy)(config, event);
     530             :         }
     531           0 :     }
     532           0 : }
     533             : 
     534             : template<>
     535         416 : void BgpConfigManager::Notify<BgpProtocolConfig>(
     536             :         const BgpProtocolConfig *config, EventType event) {
     537         416 :     config->set_last_change_at(UTCTimestampUsec());
     538         832 :     for (auto obs : obs_) {
     539         416 :         if (obs.protocol) {
     540         416 :             (obs.protocol)(config, event);
     541             :         }
     542         416 :     }
     543         416 : }
     544             : 
     545             : template<>
     546        1004 : void BgpConfigManager::Notify<BgpNeighborConfig>(
     547             :         const BgpNeighborConfig *config, EventType event) {
     548        1004 :     config->set_last_change_at(UTCTimestampUsec());
     549        2008 :     for (auto obs : obs_) {
     550        1004 :         if (obs.neighbor) {
     551        1004 :             (obs.neighbor)(config, event);
     552             :         }
     553        1004 :     }
     554        1004 : }
     555             : 
     556             : template<>
     557         246 : void BgpConfigManager::Notify<BgpGlobalSystemConfig>(
     558             :         const BgpGlobalSystemConfig *config, EventType event) {
     559         246 :     config->set_last_change_at(UTCTimestampUsec());
     560         492 :     for (auto obs : obs_) {
     561         246 :         if (obs.system) {
     562         246 :             (obs.system)(config, event);
     563             :         }
     564         246 :     }
     565         246 : }
     566             : 
     567             : template<>
     568           0 : void BgpConfigManager::Notify<BgpGlobalQosConfig>(
     569             :         const BgpGlobalQosConfig *config, EventType event) {
     570           0 :     config->set_last_change_at(UTCTimestampUsec());
     571           0 :     for (auto obs : obs_) {
     572           0 :         if (obs.qos) {
     573           0 :             (obs.qos)(config, event);
     574             :         }
     575           0 :     }
     576           0 : }

Generated by: LCOV version 1.14