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: 153 391 39.1 %
Date: 2026-09-21 02:11:39 Functions: 23 57 40.4 %
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         256 : AuthenticationData::AuthenticationData() : key_type_(NIL) {
      50         256 : }
      51             : 
      52           0 : AuthenticationData::AuthenticationData(KeyType type,
      53           0 :         const AuthenticationKeyChain &chain) :
      54           0 :     key_type_(type), key_chain_(chain) {
      55           0 : }
      56             : 
      57          64 : bool AuthenticationData::operator<(const AuthenticationData &rhs) const {
      58          64 :     BOOL_KEY_COMPARE(key_type_, rhs.key_type());
      59          64 :     BOOL_KEY_COMPARE(key_chain_, rhs.key_chain());
      60          64 :     return false;
      61             : }
      62             : 
      63         112 : bool AuthenticationData::operator==(const AuthenticationData &rhs) const {
      64         224 :     if ((key_chain_.size() != rhs.key_chain().size()) ||
      65         112 :         (key_type_ != rhs.key_type())) {
      66           0 :         return false;
      67             :     }
      68             : 
      69         112 :     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         112 :     return true;
      82             : }
      83             : 
      84          64 : AuthenticationData &AuthenticationData::operator=(
      85             :         const AuthenticationData &rhs) {
      86          64 :     set_key_type(rhs.key_type());
      87          64 :     set_key_chain(rhs.key_chain());
      88          64 :     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          64 : bool AuthenticationData::Empty() const {
     107          64 :     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         112 : BgpNeighborConfig::OriginOverrideConfig::OriginOverrideConfig()
     154         112 :         : origin_override(false), origin("IGP") {
     155         112 : }
     156             : 
     157          64 : bool BgpNeighborConfig::OriginOverrideConfig::operator<(
     158             :                 const OriginOverrideConfig &rhs) const {
     159          64 :     if (origin_override == rhs.origin_override) {
     160          64 :         if (origin_override) {
     161             :             // chek origin value only if override is set
     162           0 :             return origin < rhs.origin;
     163             :         }
     164          64 :         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         112 : BgpNeighborConfig::BgpNeighborConfig()
     186         112 :         : type_(UNSPECIFIED),
     187         112 :           admin_down_(false),
     188         112 :           passive_(false),
     189         112 :           as_override_(false),
     190         112 :           cluster_id_(0),
     191         112 :           peer_as_(0),
     192         112 :           identifier_(0),
     193         112 :           port_(BgpConfigManager::kDefaultPort),
     194         112 :           source_port_(0),
     195         112 :           hold_time_(0),
     196         112 :           loop_count_(0),
     197         112 :           local_as_(0),
     198         112 :           local_identifier_(0),
     199         112 :           last_change_at_(UTCTimestampUsec()) {
     200         112 : }
     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          32 : int BgpNeighborConfig::CompareTo(const BgpNeighborConfig &rhs) const {
     228          32 :     KEY_COMPARE(name_, rhs.name_);
     229          32 :     KEY_COMPARE(uuid_, rhs.uuid_);
     230          32 :     KEY_COMPARE(instance_name_, rhs.instance_name_);
     231          32 :     KEY_COMPARE(type_, rhs.type_);
     232          32 :     KEY_COMPARE(admin_down_, rhs.admin_down_);
     233          32 :     KEY_COMPARE(passive_, rhs.passive_);
     234          32 :     KEY_COMPARE(as_override_, rhs.as_override_);
     235          32 :     KEY_COMPARE(origin_override_, rhs.origin_override_);
     236          32 :     KEY_COMPARE(private_as_action_, rhs.private_as_action_);
     237          32 :     KEY_COMPARE(cluster_id_, rhs.cluster_id_);
     238          32 :     KEY_COMPARE(peer_as_, rhs.peer_as_);
     239          32 :     KEY_COMPARE(identifier_, rhs.identifier_);
     240          32 :     KEY_COMPARE(address_, rhs.address_);
     241          32 :     KEY_COMPARE(inet_gateway_address_, rhs.inet_gateway_address_);
     242          32 :     KEY_COMPARE(inet6_gateway_address_, rhs.inet6_gateway_address_);
     243          32 :     KEY_COMPARE(port_, rhs.port_);
     244          32 :     KEY_COMPARE(source_port_, rhs.source_port_);
     245          32 :     KEY_COMPARE(hold_time_, rhs.hold_time_);
     246          32 :     KEY_COMPARE(loop_count_, rhs.loop_count_);
     247          32 :     KEY_COMPARE(local_as_, rhs.local_as_);
     248          32 :     KEY_COMPARE(local_identifier_, rhs.local_identifier_);
     249          32 :     KEY_COMPARE(auth_data_, rhs.auth_data_);
     250          32 :     return STLSortedCompare(
     251             :         family_attributes_list_.begin(), family_attributes_list_.end(),
     252             :         rhs.family_attributes_list_.begin(), rhs.family_attributes_list_.end(),
     253          32 :         BgpFamilyAttributesConfigCompare());
     254             : }
     255             : 
     256           0 : void BgpNeighborConfig::SetOriginOverride(bool origin_override,
     257             :                                           std::string origin) {
     258           0 :     origin_override_.origin_override = origin_override;
     259           0 :     origin_override_.origin = origin;
     260           0 : }
     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         112 : BgpNeighborConfig::GetAddressFamilies() const {
     284         112 :     BgpNeighborConfig::AddressFamilyList family_list;
     285         304 :     for (const auto& family_config : family_attributes_list_) {
     286         192 :         family_list.push_back(family_config.family);
     287             :     }
     288         112 :     sort(family_list.begin(), family_list.end());
     289         112 :     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          32 : BgpProtocolConfig::BgpProtocolConfig(const string &instance_name)
     310          32 :     : instance_name_(instance_name),
     311          32 :       admin_down_(false),
     312          32 :       cluster_id_(0),
     313          32 :       autonomous_system_(0),
     314          32 :       local_autonomous_system_(0),
     315          32 :       identifier_(0),
     316          32 :       port_(0),
     317          32 :       hold_time_(0),
     318          32 :       last_change_at_(UTCTimestampUsec()) {
     319          32 : }
     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         128 : BgpInstanceConfig::BgpInstanceConfig(const string &name)
     332         128 :     : name_(name),
     333         128 :       has_pnf_(false),
     334         128 :       virtual_network_index_(0),
     335         128 :       virtual_network_allow_transit_(false),
     336         128 :       virtual_network_pbb_evpn_enable_(false),
     337         128 :       index_(-1),
     338         128 :       vxlan_id_(0),
     339         128 :       last_change_at_(UTCTimestampUsec()) {
     340         128 : }
     341             : 
     342         128 : BgpInstanceConfig::~BgpInstanceConfig() {
     343         128 : }
     344             : 
     345         224 : void BgpInstanceConfig::Clear() {
     346         224 :     import_list_.clear();
     347         224 :     export_list_.clear();
     348         224 :     has_pnf_ = false;
     349         224 :     virtual_network_.clear();
     350         224 :     virtual_network_index_ = 0;
     351         224 :     virtual_network_allow_transit_ = false;
     352         224 :     virtual_network_pbb_evpn_enable_ = false;
     353         224 :     vxlan_id_ = 0;
     354         224 :     inet_static_routes_.clear();
     355         224 :     inet6_static_routes_.clear();
     356         224 :     service_chain_list_.clear();
     357         224 : }
     358             : 
     359         192 : const BgpInstanceConfig::StaticRouteList &BgpInstanceConfig::static_routes(
     360             :     Address::Family family) const {
     361         192 :     assert(family == Address::INET || family == Address::INET6);
     362         192 :     if (family == Address::INET) {
     363          96 :         return inet_static_routes_;
     364             :     } else {
     365          96 :         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         423 : const ServiceChainConfig *BgpInstanceConfig::service_chain_info(
     380             :     SCAddress::Family family) const {
     381         423 :     for (ServiceChainList::const_iterator it = service_chain_list_.begin();
     382         423 :          it != service_chain_list_.end(); ++it) {
     383           0 :         if (it->family == family)
     384           0 :             return it.operator->();
     385             :     }
     386         422 :     return NULL;
     387             : }
     388             : 
     389             : const BgpInstanceConfig::AggregateRouteList &
     390         192 : BgpInstanceConfig::aggregate_routes(Address::Family family) const {
     391         192 :     assert(family == Address::INET || family == Address::INET6);
     392         192 :     if (family == Address::INET) {
     393          96 :         return inet_aggregate_routes_;
     394             :     } else {
     395          96 :         return inet6_aggregate_routes_;
     396             :     }
     397             : }
     398             : 
     399         448 : void BgpInstanceConfig::swap_aggregate_routes(Address::Family family,
     400             :                                               AggregateRouteList *list) {
     401         448 :     assert(family == Address::INET || family == Address::INET6);
     402         448 :     if (family == Address::INET) {
     403         224 :         swap(inet_aggregate_routes_, *list);
     404             :     } else {
     405         224 :         swap(inet6_aggregate_routes_, *list);
     406             :     }
     407         448 : }
     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          32 : BgpConfigManager::BgpConfigManager(BgpServer *server)
     506          32 :         : server_(server) {
     507          32 : }
     508             : 
     509          32 : BgpConfigManager::~BgpConfigManager() {
     510          32 : }
     511             : 
     512             : template<>
     513         384 : void BgpConfigManager::Notify<BgpInstanceConfig>(
     514             :         const BgpInstanceConfig *config, EventType event) {
     515         384 :     config->set_last_change_at(UTCTimestampUsec());
     516         768 :     for (auto obs : obs_) {
     517         384 :         if (obs.instance) {
     518         384 :             (obs.instance)(config, event);
     519             :         }
     520         384 :     }
     521         384 : }
     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          32 : void BgpConfigManager::Notify<BgpProtocolConfig>(
     536             :         const BgpProtocolConfig *config, EventType event) {
     537          32 :     config->set_last_change_at(UTCTimestampUsec());
     538          64 :     for (auto obs : obs_) {
     539          32 :         if (obs.protocol) {
     540          32 :             (obs.protocol)(config, event);
     541             :         }
     542          32 :     }
     543          32 : }
     544             : 
     545             : template<>
     546          32 : void BgpConfigManager::Notify<BgpNeighborConfig>(
     547             :         const BgpNeighborConfig *config, EventType event) {
     548          32 :     config->set_last_change_at(UTCTimestampUsec());
     549          64 :     for (auto obs : obs_) {
     550          32 :         if (obs.neighbor) {
     551          32 :             (obs.neighbor)(config, event);
     552             :         }
     553          32 :     }
     554          32 : }
     555             : 
     556             : template<>
     557           0 : void BgpConfigManager::Notify<BgpGlobalSystemConfig>(
     558             :         const BgpGlobalSystemConfig *config, EventType event) {
     559           0 :     config->set_last_change_at(UTCTimestampUsec());
     560           0 :     for (auto obs : obs_) {
     561           0 :         if (obs.system) {
     562           0 :             (obs.system)(config, event);
     563             :         }
     564           0 :     }
     565           0 : }
     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