LCOV - code coverage report
Current view: top level - bgp - bgp_xmpp_channel.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 1731 1918 90.3 %
Date: 2026-06-04 02:06:09 Functions: 155 164 94.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
       3             :  */
       4             : 
       5             : #include "bgp/bgp_xmpp_channel.h"
       6             : 
       7             : #include <boost/assign/list_of.hpp>
       8             : #include <boost/foreach.hpp>
       9             : 
      10             : #include <limits>
      11             : #include <sstream>
      12             : #include <vector>
      13             : #include <atomic>
      14             : 
      15             : #include "base/regex.h"
      16             : #include "base/task_annotations.h"
      17             : #include "bgp/bgp_config.h"
      18             : #include "bgp/bgp_factory.h"
      19             : #include "bgp/bgp_log.h"
      20             : #include "bgp/bgp_membership.h"
      21             : #include "bgp/bgp_server.h"
      22             : #include "bgp/bgp_update_sender.h"
      23             : #include "bgp/bgp_xmpp_peer_close.h"
      24             : #include "bgp/inet/inet_table.h"
      25             : #include "bgp/inet6/inet6_table.h"
      26             : #include "bgp/extended-community/etree.h"
      27             : #include "bgp/extended-community/load_balance.h"
      28             : #include "bgp/extended-community/mac_mobility.h"
      29             : #include "bgp/extended-community/local_sequence_number.h"
      30             : #include "bgp/extended-community/router_mac.h"
      31             : #include "bgp/extended-community/tag.h"
      32             : #include "bgp/large-community/tag.h"
      33             : #include "bgp/ermvpn/ermvpn_table.h"
      34             : #include "bgp/evpn/evpn_route.h"
      35             : #include "bgp/evpn/evpn_table.h"
      36             : #include "bgp/mvpn/mvpn_table.h"
      37             : #include "bgp/peer_close_manager.h"
      38             : #include "bgp/peer_stats.h"
      39             : #include "bgp/security_group/security_group.h"
      40             : #include "bgp/tunnel_encap/tunnel_encap.h"
      41             : #include "bgp/bgp_xmpp_rtarget_manager.h"
      42             : #include "control-node/sandesh/control_node_types.h"
      43             : #include "net/community_type.h"
      44             : #include "schema/xmpp_multicast_types.h"
      45             : #include "schema/xmpp_enet_types.h"
      46             : #include "schema/xmpp_mvpn_types.h"
      47             : #include "xml/xml_pugi.h"
      48             : #include "xmpp/xmpp_connection.h"
      49             : #include "xmpp/xmpp_init.h"
      50             : #include "xmpp/xmpp_server.h"
      51             : #include "xmpp/sandesh/xmpp_peer_info_types.h"
      52             : 
      53             : using autogen::EnetItemType;
      54             : using autogen::EnetNextHopListType;
      55             : using autogen::EnetSecurityGroupListType;
      56             : using autogen::EnetTunnelEncapsulationListType;
      57             : 
      58             : using autogen::McastItemType;
      59             : using autogen::McastNextHopsType;
      60             : using autogen::McastTunnelEncapsulationListType;
      61             : 
      62             : using autogen::MvpnItemType;
      63             : using autogen::MvpnNextHopType;
      64             : using autogen::MvpnTunnelEncapsulationListType;
      65             : 
      66             : using autogen::ItemType;
      67             : using autogen::NextHopListType;
      68             : using autogen::SecurityGroupListType;
      69             : using autogen::CommunityTagListType;
      70             : using autogen::TunnelEncapsulationListType;
      71             : using autogen::TagListType;
      72             : 
      73             : using boost::assign::list_of;
      74             : using boost::smatch;
      75             : using boost::system::error_code;
      76             : using contrail::regex;
      77             : using contrail::regex_match;
      78             : using contrail::regex_search;
      79             : using pugi::xml_node;
      80             : using std::unique_ptr;
      81             : using std::make_pair;
      82             : using std::numeric_limits;
      83             : using std::ostringstream;
      84             : using std::pair;
      85             : using std::set;
      86             : using std::string;
      87             : using std::vector;
      88             : 
      89             : //
      90             : // Calculate med from local preference.
      91             : // Should move agent definitions to a common location and use those here
      92             : // instead of hard coded values.
      93             : //
      94       12366 : static uint32_t GetMedFromLocalPref(uint32_t local_pref) {
      95       12366 :     if (local_pref == 0)
      96        2384 :         return 0;
      97        9982 :     if (local_pref == 100)
      98        6861 :         return 200;
      99        3121 :     if (local_pref == 200)
     100          34 :         return 100;
     101        3087 :     return numeric_limits<uint32_t>::max() - local_pref;
     102             : }
     103             : 
     104           2 : void BgpXmppChannel::ErrorStats::incr_inet6_rx_bad_xml_token_count() {
     105           2 :     ++inet6_rx_bad_xml_token_count;
     106           2 : }
     107             : 
     108           2 : void BgpXmppChannel::ErrorStats::incr_inet6_rx_bad_prefix_count() {
     109           2 :     ++inet6_rx_bad_prefix_count;
     110           2 : }
     111             : 
     112           3 : void BgpXmppChannel::ErrorStats::incr_inet6_rx_bad_nexthop_count() {
     113           3 :     ++inet6_rx_bad_nexthop_count;
     114           3 : }
     115             : 
     116           3 : void BgpXmppChannel::ErrorStats::incr_inet6_rx_bad_afi_safi_count() {
     117           3 :     ++inet6_rx_bad_afi_safi_count;
     118           3 : }
     119             : 
     120         108 : uint64_t BgpXmppChannel::ErrorStats::get_inet6_rx_bad_xml_token_count() const {
     121         108 :     return inet6_rx_bad_xml_token_count;
     122             : }
     123             : 
     124         107 : uint64_t BgpXmppChannel::ErrorStats::get_inet6_rx_bad_prefix_count() const {
     125         107 :     return inet6_rx_bad_prefix_count;
     126             : }
     127             : 
     128         107 : uint64_t BgpXmppChannel::ErrorStats::get_inet6_rx_bad_nexthop_count() const {
     129         107 :     return inet6_rx_bad_nexthop_count;
     130             : }
     131             : 
     132         110 : uint64_t BgpXmppChannel::ErrorStats::get_inet6_rx_bad_afi_safi_count() const {
     133         110 :     return inet6_rx_bad_afi_safi_count;
     134             : }
     135             : 
     136             : class BgpXmppChannel::PeerStats : public IPeerDebugStats {
     137             : public:
     138       10050 :     explicit PeerStats(BgpXmppChannel *peer)
     139       10050 :         : parent_(peer) {
     140       10050 :     }
     141             : 
     142             :     // Used when peer flaps.
     143             :     // Don't need to do anything since the BgpXmppChannel itself gets deleted.
     144           0 :     virtual void Clear() {
     145           0 :     }
     146             : 
     147             :     // Printable name
     148           0 :     virtual string ToString() const {
     149           0 :         return parent_->ToString();
     150             :     }
     151             : 
     152             :     // Previous State of the peer
     153         487 :     virtual string last_state() const {
     154         487 :         return (parent_->channel_->LastStateName());
     155             :     }
     156             :     // Last state change occurred at
     157         487 :     virtual string last_state_change_at() const {
     158         487 :         return (parent_->channel_->LastStateChangeAt());
     159             :     }
     160             : 
     161             :     // Last error on this peer
     162         487 :     virtual string last_error() const {
     163         487 :         return "";
     164             :     }
     165             : 
     166             :     // Last Event on this peer
     167         487 :     virtual string last_event() const {
     168         487 :         return (parent_->channel_->LastEvent());
     169             :     }
     170             : 
     171             :     // When was the Last
     172        1461 :     virtual string last_flap() const {
     173        1461 :         return (parent_->channel_->LastFlap());
     174             :     }
     175             : 
     176             :     // Total number of flaps
     177        1461 :     virtual uint64_t num_flaps() const {
     178        1461 :         return (parent_->channel_->FlapCount());
     179             :     }
     180             : 
     181         590 :     virtual void GetRxProtoStats(ProtoStats *stats) const {
     182         590 :         stats->open = parent_->channel_->rx_open();
     183         590 :         stats->close = parent_->channel_->rx_close();
     184         590 :         stats->keepalive = parent_->channel_->rx_keepalive();
     185         590 :         stats->update = parent_->channel_->rx_update();
     186         590 :     }
     187             : 
     188         590 :     virtual void GetTxProtoStats(ProtoStats *stats) const {
     189         590 :         stats->open = parent_->channel_->tx_open();
     190         590 :         stats->close = parent_->channel_->tx_close();
     191         590 :         stats->keepalive = parent_->channel_->tx_keepalive();
     192         590 :         stats->update = parent_->channel_->tx_update();
     193         590 :     }
     194             : 
     195         693 :     virtual void GetRxRouteUpdateStats(UpdateStats *stats)  const {
     196         693 :         stats->reach = parent_->stats_[RX].reach.load();
     197         693 :         stats->unreach = parent_->stats_[RX].unreach.load();
     198         693 :         stats->end_of_rib = parent_->stats_[RX].end_of_rib.load();
     199         693 :         stats->total = stats->reach + stats->unreach + stats->end_of_rib;
     200         693 :     }
     201             : 
     202         693 :     virtual void GetTxRouteUpdateStats(UpdateStats *stats)  const {
     203         693 :         stats->reach = parent_->stats_[TX].reach.load();
     204         693 :         stats->unreach = parent_->stats_[TX].unreach.load();
     205         693 :         stats->end_of_rib = parent_->stats_[TX].end_of_rib.load();
     206         693 :         stats->total = stats->reach + stats->unreach + stats->end_of_rib;
     207         693 :     }
     208             : 
     209         487 :     virtual void GetRxSocketStats(IPeerDebugStats::SocketStats *stats) const {
     210         487 :         const XmppSession *session = parent_->GetSession();
     211         487 :         if (session) {
     212         475 :             const io::SocketStats &socket_stats = session->GetSocketStats();
     213         475 :             stats->calls = socket_stats.read_calls;
     214         475 :             stats->bytes = socket_stats.read_bytes;
     215             :         }
     216         487 :     }
     217             : 
     218         487 :     virtual void GetTxSocketStats(IPeerDebugStats::SocketStats *stats) const {
     219         487 :         const XmppSession *session = parent_->GetSession();
     220         487 :         if (session) {
     221         475 :             const io::SocketStats &socket_stats = session->GetSocketStats();
     222         475 :             stats->calls = socket_stats.write_calls;
     223         475 :             stats->bytes = socket_stats.write_bytes;
     224         475 :             stats->blocked_count = socket_stats.write_blocked;
     225         475 :             stats->blocked_duration_usecs =
     226         475 :                 socket_stats.write_blocked_duration_usecs;
     227             :         }
     228         487 :     }
     229             : 
     230         103 :     virtual void GetRxErrorStats(RxErrorStats *stats) const {
     231         103 :         const BgpXmppChannel::ErrorStats &err_stats = parent_->error_stats();
     232         103 :         stats->inet6_bad_xml_token_count =
     233         103 :             err_stats.get_inet6_rx_bad_xml_token_count();
     234         103 :         stats->inet6_bad_prefix_count =
     235         103 :             err_stats.get_inet6_rx_bad_prefix_count();
     236         103 :         stats->inet6_bad_nexthop_count =
     237         103 :             err_stats.get_inet6_rx_bad_nexthop_count();
     238         103 :         stats->inet6_bad_afi_safi_count =
     239         103 :             err_stats.get_inet6_rx_bad_afi_safi_count();
     240         103 :     }
     241             : 
     242         103 :     virtual void GetRxRouteStats(RxRouteStats *stats) const {
     243         103 :         stats->total_path_count = parent_->Peer()->GetTotalPathCount();
     244         103 :         stats->primary_path_count = parent_->Peer()->GetPrimaryPathCount();
     245         103 :     }
     246             : 
     247     1599784 :     virtual void UpdateTxUnreachRoute(uint64_t count) {
     248     1599784 :         parent_->stats_[TX].unreach += count;
     249     1599838 :     }
     250             : 
     251     1599656 :     virtual void UpdateTxReachRoute(uint64_t count) {
     252     1599656 :         parent_->stats_[TX].reach += count;
     253     1599828 :     }
     254             : 
     255             : private:
     256             :     BgpXmppChannel *parent_;
     257             : };
     258             : 
     259             : class BgpXmppChannel::XmppPeer : public IPeer {
     260             : public:
     261       10049 :     XmppPeer(BgpServer *server, BgpXmppChannel *channel)
     262       20098 :         : server_(server),
     263       10049 :           parent_(channel),
     264       10049 :           is_closed_(false),
     265       10049 :           send_ready_(true),
     266       10049 :           closed_at_(0) {
     267       10049 :         total_path_count_ = 0;
     268       10050 :         primary_path_count_ = 0;
     269       10050 :     }
     270             : 
     271       20100 :     virtual ~XmppPeer() {
     272       10050 :         assert(GetTotalPathCount() == 0);
     273             : 
     274       20100 :         XmppPeerInfoData peer_info;
     275       10050 :         peer_info.set_name(ToUVEKey());
     276       10050 :         peer_info.set_deleted(true);
     277       10050 :         parent_->XMPPPeerInfoSend(peer_info);
     278             : 
     279       20100 :         PeerStatsData peer_stats_data;
     280       10050 :         peer_stats_data.set_name(ToUVEKey());
     281       10050 :         peer_stats_data.set_deleted(true);
     282       10050 :         assert(!peer_stats_data.get_name().empty());
     283       10050 :         BGP_UVE_SEND2(PeerStatsUve, peer_stats_data, "ObjectXmppPeerInfo");
     284       20100 :     }
     285             : 
     286       19567 :     virtual bool MembershipPathCallback(DBTablePartBase *tpart, BgpRoute *rt,
     287             :                                         BgpPath *path) {
     288       19567 :         if (parent_->close_manager_->IsMembershipInUse())
     289       19504 :             return parent_->close_manager_->MembershipPathCallback(tpart, rt,
     290       19520 :                                                                    path);
     291             : 
     292          65 :         BgpTable *table = static_cast<BgpTable *>(tpart->parent());
     293          65 :         return table->DeletePath(tpart, rt, path);
     294             :     }
     295             : 
     296             :     virtual bool SendUpdate(const uint8_t *msg, size_t msgsize,
     297             :                             const std::string *msg_str);
     298       56939 :     virtual bool SendUpdate(const uint8_t *msg, size_t msgsize) {
     299       56939 :         return SendUpdate(msg, msgsize, NULL);
     300             :     }
     301     1692822 :     virtual const string &ToString() const {
     302     1692822 :         return parent_->ToString();
     303             :     }
     304             : 
     305        6291 :     virtual bool CanUseMembershipManager() const {
     306        6291 :         return parent_->GetMembershipRequestQueueSize() == 0;
     307             :     }
     308             : 
     309       59318 :     virtual bool IsRegistrationRequired() const { return true; }
     310             : 
     311      631495 :     virtual const string &ToUVEKey() const {
     312      631495 :         return parent_->ToUVEKey();
     313             :     }
     314             : 
     315      751635 :     virtual BgpServer *server() { return server_; }
     316     3937040 :     virtual BgpServer *server() const { return server_; }
     317           0 :     virtual IPeerClose *peer_close() {
     318           0 :         return parent_->peer_close_.get();
     319             :     }
     320       65873 :     virtual IPeerClose *peer_close() const {
     321       65873 :         return parent_->peer_close_.get();
     322             :     }
     323             : 
     324       65872 :     void UpdateCloseRouteStats(Address::Family family, const BgpPath *old_path,
     325             :                                uint32_t path_flags) const {
     326       65872 :         peer_close()->UpdateRouteStats(family, old_path, path_flags);
     327       65870 :     }
     328             : 
     329     1599712 :     virtual IPeerDebugStats *peer_stats() {
     330     1599712 :         return parent_->peer_stats_.get();
     331             :     }
     332        2641 :     virtual const IPeerDebugStats *peer_stats() const {
     333        2641 :         return parent_->peer_stats_.get();
     334             :     }
     335             : 
     336      190683 :     virtual bool IsReady() const {
     337      190683 :         return (parent_->channel_->GetPeerState() == xmps::READY);
     338             :     }
     339           0 :     virtual const string GetStateName() const {
     340           0 :         switch (parent_->channel_->GetPeerState()) {
     341           0 :             case xmps::UNKNOWN: return "UNKNOWN";
     342           0 :             case xmps::READY: return "READY";
     343           0 :             case xmps::NOT_READY: return "NOT_READY";
     344           0 :             case xmps::TIMEDOUT: return "TIMEDOUT";
     345             :         }
     346           0 :         return "UNKNOWN";
     347             :     }
     348     1758199 :     virtual bool IsXmppPeer() const {
     349     1758199 :         return true;
     350             :     }
     351             :     virtual void Close(bool graceful);
     352             : 
     353       74495 :     const bool IsDeleted() const { return is_closed_; }
     354       16624 :     void SetPeerClosed(bool closed) {
     355       16624 :         is_closed_ = closed;
     356       16624 :         if (is_closed_)
     357       16400 :             closed_at_ = UTCTimestampUsec();
     358       16625 :     }
     359         974 :     uint64_t closed_at() const { return closed_at_; }
     360             : 
     361      493259 :     virtual BgpProto::BgpPeerType PeerType() const {
     362      493259 :         return BgpProto::XMPP;
     363             :     }
     364             : 
     365      228835 :     virtual uint32_t bgp_identifier() const {
     366      228835 :         const TcpSession::Endpoint &remote = parent_->endpoint();
     367      228833 :         if (remote.address().is_v4()) {
     368      228833 :             return remote.address().to_v4().to_ulong();
     369             :         }
     370           0 :         return 0;
     371             :     }
     372             : 
     373      251391 :     virtual void UpdateTotalPathCount(int count) const {
     374      251391 :         total_path_count_ += count;
     375      251393 :     }
     376       10153 :     virtual int GetTotalPathCount() const {
     377       10153 :         return total_path_count_;
     378             :     }
     379           0 :     virtual bool IsAs4Supported() const { return true; }
     380      129159 :     virtual void UpdatePrimaryPathCount(int count,
     381             :         Address::Family family) const {
     382      129159 :         primary_path_count_ += count;
     383      129166 :     }
     384        1077 :     virtual int GetPrimaryPathCount() const {
     385        1077 :          return primary_path_count_;
     386             :     }
     387      125301 :     virtual void ProcessPathTunnelEncapsulation(const BgpPath *path,
     388             :         BgpAttr *attr, ExtCommunityDB *extcomm_db, const BgpTable *table)
     389             :         const {
     390      125301 :     }
     391           0 :     virtual const std::vector<std::string> GetDefaultTunnelEncap(
     392             :         Address::Family family) const {
     393           0 :         return std::vector<std::string>();
     394             :     }
     395           0 :     virtual bool IsInGRTimerWaitState() const {
     396           0 :         return parent_->close_manager_->IsInGRTimerWaitState();
     397             :     }
     398             : 
     399      141191 :     void MembershipRequestCallback(BgpTable *table) {
     400      141191 :         parent_->MembershipRequestCallback(table);
     401      141191 :     }
     402             : 
     403     1827661 :     virtual bool send_ready() const { return send_ready_; }
     404       26147 :     bool IsRouterTypeBGPaaS() const { return false; }
     405             : 
     406             : private:
     407           1 :     void WriteReadyCb(const boost::system::error_code &ec) {
     408           1 :         if (!server_) return;
     409           1 :         BgpUpdateSender *sender = server_->update_sender();
     410           2 :         BGP_LOG_PEER(Event, this, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_ALL,
     411             :                      BGP_PEER_DIR_NA, "Send ready");
     412           1 :         sender->PeerSendReady(this);
     413           1 :         send_ready_ = true;
     414             : 
     415             :         // Restart EndOfRib Send timer if necessary.
     416           1 :         parent_->ResetEndOfRibSendState();
     417             :     }
     418             : 
     419             :     BgpServer *server_;
     420             :     BgpXmppChannel *parent_;
     421             :     mutable std::atomic<int> total_path_count_;
     422             :     mutable std::atomic<int> primary_path_count_;
     423             :     bool is_closed_;
     424             :     bool send_ready_;
     425             :     uint64_t closed_at_;
     426             : };
     427             : 
     428             : // Skip sending updates if the destinatin matches against the pattern.
     429             : // XXX Used in test environments only
     430     1653188 : bool BgpXmppChannel::SkipUpdateSend() {
     431     1653188 :     static char *skip_env_ = getenv("XMPP_SKIP_UPDATE_SEND");
     432     1653227 :     if (!skip_env_)
     433     1653227 :         return false;
     434             : 
     435             :     // Use XMPP_SKIP_UPDATE_SEND as a regex pattern to match against destination
     436             :     // Cache the result to avoid redundant regex evaluation
     437           0 :     if (!skip_update_send_cached_) {
     438           0 :         smatch matches;
     439           0 :         skip_update_send_ = regex_search(ToString(), matches, regex(skip_env_));
     440           0 :         skip_update_send_cached_ = true;
     441           0 :     }
     442           0 :     return skip_update_send_;
     443             : }
     444             : 
     445     1656481 : bool BgpXmppChannel::XmppPeer::SendUpdate(const uint8_t *msg, size_t msgsize,
     446             :     const string *msg_str) {
     447     1656481 :     XmppChannel *channel = parent_->channel_;
     448     1656481 :     if (channel->GetPeerState() == xmps::READY) {
     449     1652959 :         parent_->stats_[TX].rt_updates++;
     450     1653268 :         if (parent_->SkipUpdateSend())
     451           0 :             return true;
     452     1653225 :         send_ready_ = channel->Send(msg, msgsize, msg_str, xmps::BGP,
     453             :                 boost::bind(&BgpXmppChannel::XmppPeer::WriteReadyCb, this, _1));
     454     1653211 :         if (!send_ready_) {
     455         105 :             BGP_LOG_PEER(Event, this, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_ALL,
     456             :                          BGP_PEER_DIR_NA, "Send blocked");
     457             : 
     458             :             // If EndOfRib Send timer is running, cancel it and reschedule it
     459             :             // after socket gets unblocked.
     460          79 :             if (parent_->eor_send_timer_ && parent_->eor_send_timer_->running())
     461          58 :                 parent_->eor_send_timer_->Cancel();
     462             :         }
     463     1653118 :         return send_ready_;
     464             :     } else {
     465        3481 :         return false;
     466             :     }
     467             : }
     468             : 
     469       10177 : void BgpXmppChannel::XmppPeer::Close(bool graceful) {
     470       10177 :     send_ready_ = true;
     471       10177 :     parent_->set_peer_closed(true);
     472       10176 :     if (server_ == NULL)
     473        3815 :         return;
     474             : 
     475             :     XmppConnection *connection =
     476        6361 :         const_cast<XmppConnection *>(parent_->channel_->connection());
     477             : 
     478        6362 :     if (connection && !connection->IsActiveChannel()) {
     479             : 
     480             :         // Clear EOR state.
     481        6351 :         parent_->ClearEndOfRibState();
     482             : 
     483        6352 :         parent_->peer_close_->Close(graceful);
     484             :     }
     485             : }
     486             : 
     487       10050 : BgpXmppChannel::BgpXmppChannel(XmppChannel *channel,
     488             :                                BgpServer *bgp_server,
     489       10050 :                                BgpXmppChannelManager *manager)
     490       10050 :     : channel_(channel),
     491       10050 :       peer_id_(xmps::BGP),
     492       10050 :       rtarget_manager_(new BgpXmppRTargetManager(this)),
     493       10049 :       bgp_server_(bgp_server),
     494       10049 :       peer_(new XmppPeer(bgp_server, this)),
     495       10050 :       peer_close_(new BgpXmppPeerClose(this)),
     496       10050 :       peer_stats_(new PeerStats(this)),
     497       10050 :       bgp_policy_(BgpProto::XMPP, RibExportPolicy::XMPP, -1, 0),
     498       10049 :       manager_(manager),
     499       10049 :       delete_in_progress_(false),
     500       10049 :       deleted_(false),
     501       10049 :       defer_peer_close_(false),
     502       10049 :       skip_update_send_(false),
     503       10049 :       skip_update_send_cached_(false),
     504       10049 :       eor_sent_(false),
     505       10049 :       eor_receive_timer_(NULL),
     506       10049 :       eor_send_timer_(NULL),
     507       10049 :       eor_receive_timer_start_time_(0),
     508       10049 :       eor_send_timer_start_time_(0),
     509       20098 :       membership_response_worker_(
     510             :             TaskScheduler::GetInstance()->GetTaskId("xmpp::StateMachine"),
     511       10049 :             channel->GetTaskInstance(),
     512             :             boost::bind(&BgpXmppChannel::MembershipResponseHandler, this, _1)),
     513       60300 :       lb_mgr_(new LabelBlockManager()) {
     514       10050 :     close_manager_.reset(
     515       10050 :         BgpStaticObjectFactory::Create<PeerCloseManager>(static_cast<IPeerClose*>(peer_close_.get())));
     516       10050 :     if (bgp_server) {
     517        6235 :         eor_receive_timer_ =
     518        6235 :             TimerManager::CreateTimer(*bgp_server->ioservice(),
     519             :                 "EndOfRib receive timer",
     520             :                 TaskScheduler::GetInstance()->GetTaskId("xmpp::StateMachine"),
     521        6235 :                 channel->GetTaskInstance());
     522        6235 :         eor_send_timer_ =
     523        6235 :             TimerManager::CreateTimer(*bgp_server->ioservice(),
     524             :                 "EndOfRib send timer",
     525             :                 TaskScheduler::GetInstance()->GetTaskId("xmpp::StateMachine"),
     526        6235 :                 channel->GetTaskInstance());
     527             :     }
     528       10050 :     channel_->RegisterReferer(peer_id_);
     529       10050 :     channel_->RegisterReceive(peer_id_,
     530             :          boost::bind(&BgpXmppChannel::ReceiveUpdate, this, _1));
     531       12457 :     BGP_LOG_PEER(Event, peer_.get(), SandeshLevel::SYS_INFO, BGP_LOG_FLAG_ALL,
     532             :         BGP_PEER_DIR_NA, "Created");
     533       10050 : }
     534             : 
     535       15603 : BgpXmppChannel::~BgpXmppChannel() {
     536       10050 :     if (channel_->connection() && !channel_->connection()->IsActiveChannel()) {
     537        6186 :         CHECK_CONCURRENCY("bgp::Config");
     538             :     }
     539             : 
     540       10050 :     if (manager_)
     541        6196 :         manager_->RemoveChannel(channel_);
     542       10050 :     if (manager_ && delete_in_progress_)
     543        6186 :         manager_->decrement_deleting_count();
     544       10050 :     STLDeleteElements(&defer_q_);
     545       10050 :     assert(peer_deleted());
     546       10050 :     assert(!close_manager_->IsMembershipInUse());
     547       10050 :     assert(table_membership_request_map_.empty());
     548       10050 :     TimerManager::DeleteTimer(eor_receive_timer_);
     549       10050 :     TimerManager::DeleteTimer(eor_send_timer_);
     550       12457 :     BGP_LOG_PEER(Event, peer_.get(), SandeshLevel::SYS_INFO, BGP_LOG_FLAG_ALL,
     551             :         BGP_PEER_DIR_NA, "Deleted");
     552       10050 :     channel_->UnRegisterWriteReady(peer_id_);
     553       10050 :     channel_->UnRegisterReferer(peer_id_);
     554       10050 :     channel_->UnRegisterReceive(peer_id_);
     555       15603 : }
     556             : 
     557       10050 : void BgpXmppChannel::XMPPPeerInfoSend(const XmppPeerInfoData &peer_info) const {
     558       10050 :     assert(!peer_info.get_name().empty());
     559       10050 :     BGP_UVE_SEND(XMPPPeerInfo, peer_info);
     560       10050 : }
     561             : 
     562        5662 : const XmppSession *BgpXmppChannel::GetSession() const {
     563        5662 :     if (channel_ && channel_->connection()) {
     564        5662 :         return channel_->connection()->session();
     565             :     }
     566           0 :     return NULL;
     567             : }
     568             : 
     569     1695800 : const string &BgpXmppChannel::ToString() const {
     570     1695800 :     return channel_->ToString();
     571             : }
     572             : 
     573      631490 : const string &BgpXmppChannel::ToUVEKey() const {
     574      631490 :     if (channel_->connection()) {
     575      631129 :         return channel_->connection()->ToUVEKey();
     576             :     } else {
     577         368 :         return channel_->ToString();
     578             :     }
     579             : }
     580             : 
     581         974 : string BgpXmppChannel::StateName() const {
     582         974 :     return channel_->StateName();
     583             : }
     584             : 
     585             : 
     586        6291 : size_t BgpXmppChannel::GetMembershipRequestQueueSize() const {
     587        6291 :     return table_membership_request_map_.size();
     588             : }
     589             : 
     590        2803 : void BgpXmppChannel::RoutingInstanceCallback(string vrf_name, int op) {
     591        2803 :     if (delete_in_progress_)
     592          76 :         return;
     593        2727 :     if (vrf_name == BgpConfigManager::kMasterInstance)
     594         131 :         return;
     595        2596 :     if (op == RoutingInstanceMgr::INSTANCE_DELETE)
     596         434 :         return;
     597             : 
     598        2162 :     RoutingInstanceMgr *instance_mgr = bgp_server_->routing_instance_mgr();
     599        2162 :     assert(instance_mgr);
     600        2162 :     RoutingInstance *rt_instance = instance_mgr->GetRoutingInstance(vrf_name);
     601        2161 :     assert(rt_instance);
     602             : 
     603        2161 :     if (op == RoutingInstanceMgr::INSTANCE_ADD) {
     604             :         const InstanceMembershipRequestState *imr_state =
     605          66 :             GetInstanceMembershipState(vrf_name);
     606          66 :         if (!imr_state)
     607          34 :             return;
     608          32 :         ProcessDeferredSubscribeRequest(rt_instance, *imr_state);
     609          32 :         DeleteInstanceMembershipState(vrf_name);
     610             :     } else {
     611        2095 :         SubscriptionState *sub_state = GetSubscriptionState(rt_instance);
     612        2095 :         if (!sub_state)
     613         772 :             return;
     614        1323 :         rtarget_manager_->RoutingInstanceCallback(
     615             :             rt_instance, &sub_state->targets);
     616             :     }
     617             : }
     618             : 
     619     1540376 : IPeer *BgpXmppChannel::Peer() {
     620     1540376 :     return peer_.get();
     621             : }
     622             : 
     623        5283 : const IPeer *BgpXmppChannel::Peer() const {
     624        5283 :     return peer_.get();
     625             : }
     626             : 
     627      228824 : TcpSession::Endpoint BgpXmppChannel::endpoint() const {
     628      228824 :     return channel_->connection()->endpoint();
     629             : }
     630             : 
     631       30044 : bool BgpXmppChannel::XmppDecodeAddress(int af, const string &address,
     632             :                                        IpAddress *addrp, bool zero_ok) {
     633       30044 :     if (af != BgpAf::IPv4 && af != BgpAf::IPv6 && af != BgpAf::L2Vpn)
     634           0 :         return false;
     635             : 
     636       30044 :     error_code error;
     637       30044 :     *addrp = IpAddress::from_string(address, error);
     638       30045 :     if (error)
     639          17 :         return false;
     640             : 
     641       30028 :     return (zero_ok ? true : !addrp->is_unspecified());
     642             : }
     643             : 
     644             : //
     645             : // Return true if there's a pending request, false otherwise.
     646             : //
     647       40080 : bool BgpXmppChannel::GetMembershipInfo(BgpTable *table,
     648             :     int *instance_id, uint64_t *subscription_gen_id, RequestType *req_type) {
     649       40080 :     *instance_id = -1;
     650       40080 :     *subscription_gen_id = 0;
     651             :     TableMembershipRequestState *tmr_state =
     652       40080 :         GetTableMembershipState(table->name());
     653       40080 :     if (tmr_state) {
     654        1149 :         *req_type = tmr_state->pending_req;
     655        1149 :         *instance_id = tmr_state->instance_id;
     656        1149 :         return true;
     657             :     } else {
     658       38931 :         *req_type = NONE;
     659       38931 :         BgpMembershipManager *mgr = bgp_server_->membership_mgr();
     660       38931 :         mgr->GetRegistrationInfo(peer_.get(), table,
     661             :                                  instance_id, subscription_gen_id);
     662       38936 :         return false;
     663             :     }
     664             : }
     665             : 
     666             : //
     667             : // Add entry to the pending table request map.
     668             : //
     669       72831 : void BgpXmppChannel::AddTableMembershipState(const string &table_name,
     670             :     TableMembershipRequestState tmr_state) {
     671       72831 :     table_membership_request_map_.insert(make_pair(table_name, tmr_state));
     672       72831 : }
     673             : 
     674             : //
     675             : // Delete entry from the pending table request map.
     676             : // Return true if the entry was found and deleted.
     677             : //
     678       72830 : bool BgpXmppChannel::DeleteTableMembershipState(const string &table_name) {
     679       72830 :     return (table_membership_request_map_.erase(table_name) > 0);
     680             : }
     681             : 
     682             : //
     683             : // Find entry in the pending table request map.
     684             : //
     685             : BgpXmppChannel::TableMembershipRequestState *
     686      185987 : BgpXmppChannel::GetTableMembershipState(
     687             :     const string &table_name) {
     688             :     TableMembershipRequestMap::iterator loc =
     689      185987 :         table_membership_request_map_.find(table_name);
     690      185985 :     return (loc == table_membership_request_map_.end() ? NULL : &loc->second);
     691             : }
     692             : 
     693             : //
     694             : // Find entry in the pending table request map.
     695             : // Const version.
     696             : //
     697             : const BgpXmppChannel::TableMembershipRequestState *
     698        9500 : BgpXmppChannel::GetTableMembershipState(
     699             :     const string &table_name) const {
     700             :     TableMembershipRequestMap::const_iterator loc =
     701        9500 :         table_membership_request_map_.find(table_name);
     702        9500 :     return (loc == table_membership_request_map_.end() ? NULL : &loc->second);
     703             : }
     704             : 
     705             : //
     706             : // Add entry to the pending instance request map.
     707             : //
     708         143 : void BgpXmppChannel::AddInstanceMembershipState(const string &instance,
     709             :     InstanceMembershipRequestState imr_state) {
     710         143 :     instance_membership_request_map_.insert(make_pair(instance, imr_state));
     711         143 : }
     712             : 
     713             : //
     714             : // Delete entry from the pending instance request map.
     715             : // Return true if the entry was found and deleted.
     716             : //
     717         193 : bool BgpXmppChannel::DeleteInstanceMembershipState(const string &instance) {
     718         193 :     return (instance_membership_request_map_.erase(instance) > 0);
     719             : }
     720             : 
     721             : //
     722             : // Find the entry in the pending instance request map.
     723             : //
     724             : const BgpXmppChannel::InstanceMembershipRequestState *
     725        5599 : BgpXmppChannel::GetInstanceMembershipState(const string &instance) const {
     726             :     InstanceMembershipRequestMap::const_iterator loc =
     727        5599 :         instance_membership_request_map_.find(instance);
     728        5599 :     return loc != instance_membership_request_map_.end() ? &loc->second : NULL;
     729             : }
     730             : 
     731             : //
     732             : // Verify that there's a subscribe or pending subscribe for the table
     733             : // corresponding to the vrf and family.
     734             : // If there's a subscribe, populate the table and instance_id.
     735             : // If there's a pending subscribe, populate the instance_id.
     736             : // The subscribe_pending parameter is set appropriately.
     737             : //
     738             : // Return true if there's a subscribe or pending subscribe, false otherwise.
     739             : //
     740       41641 : bool BgpXmppChannel::VerifyMembership(const string &vrf_name,
     741             :     Address::Family family, BgpTable **table,
     742             :     int *instance_id, uint64_t *subscription_gen_id, bool *subscribe_pending,
     743             :     bool add_change) {
     744       41641 :     *table = NULL;
     745       41641 :     *subscribe_pending = false;
     746             : 
     747       41641 :     RoutingInstanceMgr *instance_mgr = bgp_server_->routing_instance_mgr();
     748       41643 :     RoutingInstance *rt_instance = instance_mgr->GetRoutingInstance(vrf_name);
     749       41640 :     if (rt_instance)
     750       41584 :         *table = rt_instance->GetTable(family);
     751       41637 :     if (rt_instance != NULL && !rt_instance->deleted()) {
     752             :         RequestType req_type;
     753       40080 :         if (GetMembershipInfo(*table, instance_id,
     754             :                               subscription_gen_id, &req_type)) {
     755             :             // Bail if there's a pending unsubscribe.
     756        1149 :             if (req_type != SUBSCRIBE) {
     757           8 :                 BGP_LOG_PEER_INSTANCE_CRITICAL(Peer(), vrf_name,
     758             :                     BGP_PEER_DIR_IN, BGP_LOG_FLAG_ALL,
     759             :                     "Received route after unsubscribe");
     760          25 :                 return false;
     761             :             }
     762        1145 :             *subscribe_pending = true;
     763             :         } else {
     764             :             // Bail if we are not subscribed to the table.
     765       38936 :             if (*instance_id < 0) {
     766          33 :                 BGP_LOG_PEER_INSTANCE_CRITICAL(Peer(), vrf_name,
     767             :                     BGP_PEER_DIR_IN, BGP_LOG_FLAG_ALL,
     768             :                     "Received route without subscribe");
     769          21 :                 return false;
     770             :             }
     771             :         }
     772             :     } else {
     773             :         // Bail if there's no pending subscribe for the instance.
     774             :         // Note that route retract can be received while the instance is
     775             :         // marked for deletion.
     776             :         const InstanceMembershipRequestState *imr_state =
     777        1558 :             GetInstanceMembershipState(vrf_name);
     778        1558 :         if (imr_state) {
     779          55 :             *instance_id = imr_state->instance_id;
     780          55 :             *subscribe_pending = true;
     781        1503 :         } else if (add_change || !rt_instance) {
     782          16 :             BGP_LOG_PEER_INSTANCE_CRITICAL(Peer(), vrf_name, BGP_PEER_DIR_IN,
     783             :                BGP_LOG_FLAG_ALL, "Received route without pending subscribe");
     784           8 :             return false;
     785             :         }
     786             :     }
     787             : 
     788       41610 :     return true;
     789             : }
     790             : 
     791        1166 : bool BgpXmppChannel::ProcessMcastItem(string vrf_name,
     792             :     const pugi::xml_node &node, bool add_change) {
     793        1166 :     McastItemType item;
     794        1166 :     item.Clear();
     795             : 
     796        1166 :     if (!item.XmlParse(node)) {
     797           2 :         BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name,
     798             :             BGP_LOG_FLAG_ALL, "Invalid multicast route message received");
     799           1 :         return false;
     800             :     }
     801             : 
     802        1165 :     if (item.entry.nlri.af != BgpAf::IPv4) {
     803           2 :         BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name, BGP_LOG_FLAG_ALL,
     804             :             "Unsupported address family " << item.entry.nlri.af <<
     805             :             " for multicast route");
     806           1 :         return false;
     807             :     }
     808             : 
     809        1164 :     if (item.entry.nlri.safi != BgpAf::Mcast) {
     810           2 :         BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name,
     811             :             BGP_LOG_FLAG_ALL, "Unsupported subsequent address family " <<
     812             :             item.entry.nlri.safi << " for multicast route");
     813           1 :         return false;
     814             :     }
     815             : 
     816        1163 :     error_code error;
     817        1163 :     IpAddress grp_address = IpAddress::from_string("0.0.0.0", error);
     818        1163 :     if (!item.entry.nlri.group.empty()) {
     819        1163 :         if (!XmppDecodeAddress(item.entry.nlri.af,
     820             :             item.entry.nlri.group, &grp_address, false)) {
     821           7 :             BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name, BGP_LOG_FLAG_ALL,
     822             :                 "Bad group address " << item.entry.nlri.group);
     823           4 :             return false;
     824             :         }
     825             :     }
     826             : 
     827        1159 :     IpAddress src_address = IpAddress::from_string("0.0.0.0", error);
     828        1159 :     if (!item.entry.nlri.source.empty()) {
     829        1159 :         if (!XmppDecodeAddress(item.entry.nlri.af,
     830             :             item.entry.nlri.source, &src_address, true)) {
     831           5 :             BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name, BGP_LOG_FLAG_ALL,
     832             :                 "Bad source address " << item.entry.nlri.source);
     833           3 :             return false;
     834             :         }
     835             :     }
     836             : 
     837             :     bool subscribe_pending;
     838             :     int instance_id;
     839             :     uint64_t subscription_gen_id;
     840             :     BgpTable *table;
     841        1155 :     if (!VerifyMembership(vrf_name, Address::ERMVPN, &table, &instance_id,
     842             :         &subscription_gen_id, &subscribe_pending, add_change)) {
     843           6 :         channel_->Close();
     844           6 :         return false;
     845             :     }
     846             : 
     847             :     // Build the key to the Multicast DBTable
     848             :     uint16_t cluster_seed =
     849        1150 :         bgp_server_->global_config()->rd_cluster_seed();
     850        1150 :     RouteDistinguisher mc_rd;
     851        1150 :     if (cluster_seed) {
     852           0 :         mc_rd = RouteDistinguisher(cluster_seed, peer_->bgp_identifier(),
     853           0 :                                    instance_id);
     854             :     } else {
     855        1150 :         mc_rd = RouteDistinguisher(peer_->bgp_identifier(), instance_id);
     856             :     }
     857             : 
     858             :     ErmVpnPrefix mc_prefix(ErmVpnPrefix::NativeRoute, mc_rd,
     859        1150 :         grp_address.to_v4(), src_address.to_v4());
     860             : 
     861             :     // Build and enqueue a DB request for route-addition
     862        1149 :     DBRequest req;
     863        1149 :     req.key.reset(new ErmVpnTable::RequestKey(mc_prefix, peer_.get()));
     864             : 
     865        1149 :     uint32_t flags = 0;
     866        1149 :     ExtCommunitySpec ext;
     867        1150 :     string label_range("none");
     868             : 
     869        1150 :     if (add_change) {
     870         729 :         req.oper = DBRequest::DB_ENTRY_ADD_CHANGE;
     871         729 :         vector<uint32_t> labels;
     872         729 :         const McastNextHopsType &inh_list = item.entry.next_hops;
     873             : 
     874         729 :         if (inh_list.next_hop.empty()) {
     875           2 :             BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name,
     876             :                 BGP_LOG_FLAG_ALL, "Missing next-hop for multicast route " <<
     877             :                 mc_prefix.ToString());
     878           1 :             return false;
     879             :         }
     880             : 
     881             :         // Agents should send only one next-hop in the item
     882         727 :         if (inh_list.next_hop.size() != 1) {
     883           2 :             BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name, BGP_LOG_FLAG_ALL,
     884             :                 "More than one nexthop received for multicast route " <<
     885             :                 mc_prefix.ToString());
     886           1 :             return false;
     887             :         }
     888             : 
     889         726 :         McastNextHopsType::const_iterator nit = inh_list.begin();
     890             : 
     891             :         // Label Allocation item.entry.label by parsing the range
     892         726 :         label_range = nit->label;
     893        1453 :         if (!stringToIntegerList(label_range, "-", labels) ||
     894         727 :             labels.size() != 2) {
     895           4 :             BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name, BGP_LOG_FLAG_ALL,
     896             :                 "Bad label range " << label_range <<
     897             :                 " for multicast route " << mc_prefix.ToString());
     898           3 :             return false;
     899             :         }
     900             : 
     901         724 :         if (!labels[0] || !labels[1] || labels[1] < labels[0]) {
     902           6 :             BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name,
     903             :                 BGP_LOG_FLAG_ALL, "Bad label range " << label_range <<
     904             :                 " for multicast route " << mc_prefix.ToString());
     905           3 :             return false;
     906             :         }
     907             : 
     908         721 :         BgpAttrSpec attrs;
     909         721 :         LabelBlockPtr lbptr = lb_mgr_->LocateBlock(labels[0], labels[1]);
     910             : 
     911         721 :         BgpAttrLabelBlock attr_label(lbptr);
     912         721 :         attrs.push_back(&attr_label);
     913             : 
     914             :         // Next-hop ip address
     915         720 :         IpAddress nh_address;
     916         720 :         if (!XmppDecodeAddress(nit->af, nit->address, &nh_address)) {
     917           5 :             BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name,
     918             :                 BGP_LOG_FLAG_ALL, "Bad nexthop address " << nit->address <<
     919             :                 " for multicast route " << mc_prefix.ToString());
     920           3 :             return false;
     921             :         }
     922         718 :         BgpAttrNextHop nexthop(nh_address.to_v4().to_ulong());
     923         718 :         attrs.push_back(&nexthop);
     924             : 
     925             :         // Process tunnel encapsulation list.
     926         718 :         bool no_tunnel_encap = true;
     927         718 :         bool no_valid_tunnel_encap = true;
     928         718 :         for (McastTunnelEncapsulationListType::const_iterator eit =
     929         718 :              nit->tunnel_encapsulation_list.begin();
     930         753 :              eit != nit->tunnel_encapsulation_list.end(); ++eit) {
     931          35 :             no_tunnel_encap = false;
     932          35 :             TunnelEncap tun_encap(*eit);
     933          35 :             if (tun_encap.tunnel_encap() == TunnelEncapType::UNSPEC)
     934           0 :                 continue;
     935          35 :             no_valid_tunnel_encap = false;
     936          35 :             ext.communities.push_back(tun_encap.GetExtCommunityValue());
     937             :         }
     938             : 
     939             :         // Mark the path as infeasible if all tunnel encaps published
     940             :         // by agent are invalid.
     941         718 :         if (!no_tunnel_encap && no_valid_tunnel_encap) {
     942           0 :             flags = BgpPath::NoTunnelEncap;
     943             :         }
     944             : 
     945         718 :         if (!ext.communities.empty())
     946          23 :             attrs.push_back(&ext);
     947             : 
     948         718 :         BgpAttrPtr attr = bgp_server_->attr_db()->Locate(attrs);
     949         718 :         req.data.reset(new ErmVpnTable::RequestData(
     950         718 :             attr, flags, 0, 0, subscription_gen_id));
     951         718 :         stats_[RX].reach++;
     952         737 :     } else {
     953         421 :         req.oper = DBRequest::DB_ENTRY_DELETE;
     954         421 :         stats_[RX].unreach++;
     955             :     }
     956             : 
     957             :     // Defer all requests till subscribe is processed.
     958        1139 :     if (subscribe_pending) {
     959          50 :         DBRequest *request_entry = new DBRequest();
     960          50 :         request_entry->Swap(&req);
     961             :         string table_name =
     962          50 :             RoutingInstance::GetTableName(vrf_name, Address::ERMVPN);
     963          50 :         defer_q_.insert(make_pair(
     964         100 :             make_pair(vrf_name, table_name), request_entry));
     965          50 :         return true;
     966          50 :     }
     967             : 
     968        1089 :     assert(table);
     969        1308 :     BGP_LOG_PEER_INSTANCE(Peer(), vrf_name,
     970             :         SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_TRACE,
     971             :         "Multicast group " << item.entry.nlri.group <<
     972             :         " source " << item.entry.nlri.source <<
     973             :         " and label range " << label_range <<
     974             :         " enqueued for " << (add_change ? "add/change" : "delete"));
     975        1089 :     table->Enqueue(&req);
     976        1089 :     return true;
     977        1166 : }
     978             : 
     979          88 : void BgpXmppChannel::CreateType5MvpnRouteRequest(IpAddress grp_address,
     980             :         IpAddress src_address, bool add_change, uint64_t subscription_gen_id,
     981             :         int instance_id, DBRequest& req, const MvpnNextHopType &nexthop) {
     982          88 :     RouteDistinguisher mc_rd =  RouteDistinguisher::kZeroRd;
     983             :     MvpnPrefix mc_prefix(MvpnPrefix::SourceActiveADRoute, mc_rd,
     984          88 :             grp_address.to_v4(), src_address.to_v4());
     985          88 :     uint32_t flags = 0;
     986             : 
     987             :     // Build and enqueue a DB request for route-addition
     988          88 :     req.key.reset(new MvpnTable::RequestKey(mc_prefix, peer_.get()));
     989             : 
     990          88 :     if (add_change) {
     991          76 :         req.oper = DBRequest::DB_ENTRY_ADD_CHANGE;
     992             : 
     993          76 :         BgpAttrSpec attrs;
     994             :         // Next-hop ip address
     995          76 :         IpAddress nh_address;
     996          76 :         if (!XmppDecodeAddress(nexthop.af, nexthop.address, &nh_address)) {
     997           0 :             return;
     998             :         }
     999             : 
    1000             :         BgpAttrSourceRd source_rd(
    1001          76 :                 RouteDistinguisher(nh_address.to_v4().to_ulong(), instance_id));
    1002          76 :         attrs.push_back(&source_rd);
    1003          76 :         BgpAttrPtr attr = bgp_server_->attr_db()->Locate(attrs);
    1004          76 :         req.data.reset(new MvpnTable::RequestData(
    1005          76 :             attr, flags, 0, 0, subscription_gen_id));
    1006          76 :         stats_[RX].reach++;
    1007          76 :     } else {
    1008          12 :         req.oper = DBRequest::DB_ENTRY_DELETE;
    1009          12 :         stats_[RX].unreach++;
    1010             :     }
    1011          88 : }
    1012             : 
    1013         158 : void BgpXmppChannel::CreateType7MvpnRouteRequest(IpAddress grp_address,
    1014             :         IpAddress src_address, bool add_change, uint64_t subscription_gen_id,
    1015             :         DBRequest& req) {
    1016         158 :     RouteDistinguisher mc_rd =  RouteDistinguisher::kZeroRd;
    1017             :     MvpnPrefix mc_prefix(MvpnPrefix::SourceTreeJoinRoute, mc_rd, 0,
    1018         158 :             grp_address.to_v4(), src_address.to_v4());
    1019         158 :     uint32_t flags = BgpPath::ResolveNexthop;
    1020             : 
    1021             :     // Build and enqueue a DB request for route-addition
    1022         158 :     req.key.reset(new MvpnTable::RequestKey(mc_prefix, peer_.get()));
    1023             : 
    1024         158 :     if (add_change) {
    1025         126 :         req.oper = DBRequest::DB_ENTRY_ADD_CHANGE;
    1026             : 
    1027         126 :         BgpAttrSpec attrs;
    1028             : 
    1029             :         // Next-hop ip address
    1030         126 :         BgpAttrNextHop nexthop(src_address);
    1031         126 :         attrs.push_back(&nexthop);
    1032             : 
    1033         126 :         BgpAttrPtr attr = bgp_server_->attr_db()->Locate(attrs);
    1034         126 :         req.data.reset(new MvpnTable::RequestData(
    1035         126 :             attr, flags, 0, 0, subscription_gen_id));
    1036         126 :         stats_[RX].reach++;
    1037         126 :     } else {
    1038          32 :         req.oper = DBRequest::DB_ENTRY_DELETE;
    1039          32 :         stats_[RX].unreach++;
    1040             :     }
    1041         158 : }
    1042             : 
    1043         248 : bool BgpXmppChannel::ProcessMvpnItem(string vrf_name,
    1044             :     const pugi::xml_node &node, bool add_change) {
    1045         248 :     MvpnItemType item;
    1046         248 :     item.Clear();
    1047             : 
    1048         248 :     if (!item.XmlParse(node)) {
    1049           0 :         BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name,
    1050             :             BGP_LOG_FLAG_ALL, "Invalid multicast route message received");
    1051           0 :         return false;
    1052             :     }
    1053             : 
    1054         248 :     if (item.entry.nlri.af != BgpAf::IPv4) {
    1055           0 :         BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name, BGP_LOG_FLAG_ALL,
    1056             :             "Unsupported address family " << item.entry.nlri.af <<
    1057             :             " for multicast route");
    1058           0 :         return false;
    1059             :     }
    1060             : 
    1061         248 :     if (item.entry.nlri.safi != BgpAf::MVpn) {
    1062           0 :         BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name,
    1063             :             BGP_LOG_FLAG_ALL, "Unsupported subsequent address family " <<
    1064             :             item.entry.nlri.safi << " for multicast route");
    1065           0 :         return false;
    1066             :     }
    1067             : 
    1068         248 :     if (item.entry.nlri.group.empty()) {
    1069           0 :         BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name, BGP_LOG_FLAG_ALL,
    1070             :             "Mandatory group address not specified");
    1071           0 :         return false;
    1072             :     }
    1073             : 
    1074         248 :     error_code error;
    1075         248 :     IpAddress grp_address = IpAddress::from_string("0.0.0.0", error);
    1076         248 :     if (!XmppDecodeAddress(item.entry.nlri.af,
    1077             :         item.entry.nlri.group, &grp_address, false)) {
    1078           2 :         BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name, BGP_LOG_FLAG_ALL,
    1079             :             "Bad group address " << item.entry.nlri.group);
    1080           1 :         return false;
    1081             :     }
    1082             : 
    1083         247 :     if (item.entry.nlri.source.empty()) {
    1084           0 :         BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name, BGP_LOG_FLAG_ALL,
    1085             :             "Mandatory source address not specified");
    1086           0 :         return false;
    1087             :     }
    1088             : 
    1089         247 :     IpAddress src_address = IpAddress::from_string("0.0.0.0", error);
    1090         247 :     if (!XmppDecodeAddress(item.entry.nlri.af,
    1091             :         item.entry.nlri.source, &src_address, true)) {
    1092           2 :         BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name, BGP_LOG_FLAG_ALL,
    1093             :             "Bad source address " << item.entry.nlri.source);
    1094           1 :         return false;
    1095             :     }
    1096             : 
    1097             :     bool subscribe_pending;
    1098             :     int instance_id;
    1099             :     uint64_t subscription_gen_id;
    1100             :     BgpTable *table;
    1101         246 :     if (!VerifyMembership(vrf_name, Address::MVPN, &table, &instance_id,
    1102             :         &subscription_gen_id, &subscribe_pending, add_change)) {
    1103           0 :         channel_->Close();
    1104           0 :         return false;
    1105             :     }
    1106             : 
    1107         246 :     int rt_type = item.entry.nlri.route_type;
    1108         246 :     DBRequest req;
    1109             :     // Build the key to the Multicast DBTable
    1110         246 :     if (rt_type == MvpnPrefix::SourceTreeJoinRoute) {
    1111         158 :         CreateType7MvpnRouteRequest(grp_address, src_address, add_change,
    1112             :                 subscription_gen_id, req);
    1113          88 :     } else if (rt_type == MvpnPrefix::SourceActiveADRoute) {
    1114          88 :         CreateType5MvpnRouteRequest(grp_address, src_address, add_change,
    1115             :                 subscription_gen_id, instance_id, req, item.entry.next_hop);
    1116             :     } else {
    1117           0 :         BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name, BGP_LOG_FLAG_ALL,
    1118             :             "Unsupported route type " << item.entry.nlri.route_type);
    1119           0 :         return false;
    1120             :     }
    1121             : 
    1122             :     // Need to locate path resolver if not done already
    1123         246 :     assert(table);
    1124         246 :     table->LocatePathResolver();
    1125             : 
    1126             :     // Defer all requests till subscribe is processed.
    1127         246 :     if (subscribe_pending) {
    1128           5 :         DBRequest *request_entry = new DBRequest();
    1129           5 :         request_entry->Swap(&req);
    1130             :         string table_name =
    1131           5 :             RoutingInstance::GetTableName(vrf_name, Address::MVPN);
    1132           5 :         defer_q_.insert(make_pair(
    1133          10 :             make_pair(vrf_name, table_name), request_entry));
    1134           5 :         return true;
    1135           5 :     }
    1136             : 
    1137         482 :     BGP_LOG_PEER_INSTANCE(Peer(), vrf_name,
    1138             :         SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_TRACE,
    1139             :         "Multicast group " << item.entry.nlri.group <<
    1140             :         " source " << item.entry.nlri.source <<
    1141             :         " enqueued for " << (add_change ? "add/change" : "delete"));
    1142         241 :     table->Enqueue(&req);
    1143         241 :     return true;
    1144         248 : }
    1145             : 
    1146       25615 : bool BgpXmppChannel::ProcessItem(string vrf_name,
    1147             :     const pugi::xml_node &node, bool add_change, int primary_instance_id) {
    1148       25615 :     ItemType item;
    1149       25616 :     item.Clear();
    1150             : 
    1151       25616 :     if (!item.XmlParse(node)) {
    1152           2 :         BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name, BGP_LOG_FLAG_ALL,
    1153             :             "Invalid inet route message received");
    1154           1 :         return false;
    1155             :     }
    1156             : 
    1157       25615 :     if (item.entry.nlri.af != BgpAf::IPv4) {
    1158           2 :         BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name, BGP_LOG_FLAG_ALL,
    1159             :             "Unsupported address family " << item.entry.nlri.af <<
    1160             :             " for inet route " << item.entry.nlri.address);
    1161           1 :         return false;
    1162             :     }
    1163             : 
    1164       25614 :     if ((item.entry.nlri.safi != BgpAf::Unicast) &&
    1165          12 :           (item.entry.nlri.safi != BgpAf::Mpls)) {
    1166           0 :         BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name, BGP_LOG_FLAG_ALL,
    1167             :             "Unsupported subsequent address family " << item.entry.nlri.safi <<
    1168             :             " for inet route " << item.entry.nlri.address);
    1169           0 :         return false;
    1170             :     }
    1171       25614 :     error_code error;
    1172             :     Ip4Prefix inet_prefix =
    1173       25614 :         Ip4Prefix::FromString(item.entry.nlri.address, &error);
    1174       25614 :     if (error) {
    1175           4 :         BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name, BGP_LOG_FLAG_ALL,
    1176             :             "Bad inet route " << item.entry.nlri.address);
    1177           2 :         return false;
    1178             :     }
    1179             : 
    1180       25612 :     if (add_change && item.entry.next_hops.next_hop.empty()) {
    1181           2 :         BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name, BGP_LOG_FLAG_ALL,
    1182             :             "Missing next-hops for inet route " << inet_prefix.ToString());
    1183           1 :         return false;
    1184             :     }
    1185             : 
    1186             :     // Rules for routes in master instance:
    1187             :     // - Label must be 0 unless it is INETMPLS
    1188             :     // - Tunnel encapsulation is not required
    1189             :     // - Do not add SourceRd and ExtCommunitySpec
    1190       25611 :     bool master = (vrf_name == BgpConfigManager::kMasterInstance);
    1191             :     bool subscribe_pending;
    1192             :     int instance_id;
    1193             :     uint64_t subscription_gen_id;
    1194             :     BgpTable *table;
    1195       51222 :     Address::Family family = BgpAf::AfiSafiToFamily(item.entry.nlri.af,
    1196       25611 :                                                     item.entry.nlri.safi);
    1197       25611 :     if (!VerifyMembership(vrf_name, family, &table, &instance_id,
    1198             :         &subscription_gen_id, &subscribe_pending, add_change)) {
    1199           6 :         channel_->Close();
    1200           6 :         return false;
    1201             :     }
    1202             : 
    1203       25605 :     DBRequest req;
    1204       25604 :     req.key.reset(new InetTable::RequestKey(inet_prefix, peer_.get()));
    1205             : 
    1206       25604 :     IpAddress nh_address(Ip4Address(0));
    1207       25604 :     uint32_t label = 0;
    1208       25604 :     uint32_t flags = 0;
    1209       25604 :     ExtCommunitySpec ext;
    1210       25604 :     LargeCommunitySpec largecomm;
    1211       25604 :     CommunitySpec comm;
    1212             : 
    1213       25604 :     if (add_change) {
    1214       15218 :         req.oper = DBRequest::DB_ENTRY_ADD_CHANGE;
    1215       15218 :         BgpAttrSpec attrs;
    1216             : 
    1217       15218 :         const NextHopListType &inh_list = item.entry.next_hops;
    1218             : 
    1219             :         // Agents should send only one next-hop in the item.
    1220       15218 :         if (inh_list.next_hop.size() != 1) {
    1221           0 :             BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name,
    1222             :                 BGP_LOG_FLAG_ALL,
    1223             :                 "More than one nexthop received for inet route " <<
    1224             :                 inet_prefix.ToString());
    1225           0 :             return false;
    1226             :         }
    1227             : 
    1228       15218 :         NextHopListType::const_iterator nit = inh_list.begin();
    1229             : 
    1230       15218 :         IpAddress nhop_address(Ip4Address(0));
    1231       15218 :         if (!XmppDecodeAddress(nit->af, nit->address, &nhop_address)) {
    1232           6 :             BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name,
    1233             :                 BGP_LOG_FLAG_ALL,
    1234             :                 "Bad nexthop address " << nit->address <<
    1235             :                 " for inet route " << inet_prefix.ToString());
    1236           3 :             return false;
    1237             :         }
    1238             : 
    1239       17903 :         if (nit->label > EvpnPrefix::kMaxVniSigned ||
    1240        2688 :             ((master && nit->label) &&
    1241             :              !(family == Address::INETMPLS))) {
    1242           7 :              BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name,
    1243             :                 BGP_LOG_FLAG_ALL,
    1244             :                 "Bad label " << nit->label <<
    1245             :                 " for inet route " << inet_prefix.ToString());
    1246           7 :             return false;
    1247             :         }
    1248       27741 :         if ((!master || (master && (family == Address::INETMPLS))) &&
    1249       12533 :             !nit->label) {
    1250           4 :             BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name,
    1251             :                BGP_LOG_FLAG_ALL,
    1252             :                "Bad label " << nit->label <<
    1253             :                " for inet route in master instance(mpls)/non master instance" <<
    1254             :                inet_prefix.ToString());
    1255           2 :            return false;
    1256             :         }
    1257             : 
    1258       15206 :         nh_address = nhop_address;
    1259       15206 :         label = nit->label;
    1260             : 
    1261             :         // Process tunnel encapsulation list.
    1262       15206 :         bool no_tunnel_encap = true;
    1263       15206 :         bool no_valid_tunnel_encap = true;
    1264       15206 :         for (TunnelEncapsulationListType::const_iterator eit =
    1265       15206 :             nit->tunnel_encapsulation_list.begin();
    1266       28607 :             eit != nit->tunnel_encapsulation_list.end(); ++eit) {
    1267       13401 :             no_tunnel_encap = false;
    1268       13401 :             TunnelEncap tun_encap(*eit);
    1269       13401 :             if (tun_encap.tunnel_encap() == TunnelEncapType::UNSPEC)
    1270           0 :                 continue;
    1271       13401 :             no_valid_tunnel_encap = false;
    1272       13401 :             ext.communities.push_back(tun_encap.GetExtCommunityValue());
    1273             :         }
    1274             : 
    1275             :         // Mark the path as infeasible if all tunnel encaps published
    1276             :         // by agent are invalid.
    1277       15206 :         if (!no_tunnel_encap && no_valid_tunnel_encap && !master) {
    1278           0 :             flags = BgpPath::NoTunnelEncap;
    1279             :         }
    1280             : 
    1281             :         // Process router-mac as ext-community.
    1282       15206 :         if (!nit->mac.empty()) {
    1283             :             MacAddress mac_addr =
    1284           0 :                         MacAddress::FromString(nit->mac, &error);
    1285           0 :             if (error) {
    1286           0 :                 BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name,
    1287             :                     BGP_LOG_FLAG_ALL,
    1288             :                     "Bad next-hop mac address " << nit->mac);
    1289           0 :                 return false;
    1290             :             }
    1291           0 :             if (!mac_addr.IsZero()) {
    1292           0 :                 RouterMac router_mac(mac_addr);
    1293           0 :                 ext.communities.push_back(router_mac.GetExtCommunityValue());
    1294             :             }
    1295             :         }
    1296             : 
    1297             :         // Process tags list.
    1298       15206 :         uint64_t tag_val = 0;
    1299       15206 :         for (TagListType::const_iterator tit = nit->tag_list.begin();
    1300       15216 :             tit != nit->tag_list.end(); ++tit) {
    1301          10 :             tag_val = nit->is_new_tags_list ? *tit :
    1302           0 :                 ((0xFFFF0000 & *tit) << 16) | (0x0000FFFF & *tit);
    1303          10 :             TagLC tag_lc(bgp_server_->autonomous_system(), tag_val);
    1304          40 :             for (const auto &value_data : tag_lc.GetLargeCommunityValue()) {
    1305          30 :                 largecomm.communities.push_back(value_data);
    1306          10 :             }
    1307             :         }
    1308             : 
    1309             :         // Process local sequence_number
    1310       15206 :         if (nit->local_sequence_number) {
    1311           0 :             LocalSequenceNumber lsn (nit->local_sequence_number);
    1312           0 :             ext.communities.push_back(lsn.GetExtCommunityValue());
    1313             :         }
    1314             : 
    1315       15206 :         BgpAttrLocalPref local_pref(item.entry.local_preference);
    1316       15206 :         if (local_pref.local_pref != 0)
    1317       12821 :             attrs.push_back(&local_pref);
    1318             : 
    1319             :         // If there's no explicit med, calculate it automatically from the
    1320             :         // local pref.
    1321       15206 :         uint32_t med_value = item.entry.med;
    1322       15206 :         if (!med_value)
    1323        7770 :             med_value = GetMedFromLocalPref(local_pref.local_pref);
    1324       15206 :         BgpAttrMultiExitDisc med(med_value);
    1325       15206 :         if (med.med != 0)
    1326       12822 :             attrs.push_back(&med);
    1327             : 
    1328             :         // Process community tags.
    1329       15206 :         const CommunityTagListType &ict_list = item.entry.community_tag_list;
    1330       15206 :         for (CommunityTagListType::const_iterator cit = ict_list.begin();
    1331       15218 :             cit != ict_list.end(); ++cit) {
    1332          12 :             error_code error;
    1333             :             uint32_t rt_community =
    1334          12 :                 CommunityType::CommunityFromString(*cit, &error);
    1335          12 :             if (error)
    1336           0 :                 continue;
    1337          12 :             comm.communities.push_back(rt_community);
    1338             :         }
    1339             : 
    1340       15206 :         uint32_t addr = nh_address.to_v4().to_ulong();
    1341       15206 :         BgpAttrNextHop nexthop(addr);
    1342       15206 :         attrs.push_back(&nexthop);
    1343             :         uint16_t cluster_seed =
    1344       15206 :             bgp_server_->global_config()->rd_cluster_seed();
    1345       15206 :         BgpAttrSourceRd source_rd;
    1346       15206 :         if (!master || primary_instance_id) {
    1347       12537 :             if (master)
    1348          10 :                 instance_id = primary_instance_id;
    1349       12537 :             if (cluster_seed) {
    1350           6 :                 source_rd = BgpAttrSourceRd(
    1351           9 :                     RouteDistinguisher(cluster_seed, addr, instance_id));
    1352             :             } else {
    1353       25068 :                 source_rd = BgpAttrSourceRd(
    1354       37602 :                     RouteDistinguisher(addr, instance_id));
    1355             :             }
    1356       12537 :             attrs.push_back(&source_rd);
    1357             :         }
    1358             : 
    1359             :         // Process security group list.
    1360       15206 :         uint16_t sg_index = 0;
    1361       15206 :         const SecurityGroupListType &isg_list = item.entry.security_group_list;
    1362       15206 :         for (SecurityGroupListType::const_iterator sit = isg_list.begin();
    1363       30930 :             sit != isg_list.end(); ++sit) {
    1364       15724 :             if (bgp_server_->autonomous_system() <= AS2_MAX) {
    1365       15724 :                 SecurityGroup sg(bgp_server_->autonomous_system(), *sit);
    1366       15724 :                 ext.communities.push_back(sg.GetExtCommunityValue());
    1367             :             } else {
    1368           0 :                 SecurityGroup sg(sg_index, *sit);
    1369           0 :                 SecurityGroup4ByteAs sg4(bgp_server_->autonomous_system(),
    1370           0 :                                          sg_index++);
    1371           0 :                 ext.communities.push_back(sg4.GetExtCommunityValue());
    1372           0 :                 ext.communities.push_back(sg.GetExtCommunityValue());
    1373             :             }
    1374             :         }
    1375             : 
    1376       15206 :         if (item.entry.mobility.seqno) {
    1377         512 :             MacMobility mm(item.entry.mobility.seqno,
    1378         512 :                            item.entry.mobility.sticky);
    1379         512 :             ext.communities.push_back(mm.GetExtCommunityValue());
    1380       14694 :         } else if (item.entry.sequence_number) {
    1381           0 :             MacMobility mm(item.entry.sequence_number);
    1382           0 :             ext.communities.push_back(mm.GetExtCommunityValue());
    1383             :         }
    1384             : 
    1385             :         // Process load-balance extended community.
    1386       15206 :         LoadBalance load_balance(item.entry.load_balance);
    1387       15206 :         if (!load_balance.IsDefault())
    1388           2 :             ext.communities.push_back(load_balance.GetExtCommunityValue());
    1389             : 
    1390       15206 :         if (!comm.communities.empty())
    1391           7 :             attrs.push_back(&comm);
    1392       15206 :         if (!master && !ext.communities.empty())
    1393       12527 :             attrs.push_back(&ext);
    1394       15206 :         if (!master && !largecomm.communities.empty())
    1395           3 :             attrs.push_back(&largecomm);
    1396             : 
    1397             :         // Process sub-protocol(route types)
    1398       15206 :         BgpAttrSubProtocol sbp(item.entry.sub_protocol);
    1399       15206 :         attrs.push_back(&sbp);
    1400             : 
    1401       15206 :         BgpAttrPtr attr = bgp_server_->attr_db()->Locate(attrs);
    1402       15206 :         req.data.reset(new BgpTable::RequestData(
    1403       15206 :             attr, flags, label, 0, subscription_gen_id));
    1404       15218 :     } else {
    1405       10386 :         req.oper = DBRequest::DB_ENTRY_DELETE;
    1406             :     }
    1407             : 
    1408             :     // Defer all requests till subscribe is processed.
    1409       25592 :     if (subscribe_pending) {
    1410         434 :         DBRequest *request_entry = new DBRequest();
    1411         434 :         request_entry->Swap(&req);
    1412             :         string table_name =
    1413         434 :             RoutingInstance::GetTableName(vrf_name, family);
    1414         434 :         defer_q_.insert(make_pair(
    1415         868 :             make_pair(vrf_name, table_name), request_entry));
    1416         434 :        return true;
    1417         434 :     }
    1418             : 
    1419       25158 :     assert(table);
    1420       33986 :     BGP_LOG_PEER_INSTANCE(Peer(), vrf_name,
    1421             :         SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_TRACE,
    1422             :         "Inet route " << item.entry.nlri.address <<
    1423             :         " with next-hop " << nh_address << " and label " << label <<
    1424             :         " enqueued for " << (add_change ? "add/change" : "delete") <<
    1425             :         " to table " << table->name());
    1426       25158 :     table->Enqueue(&req);
    1427             : 
    1428       25159 :     if (add_change) {
    1429       14790 :         stats_[RX].reach++;
    1430             :     } else {
    1431       10369 :         stats_[RX].unreach++;
    1432             :     }
    1433             : 
    1434       25159 :     return true;
    1435       25616 : }
    1436             : 
    1437        9103 : bool BgpXmppChannel::ProcessInet6Item(string vrf_name,
    1438             :     const pugi::xml_node &node, bool add_change) {
    1439        9103 :     ItemType item;
    1440        9103 :     item.Clear();
    1441             : 
    1442        9103 :     if (!item.XmlParse(node)) {
    1443           2 :         error_stats().incr_inet6_rx_bad_xml_token_count();
    1444           3 :         BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name, BGP_LOG_FLAG_ALL,
    1445             :             "Invalid inet6 route message received");
    1446           2 :         return false;
    1447             :     }
    1448             : 
    1449        9101 :     if (item.entry.nlri.af != BgpAf::IPv6) {
    1450           2 :         error_stats().incr_inet6_rx_bad_afi_safi_count();
    1451           3 :         BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name, BGP_LOG_FLAG_ALL,
    1452             :             "Unsupported address family " << item.entry.nlri.af <<
    1453             :             " for inet6 route " << item.entry.nlri.address);
    1454           2 :         return false;
    1455             :     }
    1456             : 
    1457        9099 :     if (item.entry.nlri.safi != BgpAf::Unicast) {
    1458           1 :         error_stats().incr_inet6_rx_bad_afi_safi_count();
    1459           1 :         BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name, BGP_LOG_FLAG_ALL,
    1460             :             "Unsupported subsequent address family " << item.entry.nlri.safi <<
    1461             :             " for inet6 route " << item.entry.nlri.address);
    1462           1 :         return false;
    1463             :     }
    1464             : 
    1465        9098 :     error_code error;
    1466             :     Inet6Prefix inet6_prefix =
    1467        9098 :         Inet6Prefix::FromString(item.entry.nlri.address, &error);
    1468        9098 :     if (error) {
    1469           2 :         error_stats().incr_inet6_rx_bad_prefix_count();
    1470           3 :         BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name, BGP_LOG_FLAG_ALL,
    1471             :             "Bad inet6 route " << item.entry.nlri.address);
    1472           2 :         return false;
    1473             :     }
    1474             : 
    1475        9096 :     if (add_change && item.entry.next_hops.next_hop.empty()) {
    1476           2 :         BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name, BGP_LOG_FLAG_ALL,
    1477             :             "Missing next-hops for inet6 route " << inet6_prefix.ToString());
    1478           1 :         return false;
    1479             :     }
    1480             : 
    1481             :     // Rules for routes in master instance:
    1482             :     // - Label must be 0
    1483             :     // - Tunnel encapsulation is not required
    1484             :     // - Do not add SourceRd and ExtCommunitySpec
    1485        9095 :     bool master = (vrf_name == BgpConfigManager::kMasterInstance);
    1486             : 
    1487             :     // vector<Address::Family> family_list = list_of(Address::INET6)(Address::EVPN);
    1488        9095 :     vector<Address::Family> family_list = list_of(Address::INET6);
    1489       27267 :     BOOST_FOREACH(Address::Family family, family_list) {
    1490             :         bool subscribe_pending;
    1491             :         int instance_id;
    1492             :         uint64_t subscription_gen_id;
    1493             :         BgpTable *table;
    1494        9095 :         if (!VerifyMembership(vrf_name, family, &table, &instance_id,
    1495             :             &subscription_gen_id, &subscribe_pending, add_change)) {
    1496           6 :             channel_->Close();
    1497           9 :             return false;
    1498             :         }
    1499             : 
    1500        9089 :         DBRequest req;
    1501        9089 :         if (family == Address::INET6) {
    1502        9089 :             req.key.reset(new Inet6Table::RequestKey(inet6_prefix, peer_.get()));
    1503             :         } else {
    1504             :             EvpnPrefix evpn_prefix(RouteDistinguisher::kZeroRd,
    1505           0 :                 inet6_prefix.addr(), inet6_prefix.prefixlen());
    1506           0 :             req.key.reset(new EvpnTable::RequestKey(evpn_prefix, peer_.get()));
    1507             :         }
    1508             : 
    1509        9089 :         IpAddress nh_address(Ip4Address(0));
    1510        9089 :         uint32_t label = 0;
    1511        9089 :         uint32_t flags = 0;
    1512        9089 :         ExtCommunitySpec ext;
    1513        9089 :         LargeCommunitySpec largecomm;
    1514        9089 :         CommunitySpec comm;
    1515             : 
    1516        9089 :         if (add_change) {
    1517        6770 :             req.oper = DBRequest::DB_ENTRY_ADD_CHANGE;
    1518        6770 :             BgpAttrSpec attrs;
    1519             : 
    1520        6770 :             const NextHopListType &inh_list = item.entry.next_hops;
    1521             : 
    1522             :             // Agents should send only one next-hop in the item.
    1523        6770 :             if (inh_list.next_hop.size() != 1) {
    1524           0 :                 BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name,
    1525             :                     BGP_LOG_FLAG_ALL,
    1526             :                     "More than one nexthop received for inet6 route " <<
    1527             :                     inet6_prefix.ToString());
    1528           0 :                 return false;
    1529             :             }
    1530             : 
    1531        6770 :             NextHopListType::const_iterator nit = inh_list.begin();
    1532             : 
    1533        6770 :             IpAddress nhop_address(Ip4Address(0));
    1534        6770 :             if (!XmppDecodeAddress(nit->af, nit->address, &nhop_address)) {
    1535           3 :                 error_stats().incr_inet6_rx_bad_nexthop_count();
    1536           5 :                 BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name,
    1537             :                     BGP_LOG_FLAG_ALL,
    1538             :                     "Bad nexthop address " << nit->address <<
    1539             :                     " for inet6 route " << inet6_prefix.ToString());
    1540           3 :                 return false;
    1541             :             }
    1542             : 
    1543        6767 :             if (family == Address::EVPN) {
    1544           0 :                 if (nit->vni > EvpnPrefix::kMaxVniSigned) {
    1545           0 :                     BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name,
    1546             :                         BGP_LOG_FLAG_ALL,
    1547             :                         "Bad label " << nit->vni <<
    1548             :                         " for inet6 route " << inet6_prefix.ToString());
    1549           0 :                     return false;
    1550             :                 }
    1551           0 :                 if (!nit->vni)
    1552           0 :                     continue;
    1553           0 :                 if (nit->mac.empty())
    1554           0 :                     continue;
    1555             : 
    1556             :                 MacAddress mac_addr =
    1557           0 :                     MacAddress::FromString(nit->mac, &error);
    1558           0 :                 if (error) {
    1559           0 :                     BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name,
    1560             :                         BGP_LOG_FLAG_ALL,
    1561             :                         "Bad next-hop mac address " << nit->mac);
    1562           0 :                     return false;
    1563             :                 }
    1564           0 :                 RouterMac router_mac(mac_addr);
    1565           0 :                 ext.communities.push_back(router_mac.GetExtCommunityValue());
    1566             :             } else {
    1567        6767 :                 if (nit->label > EvpnPrefix::kMaxVniSigned || (master && nit->label)) {
    1568           0 :                     BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name,
    1569             :                         BGP_LOG_FLAG_ALL,
    1570             :                         "Bad label " << nit->label <<
    1571             :                         " for inet6 route " << inet6_prefix.ToString());
    1572           0 :                     return false;
    1573             :                 }
    1574        6767 :                 if (!master && !nit->label)
    1575           0 :                     continue;
    1576             :             }
    1577             : 
    1578        6767 :             nh_address = nhop_address;
    1579        6767 :             if (family == Address::INET6) {
    1580        6767 :                 label = nit->label;
    1581             :             } else {
    1582           0 :                 label = nit->vni;
    1583             :             }
    1584             : 
    1585             :             // Process tunnel encapsulation list.
    1586        6767 :             bool no_tunnel_encap = true;
    1587        6767 :             bool no_valid_tunnel_encap = true;
    1588        6767 :             for (TunnelEncapsulationListType::const_iterator eit =
    1589        6767 :                 nit->tunnel_encapsulation_list.begin();
    1590       16596 :                 eit != nit->tunnel_encapsulation_list.end(); ++eit) {
    1591        9829 :                 no_tunnel_encap = false;
    1592        9829 :                 TunnelEncap tun_encap(*eit);
    1593        9829 :                 if (tun_encap.tunnel_encap() == TunnelEncapType::UNSPEC)
    1594           0 :                     continue;
    1595        9828 :                 no_valid_tunnel_encap = false;
    1596        9828 :                 ext.communities.push_back(tun_encap.GetExtCommunityValue());
    1597             :             }
    1598             : 
    1599             :             // Mark the path as infeasible if all tunnel encaps published
    1600             :             // by agent are invalid.
    1601        6767 :             if (!no_tunnel_encap && no_valid_tunnel_encap && !master) {
    1602           0 :                 flags = BgpPath::NoTunnelEncap;
    1603             :             }
    1604             : 
    1605             :             // Process router-mac as ext-community.
    1606        6767 :             if (!nit->mac.empty()) {
    1607             :                 MacAddress mac_addr =
    1608           0 :                         MacAddress::FromString(nit->mac, &error);
    1609           0 :                 if (error) {
    1610           0 :                     BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name,
    1611             :                         BGP_LOG_FLAG_ALL,
    1612             :                         "Bad next-hop mac address " << nit->mac);
    1613           0 :                     return false;
    1614             :                 }
    1615           0 :                 if (!mac_addr.IsZero()) {
    1616           0 :                     RouterMac router_mac(mac_addr);
    1617           0 :                     ext.communities.push_back(router_mac.GetExtCommunityValue());
    1618             :                 }
    1619             :             }
    1620             : 
    1621             :             // Process tags list.
    1622        6767 :             uint64_t tag_val = 0;
    1623        6767 :             for (TagListType::const_iterator tit = nit->tag_list.begin();
    1624        6769 :                 tit != nit->tag_list.end(); ++tit) {
    1625           2 :                 tag_val = nit->is_new_tags_list ? *tit :
    1626           2 :                     ((0xFFFF0000 & *tit) << 16) | (0x0000FFFF & *tit);
    1627           2 :                 TagLC tag_lc(bgp_server_->autonomous_system(), tag_val);
    1628           2 :                 for (const auto &value_data :
    1629          10 :                     tag_lc.GetLargeCommunityValue()) {
    1630           6 :                     largecomm.communities.push_back(value_data);
    1631           2 :                 }
    1632             :             }
    1633             : 
    1634             :             // Process local sequence_number
    1635        6767 :             if (nit->local_sequence_number) {
    1636           0 :                 LocalSequenceNumber lsn (nit->local_sequence_number);
    1637           0 :                 ext.communities.push_back(lsn.GetExtCommunityValue());
    1638             :             }
    1639             : 
    1640        6767 :             BgpAttrLocalPref local_pref(item.entry.local_preference);
    1641        6767 :             if (local_pref.local_pref != 0)
    1642        6767 :                 attrs.push_back(&local_pref);
    1643             : 
    1644             :             // If there's no explicit med, calculate it automatically from the
    1645             :             // local pref.
    1646        6766 :             uint32_t med_value = item.entry.med;
    1647        6766 :             if (!med_value)
    1648         230 :                 med_value = GetMedFromLocalPref(local_pref.local_pref);
    1649        6766 :             BgpAttrMultiExitDisc med(med_value);
    1650        6766 :             if (med.med != 0)
    1651        6766 :                 attrs.push_back(&med);
    1652             : 
    1653             :             // Process community tags.
    1654        6766 :             const CommunityTagListType &ict_list =
    1655             :                 item.entry.community_tag_list;
    1656        6766 :             for (CommunityTagListType::const_iterator cit = ict_list.begin();
    1657        6774 :                 cit != ict_list.end(); ++cit) {
    1658           8 :                 error_code error;
    1659             :                 uint32_t rt_community =
    1660           8 :                     CommunityType::CommunityFromString(*cit, &error);
    1661           8 :                 if (error)
    1662           0 :                     continue;
    1663           8 :                 comm.communities.push_back(rt_community);
    1664             :             }
    1665             : 
    1666        6766 :             BgpAttrNextHop nexthop(nh_address);
    1667        6766 :             attrs.push_back(&nexthop);
    1668             : 
    1669        6767 :             BgpAttrSourceRd source_rd;
    1670        6767 :             if (!master) {
    1671        4102 :                 uint32_t addr = nh_address.to_v4().to_ulong();
    1672             :                 uint16_t cluster_seed =
    1673        4102 :                   bgp_server_->global_config()->rd_cluster_seed();
    1674        4102 :                 if (cluster_seed) {
    1675           6 :                     source_rd = BgpAttrSourceRd(
    1676           9 :                         RouteDistinguisher(cluster_seed, addr, instance_id));
    1677             :                 } else {
    1678        8198 :                     source_rd = BgpAttrSourceRd(
    1679       12297 :                         RouteDistinguisher(addr, instance_id));
    1680             :                 }
    1681        4102 :                 attrs.push_back(&source_rd);
    1682             :             }
    1683             : 
    1684             :             // Process security group list.
    1685        6767 :             const SecurityGroupListType &isg_list =
    1686             :                 item.entry.security_group_list;
    1687        6767 :             uint16_t sg_index = 0;
    1688        6767 :             for (SecurityGroupListType::const_iterator sit = isg_list.begin();
    1689       13544 :                 sit != isg_list.end(); ++sit) {
    1690        6777 :                 if (bgp_server_->autonomous_system() <= AS2_MAX) {
    1691        6777 :                     SecurityGroup sg(bgp_server_->autonomous_system(), *sit);
    1692        6776 :                     ext.communities.push_back(sg.GetExtCommunityValue());
    1693             :                 } else {
    1694           0 :                     SecurityGroup sg(sg_index, *sit);
    1695           0 :                     SecurityGroup4ByteAs sg4(bgp_server_->autonomous_system(),
    1696           0 :                                              sg_index++);
    1697           0 :                     ext.communities.push_back(sg4.GetExtCommunityValue());
    1698           0 :                     ext.communities.push_back(sg.GetExtCommunityValue());
    1699             :                 }
    1700             :             }
    1701             : 
    1702        6767 :             if (item.entry.mobility.seqno) {
    1703          18 :                 MacMobility mm(item.entry.mobility.seqno,
    1704          18 :                     item.entry.mobility.sticky);
    1705          18 :                 ext.communities.push_back(mm.GetExtCommunityValue());
    1706        6749 :             } else if (item.entry.sequence_number) {
    1707           0 :                 MacMobility mm(item.entry.sequence_number);
    1708           0 :                 ext.communities.push_back(mm.GetExtCommunityValue());
    1709             :             }
    1710             : 
    1711             :             // Process load-balance extended community.
    1712        6767 :             LoadBalance load_balance(item.entry.load_balance);
    1713        6767 :             if (!load_balance.IsDefault())
    1714           0 :                 ext.communities.push_back(load_balance.GetExtCommunityValue());
    1715             : 
    1716             :             // Process sub-protocol(route types)
    1717        6767 :             BgpAttrSubProtocol sbp(item.entry.sub_protocol);
    1718        6767 :             attrs.push_back(&sbp);
    1719             : 
    1720        6767 :             if (!comm.communities.empty())
    1721           5 :                 attrs.push_back(&comm);
    1722        6767 :             if (!master && !ext.communities.empty())
    1723        4102 :                 attrs.push_back(&ext);
    1724        6766 :             if (!master && !largecomm.communities.empty())
    1725           1 :                 attrs.push_back(&largecomm);
    1726             : 
    1727        6766 :             BgpAttrPtr attr = bgp_server_->attr_db()->Locate(attrs);
    1728        6767 :             req.data.reset(new BgpTable::RequestData(
    1729        6767 :                 attr, flags, label, 0, subscription_gen_id));
    1730        6770 :         } else {
    1731        2319 :             req.oper = DBRequest::DB_ENTRY_DELETE;
    1732             :         }
    1733             : 
    1734             :         // Defer all requests till subscribe is processed.
    1735        9086 :         if (subscribe_pending) {
    1736         338 :             DBRequest *request_entry = new DBRequest();
    1737         338 :             request_entry->Swap(&req);
    1738             :             string table_name =
    1739         338 :                 RoutingInstance::GetTableName(vrf_name, family);
    1740         338 :             defer_q_.insert(make_pair(
    1741         676 :                 make_pair(vrf_name, table_name), request_entry));
    1742         338 :             continue;
    1743         338 :         }
    1744             : 
    1745        8748 :         assert(table);
    1746       16683 :         BGP_LOG_PEER_INSTANCE(Peer(), vrf_name,
    1747             :             SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_TRACE,
    1748             :             "Inet6 route " << item.entry.nlri.address <<
    1749             :             " with next-hop " << nh_address << " and label " << label <<
    1750             :             " enqueued for " << (add_change ? "add/change" : "delete") <<
    1751             :             " to table " << table->name());
    1752        8748 :         table->Enqueue(&req);
    1753       10112 :     }
    1754             : 
    1755        9086 :     if (add_change) {
    1756        6767 :         stats_[RX].reach++;
    1757             :     } else {
    1758        2319 :         stats_[RX].unreach++;
    1759             :     }
    1760             : 
    1761        9086 :     return true;
    1762        9103 : }
    1763             : 
    1764        5543 : bool BgpXmppChannel::ProcessEnetItem(string vrf_name,
    1765             :     const pugi::xml_node &node, bool add_change) {
    1766        5543 :     EnetItemType item;
    1767        5543 :     item.Clear();
    1768             : 
    1769        5543 :     if (!item.XmlParse(node)) {
    1770           2 :         BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name, BGP_LOG_FLAG_ALL,
    1771             :             "Invalid enet route message received");
    1772           1 :         return false;
    1773             :     }
    1774             : 
    1775        5542 :     if (item.entry.nlri.af != BgpAf::L2Vpn) {
    1776           2 :         BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name, BGP_LOG_FLAG_ALL,
    1777             :             "Unsupported address family " << item.entry.nlri.af <<
    1778             :             " for enet route " << item.entry.nlri.address);
    1779           1 :         return false;
    1780             :     }
    1781             : 
    1782        5541 :     if (item.entry.nlri.safi != BgpAf::Enet) {
    1783           2 :         BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name, BGP_LOG_FLAG_ALL,
    1784             :             "Unsupported subsequent address family " << item.entry.nlri.safi <<
    1785             :             " for enet route " << item.entry.nlri.mac);
    1786           1 :         return false;
    1787             :     }
    1788             : 
    1789        5540 :     bool type6 = false;
    1790        5540 :     error_code error;
    1791        5540 :     IpAddress group= IpAddress::from_string("0.0.0.0", error);
    1792        5540 :     if (!item.entry.nlri.group.empty()) {
    1793          36 :         type6 = true;
    1794          36 :         if (!XmppDecodeAddress(item.entry.nlri.af,
    1795             :                     item.entry.nlri.group, &group, false)) {
    1796           0 :             BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name, BGP_LOG_FLAG_ALL,
    1797             :                 "Bad group address " << item.entry.nlri.group);
    1798             :         }
    1799             :     }
    1800             : 
    1801        5540 :     IpAddress source = IpAddress::from_string("0.0.0.0", error);
    1802        5540 :     if (!item.entry.nlri.source.empty() && !XmppDecodeAddress(
    1803             :                 item.entry.nlri.af, item.entry.nlri.source, &source, true)) {
    1804           0 :         BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name, BGP_LOG_FLAG_ALL,
    1805             :             "Bad source address " << item.entry.nlri.source);
    1806             :     }
    1807             : 
    1808             :     //error_code error;
    1809        5540 :     MacAddress mac_addr = MacAddress::FromString(item.entry.nlri.mac, &error);
    1810             : 
    1811        5540 :     if (error) {
    1812           2 :         BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name, BGP_LOG_FLAG_ALL,
    1813             :             "Bad mac address " << item.entry.nlri.mac);
    1814           1 :         return false;
    1815             :     }
    1816             : 
    1817        5539 :     bool type2 = type6 ? false : !mac_addr.IsZero();
    1818        5538 :     Ip4Prefix inet_prefix;
    1819        5538 :     Inet6Prefix inet6_prefix;
    1820        5538 :     IpAddress ip_addr;
    1821        5538 :     int prefix_len = 0;
    1822        5538 :     if (!item.entry.nlri.address.empty()) {
    1823        1359 :         size_t pos = item.entry.nlri.address.find('/');
    1824        1359 :         if (pos == string::npos) {
    1825           2 :             BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name, BGP_LOG_FLAG_ALL,
    1826             :                 "Missing / in address " << item.entry.nlri.address);
    1827           1 :             return false;
    1828             :         }
    1829             : 
    1830        1358 :         bool ipv6 = item.entry.nlri.address.find(':') != string::npos;
    1831        1358 :         if (!ipv6) {
    1832             :             inet_prefix =
    1833        1315 :                 Ip4Prefix::FromString(item.entry.nlri.address, &error);
    1834        1315 :             if (error) {
    1835           2 :                 BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name,
    1836             :                     BGP_LOG_FLAG_ALL,
    1837             :                     "Cannot parse inet prefix string " <<
    1838             :                         item.entry.nlri.address);
    1839           1 :                 return false;
    1840             :             }
    1841             : 
    1842        1319 :             if (type2 && inet_prefix.prefixlen() != 32 &&
    1843           5 :                 item.entry.nlri.address != "0.0.0.0/0") {
    1844           2 :                 BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name,
    1845             :                     BGP_LOG_FLAG_ALL,
    1846             :                     "Bad inet address " << item.entry.nlri.address);
    1847           1 :                 return false;
    1848             :             }
    1849             : 
    1850        1313 :             ip_addr = inet_prefix.ip4_addr();
    1851        1313 :             prefix_len = inet_prefix.prefixlen();
    1852             :         } else {
    1853             :             inet6_prefix =
    1854          43 :                 Inet6Prefix::FromString(item.entry.nlri.address, &error);
    1855             : 
    1856          43 :             if (error) {
    1857           2 :                 BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name,
    1858             :                     BGP_LOG_FLAG_ALL,
    1859             :                     "Cannot parse inet6 prefix string " <<
    1860             :                         item.entry.nlri.address);
    1861           1 :                 return false;
    1862             :             }
    1863             : 
    1864          42 :             if (type2 && inet6_prefix.prefixlen() != 128 &&
    1865           0 :                 item.entry.nlri.address != "::/0") {
    1866           0 :                 BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name,
    1867             :                     BGP_LOG_FLAG_ALL,
    1868             :                     "Bad inet6 address " << item.entry.nlri.address);
    1869           0 :                 return false;
    1870             :             }
    1871          42 :             ip_addr = inet6_prefix.ip6_addr();
    1872          42 :             prefix_len = inet6_prefix.prefixlen();
    1873             :         }
    1874             :     }
    1875             : 
    1876             :     bool subscribe_pending;
    1877             :     int instance_id;
    1878             :     uint64_t subscription_gen_id;
    1879             :     BgpTable *table;
    1880        5534 :     if (!VerifyMembership(vrf_name, Address::EVPN, &table, &instance_id,
    1881             :         &subscription_gen_id, &subscribe_pending, add_change)) {
    1882          15 :         channel_->Close();
    1883          15 :         return false;
    1884             :     }
    1885             : 
    1886        5520 :     RouteDistinguisher rd;
    1887        5520 :     if (mac_addr.IsBroadcast()) {
    1888         710 :         rd = RouteDistinguisher(peer_->bgp_identifier(), instance_id);
    1889        4810 :     } else if (type6) {
    1890          72 :         rd = RouteDistinguisher(bgp_server_->bgp_identifier(),
    1891          72 :                                 table->routing_instance()->index());
    1892             :     } else {
    1893        4774 :         rd = RouteDistinguisher::kZeroRd;
    1894             :     }
    1895             : 
    1896        5520 :     uint32_t ethernet_tag = item.entry.nlri.ethernet_tag;
    1897             :     EvpnPrefix evpn_prefix = type6 ?
    1898             :         EvpnPrefix(rd, ethernet_tag, source, group,
    1899          36 :                    Ip4Address(bgp_server_->bgp_identifier())) :
    1900             :         type2 ? EvpnPrefix(rd, ethernet_tag, mac_addr, ip_addr) :
    1901        5556 :         EvpnPrefix(rd, ip_addr, prefix_len);
    1902             : 
    1903        5518 :     DBRequest req;
    1904        5519 :     ExtCommunitySpec ext;
    1905        5518 :     LargeCommunitySpec largecomm;
    1906        5520 :     req.key.reset(new EvpnTable::RequestKey(evpn_prefix, peer_.get()));
    1907             : 
    1908        5518 :     IpAddress nh_address(Ip4Address(0));
    1909        5518 :     uint32_t label = 0;
    1910        5518 :     uint32_t l3_label = 0;
    1911        5518 :     uint32_t flags = 0;
    1912             : 
    1913        5518 :     if (add_change) {
    1914        4368 :         req.oper = DBRequest::DB_ENTRY_ADD_CHANGE;
    1915        4368 :         BgpAttrSpec attrs;
    1916        4368 :         const EnetNextHopListType &inh_list = item.entry.next_hops;
    1917             : 
    1918        4368 :         if (inh_list.next_hop.empty()) {
    1919           2 :             BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name,
    1920             :                 BGP_LOG_FLAG_ALL, "Missing next-hops for enet route " <<
    1921             :                                   evpn_prefix.ToXmppIdString());
    1922           1 :             return false;
    1923             :         }
    1924             : 
    1925             :         // Agents should send only one next-hop in the item.
    1926        4367 :         if (inh_list.next_hop.size() != 1) {
    1927           0 :             BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name,
    1928             :                 BGP_LOG_FLAG_ALL,
    1929             :                 "More than one nexthop received for enet route " <<
    1930             :                 evpn_prefix.ToXmppIdString());
    1931           0 :             return false;
    1932             :         }
    1933             : 
    1934        4367 :         EnetNextHopListType::const_iterator nit = inh_list.begin();
    1935             : 
    1936        4367 :         IpAddress nhop_address(Ip4Address(0));
    1937             : 
    1938        4367 :         if (!XmppDecodeAddress(nit->af, nit->address, &nhop_address)) {
    1939           4 :             BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name,
    1940             :                 BGP_LOG_FLAG_ALL, "Bad nexthop address " << nit->address <<
    1941             :                 " for enet route " << evpn_prefix.ToXmppIdString());
    1942           2 :             return false;
    1943             :         }
    1944             : 
    1945        4366 :         nh_address = nhop_address;
    1946        4366 :         label = nit->label;
    1947        4366 :         l3_label = nit->l3_label;
    1948        4366 :         if (!nit->mac.empty()) {
    1949             :             MacAddress rmac_addr =
    1950          10 :                 MacAddress::FromString(nit->mac, &error);
    1951          10 :             if (error) {
    1952           0 :                 BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name,
    1953             :                     BGP_LOG_FLAG_ALL,
    1954             :                     "Bad next-hop mac address " << nit->mac <<
    1955             :                     " for enet route " << evpn_prefix.ToXmppIdString());
    1956           0 :                 return false;
    1957             :             }
    1958          10 :             RouterMac router_mac(rmac_addr);
    1959          10 :             ext.communities.push_back(router_mac.GetExtCommunityValue());
    1960             :         }
    1961             : 
    1962             :         // Process tunnel encapsulation list.
    1963        4366 :         bool no_tunnel_encap = true;
    1964        4366 :         bool no_valid_tunnel_encap = true;
    1965        4366 :         for (EnetTunnelEncapsulationListType::const_iterator eit =
    1966        4366 :             nit->tunnel_encapsulation_list.begin();
    1967        8731 :             eit != nit->tunnel_encapsulation_list.end(); ++eit) {
    1968        4365 :             no_tunnel_encap = false;
    1969        4365 :             TunnelEncap tun_encap(*eit);
    1970        4365 :             if (tun_encap.tunnel_encap() == TunnelEncapType::UNSPEC)
    1971           0 :                 continue;
    1972        4365 :             no_valid_tunnel_encap = false;
    1973        4365 :             ext.communities.push_back(tun_encap.GetExtCommunityValue());
    1974        4365 :             if (tun_encap.tunnel_encap() == TunnelEncapType::GRE) {
    1975        4319 :                 TunnelEncap alt_tun_encap(TunnelEncapType::MPLS_O_GRE);
    1976        4320 :                 ext.communities.push_back(alt_tun_encap.GetExtCommunityValue());
    1977             :             }
    1978             :         }
    1979             : 
    1980             :         // Mark the path as infeasible if all tunnel encaps published
    1981             :         // by agent are invalid.
    1982        4365 :         if (!no_tunnel_encap && no_valid_tunnel_encap) {
    1983           0 :             flags = BgpPath::NoTunnelEncap;
    1984             :         }
    1985             : 
    1986             :         // Process tags list.
    1987        4365 :         uint64_t tag_val = 0;
    1988        4365 :         for (TagListType::const_iterator tit = nit->tag_list.begin();
    1989        4369 :             tit != nit->tag_list.end(); ++tit) {
    1990           4 :             tag_val = nit->is_new_tags_list ? *tit :
    1991           4 :                 ((0x0000FFFF0000 & *tit) << 16) |
    1992           4 :                 (0x00000000FFFF & *tit);
    1993           4 :             TagLC tag_lc(bgp_server_->autonomous_system(), tag_val);
    1994          16 :             for (const auto &value_data : tag_lc.GetLargeCommunityValue()) {
    1995          12 :                 largecomm.communities.push_back(value_data);
    1996           4 :             }
    1997             :         }
    1998             : 
    1999             :         // Process local sequence_number
    2000        4365 :         if (nit->local_sequence_number) {
    2001           0 :             LocalSequenceNumber lsn (nit->local_sequence_number);
    2002           0 :             ext.communities.push_back(lsn.GetExtCommunityValue());
    2003             :         }
    2004             : 
    2005        4365 :         BgpAttrLocalPref local_pref(item.entry.local_preference);
    2006        4365 :         if (local_pref.local_pref != 0) {
    2007        4365 :             attrs.push_back(&local_pref);
    2008             :         }
    2009             : 
    2010             :         // If there's no explicit med, calculate it automatically from the
    2011             :         // local pref.
    2012        4366 :         uint32_t med_value = item.entry.med;
    2013        4366 :         if (!med_value)
    2014        4366 :             med_value = GetMedFromLocalPref(local_pref.local_pref);
    2015        4366 :         BgpAttrMultiExitDisc med(med_value);
    2016        4366 :         if (med.med != 0)
    2017        4366 :             attrs.push_back(&med);
    2018             : 
    2019        4366 :         BgpAttrNextHop nexthop(nh_address.to_v4().to_ulong());
    2020        4365 :         if (type6) {
    2021          36 :             flags |= BgpPath::CheckGlobalErmVpnRoute;
    2022          72 :             if (item.entry.replicator_address.empty() &&
    2023          36 :                     item.entry.edge_replication_not_supported) {
    2024             :                 // Only for test to inject remote smet routes
    2025           0 :                 flags &= ~BgpPath::CheckGlobalErmVpnRoute;
    2026           0 :                 attrs.push_back(&nexthop);
    2027             :             }
    2028             :         } else {
    2029        4329 :             attrs.push_back(&nexthop);
    2030             :         }
    2031             : 
    2032        4365 :         uint16_t cluster_seed = bgp_server_->global_config()->rd_cluster_seed();
    2033        4365 :         BgpAttrSourceRd source_rd;
    2034        4364 :         if (cluster_seed) {
    2035           0 :             source_rd = BgpAttrSourceRd(RouteDistinguisher(cluster_seed,
    2036           0 :                 nh_address.to_v4().to_ulong(), instance_id));
    2037             :         } else {
    2038        8728 :             source_rd = BgpAttrSourceRd(RouteDistinguisher(
    2039       13092 :                 nh_address.to_v4().to_ulong(), instance_id));
    2040             :         }
    2041        4364 :         attrs.push_back(&source_rd);
    2042             : 
    2043             :         // Process security group list.
    2044        4364 :         const EnetSecurityGroupListType &isg_list =
    2045             :             item.entry.security_group_list;
    2046        4364 :         uint16_t sg_index = 0;
    2047        4364 :         for (EnetSecurityGroupListType::const_iterator sit = isg_list.begin();
    2048        8734 :             sit != isg_list.end(); ++sit) {
    2049        4368 :             if (bgp_server_->autonomous_system() <= AS2_MAX) {
    2050        4369 :                 SecurityGroup sg(bgp_server_->autonomous_system(), *sit);
    2051        4370 :                 ext.communities.push_back(sg.GetExtCommunityValue());
    2052             :             } else {
    2053           0 :                 SecurityGroup sg(sg_index, *sit);
    2054           0 :                 SecurityGroup4ByteAs sg4(bgp_server_->autonomous_system(),
    2055           0 :                                              sg_index++);
    2056           0 :                 ext.communities.push_back(sg4.GetExtCommunityValue());
    2057           0 :                 ext.communities.push_back(sg.GetExtCommunityValue());
    2058             :             }
    2059             :         }
    2060             : 
    2061        4366 :         if (item.entry.mobility.seqno) {
    2062           6 :             MacMobility mm(item.entry.mobility.seqno,
    2063           6 :                 item.entry.mobility.sticky);
    2064           6 :             ext.communities.push_back(mm.GetExtCommunityValue());
    2065        4360 :         } else if (item.entry.sequence_number) {
    2066           2 :             MacMobility mm(item.entry.sequence_number);
    2067           2 :             ext.communities.push_back(mm.GetExtCommunityValue());
    2068             :         }
    2069             : 
    2070        4366 :         ETree etree(item.entry.etree_leaf);
    2071        4365 :         ext.communities.push_back(etree.GetExtCommunityValue());
    2072             : 
    2073        4364 :         if (!ext.communities.empty())
    2074        4364 :             attrs.push_back(&ext);
    2075        4364 :         if (!largecomm.communities.empty())
    2076           2 :             attrs.push_back(&largecomm);
    2077             : 
    2078        4364 :         PmsiTunnelSpec pmsi_spec;
    2079        4364 :         if (mac_addr.IsBroadcast()) {
    2080         355 :             if (!item.entry.replicator_address.empty()) {
    2081           4 :                 IpAddress replicator_address;
    2082           4 :                 if (!XmppDecodeAddress(BgpAf::IPv4,
    2083             :                     item.entry.replicator_address, &replicator_address)) {
    2084           4 :                     BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name,
    2085             :                         BGP_LOG_FLAG_ALL,
    2086             :                         "Bad replicator address " <<
    2087             :                         item.entry.replicator_address <<
    2088             :                         " for enet route " << evpn_prefix.ToXmppIdString());
    2089           2 :                     return false;
    2090             :                 }
    2091           2 :                 pmsi_spec.tunnel_type =
    2092             :                     PmsiTunnelSpec::AssistedReplicationContrail;
    2093           2 :                 pmsi_spec.tunnel_flags = PmsiTunnelSpec::ARLeaf;
    2094           2 :                 pmsi_spec.SetIdentifier(replicator_address.to_v4());
    2095             :             } else {
    2096         351 :                 pmsi_spec.tunnel_type = PmsiTunnelSpec::IngressReplication;
    2097         351 :                 if (item.entry.assisted_replication_supported) {
    2098           0 :                     pmsi_spec.tunnel_flags |= PmsiTunnelSpec::ARReplicator;
    2099           0 :                     pmsi_spec.tunnel_flags |= PmsiTunnelSpec::LeafInfoRequired;
    2100             :                 }
    2101         351 :                 if (!item.entry.edge_replication_not_supported) {
    2102         175 :                     pmsi_spec.tunnel_flags |=
    2103             :                         PmsiTunnelSpec::EdgeReplicationSupported;
    2104             :                 }
    2105         351 :                 pmsi_spec.SetIdentifier(nh_address.to_v4());
    2106             :             }
    2107         353 :             ExtCommunity ext_comm(bgp_server_->extcomm_db(), ext);
    2108         353 :             pmsi_spec.SetLabel(label, &ext_comm);
    2109         353 :             attrs.push_back(&pmsi_spec);
    2110         353 :         }
    2111             : 
    2112        4363 :         BgpAttrPtr attr = bgp_server_->attr_db()->Locate(attrs);
    2113             : 
    2114        4364 :         req.data.reset(new EvpnTable::RequestData(
    2115        4364 :             attr, flags, label, l3_label, subscription_gen_id));
    2116        4364 :         stats_[RX].reach++;
    2117        4379 :     } else {
    2118        1150 :         req.oper = DBRequest::DB_ENTRY_DELETE;
    2119        1150 :         stats_[RX].unreach++;
    2120             :     }
    2121             : 
    2122             :     // Defer all requests till subscribe is processed.
    2123        5514 :     if (subscribe_pending) {
    2124         349 :         DBRequest *request_entry = new DBRequest();
    2125         349 :         request_entry->Swap(&req);
    2126             :         string table_name =
    2127         349 :             RoutingInstance::GetTableName(vrf_name, Address::EVPN);
    2128         349 :         defer_q_.insert(make_pair(
    2129         698 :             make_pair(vrf_name, table_name), request_entry));
    2130         349 :         return true;
    2131         349 :     }
    2132             : 
    2133        5165 :     assert(table);
    2134        9652 :     BGP_LOG_PEER_INSTANCE(Peer(), vrf_name,
    2135             :         SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_TRACE,
    2136             :         "Enet route " << evpn_prefix.ToXmppIdString() <<
    2137             :         " with next-hop " << nh_address <<
    2138             :         " label " << label << " l3-label " << l3_label <<
    2139             :         " enqueued for " << (add_change ? "add/change" : "delete"));
    2140        5165 :     table->Enqueue(&req);
    2141        5166 :     return true;
    2142        5543 : }
    2143             : 
    2144         948 : void BgpXmppChannel::DequeueRequest(const string &table_name,
    2145             :                                     DBRequest *request) {
    2146         948 :     unique_ptr<DBRequest> ptr(request);
    2147             : 
    2148             :     BgpTable *table = static_cast<BgpTable *>
    2149         948 :         (bgp_server_->database()->FindTable(table_name));
    2150         948 :     if (table == NULL || table->IsDeleted()) {
    2151           5 :         return;
    2152             :     }
    2153             : 
    2154         943 :     BgpMembershipManager *mgr = bgp_server_->membership_mgr();
    2155         943 :     if (mgr) {
    2156         943 :         int instance_id = -1;
    2157         943 :         uint64_t subscription_gen_id = 0;
    2158         943 :         bool is_registered = mgr->GetRegistrationInfo(peer_.get(), table,
    2159             :                                             &instance_id, &subscription_gen_id);
    2160         943 :         if (!is_registered) {
    2161           0 :             BGP_LOG_PEER_WARNING(Membership, Peer(),
    2162             :                 BGP_LOG_FLAG_ALL, BGP_PEER_DIR_NA,
    2163             :                 "Not subscribed to table " << table->name());
    2164           0 :             return;
    2165             :         }
    2166         943 :         if (ptr->oper == DBRequest::DB_ENTRY_ADD_CHANGE) {
    2167         940 :             ((BgpTable::RequestData *)ptr->data.get())
    2168         940 :                 ->set_subscription_gen_id(subscription_gen_id);
    2169             :         }
    2170             :     }
    2171             : 
    2172         943 :     table->Enqueue(ptr.get());
    2173         948 : }
    2174             : 
    2175          90 : bool BgpXmppChannel::ResumeClose() {
    2176          90 :     peer_->Close(true);
    2177          90 :     return true;
    2178             : }
    2179             : 
    2180       68876 : void BgpXmppChannel::RegisterTable(int line, BgpTable *table,
    2181             :     const TableMembershipRequestState *tmr_state) {
    2182             :     // Defer if Membership manager is in use (by close manager).
    2183       68876 :     if (close_manager_->IsMembershipInUse()) {
    2184         276 :         BGP_LOG_PEER_TABLE(Peer(), SandeshLevel::SYS_DEBUG,
    2185             :                            BGP_LOG_FLAG_ALL, table, "RegisterTable deferred "
    2186             :                            "from :" << line);
    2187          92 :         return;
    2188             :     }
    2189             : 
    2190       68784 :     BgpMembershipManager *mgr = bgp_server_->membership_mgr();
    2191       85089 :     BGP_LOG_PEER(Membership, Peer(), SandeshLevel::SYS_DEBUG,
    2192             :                  BGP_LOG_FLAG_ALL, BGP_PEER_DIR_NA,
    2193             :                  "Subscribe to table " << table->name() <<
    2194             :                  (tmr_state->no_ribout ? " (no ribout)" : "") <<
    2195             :                  " with id " << tmr_state->instance_id);
    2196       68784 :     if (tmr_state->no_ribout) {
    2197          62 :         mgr->RegisterRibIn(peer_.get(), table);
    2198          62 :         mgr->SetRegistrationInfo(peer_.get(), table, tmr_state->instance_id,
    2199          62 :             manager_->get_subscription_gen_id());
    2200          62 :         channel_stats_.table_subscribe++;
    2201          62 :         MembershipRequestCallback(table);
    2202             :     } else {
    2203       68722 :         mgr->Register(peer_.get(), table, bgp_policy_, tmr_state->instance_id);
    2204       68722 :         channel_stats_.table_subscribe++;
    2205             :     }
    2206             : 
    2207             :     // If EndOfRib Send timer is running, cancel it and reschedule it after all
    2208             :     // outstanding membership registrations are complete.
    2209       68784 :     if (eor_send_timer_->running())
    2210       13618 :         eor_send_timer_->Cancel();
    2211             : }
    2212             : 
    2213        4486 : void BgpXmppChannel::UnregisterTable(int line, BgpTable *table) {
    2214             :     // Defer if Membership manager is in use (by close manager).
    2215        4486 :     if (close_manager_->IsMembershipInUse()) {
    2216         948 :         BGP_LOG_PEER_TABLE(Peer(), SandeshLevel::SYS_DEBUG,
    2217             :                            BGP_LOG_FLAG_ALL, table, "UnregisterTable deferred "
    2218             :                            "from :" << line);
    2219         316 :         return;
    2220             :     }
    2221             : 
    2222        4170 :     BgpMembershipManager *mgr = bgp_server_->membership_mgr();
    2223        5770 :     BGP_LOG_PEER(Membership, Peer(), SandeshLevel::SYS_DEBUG,
    2224             :                  BGP_LOG_FLAG_ALL, BGP_PEER_DIR_NA,
    2225             :                  "Unsubscribe to table " << table->name());
    2226        4170 :     mgr->Unregister(peer_.get(), table);
    2227        4170 :     channel_stats_.table_unsubscribe++;
    2228             : }
    2229             : 
    2230             : #define RegisterTable(table, tmr_state) \
    2231             :     RegisterTable(__LINE__, table, tmr_state)
    2232             : #define UnregisterTable(table) UnregisterTable(__LINE__, table)
    2233             : 
    2234             : // Process all pending membership requests of various tables.
    2235         264 : void BgpXmppChannel::ProcessPendingSubscriptions() {
    2236         264 :     assert(!close_manager_->IsMembershipInUse());
    2237        1080 :     BOOST_FOREACH(TableMembershipRequestMap::value_type &entry,
    2238             :                   table_membership_request_map_) {
    2239             :         BgpTable *table = static_cast<BgpTable *>(
    2240         408 :             bgp_server_->database()->FindTable(entry.first));
    2241         408 :         const TableMembershipRequestState &tmr_state = entry.second;
    2242         408 :         if (tmr_state.current_req == SUBSCRIBE) {
    2243          92 :             RegisterTable(table, &tmr_state);
    2244             :         } else {
    2245         316 :             assert(tmr_state.current_req == UNSUBSCRIBE);
    2246         316 :             UnregisterTable(table);
    2247             :         }
    2248             :     }
    2249         264 : }
    2250             : 
    2251       10823 : size_t BgpXmppChannel::table_membership_requests() const {
    2252       10823 :     return table_membership_request_map_.size();
    2253             : }
    2254             : 
    2255      141085 : bool BgpXmppChannel::MembershipResponseHandler(string table_name) {
    2256      141085 :     if (close_manager_->IsMembershipInUse()) {
    2257       68122 :         close_manager_->MembershipRequestCallback();
    2258       68311 :         return true;
    2259             :     }
    2260             : 
    2261             :     TableMembershipRequestState *tmr_state =
    2262       72951 :         GetTableMembershipState(table_name);
    2263       72945 :     if (!tmr_state) {
    2264           0 :         BGP_LOG_PEER_INSTANCE_CRITICAL(Peer(), table_name,
    2265             :                      BGP_PEER_DIR_IN, BGP_LOG_FLAG_ALL,
    2266             :                      "Table not in subscribe/unsubscribe request queue");
    2267           0 :         assert(false);
    2268             :     }
    2269             : 
    2270       72945 :     if (tmr_state->current_req == SUBSCRIBE) {
    2271       85080 :         BGP_LOG_PEER(Membership, Peer(), SandeshLevel::SYS_DEBUG,
    2272             :                      BGP_LOG_FLAG_ALL, BGP_PEER_DIR_NA,
    2273             :                      "Subscribe to table " << table_name << " completed");
    2274       68778 :         channel_stats_.table_subscribe_complete++;
    2275             :     } else {
    2276        5770 :         BGP_LOG_PEER(Membership, Peer(), SandeshLevel::SYS_DEBUG,
    2277             :                      BGP_LOG_FLAG_ALL, BGP_PEER_DIR_NA,
    2278             :                      "Unsubscribe to table " << table_name << " completed");
    2279        4170 :         channel_stats_.table_unsubscribe_complete++;
    2280             :     }
    2281             : 
    2282       72954 :     if (defer_peer_close_) {
    2283         646 :         DeleteTableMembershipState(table_name);
    2284         646 :         if (table_membership_requests())
    2285         556 :             return true;
    2286          90 :         defer_peer_close_ = false;
    2287          90 :         ResumeClose();
    2288             :     } else {
    2289       72308 :         ProcessMembershipResponse(table_name, tmr_state);
    2290             :     }
    2291             : 
    2292       72395 :     assert(channel_stats_.table_subscribe_complete <=
    2293             :                channel_stats_.table_subscribe);
    2294       72395 :     assert(channel_stats_.table_unsubscribe_complete <=
    2295             :                channel_stats_.table_unsubscribe);
    2296             : 
    2297             :     // Restart EndOfRib send if necessary.
    2298       72395 :     ResetEndOfRibSendState();
    2299             : 
    2300             :     // If Close manager is waiting to use membership, try now.
    2301       72397 :     if (close_manager_->IsMembershipInWait())
    2302          36 :         close_manager_->MembershipRequest();
    2303             : 
    2304       72397 :     return true;
    2305             : }
    2306             : 
    2307       72306 : bool BgpXmppChannel::ProcessMembershipResponse(string table_name,
    2308             :     TableMembershipRequestState *tmr_state) {
    2309             :     BgpTable *table = static_cast<BgpTable *>
    2310       72306 :         (bgp_server_->database()->FindTable(table_name));
    2311       72305 :     if (!table) {
    2312         142 :         DeleteTableMembershipState(table_name);
    2313         142 :         return true;
    2314             :     }
    2315       72163 :     BgpMembershipManager *mgr = bgp_server_->membership_mgr();
    2316             : 
    2317       72163 :     if ((tmr_state->current_req == UNSUBSCRIBE) &&
    2318        3890 :         (tmr_state->pending_req == SUBSCRIBE)) {
    2319             :         // Process pending subscribe now that unsubscribe has completed.
    2320          44 :         tmr_state->current_req = SUBSCRIBE;
    2321          44 :         RegisterTable(table, tmr_state);
    2322          44 :         return true;
    2323       72119 :     } else if ((tmr_state->current_req == SUBSCRIBE) &&
    2324       68273 :                (tmr_state->pending_req == UNSUBSCRIBE)) {
    2325             :         // Process pending unsubscribe now that subscribe has completed.
    2326          59 :         tmr_state->current_req = UNSUBSCRIBE;
    2327          59 :         UnregisterTable(table);
    2328          59 :         return true;
    2329      212337 :     } else if ((tmr_state->current_req == SUBSCRIBE) &&
    2330      140277 :         (tmr_state->pending_req == SUBSCRIBE) &&
    2331       68214 :         (mgr->IsRibOutRegistered(peer_.get(), table) == tmr_state->no_ribout)) {
    2332             :         // Trigger an unsubscribe so that we can subsequently subscribe with
    2333             :         // the updated value of no_ribout.
    2334          20 :         tmr_state->current_req = UNSUBSCRIBE;
    2335          20 :         UnregisterTable(table);
    2336          20 :         return true;
    2337             :     }
    2338             : 
    2339       72043 :     string vrf_name = table->routing_instance()->name();
    2340       72043 :     VrfTableName vrf_n_table = make_pair(vrf_name, table->name());
    2341             : 
    2342       72039 :     if (tmr_state->pending_req == UNSUBSCRIBE) {
    2343        3846 :         if (!GetInstanceMembershipState(vrf_name))
    2344        3845 :             assert(defer_q_.count(vrf_n_table) == 0);
    2345        3846 :         DeleteTableMembershipState(table_name);
    2346        3846 :         return true;
    2347       68193 :     } else if (tmr_state->pending_req == SUBSCRIBE) {
    2348       68195 :         mgr->SetRegistrationInfo(peer_.get(), table, tmr_state->instance_id,
    2349       68193 :             manager_->get_subscription_gen_id());
    2350       68196 :         DeleteTableMembershipState(table_name);
    2351             :     }
    2352             : 
    2353       68195 :     for (DeferQ::iterator it = defer_q_.find(vrf_n_table);
    2354       69143 :          it != defer_q_.end() && it->first.second == table->name(); ++it) {
    2355         948 :         DequeueRequest(table->name(), it->second);
    2356             :     }
    2357             : 
    2358             :     // Erase all elements for the table
    2359       68194 :     defer_q_.erase(vrf_n_table);
    2360             : 
    2361       68192 :     return true;
    2362       72038 : }
    2363             : 
    2364      141253 : void BgpXmppChannel::MembershipRequestCallback(BgpTable *table) {
    2365      141253 :     membership_response_worker_.Enqueue(table->name());
    2366      141253 : }
    2367             : 
    2368         487 : void BgpXmppChannel::FillCloseInfo(BgpNeighborResp *resp) const {
    2369         487 :     close_manager_->FillCloseInfo(resp);
    2370         487 : }
    2371             : 
    2372         487 : void BgpXmppChannel::FillInstanceMembershipInfo(BgpNeighborResp *resp) const {
    2373         487 :     vector<BgpNeighborRoutingInstance> instance_list;
    2374        4287 :     BOOST_FOREACH(const SubscribedRoutingInstanceList::value_type &entry,
    2375             :         routing_instances_) {
    2376        1900 :         BgpNeighborRoutingInstance instance;
    2377        1900 :         instance.set_name(entry.first->name());
    2378        1900 :         if (entry.second.IsLlgrStale()) {
    2379           0 :             instance.set_state("subscribed-llgr-stale");
    2380        1900 :         } else if (entry.second.IsGrStale()) {
    2381           0 :             instance.set_state("subscribed-gr-stale");
    2382             :         } else {
    2383        1900 :             instance.set_state("subscribed");
    2384             :         }
    2385        1900 :         instance.set_index(entry.second.index);
    2386        1900 :         rtarget_manager_->FillInfo(&instance, entry.second.targets);
    2387        1900 :         instance_list.push_back(instance);
    2388        1900 :     }
    2389         487 :     BOOST_FOREACH(const InstanceMembershipRequestMap::value_type &entry,
    2390             :         instance_membership_request_map_) {
    2391           0 :         const InstanceMembershipRequestState &imr_state = entry.second;
    2392           0 :         BgpNeighborRoutingInstance instance;
    2393           0 :         instance.set_name(entry.first);
    2394           0 :         instance.set_state("pending");
    2395           0 :         instance.set_index(imr_state.instance_id);
    2396           0 :         instance_list.push_back(instance);
    2397           0 :     }
    2398         487 :     resp->set_routing_instances(instance_list);
    2399         487 : }
    2400             : 
    2401         487 : void BgpXmppChannel::FillTableMembershipInfo(BgpNeighborResp *resp) const {
    2402         487 :     vector<BgpNeighborRoutingTable> old_table_list = resp->get_routing_tables();
    2403         487 :     set<string> old_table_set;
    2404         487 :     vector<BgpNeighborRoutingTable> new_table_list;
    2405             : 
    2406       19487 :     BOOST_FOREACH(const BgpNeighborRoutingTable &table, old_table_list) {
    2407        9500 :         old_table_set.insert(table.get_name());
    2408        9500 :         if (!GetTableMembershipState(table.get_name()))
    2409        9500 :             new_table_list.push_back(table);
    2410             :     }
    2411             : 
    2412         487 :     BOOST_FOREACH(const TableMembershipRequestMap::value_type &entry,
    2413             :         table_membership_request_map_) {
    2414           0 :         BgpNeighborRoutingTable table;
    2415           0 :         table.set_name(entry.first);
    2416           0 :         if (old_table_set.find(entry.first) != old_table_set.end())
    2417           0 :             table.set_current_state("subscribed");
    2418           0 :         const TableMembershipRequestState &tmr_state = entry.second;
    2419           0 :         if (tmr_state.current_req == SUBSCRIBE) {
    2420           0 :             table.set_current_request("subscribe");
    2421             :         } else {
    2422           0 :             table.set_current_request("unsubscribe");
    2423             :         }
    2424           0 :         if (tmr_state.pending_req == SUBSCRIBE) {
    2425           0 :             table.set_pending_request("subscribe");
    2426             :         } else {
    2427           0 :             table.set_pending_request("unsubscribe");
    2428             :         }
    2429           0 :         new_table_list.push_back(table);
    2430           0 :     }
    2431         487 :     resp->set_routing_tables(new_table_list);
    2432         487 : }
    2433             : 
    2434             : //
    2435             : // Erase all defer_q_ elements with the given (vrf, table).
    2436             : //
    2437          20 : void BgpXmppChannel::FlushDeferQ(string vrf_name, string table_name) {
    2438          20 :     for (DeferQ::iterator it =
    2439          20 :         defer_q_.find(make_pair(vrf_name, table_name)), itnext;
    2440          59 :         (it != defer_q_.end() && it->first.second == table_name);
    2441          39 :         it = itnext) {
    2442          39 :         itnext = it;
    2443          39 :         itnext++;
    2444          39 :         delete it->second;
    2445          39 :         defer_q_.erase(it);
    2446             :     }
    2447          20 : }
    2448             : 
    2449             : //
    2450             : // Erase all defer_q_ elements for all tables for the given vrf.
    2451             : //
    2452          10 : void BgpXmppChannel::FlushDeferQ(string vrf_name) {
    2453          10 :     for (DeferQ::iterator it =
    2454          10 :         defer_q_.lower_bound(make_pair(vrf_name, string())), itnext;
    2455          25 :         (it != defer_q_.end() && it->first.first == vrf_name);
    2456          15 :         it = itnext) {
    2457          15 :         itnext = it;
    2458          15 :         itnext++;
    2459          15 :         delete it->second;
    2460          15 :         defer_q_.erase(it);
    2461             :     }
    2462          10 : }
    2463             : 
    2464             : // Mark all current subscriptions as 'stale'. This is called when peer close
    2465             : // process is initiated by BgpXmppChannel via PeerCloseManager.
    2466         195 : void BgpXmppChannel::StaleCurrentSubscriptions() {
    2467         195 :     CHECK_CONCURRENCY(peer_close_->GetTaskName());
    2468        1675 :     BOOST_FOREACH(SubscribedRoutingInstanceList::value_type &entry,
    2469             :                   routing_instances_) {
    2470         740 :         entry.second.SetGrStale();
    2471         740 :         rtarget_manager_->UpdateRouteTargetRouteFlag(entry.first,
    2472         740 :                 entry.second.targets, BgpPath::Stale);
    2473             :     }
    2474         195 : }
    2475             : 
    2476             : // Mark all current subscriptions as 'llgr_stale'.
    2477          29 : void BgpXmppChannel::LlgrStaleCurrentSubscriptions() {
    2478          29 :     CHECK_CONCURRENCY(peer_close_->GetTaskName());
    2479         271 :     BOOST_FOREACH(SubscribedRoutingInstanceList::value_type &entry,
    2480             :                   routing_instances_) {
    2481         121 :         assert(entry.second.IsGrStale());
    2482         121 :         entry.second.SetLlgrStale();
    2483         121 :         rtarget_manager_->UpdateRouteTargetRouteFlag(entry.first,
    2484         121 :                 entry.second.targets, BgpPath::Stale | BgpPath::LlgrStale);
    2485             :     }
    2486          29 : }
    2487             : 
    2488             : // Sweep all current subscriptions which are still marked as 'stale'.
    2489          40 : void BgpXmppChannel::SweepCurrentSubscriptions() {
    2490          40 :     CHECK_CONCURRENCY(peer_close_->GetTaskName());
    2491          40 :     for (SubscribedRoutingInstanceList::iterator i = routing_instances_.begin();
    2492         216 :             i != routing_instances_.end();) {
    2493         176 :         if (i->second.IsGrStale()) {
    2494          68 :             string name = i->first->name();
    2495             : 
    2496             :             // Increment the iterator first as we expect the entry to be
    2497             :             // soon removed.
    2498          68 :             i++;
    2499         136 :             BGP_LOG_PEER(Membership, Peer(), SandeshLevel::SYS_DEBUG,
    2500             :                          BGP_LOG_FLAG_ALL, BGP_PEER_DIR_NA,
    2501             :                          "Instance subscription " << name <<
    2502             :                          " is still stale and hence unsubscribed");
    2503          68 :             ProcessSubscriptionRequest(name, NULL, false);
    2504          68 :         } else {
    2505         108 :             i++;
    2506             :         }
    2507             :     }
    2508          40 : }
    2509             : 
    2510             : // Clear staled subscription state as new subscription has been received.
    2511         252 : void BgpXmppChannel::ClearStaledSubscription(RoutingInstance *rt_instance,
    2512             :         SubscriptionState *sub_state) {
    2513         252 :     if (!sub_state->IsGrStale())
    2514           0 :         return;
    2515             : 
    2516         504 :     BGP_LOG_PEER(Membership, Peer(), SandeshLevel::SYS_DEBUG,
    2517             :                  BGP_LOG_FLAG_ALL, BGP_PEER_DIR_NA,
    2518             :                  "Instance subscription " << rt_instance->name() <<
    2519             :                  " stale flag is cleared");
    2520         252 :     sub_state->ClearStale();
    2521         252 :     rtarget_manager_->Stale(sub_state->targets);
    2522             : }
    2523             : 
    2524       14233 : void BgpXmppChannel::AddSubscriptionState(RoutingInstance *rt_instance,
    2525             :         int index) {
    2526       14233 :     SubscriptionState state(rt_instance->GetImportList(), index);
    2527             :     pair<SubscribedRoutingInstanceList::iterator, bool> ret =
    2528       14232 :         routing_instances_.insert(pair<RoutingInstance *, SubscriptionState> (
    2529             :                                       rt_instance, state));
    2530             : 
    2531             :     // During GR, we expect duplicate subscription requests. Clear stale
    2532             :     // state, as agent did re-subscribe after restart.
    2533       14233 :     if (!ret.second) {
    2534         252 :         ClearStaledSubscription(rt_instance, &ret.first->second);
    2535             :     } else {
    2536       13981 :         rtarget_manager_->PublishRTargetRoute(rt_instance, true);
    2537             :     }
    2538       14233 : }
    2539             : 
    2540         899 : void BgpXmppChannel::DeleteSubscriptionState(RoutingInstance *rt_instance) {
    2541         899 :     routing_instances_.erase(rt_instance);
    2542         899 : }
    2543             : 
    2544       17233 : BgpXmppChannel::SubscriptionState *BgpXmppChannel::GetSubscriptionState(
    2545             :     RoutingInstance *rt_instance) {
    2546             :     SubscribedRoutingInstanceList::iterator loc =
    2547       17233 :         routing_instances_.find(rt_instance);
    2548       17235 :     return (loc != routing_instances_.end() ? &loc->second : NULL);
    2549             : }
    2550             : 
    2551           0 : const BgpXmppChannel::SubscriptionState *BgpXmppChannel::GetSubscriptionState(
    2552             :     RoutingInstance *rt_instance) const {
    2553             :     SubscribedRoutingInstanceList::const_iterator loc =
    2554           0 :         routing_instances_.find(rt_instance);
    2555           0 :     return (loc != routing_instances_.end() ? &loc->second : NULL);
    2556             : }
    2557             : 
    2558          32 : void BgpXmppChannel::ProcessDeferredSubscribeRequest(RoutingInstance *instance,
    2559             :     const InstanceMembershipRequestState &imr_state) {
    2560          32 :     int instance_id = imr_state.instance_id;
    2561          32 :     bool no_ribout = imr_state.no_ribout;
    2562          32 :     AddSubscriptionState(instance, instance_id);
    2563          32 :     RoutingInstance::RouteTableList const rt_list = instance->GetTables();
    2564          32 :     for (RoutingInstance::RouteTableList::const_iterator it = rt_list.begin();
    2565         192 :          it != rt_list.end(); ++it) {
    2566         160 :         BgpTable *table = it->second;
    2567         160 :         if (table->IsVpnTable() || table->family() == Address::RTARGET)
    2568           0 :             continue;
    2569             : 
    2570             :         TableMembershipRequestState tmr_state(
    2571         160 :             SUBSCRIBE, instance_id, no_ribout);
    2572         160 :         AddTableMembershipState(table->name(), tmr_state);
    2573         160 :         RegisterTable(table, &tmr_state);
    2574             :     }
    2575          32 : }
    2576             : 
    2577       15286 : void BgpXmppChannel::ProcessSubscriptionRequest(
    2578             :         string vrf_name, const XmppStanza::XmppMessageIq *iq,
    2579             :         bool add_change) {
    2580       15286 :     int instance_id = -1;
    2581       15286 :     bool no_ribout = false;
    2582             : 
    2583       15286 :     if (add_change) {
    2584       14356 :         XmlPugi *pugi = reinterpret_cast<XmlPugi *>(iq->dom.get());
    2585       14356 :         xml_node options = pugi->FindNode("options");
    2586       28716 :         for (xml_node node = options.first_child(); node;
    2587       14360 :              node = node.next_sibling()) {
    2588       14360 :             if (strcmp(node.name(), "instance-id") == 0) {
    2589       14344 :                 instance_id = node.text().as_int();
    2590             :             }
    2591       14360 :             if (strcmp(node.name(), "no-ribout") == 0) {
    2592          16 :                 no_ribout = node.text().as_bool();
    2593             :             }
    2594             :         }
    2595             :     }
    2596             : 
    2597       15286 :     RoutingInstanceMgr *instance_mgr = bgp_server_->routing_instance_mgr();
    2598       15287 :     assert(instance_mgr);
    2599       15287 :     RoutingInstance *rt_instance = instance_mgr->GetRoutingInstance(vrf_name);
    2600       15286 :     if (rt_instance == NULL) {
    2601         174 :         BGP_LOG_PEER(Membership, Peer(), SandeshLevel::SYS_INFO,
    2602             :                      BGP_LOG_FLAG_ALL, BGP_PEER_DIR_NA,
    2603             :                      "Routing instance " << vrf_name <<
    2604             :                      " not found when processing " <<
    2605             :                      (add_change ? "subscribe" : "unsubscribe"));
    2606         146 :         if (add_change) {
    2607         136 :             if (GetInstanceMembershipState(vrf_name)) {
    2608           2 :                 BGP_LOG_PEER_WARNING(Membership, Peer(),
    2609             :                              BGP_LOG_FLAG_ALL, BGP_PEER_DIR_NA,
    2610             :                              "Duplicate subscribe for routing instance " <<
    2611             :                              vrf_name << ", triggering close");
    2612           1 :                 channel_->Close();
    2613             :             } else {
    2614         135 :                 AddInstanceMembershipState(vrf_name,
    2615             :                     InstanceMembershipRequestState(instance_id, no_ribout));
    2616         135 :                 channel_stats_.instance_subscribe++;
    2617             :             }
    2618             :         } else {
    2619          10 :             if (DeleteInstanceMembershipState(vrf_name)) {
    2620           9 :                 FlushDeferQ(vrf_name);
    2621           9 :                 channel_stats_.instance_unsubscribe++;
    2622             :             } else {
    2623           2 :                 BGP_LOG_PEER_WARNING(Membership, Peer(),
    2624             :                              BGP_LOG_FLAG_ALL, BGP_PEER_DIR_NA,
    2625             :                              "Spurious unsubscribe for routing instance " <<
    2626             :                              vrf_name << ", triggering close");
    2627           1 :                 channel_->Close();
    2628             :             }
    2629             :         }
    2630         187 :         return;
    2631       15140 :     } else if (rt_instance->deleted()) {
    2632         322 :         BGP_LOG_PEER(Membership, Peer(), SandeshLevel::SYS_DEBUG,
    2633             :                      BGP_LOG_FLAG_ALL, BGP_PEER_DIR_NA,
    2634             :                      "Routing instance " << vrf_name <<
    2635             :                      " is being deleted when processing " <<
    2636             :                      (add_change ? "subscribe" : "unsubscribe"));
    2637         161 :         if (add_change) {
    2638          10 :             if (GetInstanceMembershipState(vrf_name)) {
    2639           2 :                 BGP_LOG_PEER_WARNING(Membership, Peer(),
    2640             :                              BGP_LOG_FLAG_ALL, BGP_PEER_DIR_NA,
    2641             :                              "Duplicate subscribe for routing instance " <<
    2642             :                              vrf_name << ", triggering close");
    2643           1 :                 channel_->Close();
    2644           9 :             } else if (GetSubscriptionState(rt_instance)) {
    2645           2 :                 BGP_LOG_PEER_WARNING(Membership, Peer(),
    2646             :                              BGP_LOG_FLAG_ALL, BGP_PEER_DIR_NA,
    2647             :                              "Duplicate subscribe for routing instance " <<
    2648             :                              vrf_name << ", triggering close");
    2649           1 :                 channel_->Close();
    2650             :             } else {
    2651           8 :                 AddInstanceMembershipState(vrf_name,
    2652             :                     InstanceMembershipRequestState(instance_id, no_ribout));
    2653           8 :                 channel_stats_.instance_subscribe++;
    2654             :             }
    2655          10 :             return;
    2656             :         } else {
    2657             :             // If instance is being deleted and agent is trying to unsubscribe
    2658             :             // we need to process the unsubscribe if vrf is not in the request
    2659             :             // map.  This would be the normal case where we wait for agent to
    2660             :             // unsubscribe in order to remove routes added by it.
    2661         151 :             if (DeleteInstanceMembershipState(vrf_name)) {
    2662           1 :                 FlushDeferQ(vrf_name);
    2663           1 :                 channel_stats_.instance_unsubscribe++;
    2664           1 :                 return;
    2665         150 :             } else if (!GetSubscriptionState(rt_instance)) {
    2666           4 :                 BGP_LOG_PEER_WARNING(Membership, Peer(),
    2667             :                              BGP_LOG_FLAG_ALL, BGP_PEER_DIR_NA,
    2668             :                              "Spurious unsubscribe for routing instance " <<
    2669             :                              vrf_name << ", triggering close");
    2670           2 :                 channel_->Close();
    2671           2 :                 return;
    2672             :             }
    2673         148 :             channel_stats_.instance_unsubscribe++;
    2674             :         }
    2675             :     } else {
    2676       14979 :         if (add_change) {
    2677             :             const SubscriptionState *sub_state =
    2678       14209 :                 GetSubscriptionState(rt_instance);
    2679       14210 :             if (sub_state) {
    2680         261 :                 if (!close_manager_->IsCloseInProgress()) {
    2681           2 :                     BGP_LOG_PEER_WARNING(Membership, Peer(),
    2682             :                                  BGP_LOG_FLAG_ALL, BGP_PEER_DIR_NA,
    2683             :                                  "Duplicate subscribe for routing instance " <<
    2684             :                                  vrf_name << ", triggering close");
    2685           1 :                     channel_->Close();
    2686           1 :                     return;
    2687             :                 }
    2688         260 :                 if (!sub_state->IsGrStale()) {
    2689          16 :                     BGP_LOG_PEER_WARNING(Membership, Peer(),
    2690             :                                  BGP_LOG_FLAG_ALL, BGP_PEER_DIR_NA,
    2691             :                                  "Duplicate subscribe for routing instance " <<
    2692             :                                  vrf_name << " under GR, triggering close");
    2693           8 :                     channel_->Close();
    2694           8 :                     return;
    2695             :                 }
    2696             :             }
    2697       14201 :             channel_stats_.instance_subscribe++;
    2698             :         } else {
    2699         770 :             if (!GetSubscriptionState(rt_instance)) {
    2700          26 :                 BGP_LOG_PEER_WARNING(Membership, Peer(),
    2701             :                              BGP_LOG_FLAG_ALL, BGP_PEER_DIR_NA,
    2702             :                              "Spurious unsubscribe for routing instance " <<
    2703             :                              vrf_name << ", triggering close");
    2704          19 :                 channel_->Close();
    2705          19 :                 return;
    2706             :             }
    2707         751 :             channel_stats_.instance_unsubscribe++;
    2708             :         }
    2709             :     }
    2710             : 
    2711       15100 :     if (add_change) {
    2712       14201 :         AddSubscriptionState(rt_instance, instance_id);
    2713             :     } else  {
    2714         899 :         rtarget_manager_->PublishRTargetRoute(rt_instance, false);
    2715         899 :         DeleteSubscriptionState(rt_instance);
    2716             :     }
    2717             : 
    2718       15100 :     RoutingInstance::RouteTableList const rt_list = rt_instance->GetTables();
    2719       15100 :     for (RoutingInstance::RouteTableList::const_iterator it = rt_list.begin();
    2720       95684 :          it != rt_list.end(); ++it) {
    2721       80582 :         BgpTable *table = it->second;
    2722       80583 :         if (table->IsVpnTable() || table->family() == Address::RTARGET)
    2723        7628 :             continue;
    2724             : 
    2725       72956 :         if (add_change) {
    2726             :             TableMembershipRequestState *tmr_state =
    2727       68689 :                 GetTableMembershipState(table->name());
    2728       68689 :             if (!tmr_state) {
    2729             :                 TableMembershipRequestState tmp_tmr_state(
    2730       68580 :                     SUBSCRIBE, instance_id, no_ribout);
    2731       68580 :                 AddTableMembershipState(table->name(), tmp_tmr_state);
    2732       68580 :                 RegisterTable(table, &tmp_tmr_state);
    2733             :             } else {
    2734         109 :                 tmr_state->instance_id = instance_id;
    2735         109 :                 tmr_state->pending_req = SUBSCRIBE;
    2736         109 :                 tmr_state->no_ribout = no_ribout;
    2737             :             }
    2738             :         } else {
    2739        4267 :             if (defer_q_.count(make_pair(vrf_name, table->name()))) {
    2740          40 :                 BGP_LOG_PEER(Membership, Peer(), SandeshLevel::SYS_DEBUG,
    2741             :                              BGP_LOG_FLAG_ALL, BGP_PEER_DIR_NA,
    2742             :                              "Flush deferred route requests for table " <<
    2743             :                              table->name() << " on unsubscribe");
    2744          20 :                 FlushDeferQ(vrf_name, table->name());
    2745             :             }
    2746             : 
    2747             :             // Erase all elements for the table.
    2748             : 
    2749             :             TableMembershipRequestState *tmr_state =
    2750        4267 :                 GetTableMembershipState(table->name());
    2751        4267 :             if (!tmr_state) {
    2752        4091 :                 AddTableMembershipState(table->name(),
    2753             :                     TableMembershipRequestState(
    2754             :                         UNSUBSCRIBE, instance_id, no_ribout));
    2755        4091 :                 UnregisterTable(table);
    2756             :             } else {
    2757         176 :                 tmr_state->instance_id = -1;
    2758         176 :                 tmr_state->pending_req = UNSUBSCRIBE;
    2759         176 :                 tmr_state->no_ribout = false;
    2760             :             }
    2761             :         }
    2762             :     }
    2763       15100 : }
    2764             : 
    2765        6351 : void BgpXmppChannel::ClearEndOfRibState() {
    2766        6351 :     eor_receive_timer_->Cancel();
    2767        6351 :     eor_send_timer_->Cancel();
    2768        6352 :     eor_sent_ = false;
    2769        6352 : }
    2770             : 
    2771         385 : void BgpXmppChannel::ReceiveEndOfRIB(Address::Family family) {
    2772         385 :     eor_receive_timer_->Cancel();
    2773         385 :     close_manager_->ProcessEORMarkerReceived(family);
    2774         385 : }
    2775             : 
    2776           0 : void BgpXmppChannel::EndOfRibTimerErrorHandler(string error_name,
    2777             :                                                string error_message) {
    2778           0 :     BGP_LOG_PEER_CRITICAL(Timer, Peer(), BGP_LOG_FLAG_ALL, BGP_PEER_DIR_NA,
    2779             :                  "Timer error: " << error_name << " " << error_message);
    2780           0 : }
    2781             : 
    2782         345 : bool BgpXmppChannel::EndOfRibReceiveTimerExpired() {
    2783         345 :     if (!peer_->IsReady())
    2784           0 :         return false;
    2785             : 
    2786         345 :     uint32_t timeout = manager() && manager()->xmpp_server() ?
    2787         345 :         manager()->xmpp_server()->GetEndOfRibReceiveTime() :
    2788         345 :         BgpGlobalSystemConfig::kEndOfRibTime;
    2789             : 
    2790             :     // If max timeout has not reached yet, check if we can exit GR sooner by
    2791             :     // looking at the activity in the channel.
    2792         345 :     if (UTCTimestamp() - eor_receive_timer_start_time_ < timeout) {
    2793             : 
    2794             :         // If there is some send or receive activity in the channel in last few
    2795             :         // seconds, delay EoR receive event.
    2796           0 :         if (channel_->LastReceived(kEndOfRibSendRetryTime * 6) ||
    2797           0 :                 channel_->LastSent(kEndOfRibSendRetryTime * 6)) {
    2798           0 :             eor_receive_timer_->Reschedule(kEndOfRibSendRetryTime * 1000);
    2799           0 :             BGP_LOG_PEER(Message, Peer(), SandeshLevel::SYS_INFO,
    2800             :                          BGP_LOG_FLAG_ALL, BGP_PEER_DIR_IN,
    2801             :                          "EndOfRib Receive timer rescheduled to fire after " <<
    2802             :                          kEndOfRibSendRetryTime << " second(s)");
    2803           0 :             return true;
    2804             :         }
    2805             :     }
    2806             : 
    2807         418 :     BGP_LOG_PEER(Message, Peer(), SandeshLevel::SYS_INFO, BGP_LOG_FLAG_ALL,
    2808             :                  BGP_PEER_DIR_IN, "EndOfRib Receive timer expired");
    2809         345 :     ReceiveEndOfRIB(Address::UNSPEC);
    2810         345 :     return false;
    2811             : }
    2812             : 
    2813        8860 : time_t BgpXmppChannel::GetEndOfRibSendTime() const {
    2814        8860 :     return manager() && manager()->xmpp_server() ?
    2815        8860 :         manager()->xmpp_server()->GetEndOfRibSendTime() :
    2816        8860 :         BgpGlobalSystemConfig::kEndOfRibTime;
    2817             : }
    2818             : 
    2819        8862 : bool BgpXmppChannel::EndOfRibSendTimerExpired() {
    2820        8862 :     if (!peer_->IsReady())
    2821           0 :         return false;
    2822             : 
    2823             :     // If max timeout has not reached yet, check if we can exit GR sooner by
    2824             :     // looking at the activity in the channel.
    2825        8862 :     if (UTCTimestamp() - eor_send_timer_start_time_ < GetEndOfRibSendTime()) {
    2826             : 
    2827             :         // If there is some send or receive activity in the channel in last few
    2828             :         // seconds, delay EoR send event.
    2829        8860 :         if (channel_->LastReceived(kEndOfRibSendRetryTime * 6) ||
    2830        9164 :                 channel_->LastSent(kEndOfRibSendRetryTime * 6) ||
    2831         304 :                 manager()->bgp_server()->IsServerStartingUp()) {
    2832        8691 :             eor_send_timer_->Reschedule(kEndOfRibSendRetryTime * 1000);
    2833       10124 :             BGP_LOG_PEER(Message, Peer(), SandeshLevel::SYS_INFO,
    2834             :                          BGP_LOG_FLAG_ALL, BGP_PEER_DIR_OUT,
    2835             :                          "EndOfRib Send timer rescheduled to fire after " <<
    2836             :                          kEndOfRibSendRetryTime << " second(s)");
    2837        8689 :             return true;
    2838             :         }
    2839             :     }
    2840             : 
    2841         171 :     SendEndOfRIB();
    2842         171 :     return false;
    2843             : }
    2844             : 
    2845        6298 : void BgpXmppChannel::StartEndOfRibReceiveTimer() {
    2846        6298 :     uint32_t timeout = manager() && manager()->xmpp_server() ?
    2847        6290 :                            manager()->xmpp_server()->GetEndOfRibReceiveTime() :
    2848        6298 :                            BgpGlobalSystemConfig::kEndOfRibTime;
    2849        6298 :     eor_receive_timer_start_time_ = UTCTimestamp();
    2850        6298 :     eor_receive_timer_->Cancel();
    2851             : 
    2852        7238 :     BGP_LOG_PEER(Message, Peer(), SandeshLevel::SYS_INFO, BGP_LOG_FLAG_ALL,
    2853             :         BGP_PEER_DIR_IN, "EndOfRib Receive timer scheduled to fire after " <<
    2854             :         timeout << " second(s)");
    2855        6298 :     eor_receive_timer_->Start(timeout * 1000,
    2856             :         boost::bind(&BgpXmppChannel::EndOfRibReceiveTimerExpired, this),
    2857             :         boost::bind(&BgpXmppChannel::EndOfRibTimerErrorHandler, this, _1, _2));
    2858        6298 : }
    2859             : 
    2860       78695 : void BgpXmppChannel::ResetEndOfRibSendState() {
    2861       78695 :     if (eor_sent_)
    2862         448 :         return;
    2863             : 
    2864             :     // If socket is blocked, then wait for it to get unblocked first.
    2865       78247 :     if (!peer_->send_ready())
    2866           0 :         return;
    2867             : 
    2868             :     // If there is any outstanding subscribe pending, wait for its completion.
    2869       78248 :     if (channel_stats_.table_subscribe_complete !=
    2870       78247 :             channel_stats_.table_subscribe)
    2871       54367 :         return;
    2872             : 
    2873       23881 :     eor_send_timer_start_time_ = UTCTimestamp();
    2874       23881 :     eor_send_timer_->Cancel();
    2875             : 
    2876       29414 :     BGP_LOG_PEER(Message, Peer(), SandeshLevel::SYS_INFO, BGP_LOG_FLAG_ALL,
    2877             :         BGP_PEER_DIR_OUT, "EndOfRib Send timer scheduled to fire after " <<
    2878             :         kEndOfRibSendRetryTime << " second(s)");
    2879       23881 :     eor_send_timer_->Start(kEndOfRibSendRetryTime * 1000,
    2880             :         boost::bind(&BgpXmppChannel::EndOfRibSendTimerExpired, this),
    2881             :         boost::bind(&BgpXmppChannel::EndOfRibTimerErrorHandler, this, _1, _2));
    2882             : }
    2883             : 
    2884             : /*
    2885             :  * Empty items list constitute eor marker.
    2886             :  */
    2887         171 : void BgpXmppChannel::SendEndOfRIB() {
    2888         171 :     eor_send_timer_->Cancel();
    2889         171 :     eor_sent_ = true;
    2890             : 
    2891         171 :     string msg;
    2892         171 :     msg += "\n<message from=\"";
    2893         171 :     msg += XmppInit::kControlNodeJID;
    2894         171 :     msg += "\" to=\"";
    2895         171 :     msg += peer_->ToString();
    2896         171 :     msg += "/";
    2897         171 :     msg += XmppInit::kBgpPeer;
    2898         171 :     msg += "\">";
    2899         171 :     msg += "\n\t<event xmlns=\"http://jabber.org/protocol/pubsub\">";
    2900         342 :     msg = (msg + "\n<items node=\"") + XmppInit::kEndOfRibMarker +
    2901         171 :           "\"></items>";
    2902         171 :     msg += "\n\t</event>\n</message>\n";
    2903             : 
    2904         171 :     if (channel_->connection())
    2905         169 :         channel_->connection()->Send((const uint8_t *) msg.data(), msg.size());
    2906             : 
    2907         171 :     stats_[TX].end_of_rib++;
    2908         180 :     BGP_LOG_PEER(Message, Peer(), SandeshLevel::SYS_INFO, BGP_LOG_FLAG_ALL,
    2909             :                  BGP_PEER_DIR_OUT, "EndOfRib marker sent");
    2910         171 : }
    2911             : 
    2912             : // Process any associated primary instance-id.
    2913       25618 : int BgpXmppChannel::GetPrimaryInstanceID(const string &s,
    2914             :                                          bool expect_prefix_len) const {
    2915       25618 :     if (s.empty())
    2916           0 :         return 0;
    2917       25619 :     char *str = const_cast<char *>(s.c_str());
    2918             :     char *saveptr, *token;
    2919       25619 :     token = strtok_r(str, "/", &saveptr); // Get afi
    2920       25618 :     if (!token || !saveptr)
    2921           0 :         return 0;
    2922       25618 :     token = strtok_r(NULL, "/", &saveptr); // Get safi
    2923       25619 :     if (!token || !saveptr)
    2924           0 :         return 0;
    2925       25619 :     token = strtok_r(NULL, "/", &saveptr); // vrf name
    2926       25619 :     if (!token || !saveptr)
    2927           0 :         return 0;
    2928       25619 :     token = strtok_r(NULL, "/", &saveptr); // address
    2929       25619 :     if (!token || !saveptr)
    2930           2 :         return 0;
    2931       25617 :     if (expect_prefix_len) {
    2932       25613 :         token = strtok_r(NULL, "/", &saveptr); // prefix-length
    2933       25613 :         if (!token || !saveptr)
    2934           1 :             return 0;
    2935             :     }
    2936       25616 :     token = strtok_r(NULL, "/", &saveptr); // primary instance-id
    2937       25616 :     if (!token)
    2938       25600 :         return 0;
    2939          16 :     return strtoul(token, NULL, 0);
    2940             : }
    2941             : 
    2942       56890 : void BgpXmppChannel::ReceiveUpdate(const XmppStanza::XmppMessage *msg) {
    2943       56890 :     CHECK_CONCURRENCY("xmpp::StateMachine");
    2944             : 
    2945             :     // Bail if the connection is being deleted. It's not safe to assert
    2946             :     // because the Delete method can be called from the main thread.
    2947       56890 :     if (channel_->connection() && channel_->connection()->IsDeleted())
    2948           0 :         return;
    2949             : 
    2950             :     // Make sure that peer is not set for closure already.
    2951       56889 :     assert(!defer_peer_close_);
    2952       56889 :     assert(!peer_deleted());
    2953             : 
    2954       56890 :     if (msg->type == XmppStanza::IQ_STANZA) {
    2955       56890 :         const XmppStanza::XmppMessageIq *iq =
    2956             :                    static_cast<const XmppStanza::XmppMessageIq *>(msg);
    2957       56890 :         if (iq->iq_type.compare("set") == 0) {
    2958       56890 :             if (iq->action.compare("subscribe") == 0) {
    2959       14356 :                 ProcessSubscriptionRequest(iq->node, iq, true);
    2960       42534 :             } else if (iq->action.compare("unsubscribe") == 0) {
    2961         863 :                 ProcessSubscriptionRequest(iq->node, iq, false);
    2962       41671 :             } else if (iq->action.compare("publish") == 0) {
    2963       41664 :                 XmlBase *impl = msg->dom.get();
    2964       41664 :                 stats_[RX].rt_updates++;
    2965       41665 :                 XmlPugi *pugi = reinterpret_cast<XmlPugi *>(impl);
    2966       41665 :                 xml_node item = pugi->FindNode("item");
    2967             : 
    2968             :                 // Empty items-list can be considered as EOR Marker for all afis
    2969       41664 :                 if (item == 0) {
    2970          56 :                     BGP_LOG_PEER(Message, Peer(), SandeshLevel::SYS_INFO,
    2971             :                                  BGP_LOG_FLAG_ALL, BGP_PEER_DIR_IN,
    2972             :                                  "EndOfRib marker received");
    2973          28 :                     stats_[RX].end_of_rib++;
    2974          28 :                     ReceiveEndOfRIB(Address::UNSPEC);
    2975          28 :                     return;
    2976             :                 }
    2977       83273 :                 for (; item; item = item.next_sibling()) {
    2978       41636 :                     if (strcmp(item.name(), "item") != 0) continue;
    2979             : 
    2980       41636 :                     string id(iq->as_node.c_str());
    2981       41636 :                     char *str = const_cast<char *>(id.c_str());
    2982             :                     char *saveptr;
    2983       41636 :                     char *af = strtok_r(str, "/", &saveptr);
    2984       41637 :                     char *safi = strtok_r(NULL, "/", &saveptr);
    2985             : 
    2986       41637 :                     if (atoi(af) == BgpAf::IPv4 &&
    2987       27010 :                         ((atoi(safi) == BgpAf::Unicast) ||
    2988        1412 :                          (atoi(safi) == BgpAf::Mpls))) {
    2989       25610 :                         ProcessItem(iq->node, item, iq->is_as_node,
    2990       25610 :                             GetPrimaryInstanceID(iq->as_node, true));
    2991       16027 :                     } else if (atoi(af) == BgpAf::IPv6 &&
    2992        9097 :                                atoi(safi) == BgpAf::Unicast) {
    2993        9097 :                         ProcessInet6Item(iq->node, item, iq->is_as_node);
    2994        6930 :                     } else if (atoi(af) == BgpAf::IPv4 &&
    2995        1400 :                         atoi(safi) == BgpAf::Mcast) {
    2996        1152 :                         ProcessMcastItem(iq->node, item, iq->is_as_node);
    2997        5778 :                     } else if (atoi(af) == BgpAf::IPv4 &&
    2998         248 :                         atoi(safi) == BgpAf::MVpn) {
    2999         248 :                         ProcessMvpnItem(iq->node, item, iq->is_as_node);
    3000        5530 :                     } else if (atoi(af) == BgpAf::L2Vpn &&
    3001        5530 :                                atoi(safi) == BgpAf::Enet) {
    3002        5530 :                         ProcessEnetItem(iq->node, item, iq->is_as_node);
    3003             :                     }
    3004       41637 :                 }
    3005             :             }
    3006             :         }
    3007             :     }
    3008             : }
    3009             : 
    3010        6186 : bool BgpXmppChannelManager::DeleteChannel(BgpXmppChannel *channel) {
    3011        6186 :     if (!channel->deleted()) {
    3012        6186 :         channel->set_deleted(true);
    3013        6186 :         delete channel;
    3014             :     }
    3015        6186 :     return true;
    3016             : }
    3017             : 
    3018             : // BgpXmppChannelManager routines.
    3019        2084 : BgpXmppChannelManager::BgpXmppChannelManager(XmppServer *xmpp_server,
    3020        2084 :                                              BgpServer *server)
    3021        2084 :     : xmpp_server_(xmpp_server),
    3022        2084 :       bgp_server_(server),
    3023        2084 :       queue_(TaskScheduler::GetInstance()->GetTaskId("bgp::Config"), 0,
    3024             :           boost::bind(&BgpXmppChannelManager::DeleteChannel, this, _1)),
    3025        2084 :       id_(-1),
    3026        2084 :       asn_listener_id_(-1),
    3027        2084 :       identifier_listener_id_(-1),
    3028        4168 :       dscp_listener_id_(-1) {
    3029             :     // Initialize the gen id counter
    3030        2084 :     subscription_gen_id_ = 1;
    3031        2084 :     deleting_count_ = 0;
    3032             : 
    3033        2084 :     if (xmpp_server)
    3034        2078 :         xmpp_server->CreateConfigUpdater(server->config_manager());
    3035        2084 :     queue_.SetEntryCallback(
    3036             :             boost::bind(&BgpXmppChannelManager::IsReadyForDeletion, this));
    3037        2084 :     if (xmpp_server) {
    3038        2078 :         xmpp_server->RegisterConnectionEvent(xmps::BGP,
    3039             :                boost::bind(&BgpXmppChannelManager::XmppHandleChannelEvent,
    3040             :                            this, _1, _2));
    3041             :     }
    3042        2084 :     admin_down_listener_id_ =
    3043        2084 :         server->RegisterAdminDownCallback(boost::bind(
    3044             :             &BgpXmppChannelManager::AdminDownCallback, this));
    3045        2084 :     asn_listener_id_ =
    3046        2084 :         server->RegisterASNUpdateCallback(boost::bind(
    3047             :             &BgpXmppChannelManager::ASNUpdateCallback, this, _1, _2));
    3048        2084 :     identifier_listener_id_ =
    3049        2084 :         server->RegisterIdentifierUpdateCallback(boost::bind(
    3050             :             &BgpXmppChannelManager::IdentifierUpdateCallback, this, _1));
    3051        2084 :     dscp_listener_id_ =
    3052        2084 :         server->RegisterDSCPUpdateCallback(boost::bind(
    3053             :             &BgpXmppChannelManager::DSCPUpdateCallback, this, _1));
    3054             : 
    3055        2084 :     id_ = server->routing_instance_mgr()->RegisterInstanceOpCallback(
    3056             :         boost::bind(&BgpXmppChannelManager::RoutingInstanceCallback,
    3057             :                     this, _1, _2));
    3058        2084 : }
    3059             : 
    3060        3540 : BgpXmppChannelManager::~BgpXmppChannelManager() {
    3061        2084 :     assert(channel_map_.empty());
    3062        2084 :     assert(channel_name_map_.empty());
    3063        2084 :     assert(deleting_count_ == 0);
    3064        2084 :     if (xmpp_server_) {
    3065        2078 :         xmpp_server_->UnRegisterConnectionEvent(xmps::BGP);
    3066             :     }
    3067             : 
    3068        2084 :     queue_.Shutdown();
    3069        2084 :     bgp_server_->UnregisterAdminDownCallback(admin_down_listener_id_);
    3070        2084 :     bgp_server_->UnregisterASNUpdateCallback(asn_listener_id_);
    3071        2084 :     bgp_server_->routing_instance_mgr()->UnregisterInstanceOpCallback(id_);
    3072        2084 :     bgp_server_->UnregisterDSCPUpdateCallback(dscp_listener_id_);
    3073        3540 : }
    3074             : 
    3075       20506 : bool BgpXmppChannelManager::IsReadyForDeletion() {
    3076       20506 :     return bgp_server_->IsReadyForDeletion();
    3077             : }
    3078             : 
    3079           4 : void BgpXmppChannelManager::SetQueueDisable(bool disabled) {
    3080           4 :     queue_.set_disable(disabled);
    3081           4 : }
    3082             : 
    3083           2 : size_t BgpXmppChannelManager::GetQueueSize() const {
    3084           2 :     return queue_.Length();
    3085             : }
    3086             : 
    3087          16 : void BgpXmppChannelManager::AdminDownCallback() {
    3088          16 :     xmpp_server_->ClearAllConnections();
    3089          16 : }
    3090             : 
    3091           7 : void BgpXmppChannelManager::DSCPUpdateCallback(uint8_t dscp_value) {
    3092           7 :     xmpp_server_->SetDscpValue(dscp_value);
    3093           7 : }
    3094             : 
    3095        2419 : void BgpXmppChannelManager::ASNUpdateCallback(as_t old_asn,
    3096             :     as_t old_local_asn) {
    3097        2419 :     CHECK_CONCURRENCY("bgp::Config");
    3098        4529 :     BOOST_FOREACH(XmppChannelMap::value_type &i, channel_map_) {
    3099        1055 :         i.second->rtarget_manager()->ASNUpdateCallback(old_asn, old_local_asn);
    3100             :     }
    3101        2419 :     if (bgp_server_->autonomous_system() != old_asn) {
    3102        2390 :         xmpp_server_->ClearAllConnections();
    3103             :     }
    3104        2419 : }
    3105             : 
    3106        2408 : void BgpXmppChannelManager::IdentifierUpdateCallback(
    3107             :         Ip4Address old_identifier) {
    3108        2408 :     CHECK_CONCURRENCY("bgp::Config");
    3109        2408 :     xmpp_server_->ClearAllConnections();
    3110        2408 : }
    3111             : 
    3112       24832 : void BgpXmppChannelManager::RoutingInstanceCallback(string vrf_name, int op) {
    3113       24832 :     CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
    3114       30438 :     BOOST_FOREACH(XmppChannelMap::value_type &i, channel_map_) {
    3115        2803 :         i.second->RoutingInstanceCallback(vrf_name, op);
    3116             :     }
    3117       24833 : }
    3118             : 
    3119         296 : void BgpXmppChannelManager::VisitChannels(BgpXmppChannelManager::VisitorFn fn) {
    3120         296 :     std::scoped_lock lock(mutex_);
    3121         326 :     BOOST_FOREACH(XmppChannelMap::value_type &i, channel_map_) {
    3122          15 :         fn(i.second);
    3123             :     }
    3124         296 : }
    3125             : 
    3126         219 : void BgpXmppChannelManager::VisitChannels(BgpXmppChannelManager::VisitorFn fn)
    3127             :         const {
    3128         219 :     std::scoped_lock lock(mutex_);
    3129         425 :     BOOST_FOREACH(const XmppChannelMap::value_type &i, channel_map_) {
    3130         103 :         fn(i.second);
    3131             :     }
    3132         219 : }
    3133             : 
    3134          21 : BgpXmppChannel *BgpXmppChannelManager::FindChannel(string client) {
    3135          21 :     BOOST_FOREACH(XmppChannelMap::value_type &i, channel_map_) {
    3136          20 :         if (i.second->ToString() == client) {
    3137          20 :             return i.second;
    3138             :         }
    3139             :     }
    3140           1 :     return NULL;
    3141             : }
    3142             : 
    3143          28 : BgpXmppChannel *BgpXmppChannelManager::FindChannel(
    3144             :         const XmppChannel *ch) {
    3145          28 :     XmppChannelMap::iterator it = channel_map_.find(ch);
    3146          28 :     if (it == channel_map_.end())
    3147           0 :         return NULL;
    3148          28 :     return it->second;
    3149             : }
    3150             : 
    3151        6204 : void BgpXmppChannelManager::RemoveChannel(XmppChannel *channel) {
    3152        6204 :     if (channel->connection() && !channel->connection()->IsActiveChannel()) {
    3153        6186 :         CHECK_CONCURRENCY("bgp::Config");
    3154             :     }
    3155        6204 :     channel_map_.erase(channel);
    3156        6204 :     channel_name_map_.erase(channel->ToString());
    3157        6204 : }
    3158             : 
    3159        4007 : BgpXmppChannel *BgpXmppChannelManager::CreateChannel(XmppChannel *channel) {
    3160        4007 :     CHECK_CONCURRENCY("xmpp::StateMachine");
    3161        4006 :     BgpXmppChannel *ch = new BgpXmppChannel(channel, bgp_server_, this);
    3162             : 
    3163        4007 :     return ch;
    3164             : }
    3165             : 
    3166       12868 : void BgpXmppChannelManager::XmppHandleChannelEvent(XmppChannel *channel,
    3167             :                                                    xmps::PeerState state) {
    3168       12868 :     std::scoped_lock lock(mutex_);
    3169             : 
    3170       12872 :     XmppChannelMap::iterator it = channel_map_.find(channel);
    3171       12869 :     BgpXmppChannel *bgp_xmpp_channel = NULL;
    3172       12869 :     if (state == xmps::READY) {
    3173        6298 :         if (it == channel_map_.end()) {
    3174        6194 :             bgp_xmpp_channel = CreateChannel(channel);
    3175        6194 :             channel_map_.insert(make_pair(channel, bgp_xmpp_channel));
    3176        6194 :             channel_name_map_.insert(
    3177       12388 :                 make_pair(channel->ToString(), bgp_xmpp_channel));
    3178        7030 :             BGP_LOG_PEER(Message, bgp_xmpp_channel->Peer(),
    3179             :                          Sandesh::LoggingUtLevel(), BGP_LOG_FLAG_SYSLOG,
    3180             :                          BGP_PEER_DIR_IN,
    3181             :                          "Received XmppChannel up event");
    3182        6194 :             if (!bgp_server_->HasSelfConfiguration()) {
    3183         304 :                 BGP_LOG_PEER(Message, bgp_xmpp_channel->Peer(),
    3184             :                              SandeshLevel::SYS_INFO, BGP_LOG_FLAG_SYSLOG,
    3185             :                              BGP_PEER_DIR_IN,
    3186             :                              "No BGP configuration for self - closing channel");
    3187         296 :                 if (!getenv("CONTRAIL_CAT_FRAMEWORK"))
    3188         296 :                     channel->Close();
    3189             :             }
    3190        6194 :             if (bgp_server_->admin_down()) {
    3191         192 :                 BGP_LOG_PEER(Message, bgp_xmpp_channel->Peer(),
    3192             :                              SandeshLevel::SYS_INFO, BGP_LOG_FLAG_SYSLOG,
    3193             :                              BGP_PEER_DIR_IN,
    3194             :                              "BGP is administratively down - closing channel");
    3195         192 :                 channel->Close();
    3196             :             }
    3197             :         } else {
    3198         104 :             bgp_xmpp_channel = (*it).second;
    3199         104 :             if (bgp_xmpp_channel->peer_deleted())
    3200           0 :                 return;
    3201             : 
    3202             :             // Gracefully close the channel if GR closure is in progress.
    3203             :             // This can happen if GR timers fire just after session comes
    3204             :             // back up.
    3205         208 :             if (bgp_xmpp_channel->close_manager()->IsCloseInProgress() &&
    3206         104 :                 !bgp_xmpp_channel->close_manager()->IsInGRTimerWaitState()) {
    3207           0 :                 BGP_LOG_PEER(Message, bgp_xmpp_channel->Peer(),
    3208             :                              SandeshLevel::SYS_INFO, BGP_LOG_FLAG_SYSLOG,
    3209             :                              BGP_PEER_DIR_IN,
    3210             :                              "Graceful Closure in progress - Closing channel");
    3211           0 :                 channel->Close();
    3212             :             }
    3213         104 :             channel->RegisterReceive(xmps::BGP,
    3214             :                 boost::bind(&BgpXmppChannel::ReceiveUpdate, bgp_xmpp_channel,
    3215             :                             _1));
    3216             :         }
    3217             : 
    3218        6298 :         bgp_xmpp_channel->eor_sent_ = false;
    3219        6298 :         bgp_xmpp_channel->StartEndOfRibReceiveTimer();
    3220        6298 :         bgp_xmpp_channel->ResetEndOfRibSendState();
    3221        6571 :     } else if (state == xmps::NOT_READY) {
    3222        6571 :         if (it != channel_map_.end()) {
    3223        6357 :             bgp_xmpp_channel = (*it).second;
    3224        7359 :             BGP_LOG_PEER(Message, bgp_xmpp_channel->Peer(),
    3225             :                          Sandesh::LoggingUtLevel(), BGP_LOG_FLAG_SYSLOG,
    3226             :                          BGP_PEER_DIR_IN,
    3227             :                          "Received XmppChannel down event");
    3228             : 
    3229             :             // Trigger closure of this channel
    3230        6358 :             bgp_xmpp_channel->Close();
    3231             :         } else {
    3232         214 :             ostringstream os;
    3233         428 :             os << "Peer not found for " << channel->ToString() <<
    3234         214 :                   " on channel down event";
    3235         214 :             BGP_LOG_NOTICE(BgpMessage, BGP_LOG_FLAG_ALL, os.str());
    3236         214 :         }
    3237             :     }
    3238       12872 : }
    3239             : 
    3240         103 : void BgpXmppChannelManager::FillPeerInfo(const BgpXmppChannel *channel) const {
    3241         103 :     PeerStatsInfo stats;
    3242         103 :     PeerStats::FillPeerDebugStats(channel->Peer()->peer_stats(), &stats);
    3243             : 
    3244         206 :     XmppPeerInfoData peer_info;
    3245         103 :     peer_info.set_name(channel->Peer()->ToUVEKey());
    3246         103 :     peer_info.set_peer_stats_info(stats);
    3247         103 :     assert(!peer_info.get_name().empty());
    3248         103 :     BGP_UVE_SEND(XMPPPeerInfo, peer_info);
    3249             : 
    3250         206 :     PeerStatsData peer_stats_data;
    3251         103 :     peer_stats_data.set_name(channel->Peer()->ToUVEKey());
    3252         103 :     peer_stats_data.set_encoding("XMPP");
    3253         103 :     PeerStats::FillPeerUpdateStats(channel->Peer()->peer_stats(),
    3254             :                                    &peer_stats_data);
    3255         103 :     assert(!peer_stats_data.get_name().empty());
    3256         103 :     BGP_UVE_SEND2(PeerStatsUve, peer_stats_data, "ObjectXmppPeerInfo");
    3257         103 : }
    3258             : 
    3259         219 : bool BgpXmppChannelManager::CollectStats(BgpRouterState *state, bool first)
    3260             :          const {
    3261         219 :     CHECK_CONCURRENCY("bgp::ShowCommand");
    3262             : 
    3263         219 :     VisitChannels(boost::bind(&BgpXmppChannelManager::FillPeerInfo, this, _1));
    3264         219 :     bool change = false;
    3265         219 :     uint32_t num_xmpp = count();
    3266         219 :     if (first || num_xmpp != state->get_num_xmpp_peer()) {
    3267          18 :         state->set_num_xmpp_peer(num_xmpp);
    3268          18 :         change = true;
    3269             :     }
    3270             : 
    3271         219 :     uint32_t num_up_xmpp = NumUpPeer();
    3272         219 :     if (first || num_up_xmpp != state->get_num_up_xmpp_peer()) {
    3273          18 :         state->set_num_up_xmpp_peer(num_up_xmpp);
    3274          18 :         change = true;
    3275             :     }
    3276             : 
    3277         219 :     uint32_t num_deleting_xmpp = deleting_count();
    3278         219 :     if (first || num_deleting_xmpp != state->get_num_deleting_xmpp_peer()) {
    3279           3 :         state->set_num_deleting_xmpp_peer(num_deleting_xmpp);
    3280           3 :         change = true;
    3281             :     }
    3282             : 
    3283         219 :     return change;
    3284             : }
    3285             : 
    3286       10173 : void BgpXmppChannel::Close() {
    3287       10173 :     instance_membership_request_map_.clear();
    3288       10173 :     STLDeleteElements(&defer_q_);
    3289             : 
    3290       10173 :     if (table_membership_requests()) {
    3291         158 :         BGP_LOG_PEER(Event, peer_.get(), SandeshLevel::SYS_INFO,
    3292             :             BGP_LOG_FLAG_ALL, BGP_PEER_DIR_NA, "Close procedure deferred");
    3293          90 :         defer_peer_close_ = true;
    3294          90 :         return;
    3295             :     }
    3296       10083 :     peer_->Close(true);
    3297             : }
    3298             : 
    3299             : //
    3300             : // Return connection's remote tcp endpoint if available
    3301             : //
    3302        2740 : TcpSession::Endpoint BgpXmppChannel::remote_endpoint() const {
    3303        2740 :     const XmppSession *session = GetSession();
    3304        2740 :     if (session) {
    3305        2668 :         return session->remote_endpoint();
    3306             :     }
    3307          72 :     return TcpSession::Endpoint();
    3308             : }
    3309             : 
    3310             : //
    3311             : // Return connection's local tcp endpoint if available
    3312             : //
    3313         974 : TcpSession::Endpoint BgpXmppChannel::local_endpoint() const {
    3314         974 :     const XmppSession *session = GetSession();
    3315         974 :     if (session) {
    3316         950 :         return session->local_endpoint();
    3317             :     }
    3318          24 :     return TcpSession::Endpoint();
    3319             : }
    3320             : 
    3321             : //
    3322             : // Return connection's remote tcp endpoint string.
    3323             : //
    3324         974 : string BgpXmppChannel::transport_address_string() const {
    3325         974 :     TcpSession::Endpoint endpoint = remote_endpoint();
    3326         974 :     ostringstream oss;
    3327         974 :     oss << endpoint;
    3328        1948 :     return oss.str();
    3329         974 : }
    3330             : 
    3331             : //
    3332             : // Mark the XmppPeer as deleted.
    3333             : //
    3334       16625 : void BgpXmppChannel::set_peer_closed(bool flag) {
    3335       16625 :     peer_->SetPeerClosed(flag);
    3336       16625 : }
    3337             : 
    3338             : //
    3339             : // Return true if the XmppPeer is deleted.
    3340             : //
    3341       74494 : bool BgpXmppChannel::peer_deleted() const {
    3342       74494 :     return peer_->IsDeleted();
    3343             : }
    3344             : 
    3345             : //
    3346             : // Return time stamp of when the XmppPeer delete was initiated.
    3347             : //
    3348         974 : uint64_t BgpXmppChannel::peer_closed_at() const {
    3349         974 :     return peer_->closed_at();
    3350             : }
    3351             : 
    3352        7549 : bool BgpXmppChannel::IsSubscriptionGrStale(RoutingInstance *instance) const {
    3353             :     SubscribedRoutingInstanceList::const_iterator it =
    3354        7549 :         routing_instances_.find(instance);
    3355        7549 :     assert(it != routing_instances_.end());
    3356       15098 :     return it->second.IsGrStale();
    3357             : }
    3358             : 
    3359        7549 : bool BgpXmppChannel::IsSubscriptionLlgrStale(RoutingInstance *instance) const {
    3360             :     SubscribedRoutingInstanceList::const_iterator it =
    3361        7549 :         routing_instances_.find(instance);
    3362        7549 :     assert(it != routing_instances_.end());
    3363       15098 :     return it->second.IsLlgrStale();
    3364             : }
    3365             : 
    3366       15935 : bool BgpXmppChannel::IsSubscriptionEmpty() const {
    3367       15935 :     return routing_instances_.empty();
    3368             : }
    3369             : 
    3370       14880 : const RoutingInstance::RouteTargetList &BgpXmppChannel::GetSubscribedRTargets(
    3371             :         RoutingInstance *instance) const {
    3372             :     SubscribedRoutingInstanceList::const_iterator it =
    3373       14880 :         routing_instances_.find(instance);
    3374       14880 :     assert(it != routing_instances_.end());
    3375       14880 :     return it->second.targets;
    3376             : }

Generated by: LCOV version 1.14