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

Generated by: LCOV version 1.14